3 sst.py -- Super Star Trek 2K
5 SST2K is a Python translation of a C translation of a FORTRAN
6 original dating back to 1973. Beautiful Python it is not, but it
7 works. Translation by Eric S. Raymond; original game by David Matuszek
8 and Paul Reynolds, with modifications by Don Smith, Tom Almy,
9 Stas Sergeev, and Eric S. Raymond.
11 See the doc/HACKING file in the distribution for designers notes and advice
12 on how to modify (and how not to modify!) this code.
14 import os, sys, math, curses, time, pickle, random, copy, gettext, getpass
15 import getopt, socket, locale
17 # This import only works on Unixes. The intention is to enable
18 # Ctrl-P, Ctrl-N, and friends in Cmd.
24 # Prevent lossage under Python 3
33 docpath = (".", "doc/", "/usr/share/doc/sst/")
36 return gettext.gettext(st)
38 GALSIZE = 8 # Galaxy size in quadrants
39 NINHAB = (GALSIZE * GALSIZE // 2) # Number of inhabited worlds
40 MAXUNINHAB = 10 # Maximum uninhabited worlds
41 QUADSIZE = 10 # Quadrant size in sectors
42 BASEMIN = 2 # Minimum starbases
43 BASEMAX = (GALSIZE * GALSIZE // 12) # Maximum starbases
44 MAXKLGAME = 127 # Maximum Klingons per game
45 MAXKLQUAD = 9 # Maximum Klingons per quadrant
46 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
47 FOREVER = 1e30 # Time for the indefinite future
48 MAXBURST = 3 # Max # of torps you can launch in one turn
49 MINCMDR = 10 # Minimum number of Klingon commanders
50 DOCKFAC = 0.25 # Repair faster when docked
51 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
53 ALGERON = 2311 # Date of the Treaty of Algeron
74 class TrekError(Exception):
77 class JumpOut(Exception):
81 def __init__(self, x=None, y=None):
84 def valid_quadrant(self):
85 return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
86 def valid_sector(self):
87 return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
89 self.i = self.j = None
91 return self.i != None and self.j != None
92 def __eq__(self, other):
93 return other != None and self.i == other.i and self.j == other.j
94 def __ne__(self, other):
95 return other is None or self.i != other.i or self.j != other.j
96 def __add__(self, other):
97 return Coord(self.i+other.i, self.j+other.j)
98 def __sub__(self, other):
99 return Coord(self.i-other.i, self.j-other.j)
100 def __mul__(self, other):
101 return Coord(self.i*other, self.j*other)
102 def __rmul__(self, other):
103 return Coord(self.i*other, self.j*other)
104 def __div__(self, other):
105 return Coord(self.i/other, self.j/other)
106 def __mod__(self, other):
107 return Coord(self.i % other, self.j % other)
108 def __rdiv__(self, other):
109 return Coord(self.i/other, self.j/other)
110 def roundtogrid(self):
111 return Coord(int(round(self.i)), int(round(self.j)))
112 def distance(self, other=None):
115 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
117 return 1.90985*math.atan2(self.j, self.i)
123 s.i = self.i / abs(self.i)
127 s.j = self.j / abs(self.j)
130 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
131 return self.roundtogrid() / QUADSIZE
133 return self.roundtogrid() % QUADSIZE
136 s.i = self.i + randrange(-1, 2)
137 s.j = self.j + randrange(-1, 2)
140 if self.i is None or self.j is None:
142 return "%s - %s" % (self.i+1, self.j+1)
146 "Do not anger the Space Thingy!"
153 return (q.i, q.j) == (self.i, self.j)
157 self.name = None # string-valued if inhabited
158 self.quadrant = Coord() # quadrant located
159 self.pclass = None # could be ""M", "N", "O", or "destroyed"
160 self.crystals = "absent"# could be "mined", "present", "absent"
161 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
162 self.inhabited = False # is it inhabited?
170 self.starbase = False
173 self.supernova = False
175 self.status = "secure" # Could be "secure", "distressed", "enslaved"
180 self.starbase = False
183 return "<%s,%s,%s>" % (self.klingons, self.starbase, self.stars)
185 def fill2d(size, fillfun):
186 "Fill an empty list in 2D."
188 for i in range(size):
190 for j in range(size):
191 lst[i].append(fillfun(i, j))
196 self.snap = False # snapshot taken
197 self.crew = 0 # crew complement
198 self.remkl = 0 # remaining klingons
199 self.nscrem = 0 # remaining super commanders
200 self.starkl = 0 # destroyed stars
201 self.basekl = 0 # destroyed bases
202 self.nromrem = 0 # Romulans remaining
203 self.nplankl = 0 # destroyed uninhabited planets
204 self.nworldkl = 0 # destroyed inhabited planets
205 self.planets = [] # Planet information
206 self.date = 0.0 # stardate
207 self.remres = 0 # remaining resources
208 self.remtime = 0 # remaining time
209 self.baseq = [] # Base quadrant coordinates
210 self.kcmdr = [] # Commander quadrant coordinates
211 self.kscmdr = Coord() # Supercommander quadrant coordinates
213 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
215 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
219 self.date = None # A real number
220 self.quadrant = None # A coord structure
223 OPTION_ALL = 0xffffffff
224 OPTION_TTY = 0x00000001 # old interface
225 OPTION_CURSES = 0x00000002 # new interface
226 OPTION_IOMODES = 0x00000003 # cover both interfaces
227 OPTION_PLANETS = 0x00000004 # planets and mining
228 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
229 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
230 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
231 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
232 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
233 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
234 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
235 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
236 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
237 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
238 OPTION_CAPTURE = 0x00002000 # Enable BSD-Trek capture (Almy, 2013).
239 OPTION_CLOAK = 0x80004000 # Enable BSD-Trek capture (Almy, 2013).
240 OPTION_PLAIN = 0x01000000 # user chose plain game
241 OPTION_ALMY = 0x02000000 # user chose Almy variant
242 OPTION_COLOR = 0x04000000 # enable color display (ESR, 2010)
262 NDEVICES = 17 # Number of devices
272 return (game.damage[dev] != 0.0)
274 return not damaged(DRADIO) or game.condition=="docked"
276 # Define future events
277 FSPY = 0 # Spy event happens always (no future[] entry)
278 # can cause SC to tractor beam Enterprise
279 FSNOVA = 1 # Supernova
280 FTBEAM = 2 # Commander tractor beams Enterprise
281 FSNAP = 3 # Snapshot for time warp
282 FBATTAK = 4 # Commander attacks base
283 FCDBAS = 5 # Commander destroys base
284 FSCMOVE = 6 # Supercommander moves (might attack base)
285 FSCDBAS = 7 # Supercommander destroys base
286 FDSPROB = 8 # Move deep space probe
287 FDISTR = 9 # Emit distress call from an inhabited world
288 FENSLV = 10 # Inhabited word is enslaved */
289 FREPRO = 11 # Klingons build a ship in an enslaved system
292 # Abstract out the event handling -- underlying data structures will change
293 # when we implement stateful events
294 def findevent(evtype):
295 return game.future[evtype]
298 def __init__(self, etype=None, loc=None, power=None):
300 self.location = Coord()
305 self.power = power # enemy energy level
306 game.enemies.append(self)
308 motion = (loc != self.location)
309 if self.location.i is not None and self.location.j is not None:
312 game.quad[self.location.i][self.location.j] = '#'
314 game.quad[self.location.i][self.location.j] = '.'
316 self.location = copy.copy(loc)
317 game.quad[self.location.i][self.location.j] = self.type
318 self.kdist = self.kavgd = (game.sector - loc).distance()
320 self.location = Coord()
321 self.kdist = self.kavgd = None
322 game.enemies.remove(self)
325 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
329 self.options = None # Game options
330 self.state = Snapshot() # A snapshot structure
331 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
332 self.quad = None # contents of our quadrant
333 self.damage = [0.0] * NDEVICES # damage encountered
334 self.future = [] # future events
338 self.future.append(Event())
339 self.passwd = None # Self Destruct password
341 self.quadrant = None # where we are in the large
342 self.sector = None # where we are in the small
343 self.tholian = None # Tholian enemy object
344 self.base = None # position of base in current quadrant
345 self.battle = None # base coordinates being attacked
346 self.plnet = None # location of planet in quadrant
347 self.gamewon = False # Finished!
348 self.ididit = False # action taken -- allows enemy to attack
349 self.alive = False # we are alive (not killed)
350 self.justin = False # just entered quadrant
351 self.shldup = False # shields are up
352 self.shldchg = False # shield is changing (affects efficiency)
353 self.iscate = False # super commander is here
354 self.ientesc = False # attempted escape from supercommander
355 self.resting = False # rest time
356 self.icraft = False # Kirk in Galileo
357 self.landed = False # party on planet (true), on ship (false)
358 self.alldone = False # game is now finished
359 self.neutz = False # Romulan Neutral Zone
360 self.isarmed = False # probe is armed
361 self.inorbit = False # orbiting a planet
362 self.imine = False # mining
363 self.icrystl = False # dilithium crystals aboard
364 self.iseenit = False # seen base attack report
365 self.thawed = False # thawed game
366 self.condition = None # "green", "yellow", "red", "docked", "dead"
367 self.iscraft = None # "onship", "offship", "removed"
368 self.skill = None # Player skill level
369 self.inkling = 0 # initial number of klingons
370 self.inbase = 0 # initial number of bases
371 self.incom = 0 # initial number of commanders
372 self.inscom = 0 # initial number of commanders
373 self.inrom = 0 # initial number of commanders
374 self.instar = 0 # initial stars
375 self.intorps = 0 # initial/max torpedoes
376 self.torps = 0 # number of torpedoes
377 self.ship = 0 # ship type -- 'E' is Enterprise
378 self.abandoned = 0 # count of crew abandoned in space
379 self.length = 0 # length of game
380 self.klhere = 0 # klingons here
381 self.casual = 0 # causalties
382 self.nhelp = 0 # calls for help
383 self.nkinks = 0 # count of energy-barrier crossings
384 self.iplnet = None # planet # in quadrant
385 self.inplan = 0 # initial planets
386 self.irhere = 0 # Romulans in quadrant
387 self.isatb = 0 # =2 if super commander is attacking base
388 self.tourn = None # tournament number
389 self.nprobes = 0 # number of probes available
390 self.inresor = 0.0 # initial resources
391 self.intime = 0.0 # initial time
392 self.inenrg = 0.0 # initial/max energy
393 self.inshld = 0.0 # initial/max shield
394 self.inlsr = 0.0 # initial life support resources
395 self.indate = 0.0 # initial date
396 self.energy = 0.0 # energy level
397 self.shield = 0.0 # shield level
398 self.warpfac = 0.0 # warp speed
399 self.lsupres = 0.0 # life support reserves
400 self.optime = 0.0 # time taken by current operation
401 self.damfac = 0.0 # damage factor
402 self.lastchart = 0.0 # time star chart was last updated
403 self.cryprob = 0.0 # probability that crystal will work
404 self.probe = None # object holding probe course info
405 self.height = 0.0 # height of orbit around planet
406 self.score = 0.0 # overall score
407 self.perdate = 0.0 # rate of kills
408 self.idebug = False # Debugging instrumentation enabled?
409 self.statekscmdr = None # No SuperCommander coordinates yet.
410 self.brigcapacity = 400 # Enterprise brig capacity
411 self.brigfree = 400 # How many klingons can we put in the brig?
412 self.kcaptured = 0 # Total Klingons captured, for scoring.
413 self.iscloaked = False # Cloaking device on?
414 self.ncviol = 0 # Algreon treaty violations
415 self.isviolreported = False # We have been warned
417 # Stas thinks this should be (C expression):
418 # game.state.remkl + len(game.state.kcmdr) > 0 ?
419 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
420 # He says the existing expression is prone to divide-by-zero errors
421 # after killing the last klingon when score is shown -- perhaps also
422 # if the only remaining klingon is SCOM.
423 self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.state.kcmdr))
450 return random.random() < p
452 def randrange(*args):
453 return random.randrange(*args)
458 v *= args[0] # from [0, args[0])
460 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
463 # Code from ai.c begins here
466 "Would this quadrant welcome another Klingon?"
467 return iq.valid_quadrant() and \
468 not game.state.galaxy[iq.i][iq.j].supernova and \
469 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
471 def tryexit(enemy, look, irun):
472 "A bad guy attempts to bug out."
474 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
475 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
476 if not welcoming(iq):
478 if enemy.type == 'R':
479 return False # Romulans cannot escape!
481 # avoid intruding on another commander's territory
482 if enemy.type == 'C':
483 if iq in game.state.kcmdr:
485 # refuse to leave if currently attacking starbase
486 if game.battle == game.quadrant:
488 # don't leave if over 1000 units of energy
489 if enemy.power > 1000.0:
491 oldloc = copy.copy(enemy.location)
492 # handle local matters related to escape
495 if game.condition != "docked":
497 # Handle global matters related to escape
498 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
499 game.state.galaxy[iq.i][iq.j].klingons += 1
500 if enemy.type == 'S':
504 schedule(FSCMOVE, 0.2777)
506 game.state.kscmdr = iq
508 for cmdr in game.state.kcmdr:
509 if cmdr == game.quadrant:
510 game.state.kcmdr.append(iq)
512 # report move out of quadrant.
513 return [(True, enemy, oldloc, iq)]
515 # The bad-guy movement algorithm:
517 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
518 # If both are operating full strength, force is 1000. If both are damaged,
519 # force is -1000. Having shields down subtracts an additional 1000.
521 # 2. Enemy has forces equal to the energy of the attacker plus
522 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
523 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
525 # Attacker Initial energy levels (nominal):
526 # Klingon Romulan Commander Super-Commander
527 # Novice 400 700 1200
529 # Good 450 800 1300 1750
530 # Expert 475 850 1350 1875
531 # Emeritus 500 900 1400 2000
532 # VARIANCE 75 200 200 200
534 # Enemy vessels only move prior to their attack. In Novice - Good games
535 # only commanders move. In Expert games, all enemy vessels move if there
536 # is a commander present. In Emeritus games all enemy vessels move.
538 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
539 # forces are 1000 greater than Enterprise.
541 # Agressive action on average cuts the distance between the ship and
542 # the enemy to 1/4 the original.
544 # 4. At lower energy advantage, movement units are proportional to the
545 # advantage with a 650 advantage being to hold ground, 800 to move forward
546 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
548 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
549 # retreat, especially at high skill levels.
551 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
553 def movebaddy(enemy):
554 "Tactical movement for the bad guys."
558 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
559 if game.skill >= SKILL_EXPERT:
560 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
562 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
563 old_dist = enemy.kdist
564 mdist = int(old_dist + 0.5) # Nearest integer distance
565 # If SC, check with spy to see if should hi-tail it
566 if enemy.type == 'S' and \
567 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
571 # decide whether to advance, retreat, or hold position
572 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
574 forces += 1000 # Good for enemy if shield is down!
575 if not damaged(DPHASER) or not damaged(DPHOTON):
576 if damaged(DPHASER): # phasers damaged
579 forces -= 0.2*(game.energy - 2500.0)
580 if damaged(DPHOTON): # photon torpedoes damaged
583 forces -= 50.0*game.torps
585 # phasers and photon tubes both out!
588 if forces <= 1000.0 and game.condition != "docked": # Typical situation
589 motion = ((forces + randreal(200))/150.0) - 5.0
591 if forces > 1000.0: # Very strong -- move in for kill
592 motion = (1.0 - randreal())**2 * old_dist + 1.0
593 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
594 motion -= game.skill*(2.0-randreal()**2)
596 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
597 # don't move if no motion
600 # Limit motion according to skill
601 if abs(motion) > game.skill:
606 # calculate preferred number of steps
607 nsteps = abs(int(motion))
608 if motion > 0 and nsteps > mdist:
609 nsteps = mdist # don't overshoot
610 if nsteps > QUADSIZE:
611 nsteps = QUADSIZE # This shouldn't be necessary
613 nsteps = 1 # This shouldn't be necessary
615 proutn("NSTEPS = %d:" % nsteps)
616 # Compute preferred values of delta X and Y
617 m = game.sector - enemy.location
618 if 2.0 * abs(m.i) < abs(m.j):
620 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
622 m = (motion * m).sgn()
623 goto = enemy.location
625 for ll in range(nsteps):
627 proutn(" %d" % (ll+1))
628 # Check if preferred position available
639 attempts = 0 # Settle mysterious hang problem
640 while attempts < 20 and not success:
642 if look.i < 0 or look.i >= QUADSIZE:
644 return tryexit(enemy, look, irun)
645 if krawli == m.i or m.j == 0:
647 look.i = goto.i + krawli
649 elif look.j < 0 or look.j >= QUADSIZE:
651 return tryexit(enemy, look, irun)
652 if krawlj == m.j or m.i == 0:
654 look.j = goto.j + krawlj
656 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
657 # See if enemy should ram ship
658 if game.quad[look.i][look.j] == game.ship and \
659 (enemy.type == 'C' or enemy.type == 'S'):
660 collision(rammed=True, enemy=enemy)
662 if krawli != m.i and m.j != 0:
663 look.i = goto.i + krawli
665 elif krawlj != m.j and m.i != 0:
666 look.j = goto.j + krawlj
669 break # we have failed
680 # Enemy moved, but is still in sector
681 return [(False, enemy, old_dist, goto)]
684 "Sequence Klingon tactical movement."
687 # Figure out which Klingon is the commander (or Supercommander)
690 if game.quadrant in game.state.kcmdr:
691 for enemy in game.enemies:
692 if enemy.type == 'C':
693 tacmoves += movebaddy(enemy)
694 if game.state.kscmdr == game.quadrant:
695 for enemy in game.enemies:
696 if enemy.type == 'S':
697 tacmoves += movebaddy(enemy)
699 # If skill level is high, move other Klingons and Romulans too!
700 # Move these last so they can base their actions on what the
702 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
703 for enemy in game.enemies:
704 if enemy.type in ('K', 'R'):
705 tacmoves += movebaddy(enemy)
708 def movescom(iq, avoid):
709 "Commander movement helper."
710 # Avoid quadrants with bases if we want to avoid Enterprise
711 if not welcoming(iq) or (avoid and iq in game.state.baseq):
713 if game.justin and not game.iscate:
716 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
717 game.state.kscmdr = iq
718 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
719 if game.state.kscmdr == game.quadrant:
720 # SC has scooted, remove him from current quadrant
725 for enemy in game.enemies:
726 if enemy.type == 'S':
729 if game.condition != "docked":
732 # check for a helpful planet
733 for i in range(game.inplan):
734 if game.state.planets[i].quadrant == game.state.kscmdr and \
735 game.state.planets[i].crystals == "present":
737 game.state.planets[i].pclass = "destroyed"
738 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
741 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
742 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
743 prout(_(" by the Super-commander.\""))
745 return True # looks good!
747 def supercommander():
748 "Move the Super Commander."
755 prout("== SUPERCOMMANDER")
756 # Decide on being active or passive
757 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 \
758 (game.state.date-game.indate) < 3.0)
759 if not game.iscate and avoid:
760 # compute move away from Enterprise
761 idelta = game.state.kscmdr-game.quadrant
762 if idelta.distance() > 2.0:
764 idelta.i = game.state.kscmdr.j-game.quadrant.j
765 idelta.j = game.quadrant.i-game.state.kscmdr.i
767 # compute distances to starbases
768 if not game.state.baseq:
772 sc = game.state.kscmdr
773 for (i, base) in enumerate(game.state.baseq):
774 basetbl.append((i, (base - sc).distance()))
775 if game.state.baseq > 1:
776 basetbl.sort(key=lambda x: x[1])
777 # look for nearest base without a commander, no Enterprise, and
778 # without too many Klingons, and not already under attack.
779 ifindit = iwhichb = 0
780 for (i2, base) in enumerate(game.state.baseq):
781 i = basetbl[i2][0] # bug in original had it not finding nearest
782 if base == game.quadrant or base == game.battle or not welcoming(base):
784 # if there is a commander, and no other base is appropriate,
785 # we will take the one with the commander
786 for cmdr in game.state.kcmdr:
787 if base == cmdr and ifindit != 2:
791 else: # no commander -- use this one
796 return # Nothing suitable -- wait until next time
797 ibq = game.state.baseq[iwhichb]
798 # decide how to move toward base
799 idelta = ibq - game.state.kscmdr
800 # Maximum movement is 1 quadrant in either or both axes
801 idelta = idelta.sgn()
802 # try moving in both x and y directions
803 # there was what looked like a bug in the Almy C code here,
804 # but it might be this translation is just wrong.
805 iq = game.state.kscmdr + idelta
806 if not movescom(iq, avoid):
807 # failed -- try some other maneuvers
808 if idelta.i == 0 or idelta.j == 0:
811 iq.j = game.state.kscmdr.j + 1
812 if not movescom(iq, avoid):
813 iq.j = game.state.kscmdr.j - 1
816 iq.i = game.state.kscmdr.i + 1
817 if not movescom(iq, avoid):
818 iq.i = game.state.kscmdr.i - 1
821 # try moving just in x or y
822 iq.j = game.state.kscmdr.j
823 if not movescom(iq, avoid):
824 iq.j = game.state.kscmdr.j + idelta.j
825 iq.i = game.state.kscmdr.i
828 if len(game.state.baseq) == 0:
831 for ibq in game.state.baseq:
832 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
835 return # no, don't attack base!
838 schedule(FSCDBAS, randreal(1.0, 3.0))
839 if is_scheduled(FCDBAS):
840 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
841 if not communicating():
845 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
847 prout(_(" reports that it is under attack from the Klingon Super-commander."))
848 proutn(_(" It can survive until stardate %d.\"") \
849 % int(scheduled(FSCDBAS)))
852 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
856 game.optime = 0.0 # actually finished
858 # Check for intelligence report
859 if not game.idebug and \
861 (not communicating()) or \
862 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
865 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
866 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
871 if not game.tholian or game.justin:
874 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
877 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
880 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
883 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
887 # something is wrong!
888 game.tholian.move(None)
889 prout("***Internal error: Tholian in a bad spot.")
891 # do nothing if we are blocked
892 if game.quad[tid.i][tid.j] not in ('.', '#'):
894 here = copy.copy(game.tholian.location)
895 delta = (tid - game.tholian.location).sgn()
897 while here.i != tid.i:
899 if game.quad[here.i][here.j] == '.':
900 game.tholian.move(here)
902 while here.j != tid.j:
904 if game.quad[here.i][here.j] == '.':
905 game.tholian.move(here)
906 # check to see if all holes plugged
907 for i in range(QUADSIZE):
908 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
910 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
912 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
914 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
916 # All plugged up -- Tholian splits
917 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
919 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
920 game.tholian.move(None)
923 # Code from battle.c begins here
926 "Change cloaking-device status."
928 prout(_("Ye Faerie Queene hath no cloaking device."));
931 key = scanner.nexttok()
938 if scanner.sees("on"):
940 prout(_("The cloaking device has already been switched on."))
943 elif scanner.sees("off"):
944 if not game.iscloaked:
945 prout(_("The cloaking device has already been switched off."))
952 if not game.iscloaked:
953 proutn(_("Switch cloaking device on? "))
958 proutn(_("Switch cloaking device off? "))
965 if action == "CLOFF":
966 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
967 prout(_("Spock- \"Captain, the Treaty of Algeron is in effect.\n Are you sure this is wise?\""))
970 prout("Engineer Scott- \"Aye, Sir.\"");
971 game.iscloaked = False;
972 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
973 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
975 game.isviolreported = True
977 #if (neutz and game.state.date >= ALGERON) finish(FCLOAK);
982 prout(_("Engineer Scott- \"The cloaking device is damaged, Sir.\""))
985 if game.condition == "docked":
986 prout(_("You cannot cloak while docked."))
988 if game.state.date >= ALGERON and not game.isviolreported:
989 prout(_("Spock- \"Captain, using the cloaking device is a violation"))
990 prout(_(" of the Treaty of Algeron. Considering the alternatives,"))
991 proutn(_(" are you sure this is wise? "))
994 prout(_("Engineer Scott- \"Cloaking device has engaging, Sir...\""))
996 prout(_("Engineer Scott- \"Cloaking device has engaged, Sir.\""))
997 game.iscloaked = True
999 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
1000 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
1002 game.isviolreported = True
1004 def doshield(shraise):
1005 "Change shield status."
1011 key = scanner.nexttok()
1012 if key == "IHALPHA":
1013 if scanner.sees("transfer"):
1016 if damaged(DSHIELD):
1017 prout(_("Shields damaged and down."))
1019 if scanner.sees("up"):
1021 elif scanner.sees("down"):
1023 if action == "NONE":
1024 proutn(_("Do you wish to change shield energy? "))
1027 elif damaged(DSHIELD):
1028 prout(_("Shields damaged and down."))
1031 proutn(_("Shields are up. Do you want them down? "))
1038 proutn(_("Shields are down. Do you want them up? "))
1044 if action == "SHUP": # raise shields
1046 prout(_("Shields already up."))
1050 if game.condition != "docked":
1052 prout(_("Shields raised."))
1053 if game.energy <= 0:
1055 prout(_("Shields raising uses up last of energy."))
1060 elif action == "SHDN":
1062 prout(_("Shields already down."))
1066 prout(_("Shields lowered."))
1069 elif action == "NRG":
1070 while scanner.nexttok() != "IHREAL":
1072 proutn(_("Energy to transfer to shields- "))
1077 if nrg > game.energy:
1078 prout(_("Insufficient ship energy."))
1081 if game.shield+nrg >= game.inshld:
1082 prout(_("Shield energy maximized."))
1083 if game.shield+nrg > game.inshld:
1084 prout(_("Excess energy requested returned to ship energy"))
1085 game.energy -= game.inshld-game.shield
1086 game.shield = game.inshld
1088 if nrg < 0.0 and game.energy-nrg > game.inenrg:
1089 # Prevent shield drain loophole
1091 prout(_("Engineering to bridge--"))
1092 prout(_(" Scott here. Power circuit problem, Captain."))
1093 prout(_(" I can't drain the shields."))
1096 if game.shield+nrg < 0:
1097 prout(_("All shield energy transferred to ship."))
1098 game.energy += game.shield
1101 proutn(_("Scotty- \""))
1103 prout(_("Transferring energy to shields.\""))
1105 prout(_("Draining energy from shields.\""))
1111 "Choose a device to damage, at random."
1113 105, # DSRSENS: short range scanners 10.5%
1114 105, # DLRSENS: long range scanners 10.5%
1115 120, # DPHASER: phasers 12.0%
1116 120, # DPHOTON: photon torpedoes 12.0%
1117 25, # DLIFSUP: life support 2.5%
1118 65, # DWARPEN: warp drive 6.5%
1119 70, # DIMPULS: impulse engines 6.5%
1120 145, # DSHIELD: deflector shields 14.5%
1121 30, # DRADIO: subspace radio 3.0%
1122 45, # DSHUTTL: shuttle 4.5%
1123 15, # DCOMPTR: computer 1.5%
1124 20, # NAVCOMP: navigation system 2.0%
1125 75, # DTRANSP: transporter 7.5%
1126 20, # DSHCTRL: high-speed shield controller 2.0%
1127 10, # DDRAY: death ray 1.0%
1128 30, # DDSP: deep-space probes 3.0%
1129 0, # DCLOAK: the cloaking device 0.0
1131 assert(sum(weights) == 1000)
1132 idx = randrange(1000)
1134 for (i, w) in enumerate(weights):
1138 return None # we should never get here
1140 def collision(rammed, enemy):
1141 "Collision handling for rammong events."
1142 prouts(_("***RED ALERT! RED ALERT!"))
1144 prout(_("***COLLISION IMMINENT."))
1148 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1150 proutn(_(" rammed by "))
1153 proutn(crmena(False, enemy.type, "sector", enemy.location))
1155 proutn(_(" (original position)"))
1157 deadkl(enemy.location, enemy.type, game.sector)
1158 proutn("***" + crmshp() + " heavily damaged.")
1159 icas = randrange(10, 30)
1160 prout(_("***Sickbay reports %d casualties") % icas)
1162 game.state.crew -= icas
1163 # In the pre-SST2K version, all devices got equiprobably damaged,
1164 # which was silly. Instead, pick up to half the devices at
1165 # random according to our weighting table,
1166 ncrits = randrange(NDEVICES/2)
1170 if game.damage[dev] < 0:
1172 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1173 # Damage for at least time of travel!
1174 game.damage[dev] += game.optime + extradm
1176 prout(_("***Shields are down."))
1177 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1184 def torpedo(origin, bearing, dispersion, number, nburst):
1185 "Let a photon torpedo fly"
1186 if not damaged(DSRSENS) or game.condition == "docked":
1187 setwnd(srscan_window)
1189 setwnd(message_window)
1190 ac = bearing + 0.25*dispersion # dispersion is a random variable
1191 bullseye = (15.0 - bearing)*0.5235988
1192 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1193 bumpto = Coord(0, 0)
1194 # Loop to move a single torpedo
1195 setwnd(message_window)
1196 for step in range(1, QUADSIZE*2):
1197 if not track.nexttok():
1200 if not w.valid_sector():
1202 iquad = game.quad[w.i][w.j]
1203 tracktorpedo(w, step, number, nburst, iquad)
1207 setwnd(message_window)
1208 if not damaged(DSRSENS) or game.condition == "docked":
1209 skip(1) # start new line after text track
1210 if iquad in ('E', 'F'): # Hit our ship
1212 prout(_("Torpedo hits %s.") % crmshp())
1213 hit = 700.0 + randreal(100) - \
1214 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1215 newcnd() # we're blown out of dock
1216 if game.landed or game.condition == "docked":
1217 return hit # Cheat if on a planet
1218 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1219 # is 143 degrees, which is almost exactly 4.8 clockface units
1220 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1221 displacement.nexttok()
1222 bumpto = displacement.sector()
1223 if not bumpto.valid_sector():
1225 if game.quad[bumpto.i][bumpto.j] == ' ':
1228 if game.quad[bumpto.i][bumpto.j] != '.':
1229 # can't move into object
1231 game.sector = bumpto
1233 game.quad[w.i][w.j] = '.'
1234 game.quad[bumpto.i][bumpto.j] = iquad
1235 prout(_(" displaced by blast to Sector %s ") % bumpto)
1236 for enemy in game.enemies:
1237 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1240 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1242 if iquad in ('C', 'S') and withprob(0.05):
1243 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1244 prout(_(" torpedo neutralized."))
1246 for enemy in game.enemies:
1247 if w == enemy.location:
1248 kp = math.fabs(enemy.power)
1249 h1 = 700.0 + randrange(100) - \
1250 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1258 if enemy.power == 0:
1261 proutn(crmena(True, iquad, "sector", w))
1262 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1263 displacement.nexttok()
1264 bumpto = displacement.sector()
1265 if not bumpto.valid_sector():
1266 prout(_(" damaged but not destroyed."))
1268 if game.quad[bumpto.i][bumpto.j] == ' ':
1269 prout(_(" buffeted into black hole."))
1270 deadkl(w, iquad, bumpto)
1271 if game.quad[bumpto.i][bumpto.j] != '.':
1272 prout(_(" damaged but not destroyed."))
1274 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1275 enemy.location = bumpto
1276 game.quad[w.i][w.j] = '.'
1277 game.quad[bumpto.i][bumpto.j] = iquad
1278 for enemy in game.enemies:
1279 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1283 prout("Internal error, no enemy where expected!")
1286 elif iquad == 'B': # Hit a base
1288 prout(_("***STARBASE DESTROYED.."))
1289 game.state.baseq = [x for x in game.state.baseq if x != game.quadrant]
1290 game.quad[w.i][w.j] = '.'
1291 game.base.invalidate()
1292 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
1293 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = False
1294 game.state.basekl += 1
1297 elif iquad == 'P': # Hit a planet
1298 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1299 game.state.nplankl += 1
1300 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1301 game.iplnet.pclass = "destroyed"
1303 game.plnet.invalidate()
1304 game.quad[w.i][w.j] = '.'
1306 # captain perishes on planet
1309 elif iquad == '@': # Hit an inhabited world -- very bad!
1310 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1311 game.state.nworldkl += 1
1312 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1313 game.iplnet.pclass = "destroyed"
1315 game.plnet.invalidate()
1316 game.quad[w.i][w.j] = '.'
1318 # captain perishes on planet
1320 prout(_("The torpedo destroyed an inhabited planet."))
1322 elif iquad == '*': # Hit a star
1326 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1328 elif iquad == '?': # Hit a thingy
1329 if not (game.options & OPTION_THINGY) or withprob(0.3):
1331 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1333 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1335 proutn(_("Mr. Spock-"))
1336 prouts(_(" \"Fascinating!\""))
1340 # Stas Sergeev added the possibility that
1341 # you can shove the Thingy and piss it off.
1342 # It then becomes an enemy and may fire at you.
1345 elif iquad == ' ': # Black hole
1347 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1349 elif iquad == '#': # hit the web
1351 prout(_("***Torpedo absorbed by Tholian web."))
1353 elif iquad == 'T': # Hit a Tholian
1354 h1 = 700.0 + randrange(100) - \
1355 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1358 game.quad[w.i][w.j] = '.'
1363 proutn(crmena(True, 'T', "sector", w))
1365 prout(_(" survives photon blast."))
1367 prout(_(" disappears."))
1368 game.tholian.move(None)
1369 game.quad[w.i][w.j] = '#'
1374 proutn("Don't know how to handle torpedo collision with ")
1375 proutn(crmena(True, iquad, "sector", w))
1380 setwnd(message_window)
1381 prout(_("Torpedo missed."))
1385 "Critical-hit resolution."
1386 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1388 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1389 proutn(_("***CRITICAL HIT--"))
1390 # Select devices and cause damage
1395 # Cheat to prevent shuttle damage unless on ship
1396 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship") or (j == DCLOAK and game.ship != 'E' or j == DDRAY)):
1399 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1400 game.damage[j] += extradm
1403 for (i, j) in enumerate(cdam):
1405 if skipcount % 3 == 2 and i < len(cdam)-1:
1410 prout(_(" damaged."))
1411 if damaged(DSHIELD) and game.shldup:
1412 prout(_("***Shields knocked down."))
1414 if damaged(DCLOAK) and game.iscloaked:
1415 prout(_("***Cloaking device rendered inoperative."))
1416 game.iscloaked = False
1418 def attack(torps_ok):
1419 # bad guy attacks us
1420 # torps_ok == False forces use of phasers in an attack
1423 # game could be over at this point, check
1433 prout("=== ATTACK!")
1434 # Tholian gets to move before attacking
1437 # if you have just entered the RNZ, you'll get a warning
1438 if game.neutz: # The one chance not to be attacked
1441 # commanders get a chance to tac-move towards you
1442 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:
1443 for (bugout, enemy, old, goto) in moveklings():
1445 # we know about this if either short or long range
1446 # sensors are working
1447 if damaged(DSRSENS) and damaged(DLRSENS) \
1448 and game.condition != "docked":
1449 prout(crmena(True, enemy.type, "sector", old) + \
1450 (_(" escapes to Quadrant %s (and regains strength).") % goto))
1451 else: # Enemy still in-sector
1452 if enemy.move(goto):
1453 if not damaged(DSRSENS) or game.condition == "docked":
1454 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
1455 if enemy.kdist < old:
1456 proutn(_(" advances to "))
1458 proutn(_(" retreats to "))
1459 prout("Sector %s." % goto)
1461 # if no enemies remain after movement, we're done
1462 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered):
1464 # set up partial hits if attack happens during shield status change
1465 pfac = 1.0/game.inshld
1467 chgfac = 0.25 + randreal(0.5)
1469 # message verbosity control
1470 if game.skill <= SKILL_FAIR:
1472 for enemy in game.enemies:
1474 continue # too weak to attack
1475 # compute hit strength and diminish shield power
1477 # Increase chance of photon torpedos if docked or enemy energy is low
1478 if game.condition == "docked":
1480 if enemy.power < 500:
1482 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1484 # different enemies have different probabilities of throwing a torp
1485 usephasers = not torps_ok or \
1486 (enemy.type == 'K' and r > 0.0005) or \
1487 (enemy.type == 'C' and r > 0.015) or \
1488 (enemy.type == 'R' and r > 0.3) or \
1489 (enemy.type == 'S' and r > 0.07) or \
1490 (enemy.type == '?' and r > 0.05)
1491 if usephasers: # Enemy uses phasers
1492 if game.condition == "docked":
1493 continue # Don't waste the effort!
1494 attempt = True # Attempt to attack
1495 dustfac = randreal(0.8, 0.85)
1496 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1498 else: # Enemy uses photon torpedo
1499 # We should be able to make the bearing() method work here
1500 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1502 proutn(_("***TORPEDO INCOMING"))
1503 if not damaged(DSRSENS):
1504 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1507 dispersion = (randreal()+randreal())*0.5 - 0.5
1508 dispersion += 0.002*enemy.power*dispersion
1509 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1510 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1511 finish(FWON) # Klingons did themselves in!
1512 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1513 return # Supernova or finished
1516 # incoming phaser or torpedo, shields may dissipate it
1517 if game.shldup or game.shldchg or game.condition == "docked":
1518 # shields will take hits
1519 propor = pfac * game.shield
1520 if game.condition == "docked":
1524 hitsh = propor*chgfac*hit+1.0
1526 if absorb > game.shield:
1527 absorb = game.shield
1528 game.shield -= absorb
1530 # taking a hit blasts us out of a starbase dock
1531 if game.condition == "docked":
1533 # but the shields may take care of it
1534 if propor > 0.1 and hit < 0.005*game.energy:
1536 # hit from this opponent got through shields, so take damage
1538 proutn(_("%d unit hit") % int(hit))
1539 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1540 proutn(_(" on the ") + crmshp())
1541 if not damaged(DSRSENS) and usephasers:
1542 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1544 # Decide if hit is critical
1550 if game.energy <= 0:
1551 # Returning home upon your shield, not with it...
1554 if not attempt and game.condition == "docked":
1555 prout(_("***Enemies decide against attacking your ship."))
1556 percent = 100.0*pfac*game.shield+0.5
1558 # Shields fully protect ship
1559 proutn(_("Enemy attack reduces shield strength to "))
1561 # Emit message if starship suffered hit(s)
1563 proutn(_("Energy left %2d shields ") % int(game.energy))
1566 elif not damaged(DSHIELD):
1569 proutn(_("damaged, "))
1570 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1571 # Check if anyone was hurt
1572 if hitmax >= 200 or hittot >= 500:
1573 icas = randrange(int(hittot * 0.015))
1576 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1577 prout(_(" in that last attack.\""))
1579 game.state.crew -= icas
1580 # After attack, reset average distance to enemies
1581 for enemy in game.enemies:
1582 enemy.kavgd = enemy.kdist
1586 def deadkl(w, etype, mv):
1587 "Kill a Klingon, Tholian, Romulan, or Thingy."
1588 # Added mv to allow enemy to "move" before dying
1589 proutn(crmena(True, etype, "sector", mv))
1590 # Decide what kind of enemy it is and update appropriately
1592 # Chalk up a Romulan
1593 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1595 game.state.nromrem -= 1
1604 # Killed some type of Klingon
1605 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1608 game.state.kcmdr.remove(game.quadrant)
1610 if game.state.kcmdr:
1611 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1612 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1615 game.state.remkl -= 1
1617 game.state.nscrem -= 1
1618 game.state.kscmdr.invalidate()
1623 # For each kind of enemy, finish message to player
1624 prout(_(" destroyed."))
1625 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1628 # Remove enemy ship from arrays describing local conditions
1629 for e in game.enemies:
1636 "Return None if target is invalid, otherwise return a course angle."
1637 if not w.valid_sector():
1641 # C code this was translated from is wacky -- why the sign reversal?
1642 delta.j = (w.j - game.sector.j)
1643 delta.i = (game.sector.i - w.i)
1644 if delta == Coord(0, 0):
1646 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1647 prout(_(" I recommend an immediate review of"))
1648 prout(_(" the Captain's psychological profile.\""))
1651 return delta.bearing()
1654 "Launch photon torpedo salvo."
1657 if damaged(DPHOTON):
1658 prout(_("Photon tubes damaged."))
1662 prout(_("No torpedoes left."))
1665 # First, get torpedo count
1668 if scanner.token == "IHALPHA":
1671 elif scanner.token == "IHEOL" or not scanner.waiting():
1672 prout(_("%d torpedoes left.") % game.torps)
1674 proutn(_("Number of torpedoes to fire- "))
1675 continue # Go back around to get a number
1676 else: # key == "IHREAL"
1678 if n <= 0: # abort command
1683 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1686 scanner.chew() # User requested more torps than available
1687 continue # Go back around
1688 break # All is good, go to next stage
1692 key = scanner.nexttok()
1693 if i == 0 and key == "IHEOL":
1694 break # no coordinate waiting, we will try prompting
1695 if i == 1 and key == "IHEOL":
1696 # direct all torpedoes at one target
1698 target.append(target[0])
1699 tcourse.append(tcourse[0])
1702 scanner.push(scanner.token)
1703 target.append(scanner.getcoord())
1704 if target[-1] is None:
1706 tcourse.append(targetcheck(target[-1]))
1707 if tcourse[-1] is None:
1710 if len(target) == 0:
1711 # prompt for each one
1713 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1715 target.append(scanner.getcoord())
1716 if target[-1] is None:
1718 tcourse.append(targetcheck(target[-1]))
1719 if tcourse[-1] is None:
1722 # Loop for moving <n> torpedoes
1724 if game.condition != "docked":
1726 dispersion = (randreal()+randreal())*0.5 -0.5
1727 if math.fabs(dispersion) >= 0.47:
1729 dispersion *= randreal(1.2, 2.2)
1731 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1733 prouts(_("***TORPEDO MISFIRES."))
1736 prout(_(" Remainder of burst aborted."))
1738 prout(_("***Photon tubes damaged by misfire."))
1739 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1743 elif game.shldup or game.condition == "docked":
1744 dispersion *= 1.0 + 0.0001*game.shield
1745 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1746 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1748 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1752 "Check for phasers overheating."
1754 checkburn = (rpow-1500.0)*0.00038
1755 if withprob(checkburn):
1756 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1757 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1759 def checkshctrl(rpow):
1760 "Check shield control."
1763 prout(_("Shields lowered."))
1765 # Something bad has happened
1766 prouts(_("***RED ALERT! RED ALERT!"))
1768 hit = rpow*game.shield/game.inshld
1769 game.energy -= rpow+hit*0.8
1770 game.shield -= hit*0.2
1771 if game.energy <= 0.0:
1772 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1777 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1779 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1780 icas = randrange(int(hit*0.012))
1785 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1786 prout(_(" %d casualties so far.\"") % icas)
1788 game.state.crew -= icas
1790 prout(_("Phaser energy dispersed by shields."))
1791 prout(_("Enemy unaffected."))
1796 "Register a phaser hit on Klingons and Romulans."
1803 dustfac = randreal(0.9, 1.0)
1804 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1805 kpini = game.enemies[kk].power
1806 kp = math.fabs(kpini)
1807 if PHASEFAC*hit < kp:
1809 if game.enemies[kk].power < 0:
1810 game.enemies[kk].power -= -kp
1812 game.enemies[kk].power -= kp
1813 kpow = game.enemies[kk].power
1814 w = game.enemies[kk].location
1816 if not damaged(DSRSENS):
1818 proutn(_("%d unit hit on ") % int(hit))
1820 proutn(_("Very small hit on "))
1821 ienm = game.quad[w.i][w.j]
1824 proutn(crmena(False, ienm, "sector", w))
1828 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1832 kk -= 1 # don't do the increment
1834 else: # decide whether or not to emasculate klingon
1835 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1836 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1837 prout(_(" has just lost its firepower.\""))
1838 game.enemies[kk].power = -kpow
1843 "Fire phasers at bad guys."
1847 irec = 0 # Cheating inhibitor
1856 # SR sensors and Computer are needed for automode
1857 if damaged(DSRSENS) or damaged(DCOMPTR):
1859 if game.condition == "docked":
1860 prout(_("Phasers can't be fired through base shields."))
1863 if damaged(DPHASER):
1864 prout(_("Phaser control damaged."))
1868 if damaged(DSHCTRL):
1869 prout(_("High speed shield control damaged."))
1872 if game.energy <= 200.0:
1873 prout(_("Insufficient energy to activate high-speed shield control."))
1876 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1878 # Original code so convoluted, I re-did it all
1879 # (That was Tom Almy talking about the C code, I think -- ESR)
1880 while automode == "NOTSET":
1881 key = scanner.nexttok()
1882 if key == "IHALPHA":
1883 if scanner.sees("manual"):
1884 if len(game.enemies)==0:
1885 prout(_("There is no enemy present to select."))
1888 automode = "AUTOMATIC"
1891 key = scanner.nexttok()
1892 elif scanner.sees("automatic"):
1893 if (not itarg) and len(game.enemies) != 0:
1894 automode = "FORCEMAN"
1896 if len(game.enemies)==0:
1897 prout(_("Energy will be expended into space."))
1898 automode = "AUTOMATIC"
1899 key = scanner.nexttok()
1900 elif scanner.sees("no"):
1905 elif key == "IHREAL":
1906 if len(game.enemies)==0:
1907 prout(_("Energy will be expended into space."))
1908 automode = "AUTOMATIC"
1910 automode = "FORCEMAN"
1912 automode = "AUTOMATIC"
1915 if len(game.enemies)==0:
1916 prout(_("Energy will be expended into space."))
1917 automode = "AUTOMATIC"
1919 automode = "FORCEMAN"
1921 proutn(_("Manual or automatic? "))
1926 if automode == "AUTOMATIC":
1927 if key == "IHALPHA" and scanner.sees("no"):
1929 key = scanner.nexttok()
1930 if key != "IHREAL" and len(game.enemies) != 0:
1931 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1936 for i in range(len(game.enemies)):
1937 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1939 proutn(_("%d units required. ") % irec)
1941 proutn(_("Units to fire= "))
1942 key = scanner.nexttok()
1947 proutn(_("Energy available= %.2f") % avail)
1950 if not rpow > avail:
1956 key = scanner.nexttok()
1957 if key == "IHALPHA" and scanner.sees("no"):
1960 game.energy -= 200 # Go and do it!
1961 if checkshctrl(rpow):
1966 if len(game.enemies):
1969 for i in range(len(game.enemies)):
1973 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1974 over = randreal(1.01, 1.06) * hits[i]
1976 powrem -= hits[i] + over
1977 if powrem <= 0 and temp < hits[i]:
1986 if extra > 0 and not game.alldone:
1988 proutn(_("*** Tholian web absorbs "))
1989 if len(game.enemies)>0:
1990 proutn(_("excess "))
1991 prout(_("phaser energy."))
1993 prout(_("%d expended on empty space.") % int(extra))
1994 elif automode == "FORCEMAN":
1997 if damaged(DCOMPTR):
1998 prout(_("Battle computer damaged, manual fire only."))
2001 prouts(_("---WORKING---"))
2003 prout(_("Short-range-sensors-damaged"))
2004 prout(_("Insufficient-data-for-automatic-phaser-fire"))
2005 prout(_("Manual-fire-must-be-used"))
2007 elif automode == "MANUAL":
2009 for k in range(len(game.enemies)):
2010 aim = game.enemies[k].location
2011 ienm = game.quad[aim.i][aim.j]
2013 proutn(_("Energy available= %.2f") % (avail-0.006))
2017 if damaged(DSRSENS) and \
2018 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
2019 prout(cramen(ienm) + _(" can't be located without short range scan."))
2022 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
2027 if itarg and k > kz:
2028 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
2031 if not damaged(DCOMPTR):
2036 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
2037 key = scanner.nexttok()
2038 if key == "IHALPHA" and scanner.sees("no"):
2040 key = scanner.nexttok()
2042 if key == "IHALPHA":
2046 if k == 1: # Let me say I'm baffled by this
2049 if scanner.real < 0:
2053 hits[k] = scanner.real
2054 rpow += scanner.real
2055 # If total requested is too much, inform and start over
2057 prout(_("Available energy exceeded -- try again."))
2060 key = scanner.nexttok() # scan for next value
2063 # zero energy -- abort
2066 if key == "IHALPHA" and scanner.sees("no"):
2071 game.energy -= 200.0
2072 if checkshctrl(rpow):
2076 # Say shield raised or malfunction, if necessary
2083 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
2084 prouts(_(" CLICK CLICK POP . . ."))
2085 prout(_(" No response, sir!"))
2088 prout(_("Shields raised."))
2095 game.ididit = False # Nothing if we fail
2098 # Make sure there is room in the brig */
2099 if game.brigfree == 0:
2100 prout(_("Security reports the brig is already full."))
2104 prout(_("Uhura- \"We have no subspace radio communication, sir.\""))
2107 if damaged(DTRANSP):
2108 prout(_("Scotty- \"Transporter damaged, sir.\""))
2111 # find out if there are any at all
2113 prout(_("Uhura- \"Getting no response, sir.\""))
2116 # if there is more than one Klingon, find out which one */
2117 # Cruddy, just takes one at random. Should ask the captain.
2118 # Nah, just select the weakest one since it is most likely to
2119 # surrender (Tom Almy mod)
2120 klingons = [e for e in game.enemies if e.type == 'K']
2121 weakest = sorted(klingons, key=lambda e: e.power)[0]
2122 game.optime = 0.05 # This action will take some time
2123 game.ididit = True # So any others can strike back
2125 # check out that Klingon
2126 # The algorithm isn't that great and could use some more
2127 # intelligent design
2128 # x = 300 + 25*skill;
2129 x = game.energy / (weakest.power * len(klingons))
2130 x *= 2.5; # would originally have been equivalent of 1.4,
2131 # but we want command to work more often, more humanely */
2132 #prout(_("Prob = %d (%.4f)\n", i, x))
2133 # x = 100; // For testing, of course!
2134 if x > randreal(100):
2135 # guess what, he surrendered!!! */
2136 prout(_("Klingon captain at %s surrenders.") % weakest.location)
2139 prout(_("%d Klingons commit suicide rather than be taken captive.") % 200 - i)
2141 prout(_("%d Klingons die because there is no room for them in the brig.") % i-brigfree)
2144 prout(_("%d captives taken") % i)
2145 deadkl(weakest.location, weakest.type, game.sector)
2146 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
2150 # big surprise, he refuses to surrender */
2151 prout(_("Fat chance, captain!"))
2153 # Code from events.c begins here.
2155 # This isn't a real event queue a la BSD Trek yet -- you can only have one
2156 # event of each type active at any given time. Mostly these means we can
2157 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
2158 # BSD Trek, from which we swiped the idea, can have up to 5.
2160 def unschedule(evtype):
2161 "Remove an event from the schedule."
2162 game.future[evtype].date = FOREVER
2163 return game.future[evtype]
2165 def is_scheduled(evtype):
2166 "Is an event of specified type scheduled."
2167 return game.future[evtype].date != FOREVER
2169 def scheduled(evtype):
2170 "When will this event happen?"
2171 return game.future[evtype].date
2173 def schedule(evtype, offset):
2174 "Schedule an event of specified type."
2175 game.future[evtype].date = game.state.date + offset
2176 return game.future[evtype]
2178 def postpone(evtype, offset):
2179 "Postpone a scheduled event."
2180 game.future[evtype].date += offset
2183 "Rest period is interrupted by event."
2186 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2188 game.resting = False
2194 "Run through the event queue looking for things to do."
2196 fintim = game.state.date + game.optime
2205 def tractorbeam(yank):
2206 "Tractor-beaming cases merge here."
2208 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2210 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2211 # If Kirk & Co. screwing around on planet, handle
2212 atover(True) # atover(true) is Grab
2215 if game.icraft: # Caught in Galileo?
2218 # Check to see if shuttle is aboard
2219 if game.iscraft == "offship":
2222 prout(_("Galileo, left on the planet surface, is captured"))
2223 prout(_("by aliens and made into a flying McDonald's."))
2224 game.damage[DSHUTTL] = -10
2225 game.iscraft = "removed"
2227 prout(_("Galileo, left on the planet surface, is well hidden."))
2229 game.quadrant = game.state.kscmdr
2231 game.quadrant = game.state.kcmdr[i]
2232 game.sector = randplace(QUADSIZE)
2233 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2234 % (game.quadrant, game.sector))
2236 prout(_("(Remainder of rest/repair period cancelled.)"))
2237 game.resting = False
2239 if not damaged(DSHIELD) and game.shield > 0:
2240 doshield(shraise=True) # raise shields
2241 game.shldchg = False
2243 prout(_("(Shields not currently useable.)"))
2245 # Adjust finish time to time of tractor beaming?
2246 # fintim = game.state.date+game.optime
2247 attack(torps_ok=False)
2248 if not game.state.kcmdr:
2251 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2254 "Code merges here for any commander destroying a starbase."
2255 # Not perfect, but will have to do
2256 # Handle case where base is in same quadrant as starship
2257 if game.battle == game.quadrant:
2258 game.state.chart[game.battle.i][game.battle.j].starbase = False
2259 game.quad[game.base.i][game.base.j] = '.'
2260 game.base.invalidate()
2263 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2264 elif game.state.baseq and communicating():
2265 # Get word via subspace radio
2268 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2269 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2271 prout(_("the Klingon Super-Commander"))
2273 prout(_("a Klingon Commander"))
2274 game.state.chart[game.battle.i][game.battle.j].starbase = False
2275 # Remove Starbase from galaxy
2276 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2277 game.state.baseq = [x for x in game.state.baseq if x != game.battle]
2279 # reinstate a commander's base attack
2283 game.battle.invalidate()
2285 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2286 for i in range(1, NEVENTS):
2287 if i == FSNOVA: proutn("=== Supernova ")
2288 elif i == FTBEAM: proutn("=== T Beam ")
2289 elif i == FSNAP: proutn("=== Snapshot ")
2290 elif i == FBATTAK: proutn("=== Base Attack ")
2291 elif i == FCDBAS: proutn("=== Base Destroy ")
2292 elif i == FSCMOVE: proutn("=== SC Move ")
2293 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2294 elif i == FDSPROB: proutn("=== Probe Move ")
2295 elif i == FDISTR: proutn("=== Distress Call ")
2296 elif i == FENSLV: proutn("=== Enslavement ")
2297 elif i == FREPRO: proutn("=== Klingon Build ")
2299 prout("%.2f" % (scheduled(i)))
2302 radio_was_broken = damaged(DRADIO)
2305 # Select earliest extraneous event, evcode==0 if no events
2310 for l in range(1, NEVENTS):
2311 if game.future[l].date < datemin:
2314 prout("== Event %d fires" % evcode)
2315 datemin = game.future[l].date
2316 xtime = datemin-game.state.date
2318 game.energy -= xtime*500.0
2319 if game.energy <= 0:
2322 game.state.date = datemin
2323 # Decrement Federation resources and recompute remaining time
2324 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2326 if game.state.remtime <= 0:
2329 # Any crew left alive?
2330 if game.state.crew <= 0:
2333 # Is life support adequate?
2334 if damaged(DLIFSUP) and game.condition != "docked":
2335 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2338 game.lsupres -= xtime
2339 if game.damage[DLIFSUP] <= xtime:
2340 game.lsupres = game.inlsr
2343 if game.condition == "docked":
2345 # Don't fix Deathray here
2346 for l in range(NDEVICES):
2347 if game.damage[l] > 0.0 and l != DDRAY:
2348 if game.damage[l]-repair > 0.0:
2349 game.damage[l] -= repair
2351 game.damage[l] = 0.0
2352 # If radio repaired, update star chart and attack reports
2353 if radio_was_broken and not damaged(DRADIO):
2354 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2355 prout(_(" surveillance reports are coming in."))
2357 if not game.iseenit:
2361 prout(_(" The star chart is now up to date.\""))
2363 # Cause extraneous event EVCODE to occur
2364 game.optime -= xtime
2365 if evcode == FSNOVA: # Supernova
2368 schedule(FSNOVA, expran(0.5*game.intime))
2369 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2371 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2372 if game.state.nscrem == 0 or game.iscloaked or \
2373 ictbeam or istract or \
2374 game.condition == "docked" or game.isatb == 1 or game.iscate:
2376 if game.ientesc or \
2377 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2378 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2379 (damaged(DSHIELD) and \
2380 (game.energy < 2500 or damaged(DPHASER)) and \
2381 (game.torps < 5 or damaged(DPHOTON))):
2383 istract = ictbeam = True
2384 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2387 elif evcode == FTBEAM: # Tractor beam
2388 if not game.state.kcmdr:
2391 i = randrange(len(game.state.kcmdr))
2392 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2393 if istract or game.condition == "docked" or game.iscloaked or yank == 0:
2394 # Drats! Have to reschedule
2396 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2400 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2401 game.snapsht = copy.deepcopy(game.state)
2402 game.state.snap = True
2403 schedule(FSNAP, expran(0.5 * game.intime))
2404 elif evcode == FBATTAK: # Commander attacks starbase
2405 if not game.state.kcmdr or not game.state.baseq:
2410 ibq = None # Force battle location to persist past loop
2412 for ibq in game.state.baseq:
2413 for cmdr in game.state.kcmdr:
2414 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2416 # no match found -- try later
2417 schedule(FBATTAK, expran(0.3*game.intime))
2422 # commander + starbase combination found -- launch attack
2424 schedule(FCDBAS, randreal(1.0, 4.0))
2425 if game.isatb: # extra time if SC already attacking
2426 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2427 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2428 game.iseenit = False
2429 if not communicating():
2430 continue # No warning :-(
2434 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2435 prout(_(" reports that it is under attack and that it can"))
2436 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2439 elif evcode == FSCDBAS: # Supercommander destroys base
2442 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2443 continue # WAS RETURN!
2445 game.battle = game.state.kscmdr
2447 elif evcode == FCDBAS: # Commander succeeds in destroying base
2448 if evcode == FCDBAS:
2450 if not game.state.baseq() \
2451 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2452 game.battle.invalidate()
2454 # find the lucky pair
2455 for cmdr in game.state.kcmdr:
2456 if cmdr == game.battle:
2459 # No action to take after all
2462 elif evcode == FSCMOVE: # Supercommander moves
2463 schedule(FSCMOVE, 0.2777)
2464 if not game.ientesc and not istract and game.isatb != 1 and \
2465 (not game.iscate or not game.justin):
2467 elif evcode == FDSPROB: # Move deep space probe
2468 schedule(FDSPROB, 0.01)
2469 if not game.probe.nexttok():
2470 if not game.probe.quadrant().valid_quadrant() or \
2471 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2472 # Left galaxy or ran into supernova
2476 proutn(_("Lt. Uhura- \"The deep space probe "))
2477 if not game.probe.quadrant().valid_quadrant():
2478 prout(_("has left the galaxy.\""))
2480 prout(_("is no longer transmitting.\""))
2486 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2487 pquad = game.probe.quadrant()
2488 pdest = game.state.galaxy[pquad.i][pquad.j]
2490 game.state.chart[pquad.i][pquad.j].klingons = pdest.klingons
2491 game.state.chart[pquad.i][pquad.j].starbase = pdest.starbase
2492 game.state.chart[pquad.i][pquad.j].stars = pdest.stars
2493 pdest.charted = True
2494 game.probe.moves -= 1 # One less to travel
2495 if game.probe.arrived() and game.isarmed and pdest.stars:
2496 supernova(game.probe) # fire in the hole!
2498 if game.state.galaxy[pquad.i][pquad.j].supernova:
2500 elif evcode == FDISTR: # inhabited system issues distress call
2502 # try a whole bunch of times to find something suitable
2503 for i in range(100):
2504 # need a quadrant which is not the current one,
2505 # which has some stars which are inhabited and
2506 # not already under attack, which is not
2507 # supernova'ed, and which has some Klingons in it
2508 w = randplace(GALSIZE)
2509 q = game.state.galaxy[w.i][w.j]
2510 if not (game.quadrant == w or q.planet is None or \
2511 not q.planet.inhabited or \
2512 q.supernova or q.status!="secure" or q.klingons<=0):
2515 # can't seem to find one; ignore this call
2517 prout("=== Couldn't find location for distress event.")
2519 # got one!! Schedule its enslavement
2520 ev = schedule(FENSLV, expran(game.intime))
2522 q.status = "distressed"
2523 # tell the captain about it if we can
2525 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2526 % (q.planet, repr(w)))
2527 prout(_("by a Klingon invasion fleet."))
2530 elif evcode == FENSLV: # starsystem is enslaved
2531 ev = unschedule(FENSLV)
2532 # see if current distress call still active
2533 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2537 q.status = "enslaved"
2539 # play stork and schedule the first baby
2540 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2541 ev2.quadrant = ev.quadrant
2543 # report the disaster if we can
2545 prout(_("Uhura- We've lost contact with starsystem %s") % \
2547 prout(_("in Quadrant %s.\n") % ev.quadrant)
2548 elif evcode == FREPRO: # Klingon reproduces
2549 # If we ever switch to a real event queue, we'll need to
2550 # explicitly retrieve and restore the x and y.
2551 ev = schedule(FREPRO, expran(1.0 * game.intime))
2552 # see if current distress call still active
2553 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2557 if game.state.remkl >= MAXKLGAME:
2558 continue # full right now
2559 # reproduce one Klingon
2562 if game.klhere >= MAXKLQUAD:
2564 # this quadrant not ok, pick an adjacent one
2565 for m.i in range(w.i - 1, w.i + 2):
2566 for m.j in range(w.j - 1, w.j + 2):
2567 if not m.valid_quadrant():
2569 q = game.state.galaxy[m.i][m.j]
2570 # check for this quad ok (not full & no snova)
2571 if q.klingons >= MAXKLQUAD or q.supernova:
2574 # search for eligible quadrant failed
2579 game.state.remkl += 1
2581 if game.quadrant == w:
2583 game.enemies.append(newkling())
2584 # recompute time left
2587 if game.quadrant == w:
2588 prout(_("Spock- sensors indicate the Klingons have"))
2589 prout(_("launched a warship from %s.") % q.planet)
2591 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2592 if q.planet != None:
2593 proutn(_("near %s ") % q.planet)
2594 prout(_("in Quadrant %s.") % w)
2600 key = scanner.nexttok()
2603 proutn(_("How long? "))
2608 origTime = delay = scanner.real
2611 if delay >= game.state.remtime or len(game.enemies) != 0:
2612 proutn(_("Are you sure? "))
2615 # Alternate resting periods (events) with attacks
2619 game.resting = False
2620 if not game.resting:
2621 prout(_("%d stardates left.") % int(game.state.remtime))
2623 temp = game.optime = delay
2624 if len(game.enemies):
2625 rtime = randreal(1.0, 2.0)
2629 if game.optime < delay:
2630 attack(torps_ok=False)
2638 # Repair Deathray if long rest at starbase
2639 if origTime-delay >= 9.99 and game.condition == "docked":
2640 game.damage[DDRAY] = 0.0
2641 # leave if quadrant supernovas
2642 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2644 game.resting = False
2649 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2650 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2652 # Wow! We've supernova'ed
2653 supernova(game.quadrant)
2655 # handle initial nova
2656 game.quad[nov.i][nov.j] = '.'
2657 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2658 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2659 game.state.starkl += 1
2660 # Set up queue to recursively trigger adjacent stars
2666 for offset.i in range(-1, 1+1):
2667 for offset.j in range(-1, 1+1):
2668 if offset.j == 0 and offset.i == 0:
2670 neighbor = start + offset
2671 if not neighbor.valid_sector():
2673 iquad = game.quad[neighbor.i][neighbor.j]
2674 # Empty space ends reaction
2675 if iquad in ('.', '?', ' ', 'T', '#'):
2677 elif iquad == '*': # Affect another star
2679 # This star supernovas
2680 supernova(game.quadrant)
2683 hits.append(neighbor)
2684 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2685 game.state.starkl += 1
2686 proutn(crmena(True, '*', "sector", neighbor))
2688 game.quad[neighbor.i][neighbor.j] = '.'
2690 elif iquad in ('P', '@'): # Destroy planet
2691 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2693 game.state.nplankl += 1
2695 game.state.nworldkl += 1
2696 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2697 game.iplnet.pclass = "destroyed"
2699 game.plnet.invalidate()
2703 game.quad[neighbor.i][neighbor.j] = '.'
2704 elif iquad == 'B': # Destroy base
2705 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2706 game.state.baseq = [x for x in game.state.baseq if x!= game.quadrant]
2707 game.base.invalidate()
2708 game.state.basekl += 1
2710 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2711 game.quad[neighbor.i][neighbor.j] = '.'
2712 elif iquad in ('E', 'F'): # Buffet ship
2713 prout(_("***Starship buffeted by nova."))
2715 if game.shield >= 2000.0:
2716 game.shield -= 2000.0
2718 diff = 2000.0 - game.shield
2722 prout(_("***Shields knocked out."))
2723 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2725 game.energy -= 2000.0
2726 if game.energy <= 0:
2729 # add in course nova contributes to kicking starship
2730 bump += (game.sector-hits[-1]).sgn()
2731 elif iquad == 'K': # kill klingon
2732 deadkl(neighbor, iquad, neighbor)
2733 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2735 for ll in range(len(game.enemies)):
2736 if game.enemies[ll].location == neighbor:
2737 target = game.enemies[ll]
2739 if target is not None:
2740 target.power -= 800.0 # If firepower is lost, die
2741 if target.power <= 0.0:
2742 deadkl(neighbor, iquad, neighbor)
2743 continue # neighbor loop
2744 # Else enemy gets flung by the blast wave
2745 newc = neighbor + neighbor - hits[-1]
2746 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2747 if not newc.valid_sector():
2748 # can't leave quadrant
2751 iquad1 = game.quad[newc.i][newc.j]
2753 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2755 deadkl(neighbor, iquad, newc)
2758 # can't move into something else
2761 proutn(_(", buffeted to Sector %s") % newc)
2762 game.quad[neighbor.i][neighbor.j] = '.'
2763 game.quad[newc.i][newc.j] = iquad
2765 # Starship affected by nova -- kick it away.
2767 direc = ncourse[3*(bump.i+1)+bump.j+2]
2772 scourse = course(bearing=direc, distance=dist)
2773 game.optime = scourse.time(w=4)
2775 prout(_("Force of nova displaces starship."))
2776 imove(scourse, noattack=True)
2777 game.optime = scourse.time(w=4)
2781 "Star goes supernova."
2786 # Scheduled supernova -- select star at random.
2789 for nq.i in range(GALSIZE):
2790 for nq.j in range(GALSIZE):
2791 nstars += game.state.galaxy[nq.i][nq.j].stars
2793 return # nothing to supernova exists
2794 num = randrange(nstars) + 1
2795 for nq.i in range(GALSIZE):
2796 for nq.j in range(GALSIZE):
2797 num -= game.state.galaxy[nq.i][nq.j].stars
2803 proutn("=== Super nova here?")
2806 if not nq == game.quadrant or game.justin:
2807 # it isn't here, or we just entered (treat as enroute)
2810 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2811 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2814 # we are in the quadrant!
2815 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2816 for ns.i in range(QUADSIZE):
2817 for ns.j in range(QUADSIZE):
2818 if game.quad[ns.i][ns.j]=='*':
2825 prouts(_("***RED ALERT! RED ALERT!"))
2827 prout(_("***Incipient supernova detected at Sector %s") % ns)
2828 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2829 proutn(_("Emergency override attempts t"))
2830 prouts("***************")
2834 # destroy any Klingons in supernovaed quadrant
2835 kldead = game.state.galaxy[nq.i][nq.j].klingons
2836 game.state.galaxy[nq.i][nq.j].klingons = 0
2837 if nq == game.state.kscmdr:
2838 # did in the Supercommander!
2839 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2843 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2844 comkills = len(game.state.kcmdr) - len(survivors)
2845 game.state.kcmdr = survivors
2847 if not game.state.kcmdr:
2849 game.state.remkl -= kldead
2850 # destroy Romulans and planets in supernovaed quadrant
2851 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2852 game.state.galaxy[nq.i][nq.j].romulans = 0
2853 game.state.nromrem -= nrmdead
2855 for loop in range(game.inplan):
2856 if game.state.planets[loop].quadrant == nq:
2857 game.state.planets[loop].pclass = "destroyed"
2859 # Destroy any base in supernovaed quadrant
2860 game.state.baseq = [x for x in game.state.baseq if x != nq]
2861 # If starship caused supernova, tally up destruction
2863 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2864 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2865 game.state.nplankl += npdead
2866 # mark supernova in galaxy and in star chart
2867 if game.quadrant == nq or communicating():
2868 game.state.galaxy[nq.i][nq.j].supernova = True
2869 # If supernova destroys last Klingons give special message
2870 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2873 prout(_("Lucky you!"))
2874 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2877 # if some Klingons remain, continue or die in supernova
2882 # Code from finish.c ends here.
2885 "Self-destruct maneuver. Finish with a BANG!"
2887 if damaged(DCOMPTR):
2888 prout(_("Computer damaged; cannot execute destruct sequence."))
2890 prouts(_("---WORKING---")); skip(1)
2891 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2892 prouts(" 10"); skip(1)
2893 prouts(" 9"); skip(1)
2894 prouts(" 8"); skip(1)
2895 prouts(" 7"); skip(1)
2896 prouts(" 6"); skip(1)
2898 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2900 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2902 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2905 if game.passwd != scanner.token:
2906 prouts(_("PASSWORD-REJECTED;"))
2908 prouts(_("CONTINUITY-EFFECTED"))
2911 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2912 prouts(" 5"); skip(1)
2913 prouts(" 4"); skip(1)
2914 prouts(" 3"); skip(1)
2915 prouts(" 2"); skip(1)
2916 prouts(" 1"); skip(1)
2918 prouts(_("GOODBYE-CRUEL-WORLD"))
2926 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2930 if len(game.enemies) != 0:
2931 whammo = 25.0 * game.energy
2932 for l in range(len(game.enemies)):
2933 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2934 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2938 "Compute our rate of kils over time."
2939 elapsed = game.state.date - game.indate
2940 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2943 starting = (game.inkling + game.incom + game.inscom)
2944 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2945 return (starting - remaining)/elapsed
2949 badpt = 5.0*game.state.starkl + \
2951 10.0*game.state.nplankl + \
2952 300*game.state.nworldkl + \
2954 100.0*game.state.basekl +\
2955 3.0*game.abandoned +\
2957 if game.ship == 'F':
2959 elif game.ship is None:
2964 # end the game, with appropriate notifications
2968 prout(_("It is stardate %.1f.") % game.state.date)
2970 if ifin == FWON: # Game has been won
2971 if game.state.nromrem != 0:
2972 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2975 prout(_("You have smashed the Klingon invasion fleet and saved"))
2976 prout(_("the Federation."))
2977 if game.alive and game.brigcapacity-game.brigfree > 0:
2978 game.kcaptured += game.brigcapacity-game.brigfree
2979 prout(_("The %d captured Klingons are transferred to Star Fleet Command.") % (game.brigcapacity-game.brigfree))
2984 badpt = 0.0 # Close enough!
2985 # killsPerDate >= RateMax
2986 if game.state.date-game.indate < 5.0 or \
2987 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2989 prout(_("In fact, you have done so well that Starfleet Command"))
2990 if game.skill == SKILL_NOVICE:
2991 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2992 elif game.skill == SKILL_FAIR:
2993 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2994 elif game.skill == SKILL_GOOD:
2995 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2996 elif game.skill == SKILL_EXPERT:
2997 prout(_("promotes you to Commodore Emeritus."))
2999 prout(_("Now that you think you're really good, try playing"))
3000 prout(_("the \"Emeritus\" game. It will splatter your ego."))
3001 elif game.skill == SKILL_EMERITUS:
3003 proutn(_("Computer- "))
3004 prouts(_("ERROR-ERROR-ERROR-ERROR"))
3006 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
3008 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3010 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3012 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3014 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
3016 prout(_("Now you can retire and write your own Star Trek game!"))
3018 elif game.skill >= SKILL_EXPERT:
3019 if game.thawed and not game.idebug:
3020 prout(_("You cannot get a citation, so..."))
3022 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
3026 # Only grant long life if alive (original didn't!)
3028 prout(_("LIVE LONG AND PROSPER."))
3033 elif ifin == FDEPLETE: # Federation Resources Depleted
3034 prout(_("Your time has run out and the Federation has been"))
3035 prout(_("conquered. Your starship is now Klingon property,"))
3036 prout(_("and you are put on trial as a war criminal. On the"))
3037 proutn(_("basis of your record, you are "))
3038 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
3039 prout(_("acquitted."))
3041 prout(_("LIVE LONG AND PROSPER."))
3043 prout(_("found guilty and"))
3044 prout(_("sentenced to death by slow torture."))
3048 elif ifin == FLIFESUP:
3049 prout(_("Your life support reserves have run out, and"))
3050 prout(_("you die of thirst, starvation, and asphyxiation."))
3051 prout(_("Your starship is a derelict in space."))
3053 prout(_("Your energy supply is exhausted."))
3055 prout(_("Your starship is a derelict in space."))
3056 elif ifin == FBATTLE:
3057 prout(_("The %s has been destroyed in battle.") % crmshp())
3059 prout(_("Dulce et decorum est pro patria mori."))
3061 prout(_("You have made three attempts to cross the negative energy"))
3062 prout(_("barrier which surrounds the galaxy."))
3064 prout(_("Your navigation is abominable."))
3067 prout(_("Your starship has been destroyed by a nova."))
3068 prout(_("That was a great shot."))
3070 elif ifin == FSNOVAED:
3071 prout(_("The %s has been fried by a supernova.") % crmshp())
3072 prout(_("...Not even cinders remain..."))
3073 elif ifin == FABANDN:
3074 prout(_("You have been captured by the Klingons. If you still"))
3075 prout(_("had a starbase to be returned to, you would have been"))
3076 prout(_("repatriated and given another chance. Since you have"))
3077 prout(_("no starbases, you will be mercilessly tortured to death."))
3078 elif ifin == FDILITHIUM:
3079 prout(_("Your starship is now an expanding cloud of subatomic particles"))
3080 elif ifin == FMATERIALIZE:
3081 prout(_("Starbase was unable to re-materialize your starship."))
3082 prout(_("Sic transit gloria mundi"))
3083 elif ifin == FPHASER:
3084 prout(_("The %s has been cremated by its own phasers.") % crmshp())
3086 prout(_("You and your landing party have been"))
3087 prout(_("converted to energy, dissipating through space."))
3088 elif ifin == FMINING:
3089 prout(_("You are left with your landing party on"))
3090 prout(_("a wild jungle planet inhabited by primitive cannibals."))
3092 prout(_("They are very fond of \"Captain Kirk\" soup."))
3094 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3095 elif ifin == FDPLANET:
3096 prout(_("You and your mining party perish."))
3098 prout(_("That was a great shot."))
3101 prout(_("The Galileo is instantly annihilated by the supernova."))
3102 prout(_("You and your mining party are atomized."))
3104 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3105 prout(_("joins the Romulans, wreaking terror on the Federation."))
3106 elif ifin == FPNOVA:
3107 prout(_("You and your mining party are atomized."))
3109 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3110 prout(_("joins the Romulans, wreaking terror on the Federation."))
3111 elif ifin == FSTRACTOR:
3112 prout(_("The shuttle craft Galileo is also caught,"))
3113 prout(_("and breaks up under the strain."))
3115 prout(_("Your debris is scattered for millions of miles."))
3116 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3118 prout(_("The mutants attack and kill Spock."))
3119 prout(_("Your ship is captured by Klingons, and"))
3120 prout(_("your crew is put on display in a Klingon zoo."))
3121 elif ifin == FTRIBBLE:
3122 prout(_("Tribbles consume all remaining water,"))
3123 prout(_("food, and oxygen on your ship."))
3125 prout(_("You die of thirst, starvation, and asphyxiation."))
3126 prout(_("Your starship is a derelict in space."))
3128 prout(_("Your ship is drawn to the center of the black hole."))
3129 prout(_("You are crushed into extremely dense matter."))
3130 elif ifin == FCLOAK:
3132 prout(_("You have violated the Treaty of Algeron."))
3133 prout(_("The Romulan Empire can never trust you again."))
3135 prout(_("Your last crew member has died."))
3136 if ifin != FWON and ifin != FCLOAK and game.iscloaked:
3137 prout(_("Your ship was cloaked so your subspace radio did not receive anything."))
3138 prout(_("You may have missed some warning messages."))
3140 if game.ship == 'F':
3142 elif game.ship == 'E':
3145 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
3146 goodies = game.state.remres/game.inresor
3147 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
3148 if goodies/baddies >= randreal(1.0, 1.5):
3149 prout(_("As a result of your actions, a treaty with the Klingon"))
3150 prout(_("Empire has been signed. The terms of the treaty are"))
3151 if goodies/baddies >= randreal(3.0):
3152 prout(_("favorable to the Federation."))
3154 prout(_("Congratulations!"))
3156 prout(_("highly unfavorable to the Federation."))
3158 prout(_("The Federation will be destroyed."))
3160 prout(_("Since you took the last Klingon with you, you are a"))
3161 prout(_("martyr and a hero. Someday maybe they'll erect a"))
3162 prout(_("statue in your memory. Rest in peace, and try not"))
3163 prout(_("to think about pigeons."))
3166 scanner.chew() # Clean up leftovers
3169 "Compute player's score."
3170 timused = game.state.date - game.indate
3171 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
3173 game.perdate = killrate()
3174 ithperd = 500*game.perdate + 0.5
3177 iwon = 100*game.skill
3178 if game.ship == 'E':
3180 elif game.ship == 'F':
3184 game.score = 10*(game.inkling - game.state.remkl) \
3185 + 50*(game.incom - len(game.state.kcmdr)) \
3187 + 20*(game.inrom - game.state.nromrem) \
3188 + 200*(game.inscom - game.state.nscrem) \
3189 - game.state.nromrem \
3190 + 3 * game.kcaptured \
3195 prout(_("Your score --"))
3196 if game.inrom - game.state.nromrem:
3197 prout(_("%6d Romulans destroyed %5d") %
3198 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
3199 if game.state.nromrem and game.gamewon:
3200 prout(_("%6d Romulans captured %5d") %
3201 (game.state.nromrem, game.state.nromrem))
3202 if game.inkling - game.state.remkl:
3203 prout(_("%6d ordinary Klingons destroyed %5d") %
3204 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
3205 if game.incom - len(game.state.kcmdr):
3206 prout(_("%6d Klingon commanders destroyed %5d") %
3207 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3209 prout(_("%d Klingons captured %5d") %
3210 (game.kcaptured, 3 * game.kcaptured))
3211 if game.inscom - game.state.nscrem:
3212 prout(_("%6d Super-Commander destroyed %5d") %
3213 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3215 prout(_("%6.2f Klingons per stardate %5d") %
3216 (game.perdate, ithperd))
3217 if game.state.starkl:
3218 prout(_("%6d stars destroyed by your action %5d") %
3219 (game.state.starkl, -5*game.state.starkl))
3220 if game.state.nplankl:
3221 prout(_("%6d planets destroyed by your action %5d") %
3222 (game.state.nplankl, -10*game.state.nplankl))
3223 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3224 prout(_("%6d inhabited planets destroyed by your action %5d") %
3225 (game.state.nworldkl, -300*game.state.nworldkl))
3226 if game.state.basekl:
3227 prout(_("%6d bases destroyed by your action %5d") %
3228 (game.state.basekl, -100*game.state.basekl))
3230 prout(_("%6d calls for help from starbase %5d") %
3231 (game.nhelp, -45*game.nhelp))
3233 prout(_("%6d casualties incurred %5d") %
3234 (game.casual, -game.casual))
3236 prout(_("%6d crew abandoned in space %5d") %
3237 (game.abandoned, -3*game.abandoned))
3239 prout(_("%6d ship(s) lost or destroyed %5d") %
3240 (klship, -100*klship))
3243 prout(_("1 Treaty of Algeron violation -100"))
3245 prout(_("%6d Treaty of Algeron violations %5d\n") %
3246 (ncviol, -100*ncviol))
3248 prout(_("Penalty for getting yourself killed -200"))
3250 proutn(_("Bonus for winning "))
3251 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3252 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3253 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3254 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3255 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3256 prout(" %5d" % iwon)
3258 prout(_("TOTAL SCORE %5d") % game.score)
3261 "Emit winner's commemmorative plaque."
3264 proutn(_("File or device name for your plaque: "))
3267 fp = open(winner, "w")
3270 prout(_("Invalid name."))
3272 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3274 # The 38 below must be 64 for 132-column paper
3275 nskip = 38 - len(winner)/2
3276 fp.write("\n\n\n\n")
3277 # --------DRAW ENTERPRISE PICTURE.
3278 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3279 fp.write(" EEE E : : : E\n" )
3280 fp.write(" EE EEE E : : NCC-1701 : E\n")
3281 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3282 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3283 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3284 fp.write(" EEEEEEE EEEEE E E E E\n")
3285 fp.write(" EEE E E E E\n")
3286 fp.write(" E E E E\n")
3287 fp.write(" EEEEEEEEEEEEE E E\n")
3288 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3289 fp.write(" :E : EEEE E\n")
3290 fp.write(" .-E -:----- E\n")
3291 fp.write(" :E : E\n")
3292 fp.write(" EE : EEEEEEEE\n")
3293 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3295 fp.write(_(" U. S. S. ENTERPRISE\n"))
3296 fp.write("\n\n\n\n")
3297 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3299 fp.write(_(" Starfleet Command bestows to you\n"))
3301 fp.write("%*s%s\n\n" % (nskip, "", winner))
3302 fp.write(_(" the rank of\n\n"))
3303 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3305 if game.skill == SKILL_EXPERT:
3306 fp.write(_(" Expert level\n\n"))
3307 elif game.skill == SKILL_EMERITUS:
3308 fp.write(_("Emeritus level\n\n"))
3310 fp.write(_(" Cheat level\n\n"))
3311 timestring = time.ctime()
3312 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3313 (timestring+4, timestring+20, timestring+11))
3314 fp.write(_(" Your score: %d\n\n") % game.score)
3315 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3318 # Code from io.c begins here
3320 rows = linecount = 0 # for paging
3323 fullscreen_window = None
3324 srscan_window = None # Short range scan
3325 report_window = None # Report legends for status window
3326 status_window = None # The status window itself
3327 lrscan_window = None # Long range scan
3328 message_window = None # Main window for scrolling text
3329 prompt_window = None # Prompt window at bottom of display
3334 # for some recent versions of python2, the following enables UTF8
3335 # for the older ones we probably need to set C locale, and python3
3336 # has no problems at all
3337 if sys.version_info[0] < 3:
3338 locale.setlocale(locale.LC_ALL, "")
3339 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3340 gettext.textdomain("sst")
3341 if not (game.options & OPTION_CURSES):
3342 ln_env = os.getenv("LINES")
3348 stdscr = curses.initscr()
3352 if game.options & OPTION_COLOR:
3353 curses.start_color()
3354 curses.use_default_colors()
3355 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3356 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3357 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3358 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3359 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3360 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3361 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3362 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3363 global fullscreen_window, srscan_window, report_window, status_window
3364 global lrscan_window, message_window, prompt_window
3365 (rows, _columns) = stdscr.getmaxyx()
3366 fullscreen_window = stdscr
3367 srscan_window = curses.newwin(12, 25, 0, 0)
3368 report_window = curses.newwin(11, 0, 1, 25)
3369 status_window = curses.newwin(10, 0, 1, 39)
3370 lrscan_window = curses.newwin(5, 0, 0, 64)
3371 message_window = curses.newwin(0, 0, 12, 0)
3372 prompt_window = curses.newwin(1, 0, rows-2, 0)
3373 message_window.scrollok(True)
3374 setwnd(fullscreen_window)
3378 if game.options & OPTION_CURSES:
3379 stdscr.keypad(False)
3385 "Wait for user action -- OK to do nothing if on a TTY"
3386 if game.options & OPTION_CURSES:
3391 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3395 if game.skill > SKILL_FAIR:
3396 prompt = _("[CONTINUE?]")
3398 prompt = _("[PRESS ENTER TO CONTINUE]")
3400 if game.options & OPTION_CURSES:
3402 setwnd(prompt_window)
3403 prompt_window.clear()
3404 prompt_window.addstr(prompt)
3405 prompt_window.getstr()
3406 prompt_window.clear()
3407 prompt_window.refresh()
3408 setwnd(message_window)
3411 sys.stdout.write('\n')
3415 sys.stdout.write('\n' * rows)
3419 "Skip i lines. Pause game if this would cause a scrolling event."
3420 for _dummy in range(i):
3421 if game.options & OPTION_CURSES:
3422 (y, _x) = curwnd.getyx()
3425 except curses.error:
3430 if rows and linecount >= rows:
3433 sys.stdout.write('\n')
3435 def proutn(proutntline):
3436 "Utter a line with no following line feed."
3437 if game.options & OPTION_CURSES:
3438 (y, x) = curwnd.getyx()
3439 (my, _mx) = curwnd.getmaxyx()
3440 if curwnd == message_window and y >= my - 2:
3443 # Uncomment this to debug curses problems
3445 logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(proutntline)))
3446 curwnd.addstr(proutntline)
3449 sys.stdout.write(proutntline)
3452 def prout(proutline):
3456 def prouts(proutsline):
3458 for c in proutsline:
3459 if not replayfp or replayfp.closed: # Don't slow down replays
3462 if game.options & OPTION_CURSES:
3466 if not replayfp or replayfp.closed:
3470 "Get a line of input."
3471 if game.options & OPTION_CURSES:
3472 linein = curwnd.getstr() + "\n"
3475 if replayfp and not replayfp.closed:
3477 linein = replayfp.readline()
3480 prout("*** Replay finished")
3483 elif linein[0] != "#":
3487 linein = my_input() + "\n"
3496 "Change windows -- OK for this to be a no-op in tty mode."
3498 if game.options & OPTION_CURSES:
3499 # Uncomment this to debug curses problems
3501 if wnd == fullscreen_window:
3502 legend = "fullscreen"
3503 elif wnd == srscan_window:
3505 elif wnd == report_window:
3507 elif wnd == status_window:
3509 elif wnd == lrscan_window:
3511 elif wnd == message_window:
3513 elif wnd == prompt_window:
3517 logfp.write("#curses: setwnd(%s)\n" % legend)
3519 # Some curses implementations get confused when you try this.
3521 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3522 except curses.error:
3526 "Clear to end of line -- can be a no-op in tty mode"
3527 if game.options & OPTION_CURSES:
3532 "Clear screen -- can be a no-op in tty mode."
3534 if game.options & OPTION_CURSES:
3540 def textcolor(color=DEFAULT):
3541 if game.options & OPTION_COLOR:
3542 if color == DEFAULT:
3544 elif color == BLACK:
3545 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3547 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3548 elif color == GREEN:
3549 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3551 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3553 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3554 elif color == MAGENTA:
3555 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3556 elif color == BROWN:
3557 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3558 elif color == LIGHTGRAY:
3559 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3560 elif color == DARKGRAY:
3561 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3562 elif color == LIGHTBLUE:
3563 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3564 elif color == LIGHTGREEN:
3565 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3566 elif color == LIGHTCYAN:
3567 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3568 elif color == LIGHTRED:
3569 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3570 elif color == LIGHTMAGENTA:
3571 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3572 elif color == YELLOW:
3573 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3574 elif color == WHITE:
3575 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3578 if game.options & OPTION_COLOR:
3579 curwnd.attron(curses.A_REVERSE)
3582 # Things past this point have policy implications.
3586 "Hook to be called after moving to redraw maps."
3587 if game.options & OPTION_CURSES:
3590 setwnd(srscan_window)
3594 setwnd(status_window)
3595 status_window.clear()
3596 status_window.move(0, 0)
3597 setwnd(report_window)
3598 report_window.clear()
3599 report_window.move(0, 0)
3601 setwnd(lrscan_window)
3602 lrscan_window.clear()
3603 lrscan_window.move(0, 0)
3604 lrscan(silent=False)
3606 def put_srscan_sym(w, sym):
3607 "Emit symbol for short-range scan."
3608 srscan_window.move(w.i+1, w.j*2+2)
3609 srscan_window.addch(sym)
3610 srscan_window.refresh()
3613 "Enemy fall down, go boom."
3614 if game.options & OPTION_CURSES:
3616 setwnd(srscan_window)
3617 srscan_window.attron(curses.A_REVERSE)
3618 put_srscan_sym(w, game.quad[w.i][w.j])
3622 srscan_window.attroff(curses.A_REVERSE)
3623 put_srscan_sym(w, game.quad[w.i][w.j])
3624 curses.delay_output(500)
3625 setwnd(message_window)
3628 "Sound and visual effects for teleportation."
3629 if game.options & OPTION_CURSES:
3631 setwnd(message_window)
3633 prouts(" . . . . . ")
3634 if game.options & OPTION_CURSES:
3635 #curses.delay_output(1000)
3639 def tracktorpedo(w, step, i, n, iquad):
3640 "Torpedo-track animation."
3641 if not game.options & OPTION_CURSES:
3645 proutn(_("Track for torpedo number %d- ") % (i+1))
3648 proutn(_("Torpedo track- "))
3649 elif step==4 or step==9:
3653 if not damaged(DSRSENS) or game.condition=="docked":
3654 if i != 0 and step == 1:
3657 if (iquad=='.') or (iquad==' '):
3658 put_srscan_sym(w, '+')
3662 put_srscan_sym(w, iquad)
3664 curwnd.attron(curses.A_REVERSE)
3665 put_srscan_sym(w, iquad)
3669 curwnd.attroff(curses.A_REVERSE)
3670 put_srscan_sym(w, iquad)
3675 "Display the current galaxy chart."
3676 if game.options & OPTION_CURSES:
3677 setwnd(message_window)
3678 message_window.clear()
3680 if game.options & OPTION_TTY:
3685 def prstat(txt, data):
3687 if game.options & OPTION_CURSES:
3689 setwnd(status_window)
3691 proutn(" " * (NSYM - len(txt)))
3694 if game.options & OPTION_CURSES:
3695 setwnd(report_window)
3697 # Code from moving.c begins here
3699 def imove(icourse=None, noattack=False):
3700 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3703 def newquadrant(noattack):
3704 # Leaving quadrant -- allow final enemy attack
3705 # Don't set up attack if being pushed by nova or cloaked
3706 if len(game.enemies) != 0 and not noattack and not game.iscloaked:
3708 for enemy in game.enemies:
3709 finald = (w - enemy.location).distance()
3710 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3711 # Stas Sergeev added the condition
3712 # that attacks only happen if Klingons
3713 # are present and your skill is good.
3714 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3715 attack(torps_ok=False)
3718 # check for edge of galaxy
3724 if icourse.final.i < 0:
3725 icourse.final.i = -icourse.final.i
3727 if icourse.final.j < 0:
3728 icourse.final.j = -icourse.final.j
3730 if icourse.final.i >= GALSIZE*QUADSIZE:
3731 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3733 if icourse.final.j >= GALSIZE*QUADSIZE:
3734 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3742 if game.nkinks == 3:
3743 # Three strikes -- you're out!
3747 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3748 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3749 prout(_("YOU WILL BE DESTROYED."))
3750 # Compute final position in new quadrant
3751 if trbeam: # Don't bother if we are to be beamed
3753 game.quadrant = icourse.final.quadrant()
3754 game.sector = icourse.final.sector()
3756 prout(_("Entering Quadrant %s.") % game.quadrant)
3757 game.quad[game.sector.i][game.sector.j] = game.ship
3759 if game.skill>SKILL_NOVICE:
3760 attack(torps_ok=False)
3762 def check_collision(h):
3763 iquad = game.quad[h.i][h.j]
3765 # object encountered in flight path
3766 stopegy = 50.0*icourse.distance/game.optime
3767 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3768 for enemy in game.enemies:
3769 if enemy.location == game.sector:
3770 collision(rammed=False, enemy=enemy)
3772 # This should not happen
3773 prout(_("Which way did he go?"))
3777 prouts(_("***RED ALERT! RED ALERT!"))
3779 proutn("***" + crmshp())
3780 proutn(_(" pulled into black hole at Sector %s") % h)
3781 # Getting pulled into a black hole was certain
3782 # death in Almy's original. Stas Sergeev added a
3783 # possibility that you'll get timewarped instead.
3785 for m in range(NDEVICES):
3786 if game.damage[m]>0:
3788 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3789 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3799 prout(_(" encounters Tholian web at %s;") % h)
3801 prout(_(" blocked by object at %s;") % h)
3802 proutn(_("Emergency stop required "))
3803 prout(_("%2d units of energy.") % int(stopegy))
3804 game.energy -= stopegy
3805 if game.energy <= 0:
3812 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3813 game.inorbit = False
3814 # If tractor beam is to occur, don't move full distance
3815 if game.state.date+game.optime >= scheduled(FTBEAM):
3817 # We can't be tractor beamed if cloaked,
3818 # so move the event into the future
3819 postpone(FTBEAM, game.optime + expran(1.5*game.intime/len(game.kcmdr)))
3823 game.condition = "red"
3824 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3825 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3827 game.quad[game.sector.i][game.sector.j] = '.'
3828 for _m in range(icourse.moves):
3830 w = icourse.sector()
3831 if icourse.origin.quadrant() != icourse.location.quadrant():
3832 newquadrant(noattack)
3834 elif check_collision(w):
3835 print("Collision detected")
3839 # We're in destination quadrant -- compute new average enemy distances
3840 game.quad[game.sector.i][game.sector.j] = game.ship
3842 for enemy in game.enemies:
3843 finald = (w-enemy.location).distance()
3844 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3845 enemy.kdist = finald
3847 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3848 attack(torps_ok=False)
3849 for enemy in game.enemies:
3850 enemy.kavgd = enemy.kdist
3853 setwnd(message_window)
3857 "Dock our ship at a starbase."
3859 if game.condition == "docked" and verbose:
3860 prout(_("Already docked."))
3863 prout(_("You must first leave standard orbit."))
3865 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3866 prout(crmshp() + _(" not adjacent to base."))
3869 prout(_("You cannot dock while cloaked."))
3871 game.condition = "docked"
3875 if game.energy < game.inenrg:
3876 game.energy = game.inenrg
3877 game.shield = game.inshld
3878 game.torps = game.intorps
3879 game.lsupres = game.inlsr
3880 game.state.crew = FULLCREW
3881 if game.brigcapacity-game.brigfree > 0:
3882 prout(_("%d captured Klingons transferred to base") % (game.brigcapacity-game.brigfree))
3883 game.kcaptured += game.brigcapacity-game.brigfree
3884 game.brigfree = game.brigcapacity
3885 if not damaged(DRADIO) and \
3886 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3887 # get attack report from base
3888 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3892 def cartesian(loc1=None, loc2=None):
3894 return game.quadrant * QUADSIZE + game.sector
3896 return game.quadrant * QUADSIZE + loc1
3898 return loc1 * QUADSIZE + loc2
3900 def getcourse(isprobe):
3901 "Get a course and distance from the user."
3903 dquad = copy.copy(game.quadrant)
3904 navmode = "unspecified"
3908 if game.landed and not isprobe:
3909 prout(_("Dummy! You can't leave standard orbit until you"))
3910 proutn(_("are back aboard the ship."))
3913 while navmode == "unspecified":
3914 if damaged(DNAVSYS):
3916 prout(_("Computer damaged; manual navigation only"))
3918 prout(_("Computer damaged; manual movement only"))
3923 key = scanner.nexttok()
3925 proutn(_("Manual or automatic- "))
3928 elif key == "IHALPHA":
3929 if scanner.sees("manual"):
3931 key = scanner.nexttok()
3933 elif scanner.sees("automatic"):
3934 navmode = "automatic"
3935 key = scanner.nexttok()
3943 prout(_("(Manual navigation assumed.)"))
3945 prout(_("(Manual movement assumed.)"))
3949 if navmode == "automatic":
3950 while key == "IHEOL":
3952 proutn(_("Target quadrant or quadrant§or- "))
3954 proutn(_("Destination sector or quadrant§or- "))
3957 key = scanner.nexttok()
3961 xi = int(round(scanner.real))-1
3962 key = scanner.nexttok()
3966 xj = int(round(scanner.real))-1
3967 key = scanner.nexttok()
3969 # both quadrant and sector specified
3970 xk = int(round(scanner.real))-1
3971 key = scanner.nexttok()
3975 xl = int(round(scanner.real))-1
3981 # only one pair of numbers was specified
3983 # only quadrant specified -- go to center of dest quad
3986 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3988 # only sector specified
3992 if not dquad.valid_quadrant() or not dsect.valid_sector():
3999 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
4001 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
4002 # the actual deltas get computed here
4003 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
4004 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
4006 while key == "IHEOL":
4007 proutn(_("X and Y displacements- "))
4010 key = scanner.nexttok()
4015 delta.j = scanner.real
4016 key = scanner.nexttok()
4020 delta.i = scanner.real
4021 # Check for zero movement
4022 if delta.i == 0 and delta.j == 0:
4025 if itemp == "verbose" and not isprobe:
4027 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
4029 return course(bearing=delta.bearing(), distance=delta.distance())
4032 def __init__(self, bearing, distance, origin=None):
4033 self.distance = distance
4034 self.bearing = bearing
4036 self.origin = cartesian(game.quadrant, game.sector)
4038 self.origin = origin
4039 # The bearing() code we inherited from FORTRAN is actually computing
4040 # clockface directions!
4041 if self.bearing < 0.0:
4042 self.bearing += 12.0
4043 self.angle = ((15.0 - self.bearing) * 0.5235988)
4044 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
4045 bigger = max(abs(self.increment.i), abs(self.increment.j))
4046 self.increment /= bigger
4047 self.moves = int(round(10*self.distance*bigger))
4049 self.final = (self.location + self.moves*self.increment).roundtogrid()
4050 self.location = self.origin
4051 self.nextlocation = None
4053 self.location = self.origin
4056 return self.location.roundtogrid() == self.final
4058 "Next step on course."
4060 self.nextlocation = self.location + self.increment
4061 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
4062 self.location = self.nextlocation
4065 return self.location.quadrant()
4067 return self.location.sector()
4069 return self.distance*(w**3)*(game.shldup+1)
4071 return 10.0*self.distance/w**2
4074 "Move under impulse power."
4076 if damaged(DIMPULS):
4079 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4081 if game.energy > 30.0:
4083 icourse = getcourse(isprobe=False)
4086 power = 20.0 + 100.0*icourse.distance
4089 if power >= game.energy:
4090 # Insufficient power for trip
4092 prout(_("First Officer Spock- \"Captain, the impulse engines"))
4093 prout(_("require 20.0 units to engage, plus 100.0 units per"))
4094 if game.energy > 30:
4095 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
4096 int(0.01 * (game.energy-20.0)-0.05))
4097 prout(_(" quadrants.\""))
4099 prout(_("quadrant. They are, therefore, useless.\""))
4102 # Make sure enough time is left for the trip
4103 game.optime = icourse.distance/0.095
4104 if game.optime >= game.state.remtime:
4105 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
4106 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
4107 proutn(_("we dare spend the time?\" "))
4110 # Activate impulse engines and pay the cost
4111 imove(icourse, noattack=False)
4115 power = 20.0 + 100.0*icourse.distance
4116 game.energy -= power
4117 game.optime = icourse.distance/0.095
4118 if game.energy <= 0:
4122 def warp(wcourse, involuntary):
4123 "ove under warp drive."
4124 blooey = False; twarp = False
4125 if not involuntary: # Not WARPX entry
4130 prout(_("Engineer Scott- \"The warp engines can not be used while cloaked, Sir.\""))
4132 if game.damage[DWARPEN] > 10.0:
4135 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
4137 if damaged(DWARPEN) and game.warpfac > 4.0:
4140 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4141 prout(_(" is repaired, I can only give you warp 4.\""))
4143 # Read in course and distance
4146 wcourse = getcourse(isprobe=False)
4149 # Make sure starship has enough energy for the trip
4150 # Note: this formula is slightly different from the C version,
4151 # and lets you skate a bit closer to the edge.
4152 if wcourse.power(game.warpfac) >= game.energy:
4153 # Insufficient power for trip
4156 prout(_("Engineering to bridge--"))
4157 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
4158 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
4160 prout(_("We can't do it, Captain. We don't have enough energy."))
4162 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4165 prout(_("if you'll lower the shields."))
4169 prout(_("We haven't the energy to go that far with the shields up."))
4171 # Make sure enough time is left for the trip
4172 game.optime = wcourse.time(game.warpfac)
4173 if game.optime >= 0.8*game.state.remtime:
4175 prout(_("First Officer Spock- \"Captain, I compute that such"))
4176 proutn(_(" a trip would require approximately %2.0f") %
4177 (100.0*game.optime/game.state.remtime))
4178 prout(_(" percent of our"))
4179 proutn(_(" remaining time. Are you sure this is wise?\" "))
4185 if game.warpfac > 6.0:
4186 # Decide if engine damage will occur
4187 # ESR: Seems wrong. Probability of damage goes *down* with distance?
4188 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
4189 if prob > randreal():
4191 wcourse.distance = randreal(wcourse.distance)
4192 # Decide if time warp will occur
4193 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
4195 if game.idebug and game.warpfac==10 and not twarp:
4197 proutn("=== Force time warp? ")
4201 # If time warp or engine damage, check path
4202 # If it is obstructed, don't do warp or damage
4203 look = wcourse.moves
4207 w = wcourse.sector()
4208 if not w.valid_sector():
4210 if game.quad[w.i][w.j] != '.':
4214 # Activate Warp Engines and pay the cost
4215 imove(wcourse, noattack=False)
4218 game.energy -= wcourse.power(game.warpfac)
4219 if game.energy <= 0:
4221 game.optime = wcourse.time(game.warpfac)
4225 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4227 prout(_("Engineering to bridge--"))
4228 prout(_(" Scott here. The warp engines are damaged."))
4229 prout(_(" We'll have to reduce speed to warp 4."))
4234 "Change the warp factor."
4236 key=scanner.nexttok()
4240 proutn(_("Warp factor- "))
4244 if game.damage[DWARPEN] > 10.0:
4245 prout(_("Warp engines inoperative."))
4247 if damaged(DWARPEN) and scanner.real > 4.0:
4248 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4249 prout(_(" but right now we can only go warp 4.\""))
4251 if scanner.real > 10.0:
4252 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4254 if scanner.real < 1.0:
4255 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4257 oldfac = game.warpfac
4258 game.warpfac = scanner.real
4259 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4260 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4263 if game.warpfac < 8.00:
4264 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4266 if game.warpfac == 10.0:
4267 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4269 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4273 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4275 # is captain on planet?
4277 if damaged(DTRANSP):
4280 prout(_("Scotty rushes to the transporter controls."))
4282 prout(_("But with the shields up it's hopeless."))
4284 prouts(_("His desperate attempt to rescue you . . ."))
4289 prout(_("SUCCEEDS!"))
4292 proutn(_("The crystals mined were "))
4300 # Check to see if captain in shuttle craft
4305 # Inform captain of attempt to reach safety
4309 prouts(_("***RED ALERT! RED ALERT!"))
4311 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4312 prouts(_(" a supernova."))
4314 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4315 prout(_("safely out of quadrant."))
4316 if not damaged(DRADIO):
4317 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4318 # Try to use warp engines
4319 if damaged(DWARPEN):
4321 prout(_("Warp engines damaged."))
4324 game.warpfac = randreal(6.0, 8.0)
4325 prout(_("Warp factor set to %d") % int(game.warpfac))
4326 power = 0.75*game.energy
4327 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4328 dist = max(dist, randreal(math.sqrt(2)))
4329 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4330 game.optime = bugout.time(game.warpfac)
4332 game.inorbit = False
4333 warp(bugout, involuntary=True)
4335 # This is bad news, we didn't leave quadrant.
4339 prout(_("Insufficient energy to leave quadrant."))
4342 # Repeat if another snova
4343 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4345 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4346 finish(FWON) # Snova killed remaining enemy.
4349 "Let's do the time warp again."
4350 prout(_("***TIME WARP ENTERED."))
4351 if game.state.snap and withprob(0.5):
4353 prout(_("You are traveling backwards in time %d stardates.") %
4354 int(game.state.date-game.snapsht.date))
4355 game.state = game.snapsht
4356 game.state.snap = False
4357 if len(game.state.kcmdr):
4358 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4359 schedule(FBATTAK, expran(0.3*game.intime))
4360 schedule(FSNOVA, expran(0.5*game.intime))
4361 # next snapshot will be sooner
4362 schedule(FSNAP, expran(0.25*game.state.remtime))
4364 if game.state.nscrem:
4365 schedule(FSCMOVE, 0.2777)
4369 game.battle.invalidate()
4370 # Make sure Galileo is consistant -- Snapshot may have been taken
4371 # when on planet, which would give us two Galileos!
4373 for l in range(game.inplan):
4374 if game.state.planets[l].known == "shuttle_down":
4376 if game.iscraft == "onship" and game.ship=='E':
4377 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4378 game.iscraft = "offship"
4379 # Likewise, if in the original time the Galileo was abandoned, but
4380 # was on ship earlier, it would have vanished -- let's restore it.
4381 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4382 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4383 game.iscraft = "onship"
4384 # There used to be code to do the actual reconstrction here,
4385 # but the starchart is now part of the snapshotted galaxy state.
4386 prout(_("Spock has reconstructed a correct star chart from memory"))
4388 # Go forward in time
4389 game.optime = expran(0.5*game.intime)
4390 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4391 # cheat to make sure no tractor beams occur during time warp
4392 postpone(FTBEAM, game.optime)
4393 game.damage[DRADIO] += game.optime
4395 events() # Stas Sergeev added this -- do pending events
4398 "Launch deep-space probe."
4399 # New code to launch a deep space probe
4400 if game.nprobes == 0:
4403 if game.ship == 'E':
4404 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4406 prout(_("Ye Faerie Queene has no deep space probes."))
4411 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4413 if is_scheduled(FDSPROB):
4416 if damaged(DRADIO) and game.condition != "docked":
4417 prout(_("Spock- \"Records show the previous probe has not yet"))
4418 prout(_(" reached its destination.\""))
4420 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4422 key = scanner.nexttok()
4424 if game.nprobes == 1:
4425 prout(_("1 probe left."))
4427 prout(_("%d probes left") % game.nprobes)
4428 proutn(_("Are you sure you want to fire a probe? "))
4431 game.isarmed = False
4432 if key == "IHALPHA" and scanner.token == "armed":
4434 key = scanner.nexttok()
4435 elif key == "IHEOL":
4436 proutn(_("Arm NOVAMAX warhead? "))
4438 elif key == "IHREAL": # first element of course
4439 scanner.push(scanner.token)
4441 game.probe = getcourse(isprobe=True)
4445 schedule(FDSPROB, 0.01) # Time to move one sector
4446 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4451 "Yell for help from nearest starbase."
4452 # There's more than one way to move in this game!
4454 # Test for conditions which prevent calling for help
4455 if game.condition == "docked":
4456 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4459 prout(_("Subspace radio damaged."))
4461 if not game.state.baseq:
4462 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4465 prout(_("You must be aboard the %s.") % crmshp())
4467 # OK -- call for help from nearest starbase
4470 # There's one in this quadrant
4471 ddist = (game.base - game.sector).distance()
4473 ibq = None # Force base-quadrant game to persist past loop
4475 for ibq in game.state.baseq:
4476 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4480 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4482 # Since starbase not in quadrant, set up new quadrant
4485 # dematerialize starship
4486 game.quad[game.sector.i][game.sector.j]='.'
4487 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4488 % (game.quadrant, crmshp()))
4489 game.sector.invalidate()
4490 for m in range(1, 5+1):
4491 w = game.base.scatter()
4492 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4493 # found one -- finish up
4496 if not game.sector.is_valid():
4497 prout(_("You have been lost in space..."))
4498 finish(FMATERIALIZE)
4500 # Give starbase three chances to rematerialize starship
4501 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4502 for m in range(1, 3+1):
4503 if m == 1: proutn(_("1st"))
4504 elif m == 2: proutn(_("2nd"))
4505 elif m == 3: proutn(_("3rd"))
4506 proutn(_(" attempt to re-materialize ") + crmshp())
4507 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4510 if randreal() > probf:
4514 curses.delay_output(500)
4516 game.quad[game.sector.i][game.sector.j]='?'
4519 setwnd(message_window)
4520 finish(FMATERIALIZE)
4522 game.quad[game.sector.i][game.sector.j]=game.ship
4524 prout(_("succeeds."))
4528 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4533 if game.condition=="docked":
4535 prout(_("You cannot abandon Ye Faerie Queene."))
4538 # Must take shuttle craft to exit
4539 if game.damage[DSHUTTL]==-1:
4540 prout(_("Ye Faerie Queene has no shuttle craft."))
4542 if game.damage[DSHUTTL]<0:
4543 prout(_("Shuttle craft now serving Big Macs."))
4545 if game.damage[DSHUTTL]>0:
4546 prout(_("Shuttle craft damaged."))
4549 prout(_("You must be aboard the ship."))
4551 if game.iscraft != "onship":
4552 prout(_("Shuttle craft not currently available."))
4554 # Emit abandon ship messages
4556 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4558 prouts(_("***ALL HANDS ABANDON SHIP!"))
4560 prout(_("Captain and crew escape in shuttle craft."))
4561 if not game.state.baseq:
4562 # Oops! no place to go...
4565 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4567 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4568 prout(_("Remainder of ship's complement beam down"))
4569 prout(_("to nearest habitable planet."))
4570 elif q.planet != None and not damaged(DTRANSP):
4571 prout(_("Remainder of ship's complement beam down to %s.") %
4574 prout(_("Entire crew of %d left to die in outer space.") %
4576 game.casual += game.state.crew
4577 game.abandoned += game.state.crew
4578 # If at least one base left, give 'em the Faerie Queene
4580 game.icrystl = False # crystals are lost
4581 game.nprobes = 0 # No probes
4582 prout(_("You are captured by Klingons and released to"))
4583 prout(_("the Federation in a prisoner-of-war exchange."))
4584 nb = randrange(len(game.state.baseq))
4585 # Set up quadrant and position FQ adjacient to base
4586 if not game.quadrant == game.state.baseq[nb]:
4587 game.quadrant = game.state.baseq[nb]
4588 game.sector.i = game.sector.j = 5
4591 # position next to base by trial and error
4592 game.quad[game.sector.i][game.sector.j] = '.'
4594 for l in range(QUADSIZE):
4595 game.sector = game.base.scatter()
4596 if game.sector.valid_sector() and \
4597 game.quad[game.sector.i][game.sector.j] == '.':
4600 break # found a spot
4601 game.sector.i=QUADSIZE/2
4602 game.sector.j=QUADSIZE/2
4604 # Get new commission
4605 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4606 game.state.crew = FULLCREW
4607 prout(_("Starfleet puts you in command of another ship,"))
4608 prout(_("the Faerie Queene, which is antiquated but,"))
4609 prout(_("still useable."))
4611 prout(_("The dilithium crystals have been moved."))
4613 game.iscraft = "offship" # Galileo disappears
4615 game.condition="docked"
4616 for l in range(NDEVICES):
4617 game.damage[l] = 0.0
4618 game.damage[DSHUTTL] = -1
4619 game.energy = game.inenrg = 3000.0
4620 game.shield = game.inshld = 1250.0
4621 game.torps = game.intorps = 6
4622 game.lsupres=game.inlsr=3.0
4625 game.brigfree = game.brigcapacity = 300
4628 # Code from planets.c begins here.
4631 "Abort a lengthy operation if an event interrupts it."
4634 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4639 "Report on (uninhabited) planets in the galaxy."
4643 prout(_("Spock- \"Planet report follows, Captain.\""))
4645 for i in range(game.inplan):
4646 if game.state.planets[i].pclass == "destroyed":
4648 if (game.state.planets[i].known != "unknown" \
4649 and not game.state.planets[i].inhabited) \
4652 if game.idebug and game.state.planets[i].known=="unknown":
4653 proutn("(Unknown) ")
4654 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4655 proutn(_(" class "))
4656 proutn(game.state.planets[i].pclass)
4658 if game.state.planets[i].crystals != "present":
4660 prout(_("dilithium crystals present."))
4661 if game.state.planets[i].known=="shuttle_down":
4662 prout(_(" Shuttle Craft Galileo on surface."))
4664 prout(_("No information available."))
4667 "Enter standard orbit."
4671 prout(_("Already in standard orbit."))
4673 if damaged(DWARPEN) and damaged(DIMPULS):
4674 prout(_("Both warp and impulse engines damaged."))
4676 if not game.plnet.is_valid():
4677 prout("There is no planet in this sector.")
4679 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4680 prout(crmshp() + _(" not adjacent to planet."))
4683 game.optime = randreal(0.02, 0.05)
4684 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4688 game.height = randreal(1400, 8600)
4689 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4694 "Examine planets in this quadrant."
4695 if damaged(DSRSENS):
4696 if game.options & OPTION_TTY:
4697 prout(_("Short range sensors damaged."))
4699 if game.iplnet is None:
4700 if game.options & OPTION_TTY:
4701 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4703 if game.iplnet.known == "unknown":
4704 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4706 prout(_(" Planet at Sector %s is of class %s.") %
4707 (game.plnet, game.iplnet.pclass))
4708 if game.iplnet.known=="shuttle_down":
4709 prout(_(" Sensors show Galileo still on surface."))
4710 proutn(_(" Readings indicate"))
4711 if game.iplnet.crystals != "present":
4713 prout(_(" dilithium crystals present.\""))
4714 if game.iplnet.known == "unknown":
4715 game.iplnet.known = "known"
4716 elif game.iplnet.inhabited:
4717 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4718 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4721 "Use the transporter."
4725 if damaged(DTRANSP):
4726 prout(_("Transporter damaged."))
4727 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4729 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4733 if not game.inorbit:
4734 prout(crmshp() + _(" not in standard orbit."))
4737 prout(_("Impossible to transport through shields."))
4739 if game.iplnet.known=="unknown":
4740 prout(_("Spock- \"Captain, we have no information on this planet"))
4741 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4742 prout(_(" you may not go down.\""))
4744 if not game.landed and game.iplnet.crystals=="absent":
4745 prout(_("Spock- \"Captain, I fail to see the logic in"))
4746 prout(_(" exploring a planet with no dilithium crystals."))
4747 proutn(_(" Are you sure this is wise?\" "))
4751 if not (game.options & OPTION_PLAIN):
4752 nrgneed = 50 * game.skill + game.height / 100.0
4753 if nrgneed > game.energy:
4754 prout(_("Engineering to bridge--"))
4755 prout(_(" Captain, we don't have enough energy for transportation."))
4757 if not game.landed and nrgneed * 2 > game.energy:
4758 prout(_("Engineering to bridge--"))
4759 prout(_(" Captain, we have enough energy only to transport you down to"))
4760 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4761 if game.iplnet.known == "shuttle_down":
4762 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4763 proutn(_(" Are you sure this is wise?\" "))
4768 # Coming from planet
4769 if game.iplnet.known=="shuttle_down":
4770 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4774 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4775 prout(_("Landing party assembled, ready to beam up."))
4777 prout(_("Kirk whips out communicator..."))
4778 prouts(_("BEEP BEEP BEEP"))
4780 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4783 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4785 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4787 prout(_("Kirk- \"Energize.\""))
4790 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4792 if not withprob(0.98):
4793 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4795 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4798 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4799 game.landed = not game.landed
4800 game.energy -= nrgneed
4802 prout(_("Transport complete."))
4803 if game.landed and game.iplnet.known=="shuttle_down":
4804 prout(_("The shuttle craft Galileo is here!"))
4805 if not game.landed and game.imine:
4812 "Strip-mine a world for dilithium."
4816 prout(_("Mining party not on planet."))
4818 if game.iplnet.crystals == "mined":
4819 prout(_("This planet has already been strip-mined for dilithium."))
4821 elif game.iplnet.crystals == "absent":
4822 prout(_("No dilithium crystals on this planet."))
4825 prout(_("You've already mined enough crystals for this trip."))
4827 if game.icrystl and game.cryprob == 0.05:
4828 prout(_("With all those fresh crystals aboard the ") + crmshp())
4829 prout(_("there's no reason to mine more at this time."))
4831 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4834 prout(_("Mining operation complete."))
4835 game.iplnet.crystals = "mined"
4836 game.imine = game.ididit = True
4839 "Use dilithium crystals."
4843 if not game.icrystl:
4844 prout(_("No dilithium crystals available."))
4846 if game.energy >= 1000:
4847 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4848 prout(_(" except when Condition Yellow exists."))
4850 prout(_("Spock- \"Captain, I must warn you that loading"))
4851 prout(_(" raw dilithium crystals into the ship's power"))
4852 prout(_(" system may risk a severe explosion."))
4853 proutn(_(" Are you sure this is wise?\" "))
4858 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4859 prout(_(" Mr. Spock and I will try it.\""))
4861 prout(_("Spock- \"Crystals in place, Sir."))
4862 prout(_(" Ready to activate circuit.\""))
4864 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4866 if withprob(game.cryprob):
4867 prouts(_(" \"Activating now! - - No good! It's***"))
4869 prouts(_("***RED ALERT! RED A*L********************************"))
4872 prouts(_("****************** KA-BOOM!!!! *******************"))
4876 game.energy += randreal(5000.0, 5500.0)
4877 prouts(_(" \"Activating now! - - "))
4878 prout(_("The instruments"))
4879 prout(_(" are going crazy, but I think it's"))
4880 prout(_(" going to work!! Congratulations, Sir!\""))
4885 "Use shuttlecraft for planetary jaunt."
4888 if damaged(DSHUTTL):
4889 if game.damage[DSHUTTL] == -1.0:
4890 if game.inorbit and game.iplnet.known == "shuttle_down":
4891 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4893 prout(_("Ye Faerie Queene had no shuttle craft."))
4894 elif game.damage[DSHUTTL] > 0:
4895 prout(_("The Galileo is damaged."))
4896 else: # game.damage[DSHUTTL] < 0
4897 prout(_("Shuttle craft is now serving Big Macs."))
4899 if not game.inorbit:
4900 prout(crmshp() + _(" not in standard orbit."))
4902 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4903 prout(_("Shuttle craft not currently available."))
4905 if not game.landed and game.iplnet.known=="shuttle_down":
4906 prout(_("You will have to beam down to retrieve the shuttle craft."))
4908 if game.shldup or game.condition == "docked":
4909 prout(_("Shuttle craft cannot pass through shields."))
4911 if game.iplnet.known=="unknown":
4912 prout(_("Spock- \"Captain, we have no information on this planet"))
4913 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4914 prout(_(" you may not fly down.\""))
4916 game.optime = 3.0e-5*game.height
4917 if game.optime >= 0.8*game.state.remtime:
4918 prout(_("First Officer Spock- \"Captain, I compute that such"))
4919 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4920 int(100*game.optime/game.state.remtime))
4921 prout(_("remaining time."))
4922 proutn(_("Are you sure this is wise?\" "))
4928 if game.iscraft == "onship":
4930 if not damaged(DTRANSP):
4931 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4935 proutn(_("Shuttle crew"))
4937 proutn(_("Rescue party"))
4938 prout(_(" boards Galileo and swoops toward planet surface."))
4939 game.iscraft = "offship"
4943 game.iplnet.known="shuttle_down"
4944 prout(_("Trip complete."))
4947 # Ready to go back to ship
4948 prout(_("You and your mining party board the"))
4949 prout(_("shuttle craft for the trip back to the Enterprise."))
4951 prouts(_("The short hop begins . . ."))
4953 game.iplnet.known="known"
4959 game.iscraft = "onship"
4965 prout(_("Trip complete."))
4968 # Kirk on ship and so is Galileo
4969 prout(_("Mining party assembles in the hangar deck,"))
4970 prout(_("ready to board the shuttle craft \"Galileo\"."))
4972 prouts(_("The hangar doors open; the trip begins."))
4975 game.iscraft = "offship"
4978 game.iplnet.known = "shuttle_down"
4981 prout(_("Trip complete."))
4985 "Use the big zapper."
4989 if game.ship != 'E':
4990 prout(_("Ye Faerie Queene has no death ray."))
4992 if len(game.enemies)==0:
4993 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4996 prout(_("Death Ray is damaged."))
4998 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4999 prout(_(" is highly unpredictible. Considering the alternatives,"))
5000 proutn(_(" are you sure this is wise?\" "))
5003 prout(_("Spock- \"Acknowledged.\""))
5006 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
5008 prout(_("Crew scrambles in emergency preparation."))
5009 prout(_("Spock and Scotty ready the death ray and"))
5010 prout(_("prepare to channel all ship's power to the device."))
5012 prout(_("Spock- \"Preparations complete, sir.\""))
5013 prout(_("Kirk- \"Engage!\""))
5015 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
5018 if game.options & OPTION_PLAIN:
5022 prouts(_("Sulu- \"Captain! It's working!\""))
5024 while len(game.enemies) > 0:
5025 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
5026 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
5027 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
5029 if (game.options & OPTION_PLAIN) == 0:
5030 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
5032 prout(_(" is still operational.\""))
5034 prout(_(" has been rendered nonfunctional.\""))
5035 game.damage[DDRAY] = 39.95
5037 r = randreal() # Pick failure method
5039 prouts(_("Sulu- \"Captain! It's working!\""))
5041 prouts(_("***RED ALERT! RED ALERT!"))
5043 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
5045 prouts(_("***RED ALERT! RED A*L********************************"))
5048 prouts(_("****************** KA-BOOM!!!! *******************"))
5053 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
5055 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
5057 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
5058 prout(_(" have apparently been transformed into strange mutations."))
5059 prout(_(" Vulcans do not seem to be affected."))
5061 prout(_("Kirk- \"Raauch! Raauch!\""))
5065 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
5067 proutn(_("Spock- \"I believe the word is"))
5068 prouts(_(" *ASTONISHING*"))
5069 prout(_(" Mr. Sulu."))
5070 for i in range(QUADSIZE):
5071 for j in range(QUADSIZE):
5072 if game.quad[i][j] == '.':
5073 game.quad[i][j] = '?'
5074 prout(_(" Captain, our quadrant is now infested with"))
5075 prouts(_(" - - - - - - *THINGS*."))
5077 prout(_(" I have no logical explanation.\""))
5079 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
5081 prout(_("Scotty- \"There are so many tribbles down here"))
5082 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
5086 # Code from reports.c begins here
5088 def attackreport(curt):
5089 "eport status of bases under attack."
5091 if is_scheduled(FCDBAS):
5092 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
5093 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
5094 elif game.isatb == 1:
5095 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
5096 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
5098 prout(_("No Starbase is currently under attack."))
5100 if is_scheduled(FCDBAS):
5101 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
5103 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
5107 # report on general game status
5109 s1 = (game.thawed and _("thawed ")) or ""
5110 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
5111 s3 = (None, _("novice"), _("fair"),
5112 _("good"), _("expert"), _("emeritus"))[game.skill]
5113 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
5114 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
5115 prout(_("No plaque is allowed."))
5117 prout(_("This is tournament game %d.") % game.tourn)
5118 prout(_("Your secret password is \"%s\"") % game.passwd)
5119 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
5120 (game.inkling + game.incom + game.inscom)))
5121 if game.incom - len(game.state.kcmdr):
5122 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
5123 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
5124 prout(_(", but no Commanders."))
5127 if game.skill > SKILL_FAIR:
5128 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
5129 if len(game.state.baseq) != game.inbase:
5131 if game.inbase-len(game.state.baseq)==1:
5132 proutn(_("has been 1 base"))
5134 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
5135 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
5137 prout(_("There are %d bases.") % game.inbase)
5138 if communicating() or game.iseenit:
5139 # Don't report this if not seen and
5140 # either the radio is dead or not at base!
5144 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
5145 if game.brigcapacity != game.brigfree:
5146 embriggened = brigcapacity-brigfree
5147 if embriggened == 1:
5148 prout(_("1 Klingon in brig"))
5150 prout(_("%d Klingons in brig.") % embriggened)
5151 if game.kcaptured == 0:
5153 elif game.kcaptured == 1:
5154 prout(_("1 captured Klingon turned in to Starfleet."))
5156 prout(_("%d captured Klingons turned in to Star Fleet.") % game.kcaptured)
5158 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
5159 if game.ship == 'E':
5160 proutn(_("You have "))
5162 proutn("%d" % (game.nprobes))
5165 proutn(_(" deep space probe"))
5169 if communicating() and is_scheduled(FDSPROB):
5171 proutn(_("An armed deep space probe is in "))
5173 proutn(_("A deep space probe is in "))
5174 prout("Quadrant %s." % game.probe.quadrant())
5176 if game.cryprob <= .05:
5177 prout(_("Dilithium crystals aboard ship... not yet used."))
5181 while game.cryprob > ai:
5184 prout(_("Dilithium crystals have been used %d time%s.") % \
5185 (i, (_("s"), "")[i==1]))
5189 "Long-range sensor scan."
5190 if damaged(DLRSENS):
5191 # Now allow base's sensors if docked
5192 if game.condition != "docked":
5194 prout(_("LONG-RANGE SENSORS DAMAGED."))
5197 prout(_("Starbase's long-range scan"))
5199 prout(_("Long-range scan"))
5200 for x in range(game.quadrant.i-1, game.quadrant.i+2):
5203 for y in range(game.quadrant.j-1, game.quadrant.j+2):
5204 if not Coord(x, y).valid_quadrant():
5208 if not damaged(DRADIO):
5209 game.state.galaxy[x][y].charted = True
5210 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5211 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5212 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5213 if not silent and game.state.galaxy[x][y].supernova:
5216 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
5224 for i in range(NDEVICES):
5227 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5228 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5230 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5231 game.damage[i]+0.05,
5232 DOCKFAC*game.damage[i]+0.005))
5234 prout(_("All devices functional."))
5237 "Update the chart in the Enterprise's computer from galaxy data."
5238 game.lastchart = game.state.date
5239 for i in range(GALSIZE):
5240 for j in range(GALSIZE):
5241 if game.state.galaxy[i][j].charted:
5242 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5243 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5244 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5247 "Display the star chart."
5249 if (game.options & OPTION_AUTOSCAN):
5251 if not damaged(DRADIO):
5253 if game.lastchart < game.state.date and game.condition == "docked":
5254 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5256 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5257 if game.state.date > game.lastchart:
5258 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5259 prout(" 1 2 3 4 5 6 7 8")
5260 for i in range(GALSIZE):
5261 proutn("%d |" % (i+1))
5262 for j in range(GALSIZE):
5263 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5267 if game.state.galaxy[i][j].supernova:
5269 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5271 elif game.state.galaxy[i][j].charted:
5272 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5276 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5284 def sectscan(goodScan, i, j):
5285 "Light up an individual dot in a sector."
5286 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5287 if game.quad[i][j] in ('E', 'F'):
5290 textcolor({"green":GREEN,
5294 "dead":BROWN}[game.condition])
5296 textcolor({'?':LIGHTMAGENTA,
5302 }.get(game.quad[i][j], DEFAULT))
5303 proutn("%c " % game.quad[i][j])
5309 "Emit status report lines"
5310 if not req or req == 1:
5311 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5312 % (game.state.date, game.state.remtime))
5313 if not req or req == 2:
5314 if game.condition != "docked":
5316 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5317 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5319 prout(_(", CLOAKED"))
5320 if not req or req == 3:
5321 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5322 if not req or req == 4:
5323 if damaged(DLIFSUP):
5324 if game.condition == "docked":
5325 s = _("DAMAGED, Base provides")
5327 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5330 prstat(_("Life Support"), s)
5331 if not req or req == 5:
5332 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5333 if not req or req == 6:
5335 if game.icrystl and (game.options & OPTION_SHOWME):
5336 extra = _(" (have crystals)")
5337 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5338 if not req or req == 7:
5339 prstat(_("Torpedoes"), "%d" % (game.torps))
5340 if not req or req == 8:
5341 if damaged(DSHIELD):
5347 data = _(" %d%% %.1f units") \
5348 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5349 prstat(_("Shields"), s+data)
5350 if not req or req == 9:
5351 prstat(_("Klingons Left"), "%d" \
5352 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5353 if not req or req == 10:
5354 if game.options & OPTION_WORLDS:
5355 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5356 if plnet and plnet.inhabited:
5357 prstat(_("Major system"), plnet.name)
5359 prout(_("Sector is uninhabited"))
5360 elif not req or req == 11:
5361 attackreport(not req)
5364 "Request specified status data, a historical relic from slow TTYs."
5365 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5366 while scanner.nexttok() == "IHEOL":
5367 proutn(_("Information desired? "))
5369 if scanner.token in requests:
5370 status(requests.index(scanner.token))
5372 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5373 prout((" date, condition, position, lsupport, warpfactor,"))
5374 prout((" energy, torpedoes, shields, klingons, system, time."))
5379 if damaged(DSRSENS):
5380 # Allow base's sensors if docked
5381 if game.condition != "docked":
5382 prout(_(" S.R. SENSORS DAMAGED!"))
5385 prout(_(" [Using Base's sensors]"))
5387 prout(_(" Short-range scan"))
5388 if goodScan and not damaged(DRADIO):
5389 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5390 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5391 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5392 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5393 prout(" 1 2 3 4 5 6 7 8 9 10")
5394 if game.condition != "docked":
5396 for i in range(QUADSIZE):
5397 proutn("%2d " % (i+1))
5398 for j in range(QUADSIZE):
5399 sectscan(goodScan, i, j)
5403 "Use computer to get estimated time of arrival for a warp jump."
5404 w1 = Coord(); w2 = Coord()
5406 if damaged(DCOMPTR):
5407 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5410 if scanner.nexttok() != "IHREAL":
5413 proutn(_("Destination quadrant and/or sector? "))
5414 if scanner.nexttok()!="IHREAL":
5417 w1.j = int(scanner.real-0.5)
5418 if scanner.nexttok() != "IHREAL":
5421 w1.i = int(scanner.real-0.5)
5422 if scanner.nexttok() == "IHREAL":
5423 w2.j = int(scanner.real-0.5)
5424 if scanner.nexttok() != "IHREAL":
5427 w2.i = int(scanner.real-0.5)
5429 if game.quadrant.j>w1.i:
5433 if game.quadrant.i>w1.j:
5437 if not w1.valid_quadrant() or not w2.valid_sector():
5440 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5441 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5444 prout(_("Answer \"no\" if you don't know the value:"))
5447 proutn(_("Time or arrival date? "))
5448 if scanner.nexttok()=="IHREAL":
5449 ttime = scanner.real
5450 if ttime > game.state.date:
5451 ttime -= game.state.date # Actually a star date
5452 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5453 if ttime <= 1e-10 or twarp > 10:
5454 prout(_("We'll never make it, sir."))
5461 proutn(_("Warp factor? "))
5462 if scanner.nexttok()== "IHREAL":
5464 twarp = scanner.real
5465 if twarp<1.0 or twarp > 10.0:
5469 prout(_("Captain, certainly you can give me one of these."))
5472 ttime = (10.0*dist)/twarp**2
5473 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5474 if tpower >= game.energy:
5475 prout(_("Insufficient energy, sir."))
5476 if not game.shldup or tpower > game.energy*2.0:
5479 proutn(_("New warp factor to try? "))
5480 if scanner.nexttok() == "IHREAL":
5482 twarp = scanner.real
5483 if twarp<1.0 or twarp > 10.0:
5491 prout(_("But if you lower your shields,"))
5492 proutn(_("remaining"))
5495 proutn(_("Remaining"))
5496 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5498 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5500 prout(_("Any warp speed is adequate."))
5502 prout(_("Minimum warp needed is %.2f,") % (twarp))
5503 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5504 if game.state.remtime < ttime:
5505 prout(_("Unfortunately, the Federation will be destroyed by then."))
5507 prout(_("You'll be taking risks at that speed, Captain"))
5508 if (game.isatb==1 and game.state.kscmdr == w1 and \
5509 scheduled(FSCDBAS)< ttime+game.state.date) or \
5510 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5511 prout(_("The starbase there will be destroyed by then."))
5512 proutn(_("New warp factor to try? "))
5513 if scanner.nexttok() == "IHREAL":
5515 twarp = scanner.real
5516 if twarp<1.0 or twarp > 10.0:
5524 # Code from setup.c begins here
5527 "Issue a historically correct banner."
5529 prout(_("-SUPER- STAR TREK"))
5531 # From the FORTRAN original
5532 # prout(_("Latest update-21 Sept 78"))
5538 scanner.push("emsave.trk")
5539 key = scanner.nexttok()
5541 proutn(_("File name: "))
5542 key = scanner.nexttok()
5543 if key != "IHALPHA":
5546 if '.' not in scanner.token:
5547 scanner.token += ".trk"
5549 fp = open(scanner.token, "wb")
5551 prout(_("Can't freeze game as file %s") % scanner.token)
5553 pickle.dump(game, fp)
5558 "Retrieve saved game."
5561 key = scanner.nexttok()
5563 proutn(_("File name: "))
5564 key = scanner.nexttok()
5565 if key != "IHALPHA":
5568 if '.' not in scanner.token:
5569 scanner.token += ".trk"
5571 fp = open(scanner.token, "rb")
5573 prout(_("Can't thaw game in %s") % scanner.token)
5575 game = pickle.load(fp)
5580 # I used <http://www.memory-alpha.org> to find planets
5581 # with references in ST:TOS. Earth and the Alpha Centauri
5582 # Colony have been omitted.
5584 # Some planets marked Class G and P here will be displayed as class M
5585 # because of the way planets are generated. This is a known bug.
5588 _("Andoria (Fesoan)"), # several episodes
5589 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5590 _("Vulcan (T'Khasi)"), # many episodes
5591 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5592 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5593 _("Ardana"), # TOS: "The Cloud Minders"
5594 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5595 _("Gideon"), # TOS: "The Mark of Gideon"
5596 _("Aldebaran III"), # TOS: "The Deadly Years"
5597 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5598 _("Altair IV"), # TOS: "Amok Time
5599 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5600 _("Benecia"), # TOS: "The Conscience of the King"
5601 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5602 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5603 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5604 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5605 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5606 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5607 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5608 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5609 _("Ingraham B"), # TOS: "Operation: Annihilate"
5610 _("Janus IV"), # TOS: "The Devil in the Dark"
5611 _("Makus III"), # TOS: "The Galileo Seven"
5612 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5613 _("Omega IV"), # TOS: "The Omega Glory"
5614 _("Regulus V"), # TOS: "Amok Time
5615 _("Deneva"), # TOS: "Operation -- Annihilate!"
5616 # Worlds from BSD Trek
5617 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5618 _("Beta III"), # TOS: "The Return of the Archons"
5619 _("Triacus"), # TOS: "And the Children Shall Lead",
5620 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5622 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5623 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5624 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5625 # _("Izar"), # TOS: "Whom Gods Destroy"
5626 # _("Tiburon"), # TOS: "The Way to Eden"
5627 # _("Merak II"), # TOS: "The Cloud Minders"
5628 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5629 # _("Iotia"), # TOS: "A Piece of the Action"
5633 _("S. R. Sensors"), \
5634 _("L. R. Sensors"), \
5636 _("Photon Tubes"), \
5637 _("Life Support"), \
5638 _("Warp Engines"), \
5639 _("Impulse Engines"), \
5641 _("Subspace Radio"), \
5642 _("Shuttle Craft"), \
5644 _("Navigation System"), \
5646 _("Shield Control"), \
5649 _("Cloaking Device"), \
5653 "Prepare to play, set up cosmos."
5655 # Decide how many of everything
5657 return # frozen game
5658 # Prepare the Enterprise
5659 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5661 game.state.crew = FULLCREW
5662 game.energy = game.inenrg = 5000.0
5663 game.shield = game.inshld = 2500.0
5666 game.quadrant = randplace(GALSIZE)
5667 game.sector = randplace(QUADSIZE)
5668 game.torps = game.intorps = 10
5669 game.nprobes = randrange(2, 5)
5671 for i in range(NDEVICES):
5672 game.damage[i] = 0.0
5673 # Set up assorted game parameters
5674 game.battle = Coord()
5675 game.state.date = game.indate = 100.0 * randreal(20, 51)
5676 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5677 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5678 game.isatb = game.state.nplankl = 0
5679 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5680 game.iscraft = "onship"
5685 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5687 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5689 game.state.planets = [] # Planet information
5690 game.state.baseq = [] # Base quadrant coordinates
5691 game.state.kcmdr = [] # Commander quadrant coordinates
5692 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5694 # Starchart is functional but we've never seen it
5695 game.lastchart = FOREVER
5696 # Put stars in the galaxy
5698 for i in range(GALSIZE):
5699 for j in range(GALSIZE):
5700 # Can't have more stars per quadrant than fit in one decimal digit,
5701 # if we do the chart representation will break.
5702 k = randrange(1, min(10, QUADSIZE**2/10))
5704 game.state.galaxy[i][j].stars = k
5705 # Locate star bases in galaxy
5707 prout("=== Allocating %d bases" % game.inbase)
5708 for i in range(game.inbase):
5711 w = randplace(GALSIZE)
5712 if not game.state.galaxy[w.i][w.j].starbase:
5715 # C version: for (j = i-1; j > 0; j--)
5716 # so it did them in the opposite order.
5717 for j in range(1, i):
5718 # Improved placement algorithm to spread out bases
5719 distq = (w - game.state.baseq[j]).distance()
5720 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5723 prout("=== Abandoning base #%d at %s" % (i, w))
5725 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5727 prout("=== Saving base #%d, close to #%d" % (i, j))
5731 prout("=== Placing base #%d in quadrant %s" % (i, w))
5732 game.state.baseq.append(w)
5733 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5734 # Position ordinary Klingon Battle Cruisers
5736 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5737 if klumper > MAXKLQUAD:
5741 klump = (1.0 - r*r)*klumper
5746 w = randplace(GALSIZE)
5747 if not game.state.galaxy[w.i][w.j].supernova and \
5748 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5750 game.state.galaxy[w.i][w.j].klingons += int(klump)
5753 # Position Klingon Commander Ships
5754 for i in range(game.incom):
5756 w = randplace(GALSIZE)
5757 if not welcoming(w) or w in game.state.kcmdr:
5759 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5761 game.state.galaxy[w.i][w.j].klingons += 1
5762 game.state.kcmdr.append(w)
5763 # Locate planets in galaxy
5764 for i in range(game.inplan):
5766 w = randplace(GALSIZE)
5767 if game.state.galaxy[w.i][w.j].planet is None:
5771 new.crystals = "absent"
5772 if (game.options & OPTION_WORLDS) and i < NINHAB:
5773 new.pclass = "M" # All inhabited planets are class M
5774 new.crystals = "absent"
5776 new.name = systnames[i]
5777 new.inhabited = True
5779 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5781 new.crystals = "present"
5782 new.known = "unknown"
5783 new.inhabited = False
5784 game.state.galaxy[w.i][w.j].planet = new
5785 game.state.planets.append(new)
5787 for i in range(game.state.nromrem):
5788 w = randplace(GALSIZE)
5789 game.state.galaxy[w.i][w.j].romulans += 1
5790 # Place the Super-Commander if needed
5791 if game.state.nscrem > 0:
5793 w = randplace(GALSIZE)
5796 game.state.kscmdr = w
5797 game.state.galaxy[w.i][w.j].klingons += 1
5798 # Initialize times for extraneous events
5799 schedule(FSNOVA, expran(0.5 * game.intime))
5800 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5801 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5802 schedule(FBATTAK, expran(0.3*game.intime))
5804 if game.state.nscrem:
5805 schedule(FSCMOVE, 0.2777)
5810 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5811 schedule(FDISTR, expran(1.0 + game.intime))
5816 # Place thing (in tournament game, we don't want one!)
5817 # New in SST2K: never place the Thing near a starbase.
5818 # This makes sense and avoids a special case in the old code.
5820 if game.tourn is None:
5822 thing = randplace(GALSIZE)
5823 if thing not in game.state.baseq:
5826 game.state.snap = False
5827 if game.skill == SKILL_NOVICE:
5828 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5829 prout(_("a deadly Klingon invasion force. As captain of the United"))
5830 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5831 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5832 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5833 prout(_("your mission. As you proceed you may be given more time."))
5835 prout(_("You will have %d supporting starbases.") % (game.inbase))
5836 proutn(_("Starbase locations- "))
5838 prout(_("Stardate %d.") % int(game.state.date))
5840 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5841 prout(_("An unknown number of Romulans."))
5842 if game.state.nscrem:
5843 prout(_("And one (GULP) Super-Commander."))
5844 prout(_("%d stardates.") % int(game.intime))
5845 proutn(_("%d starbases in ") % game.inbase)
5846 for i in range(game.inbase):
5847 proutn(repr(game.state.baseq[i]))
5850 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5851 proutn(_(" Sector %s") % game.sector)
5853 prout(_("Good Luck!"))
5854 if game.state.nscrem:
5855 prout(_(" YOU'LL NEED IT."))
5858 setwnd(message_window)
5860 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5862 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5863 attack(torps_ok=False)
5866 "Choose your game type."
5868 game.tourn = game.length = 0
5870 game.skill = SKILL_NONE
5871 # Do not chew here, we want to use command-line tokens
5872 if not scanner.inqueue: # Can start with command line options
5873 proutn(_("Would you like a regular, tournament, or saved game? "))
5875 if scanner.sees("tournament"):
5876 while scanner.nexttok() == "IHEOL":
5877 proutn(_("Type in tournament number-"))
5878 if scanner.real == 0:
5880 continue # We don't want a blank entry
5881 game.tourn = int(round(scanner.real))
5882 random.seed(scanner.real)
5884 logfp.write("# random.seed(%d)\n" % scanner.real)
5886 if scanner.sees("saved") or scanner.sees("frozen"):
5890 if game.passwd is None:
5892 if not game.alldone:
5893 game.thawed = True # No plaque if not finished
5897 if scanner.sees("regular"):
5899 proutn(_("What is \"%s\"? ") % scanner.token)
5901 while game.length==0 or game.skill==SKILL_NONE:
5902 if scanner.nexttok() == "IHALPHA":
5903 if scanner.sees("short"):
5905 elif scanner.sees("medium"):
5907 elif scanner.sees("long"):
5909 elif scanner.sees("novice"):
5910 game.skill = SKILL_NOVICE
5911 elif scanner.sees("fair"):
5912 game.skill = SKILL_FAIR
5913 elif scanner.sees("good"):
5914 game.skill = SKILL_GOOD
5915 elif scanner.sees("expert"):
5916 game.skill = SKILL_EXPERT
5917 elif scanner.sees("emeritus"):
5918 game.skill = SKILL_EMERITUS
5920 proutn(_("What is \""))
5921 proutn(scanner.token)
5926 proutn(_("Would you like a Short, Medium, or Long game? "))
5927 elif game.skill == SKILL_NONE:
5928 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5929 # Choose game options -- added by ESR for SST2K
5930 if scanner.nexttok() != "IHALPHA":
5932 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5934 if scanner.sees("plain"):
5935 # Approximates the UT FORTRAN version.
5936 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)
5937 game.options |= OPTION_PLAIN
5938 elif scanner.sees("almy"):
5939 # Approximates Tom Almy's version.
5940 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
5941 game.options |= OPTION_ALMY
5942 elif scanner.sees("fancy") or scanner.sees("\n"):
5944 elif len(scanner.token):
5945 proutn(_("What is \"%s\"?") % scanner.token)
5947 if game.passwd == "debug":
5949 prout("=== Debug mode enabled.")
5950 # Use parameters to generate initial values of things
5951 game.damfac = 0.5 * game.skill
5952 game.inbase = randrange(BASEMIN, BASEMAX+1)
5954 if game.options & OPTION_PLANETS:
5955 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5956 if game.options & OPTION_WORLDS:
5957 game.inplan += int(NINHAB)
5958 game.state.nromrem = game.inrom = randrange(2 * game.skill)
5959 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5960 game.state.remtime = 7.0 * game.length
5961 game.intime = game.state.remtime
5962 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5963 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5964 game.state.remres = (game.inkling+4*game.incom)*game.intime
5965 game.inresor = game.state.remres
5966 if game.inkling > 50:
5970 def dropin(iquad=None):
5971 "Drop a feature on a random dot in the current quadrant."
5973 w = randplace(QUADSIZE)
5974 if game.quad[w.i][w.j] == '.':
5976 if iquad is not None:
5977 game.quad[w.i][w.j] = iquad
5981 "Update our alert status."
5982 game.condition = "green"
5983 if game.energy < 1000.0:
5984 game.condition = "yellow"
5985 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5986 game.condition = "red"
5988 game.condition="dead"
5991 "Drop new Klingon into current quadrant."
5992 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5995 "Sort enemies by distance so 'nearest' is meaningful."
5996 game.enemies.sort(key=lambda x: x.kdist)
5999 "Set up a new state of quadrant, for when we enter or re-enter it."
6002 game.neutz = game.inorbit = game.landed = False
6003 game.ientesc = game.iseenit = game.isviolreported = False
6004 # Create a blank quadrant
6005 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
6007 # Attempt to escape Super-commander, so tbeam back!
6010 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
6011 # cope with supernova
6014 game.klhere = q.klingons
6015 game.irhere = q.romulans
6017 game.quad[game.sector.i][game.sector.j] = game.ship
6020 # Position ordinary Klingons
6021 for _i in range(game.klhere):
6023 # If we need a commander, promote a Klingon
6024 for cmdr in game.state.kcmdr:
6025 if cmdr == game.quadrant:
6026 e = game.enemies[game.klhere-1]
6027 game.quad[e.location.i][e.location.j] = 'C'
6028 e.power = randreal(950,1350) + 50.0*game.skill
6030 # If we need a super-commander, promote a Klingon
6031 if game.quadrant == game.state.kscmdr:
6033 game.quad[e.location.i][e.location.j] = 'S'
6034 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
6035 game.iscate = (game.state.remkl > 1)
6036 # Put in Romulans if needed
6037 for _i in range(q.romulans):
6038 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
6039 # If quadrant needs a starbase, put it in
6041 game.base = dropin('B')
6042 # If quadrant needs a planet, put it in
6044 game.iplnet = q.planet
6045 if not q.planet.inhabited:
6046 game.plnet = dropin('P')
6048 game.plnet = dropin('@')
6049 # Check for condition
6052 if game.irhere > 0 and game.klhere == 0:
6054 if not damaged(DRADIO):
6056 prout(_("LT. Uhura- \"Captain, an urgent message."))
6057 prout(_(" I'll put it on audio.\" CLICK"))
6059 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
6060 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
6061 # Put in THING if needed
6062 if thing == game.quadrant:
6063 Enemy(etype='?', loc=dropin(),
6064 power=randreal(6000,6500.0)+250.0*game.skill)
6065 if not damaged(DSRSENS):
6067 prout(_("Mr. Spock- \"Captain, this is most unusual."))
6068 prout(_(" Please examine your short-range scan.\""))
6069 # Decide if quadrant needs a Tholian; lighten up if skill is low
6070 if game.options & OPTION_THOLIAN:
6071 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
6072 (game.skill == SKILL_GOOD and withprob(0.05)) or \
6073 (game.skill > SKILL_GOOD and withprob(0.08)):
6076 w.i = withprob(0.5) * (QUADSIZE-1)
6077 w.j = withprob(0.5) * (QUADSIZE-1)
6078 if game.quad[w.i][w.j] == '.':
6080 game.tholian = Enemy(etype='T', loc=w,
6081 power=randrange(100, 500) + 25.0*game.skill)
6082 # Reserve unoccupied corners
6083 if game.quad[0][0]=='.':
6084 game.quad[0][0] = 'X'
6085 if game.quad[0][QUADSIZE-1]=='.':
6086 game.quad[0][QUADSIZE-1] = 'X'
6087 if game.quad[QUADSIZE-1][0]=='.':
6088 game.quad[QUADSIZE-1][0] = 'X'
6089 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
6090 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
6092 # And finally the stars
6093 for _i in range(q.stars):
6095 # Put in a few black holes
6096 for _i in range(1, 3+1):
6099 # Take out X's in corners if Tholian present
6101 if game.quad[0][0]=='X':
6102 game.quad[0][0] = '.'
6103 if game.quad[0][QUADSIZE-1]=='X':
6104 game.quad[0][QUADSIZE-1] = '.'
6105 if game.quad[QUADSIZE-1][0]=='X':
6106 game.quad[QUADSIZE-1][0] = '.'
6107 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
6108 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
6111 "Set the self-destruct password."
6112 if game.options & OPTION_PLAIN:
6115 proutn(_("Please type in a secret password- "))
6117 game.passwd = scanner.token
6118 if game.passwd != None:
6122 game.passwd += chr(ord('a')+randrange(26))
6123 game.passwd += chr(ord('a')+randrange(26))
6124 game.passwd += chr(ord('a')+randrange(26))
6126 # Code from sst.c begins here
6129 ("SRSCAN", OPTION_TTY),
6130 ("STATUS", OPTION_TTY),
6131 ("REQUEST", OPTION_TTY),
6132 ("LRSCAN", OPTION_TTY),
6144 ("SENSORS", OPTION_PLANETS),
6145 ("ORBIT", OPTION_PLANETS),
6146 ("TRANSPORT", OPTION_PLANETS),
6147 ("MINE", OPTION_PLANETS),
6148 ("CRYSTALS", OPTION_PLANETS),
6149 ("SHUTTLE", OPTION_PLANETS),
6150 ("PLANETS", OPTION_PLANETS),
6155 ("PROBE", OPTION_PROBE),
6157 ("FREEZE", 0), # Synonym for SAVE
6161 ("CAPTURE", OPTION_CAPTURE),
6162 ("CLOAK", OPTION_CLOAK),
6165 ("SOS", 0), # Synonym for MAYDAY
6166 ("CALL", 0), # Synonym for MAYDAY
6174 "Generate a list of legal commands."
6175 prout(_("LEGAL COMMANDS ARE:"))
6177 for (key, opt) in commands:
6178 if not opt or (opt & game.options):
6179 proutn("%-12s " % key)
6181 if emitted % 5 == 4:
6186 "Browse on-line help."
6187 key = scanner.nexttok()
6190 setwnd(prompt_window)
6191 proutn(_("Help on what command? "))
6192 key = scanner.nexttok()
6193 setwnd(message_window)
6196 cmds = [x[0] for x in commands]
6197 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
6204 cmd = scanner.token.upper()
6205 for directory in docpath:
6207 fp = open(os.path.join(directory, "sst.doc"), "r")
6212 prout(_("Spock- \"Captain, that information is missing from the"))
6213 prout(_(" computer. You need to find sst.doc and put it somewhere"))
6214 proutn(_(" in these directories: %s") % ":".join(docpath))
6216 # This used to continue: "You need to find SST.DOC and put
6217 # it in the current directory."
6220 linebuf = fp.readline()
6222 prout(_("Spock- \"Captain, there is no information on that command.\""))
6225 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
6226 linebuf = linebuf[3:].strip()
6227 if cmd.upper() == linebuf:
6230 prout(_("Spock- \"Captain, I've found the following information:\""))
6233 linebuf = fp.readline()
6234 if "******" in linebuf:
6240 "Command-interpretation loop."
6242 if game.irhere and game.state.date >= ALGERON and not game.isviolreported and game.iscloaked:
6243 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
6245 game.isviolreported = True
6246 while True: # command loop
6248 while True: # get a command
6250 game.optime = game.justin = False
6252 setwnd(prompt_window)
6255 if scanner.nexttok() == "IHEOL":
6256 if game.options & OPTION_CURSES:
6259 elif scanner.token == "":
6263 setwnd(message_window)
6265 abandon_passed = False
6266 cmd = "" # Force cmd to persist after loop
6267 opt = 0 # Force opt to persist after loop
6268 for (cmd, opt) in commands:
6269 # commands after ABANDON cannot be abbreviated
6270 if cmd == "ABANDON":
6271 abandon_passed = True
6272 if cmd == scanner.token.upper() or (not abandon_passed \
6273 and cmd.startswith(scanner.token.upper())):
6278 elif opt and not (opt & game.options):
6282 if cmd == "SRSCAN": # srscan
6284 elif cmd == "STATUS": # status
6286 elif cmd == "REQUEST": # status request
6288 elif cmd == "LRSCAN": # long range scan
6289 lrscan(silent=False)
6290 elif cmd == "PHASERS": # phasers
6295 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6300 elif cmd == "MOVE": # move under warp
6301 warp(wcourse=None, involuntary=False)
6302 elif cmd == "SHIELDS": # shields
6303 doshield(shraise=False)
6306 game.shldchg = False
6307 elif cmd == "DOCK": # dock at starbase
6310 attack(torps_ok=False)
6311 elif cmd == "DAMAGES": # damage reports
6313 elif cmd == "CHART": # chart
6315 elif cmd == "IMPULSE": # impulse
6317 elif cmd == "REST": # rest
6321 elif cmd == "WARP": # warp
6323 elif cmd == "SENSORS": # sensors
6325 elif cmd == "ORBIT": # orbit
6329 elif cmd == "TRANSPORT": # transport "beam"
6331 elif cmd == "MINE": # mine
6335 elif cmd == "CRYSTALS": # crystals
6339 elif cmd == "SHUTTLE": # shuttle
6343 elif cmd == "PLANETS": # Planet list
6345 elif cmd == "REPORT": # Game Report
6347 elif cmd == "COMPUTER": # use COMPUTER!
6349 elif cmd == "COMMANDS":
6351 elif cmd == "EMEXIT": # Emergency exit
6352 clrscr() # Hide screen
6353 freeze(True) # forced save
6354 raise SystemExit(1) # And quick exit
6355 elif cmd == "PROBE":
6356 probe() # Launch probe
6359 elif cmd == "ABANDON": # Abandon Ship
6361 elif cmd == "DESTRUCT": # Self Destruct
6363 elif cmd == "SAVE": # Save Game
6366 if game.skill > SKILL_GOOD:
6367 prout(_("WARNING--Saved games produce no plaques!"))
6368 elif cmd == "DEATHRAY": # Try a desparation measure
6372 elif cmd == "CAPTURE":
6374 elif cmd == "CLOAK":
6376 elif cmd == "DEBUGCMD": # What do we want for debug???
6378 elif cmd == "MAYDAY": # Call for help
6383 game.alldone = True # quit the game
6386 elif cmd == "SCORE":
6387 score() # see current score
6390 break # Game has ended
6391 if game.optime != 0.0:
6394 break # Events did us in
6395 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6398 if hitme and not game.justin:
6399 attack(torps_ok=True)
6402 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6413 "Emit the name of an enemy or feature."
6414 if ch == 'R': s = _("Romulan")
6415 elif ch == 'K': s = _("Klingon")
6416 elif ch == 'C': s = _("Commander")
6417 elif ch == 'S': s = _("Super-commander")
6418 elif ch == '*': s = _("Star")
6419 elif ch == 'P': s = _("Planet")
6420 elif ch == 'B': s = _("Starbase")
6421 elif ch == ' ': s = _("Black hole")
6422 elif ch == 'T': s = _("Tholian")
6423 elif ch == '#': s = _("Tholian web")
6424 elif ch == '?': s = _("Stranger")
6425 elif ch == '@': s = _("Inhabited World")
6426 else: s = "Unknown??"
6429 def crmena(loud, enemy, loctype, w):
6430 "Emit the name of an enemy and his location."
6434 buf += cramen(enemy) + _(" at ")
6435 if loctype == "quadrant":
6436 buf += _("Quadrant ")
6437 elif loctype == "sector":
6439 return buf + repr(w)
6442 "Emit our ship name."
6443 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6446 "Emit a line of stars"
6447 prouts("******************************************************")
6451 return -avrage*math.log(1e-7 + randreal())
6453 def randplace(size):
6454 "Choose a random location."
6456 w.i = randrange(size)
6457 w.j = randrange(size)
6467 # Get a token from the user
6470 # Fill the token quue if nothing here
6471 while not self.inqueue:
6473 if curwnd==prompt_window:
6475 setwnd(message_window)
6482 self.inqueue = sline.lstrip().split() + ["\n"]
6483 # From here on in it's all looking at the queue
6484 self.token = self.inqueue.pop(0)
6485 if self.token == "\n":
6489 self.real = float(self.token)
6490 self.type = "IHREAL"
6495 self.token = self.token.lower()
6496 self.type = "IHALPHA"
6499 def append(self, tok):
6500 self.inqueue.append(tok)
6501 def push(self, tok):
6502 self.inqueue.insert(0, tok)
6506 # Demand input for next scan
6508 self.real = self.token = None
6510 # compares s to item and returns true if it matches to the length of s
6511 return s.startswith(self.token)
6513 # Round token value to nearest integer
6514 return int(round(self.real))
6518 if self.type != "IHREAL":
6523 if self.type != "IHREAL":
6529 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6532 "Yes-or-no confirmation."
6536 if scanner.token == 'y':
6538 if scanner.token == 'n':
6541 proutn(_("Please answer with \"y\" or \"n\": "))
6544 "Complain about unparseable input."
6547 prout(_("Beg your pardon, Captain?"))
6550 "Access to the internals for debugging."
6551 proutn("Reset levels? ")
6553 if game.energy < game.inenrg:
6554 game.energy = game.inenrg
6555 game.shield = game.inshld
6556 game.torps = game.intorps
6557 game.lsupres = game.inlsr
6558 proutn("Reset damage? ")
6560 for i in range(NDEVICES):
6561 if game.damage[i] > 0.0:
6562 game.damage[i] = 0.0
6563 proutn("Toggle debug flag? ")
6565 game.idebug = not game.idebug
6567 prout("Debug output ON")
6569 prout("Debug output OFF")
6570 proutn("Cause selective damage? ")
6572 for i in range(NDEVICES):
6573 proutn("Kill %s?" % device[i])
6575 key = scanner.nexttok()
6576 if key == "IHALPHA" and scanner.sees("y"):
6577 game.damage[i] = 10.0
6578 proutn("Examine/change events? ")
6583 FSNOVA: "Supernova ",
6586 FBATTAK: "Base Attack ",
6587 FCDBAS: "Base Destroy ",
6588 FSCMOVE: "SC Move ",
6589 FSCDBAS: "SC Base Destroy ",
6590 FDSPROB: "Probe Move ",
6591 FDISTR: "Distress Call ",
6592 FENSLV: "Enslavement ",
6593 FREPRO: "Klingon Build ",
6595 for i in range(1, NEVENTS):
6598 proutn("%.2f" % (scheduled(i)-game.state.date))
6599 if i == FENSLV or i == FREPRO:
6601 proutn(" in %s" % ev.quadrant)
6606 key = scanner.nexttok()
6610 elif key == "IHREAL":
6611 ev = schedule(i, scanner.real)
6612 if i == FENSLV or i == FREPRO:
6614 proutn("In quadrant- ")
6615 key = scanner.nexttok()
6616 # "IHEOL" says to leave coordinates as they are
6619 prout("Event %d canceled, no x coordinate." % (i))
6622 w.i = int(round(scanner.real))
6623 key = scanner.nexttok()
6625 prout("Event %d canceled, no y coordinate." % (i))
6628 w.j = int(round(scanner.real))
6631 proutn("Induce supernova here? ")
6633 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6636 if __name__ == '__main__':
6638 #global line, thing, game
6642 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6643 if os.getenv("TERM"):
6644 game.options |= OPTION_CURSES
6646 game.options |= OPTION_TTY
6647 seed = int(time.time())
6648 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6650 for (switch, val) in options:
6653 replayfp = open(val, "r")
6655 sys.stderr.write("sst: can't open replay file %s\n" % val)
6658 line = replayfp.readline().strip()
6659 (leader, __, seed) = line.split()
6661 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6662 line = replayfp.readline().strip()
6663 arguments += line.split()[2:]
6666 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6668 game.options |= OPTION_TTY
6669 game.options &=~ OPTION_CURSES
6670 elif switch == '-s':
6672 elif switch == '-t':
6673 game.options |= OPTION_TTY
6674 game.options &=~ OPTION_CURSES
6675 elif switch == '-x':
6677 elif switch == '-V':
6678 print("SST2K", version)
6681 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6683 # where to save the input in case of bugs
6684 if "TMPDIR" in os.environ:
6685 tmpdir = os.environ['TMPDIR']
6689 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6691 sys.stderr.write("sst: warning, can't open logfile\n")
6694 logfp.write("# seed %s\n" % seed)
6695 logfp.write("# options %s\n" % " ".join(arguments))
6696 logfp.write("# SST2K version %s\n" % version)
6697 logfp.write("# recorded by %s@%s on %s\n" % \
6698 (getpass.getuser(),socket.gethostname(),time.ctime()))
6700 scanner = sstscanner()
6701 for arg in arguments:
6705 while True: # Play a game
6706 setwnd(fullscreen_window)
6712 game.alldone = False
6720 if game.tourn and game.alldone:
6721 proutn(_("Do you want your score recorded?"))
6727 proutn(_("Do you want to play again? "))
6731 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6735 except KeyboardInterrupt: