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] != "#":
3486 linein = my_input() + "\n"
3492 "Change windows -- OK for this to be a no-op in tty mode."
3494 if game.options & OPTION_CURSES:
3495 # Uncomment this to debug curses problems
3497 if wnd == fullscreen_window:
3498 legend = "fullscreen"
3499 elif wnd == srscan_window:
3501 elif wnd == report_window:
3503 elif wnd == status_window:
3505 elif wnd == lrscan_window:
3507 elif wnd == message_window:
3509 elif wnd == prompt_window:
3513 logfp.write("#curses: setwnd(%s)\n" % legend)
3515 # Some curses implementations get confused when you try this.
3517 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3518 except curses.error:
3522 "Clear to end of line -- can be a no-op in tty mode"
3523 if game.options & OPTION_CURSES:
3528 "Clear screen -- can be a no-op in tty mode."
3530 if game.options & OPTION_CURSES:
3536 def textcolor(color=DEFAULT):
3537 if game.options & OPTION_COLOR:
3538 if color == DEFAULT:
3540 elif color == BLACK:
3541 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3543 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3544 elif color == GREEN:
3545 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3547 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3549 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3550 elif color == MAGENTA:
3551 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3552 elif color == BROWN:
3553 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3554 elif color == LIGHTGRAY:
3555 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3556 elif color == DARKGRAY:
3557 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3558 elif color == LIGHTBLUE:
3559 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3560 elif color == LIGHTGREEN:
3561 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3562 elif color == LIGHTCYAN:
3563 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3564 elif color == LIGHTRED:
3565 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3566 elif color == LIGHTMAGENTA:
3567 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3568 elif color == YELLOW:
3569 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3570 elif color == WHITE:
3571 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3574 if game.options & OPTION_COLOR:
3575 curwnd.attron(curses.A_REVERSE)
3578 # Things past this point have policy implications.
3582 "Hook to be called after moving to redraw maps."
3583 if game.options & OPTION_CURSES:
3586 setwnd(srscan_window)
3590 setwnd(status_window)
3591 status_window.clear()
3592 status_window.move(0, 0)
3593 setwnd(report_window)
3594 report_window.clear()
3595 report_window.move(0, 0)
3597 setwnd(lrscan_window)
3598 lrscan_window.clear()
3599 lrscan_window.move(0, 0)
3600 lrscan(silent=False)
3602 def put_srscan_sym(w, sym):
3603 "Emit symbol for short-range scan."
3604 srscan_window.move(w.i+1, w.j*2+2)
3605 srscan_window.addch(sym)
3606 srscan_window.refresh()
3609 "Enemy fall down, go boom."
3610 if game.options & OPTION_CURSES:
3612 setwnd(srscan_window)
3613 srscan_window.attron(curses.A_REVERSE)
3614 put_srscan_sym(w, game.quad[w.i][w.j])
3618 srscan_window.attroff(curses.A_REVERSE)
3619 put_srscan_sym(w, game.quad[w.i][w.j])
3620 curses.delay_output(500)
3621 setwnd(message_window)
3624 "Sound and visual effects for teleportation."
3625 if game.options & OPTION_CURSES:
3627 setwnd(message_window)
3629 prouts(" . . . . . ")
3630 if game.options & OPTION_CURSES:
3631 #curses.delay_output(1000)
3635 def tracktorpedo(w, step, i, n, iquad):
3636 "Torpedo-track animation."
3637 if not game.options & OPTION_CURSES:
3641 proutn(_("Track for torpedo number %d- ") % (i+1))
3644 proutn(_("Torpedo track- "))
3645 elif step==4 or step==9:
3649 if not damaged(DSRSENS) or game.condition=="docked":
3650 if i != 0 and step == 1:
3653 if (iquad=='.') or (iquad==' '):
3654 put_srscan_sym(w, '+')
3658 put_srscan_sym(w, iquad)
3660 curwnd.attron(curses.A_REVERSE)
3661 put_srscan_sym(w, iquad)
3665 curwnd.attroff(curses.A_REVERSE)
3666 put_srscan_sym(w, iquad)
3671 "Display the current galaxy chart."
3672 if game.options & OPTION_CURSES:
3673 setwnd(message_window)
3674 message_window.clear()
3676 if game.options & OPTION_TTY:
3681 def prstat(txt, data):
3683 if game.options & OPTION_CURSES:
3685 setwnd(status_window)
3687 proutn(" " * (NSYM - len(txt)))
3690 if game.options & OPTION_CURSES:
3691 setwnd(report_window)
3693 # Code from moving.c begins here
3695 def imove(icourse=None, noattack=False):
3696 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3699 def newquadrant(noattack):
3700 # Leaving quadrant -- allow final enemy attack
3701 # Don't set up attack if being pushed by nova or cloaked
3702 if len(game.enemies) != 0 and not noattack and not game.iscloaked:
3704 for enemy in game.enemies:
3705 finald = (w - enemy.location).distance()
3706 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3707 # Stas Sergeev added the condition
3708 # that attacks only happen if Klingons
3709 # are present and your skill is good.
3710 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3711 attack(torps_ok=False)
3714 # check for edge of galaxy
3720 if icourse.final.i < 0:
3721 icourse.final.i = -icourse.final.i
3723 if icourse.final.j < 0:
3724 icourse.final.j = -icourse.final.j
3726 if icourse.final.i >= GALSIZE*QUADSIZE:
3727 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3729 if icourse.final.j >= GALSIZE*QUADSIZE:
3730 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3738 if game.nkinks == 3:
3739 # Three strikes -- you're out!
3743 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3744 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3745 prout(_("YOU WILL BE DESTROYED."))
3746 # Compute final position in new quadrant
3747 if trbeam: # Don't bother if we are to be beamed
3749 game.quadrant = icourse.final.quadrant()
3750 game.sector = icourse.final.sector()
3752 prout(_("Entering Quadrant %s.") % game.quadrant)
3753 game.quad[game.sector.i][game.sector.j] = game.ship
3755 if game.skill>SKILL_NOVICE:
3756 attack(torps_ok=False)
3758 def check_collision(h):
3759 iquad = game.quad[h.i][h.j]
3761 # object encountered in flight path
3762 stopegy = 50.0*icourse.distance/game.optime
3763 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3764 for enemy in game.enemies:
3765 if enemy.location == game.sector:
3766 collision(rammed=False, enemy=enemy)
3768 # This should not happen
3769 prout(_("Which way did he go?"))
3773 prouts(_("***RED ALERT! RED ALERT!"))
3775 proutn("***" + crmshp())
3776 proutn(_(" pulled into black hole at Sector %s") % h)
3777 # Getting pulled into a black hole was certain
3778 # death in Almy's original. Stas Sergeev added a
3779 # possibility that you'll get timewarped instead.
3781 for m in range(NDEVICES):
3782 if game.damage[m]>0:
3784 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3785 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3795 prout(_(" encounters Tholian web at %s;") % h)
3797 prout(_(" blocked by object at %s;") % h)
3798 proutn(_("Emergency stop required "))
3799 prout(_("%2d units of energy.") % int(stopegy))
3800 game.energy -= stopegy
3801 if game.energy <= 0:
3808 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3809 game.inorbit = False
3810 # If tractor beam is to occur, don't move full distance
3811 if game.state.date+game.optime >= scheduled(FTBEAM):
3813 # We can't be tractor beamed if cloaked,
3814 # so move the event into the future
3815 postpone(FTBEAM, game.optime + expran(1.5*game.intime/len(game.kcmdr)))
3819 game.condition = "red"
3820 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3821 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3823 game.quad[game.sector.i][game.sector.j] = '.'
3824 for _m in range(icourse.moves):
3826 w = icourse.sector()
3827 if icourse.origin.quadrant() != icourse.location.quadrant():
3828 newquadrant(noattack)
3830 elif check_collision(w):
3831 print("Collision detected")
3835 # We're in destination quadrant -- compute new average enemy distances
3836 game.quad[game.sector.i][game.sector.j] = game.ship
3838 for enemy in game.enemies:
3839 finald = (w-enemy.location).distance()
3840 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3841 enemy.kdist = finald
3843 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3844 attack(torps_ok=False)
3845 for enemy in game.enemies:
3846 enemy.kavgd = enemy.kdist
3849 setwnd(message_window)
3853 "Dock our ship at a starbase."
3855 if game.condition == "docked" and verbose:
3856 prout(_("Already docked."))
3859 prout(_("You must first leave standard orbit."))
3861 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3862 prout(crmshp() + _(" not adjacent to base."))
3865 prout(_("You cannot dock while cloaked."))
3867 game.condition = "docked"
3871 if game.energy < game.inenrg:
3872 game.energy = game.inenrg
3873 game.shield = game.inshld
3874 game.torps = game.intorps
3875 game.lsupres = game.inlsr
3876 game.state.crew = FULLCREW
3877 if game.brigcapacity-game.brigfree > 0:
3878 prout(_("%d captured Klingons transferred to base") % (game.brigcapacity-game.brigfree))
3879 game.kcaptured += game.brigcapacity-game.brigfree
3880 game.brigfree = game.brigcapacity
3881 if not damaged(DRADIO) and \
3882 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3883 # get attack report from base
3884 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3888 def cartesian(loc1=None, loc2=None):
3890 return game.quadrant * QUADSIZE + game.sector
3892 return game.quadrant * QUADSIZE + loc1
3894 return loc1 * QUADSIZE + loc2
3896 def getcourse(isprobe):
3897 "Get a course and distance from the user."
3899 dquad = copy.copy(game.quadrant)
3900 navmode = "unspecified"
3904 if game.landed and not isprobe:
3905 prout(_("Dummy! You can't leave standard orbit until you"))
3906 proutn(_("are back aboard the ship."))
3909 while navmode == "unspecified":
3910 if damaged(DNAVSYS):
3912 prout(_("Computer damaged; manual navigation only"))
3914 prout(_("Computer damaged; manual movement only"))
3919 key = scanner.nexttok()
3921 proutn(_("Manual or automatic- "))
3924 elif key == "IHALPHA":
3925 if scanner.sees("manual"):
3927 key = scanner.nexttok()
3929 elif scanner.sees("automatic"):
3930 navmode = "automatic"
3931 key = scanner.nexttok()
3939 prout(_("(Manual navigation assumed.)"))
3941 prout(_("(Manual movement assumed.)"))
3945 if navmode == "automatic":
3946 while key == "IHEOL":
3948 proutn(_("Target quadrant or quadrant§or- "))
3950 proutn(_("Destination sector or quadrant§or- "))
3953 key = scanner.nexttok()
3957 xi = int(round(scanner.real))-1
3958 key = scanner.nexttok()
3962 xj = int(round(scanner.real))-1
3963 key = scanner.nexttok()
3965 # both quadrant and sector specified
3966 xk = int(round(scanner.real))-1
3967 key = scanner.nexttok()
3971 xl = int(round(scanner.real))-1
3977 # only one pair of numbers was specified
3979 # only quadrant specified -- go to center of dest quad
3982 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3984 # only sector specified
3988 if not dquad.valid_quadrant() or not dsect.valid_sector():
3995 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3997 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3998 # the actual deltas get computed here
3999 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
4000 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
4002 while key == "IHEOL":
4003 proutn(_("X and Y displacements- "))
4006 key = scanner.nexttok()
4011 delta.j = scanner.real
4012 key = scanner.nexttok()
4016 delta.i = scanner.real
4017 # Check for zero movement
4018 if delta.i == 0 and delta.j == 0:
4021 if itemp == "verbose" and not isprobe:
4023 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
4025 return course(bearing=delta.bearing(), distance=delta.distance())
4028 def __init__(self, bearing, distance, origin=None):
4029 self.distance = distance
4030 self.bearing = bearing
4032 self.origin = cartesian(game.quadrant, game.sector)
4034 self.origin = origin
4035 # The bearing() code we inherited from FORTRAN is actually computing
4036 # clockface directions!
4037 if self.bearing < 0.0:
4038 self.bearing += 12.0
4039 self.angle = ((15.0 - self.bearing) * 0.5235988)
4040 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
4041 bigger = max(abs(self.increment.i), abs(self.increment.j))
4042 self.increment /= bigger
4043 self.moves = int(round(10*self.distance*bigger))
4045 self.final = (self.location + self.moves*self.increment).roundtogrid()
4046 self.location = self.origin
4047 self.nextlocation = None
4049 self.location = self.origin
4052 return self.location.roundtogrid() == self.final
4054 "Next step on course."
4056 self.nextlocation = self.location + self.increment
4057 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
4058 self.location = self.nextlocation
4061 return self.location.quadrant()
4063 return self.location.sector()
4065 return self.distance*(w**3)*(game.shldup+1)
4067 return 10.0*self.distance/w**2
4070 "Move under impulse power."
4072 if damaged(DIMPULS):
4075 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4077 if game.energy > 30.0:
4079 icourse = getcourse(isprobe=False)
4082 power = 20.0 + 100.0*icourse.distance
4085 if power >= game.energy:
4086 # Insufficient power for trip
4088 prout(_("First Officer Spock- \"Captain, the impulse engines"))
4089 prout(_("require 20.0 units to engage, plus 100.0 units per"))
4090 if game.energy > 30:
4091 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
4092 int(0.01 * (game.energy-20.0)-0.05))
4093 prout(_(" quadrants.\""))
4095 prout(_("quadrant. They are, therefore, useless.\""))
4098 # Make sure enough time is left for the trip
4099 game.optime = icourse.distance/0.095
4100 if game.optime >= game.state.remtime:
4101 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
4102 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
4103 proutn(_("we dare spend the time?\" "))
4106 # Activate impulse engines and pay the cost
4107 imove(icourse, noattack=False)
4111 power = 20.0 + 100.0*icourse.distance
4112 game.energy -= power
4113 game.optime = icourse.distance/0.095
4114 if game.energy <= 0:
4118 def warp(wcourse, involuntary):
4119 "ove under warp drive."
4120 blooey = False; twarp = False
4121 if not involuntary: # Not WARPX entry
4126 prout(_("Engineer Scott- \"The warp engines can not be used while cloaked, Sir.\""))
4128 if game.damage[DWARPEN] > 10.0:
4131 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
4133 if damaged(DWARPEN) and game.warpfac > 4.0:
4136 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4137 prout(_(" is repaired, I can only give you warp 4.\""))
4139 # Read in course and distance
4142 wcourse = getcourse(isprobe=False)
4145 # Make sure starship has enough energy for the trip
4146 # Note: this formula is slightly different from the C version,
4147 # and lets you skate a bit closer to the edge.
4148 if wcourse.power(game.warpfac) >= game.energy:
4149 # Insufficient power for trip
4152 prout(_("Engineering to bridge--"))
4153 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
4154 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
4156 prout(_("We can't do it, Captain. We don't have enough energy."))
4158 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4161 prout(_("if you'll lower the shields."))
4165 prout(_("We haven't the energy to go that far with the shields up."))
4167 # Make sure enough time is left for the trip
4168 game.optime = wcourse.time(game.warpfac)
4169 if game.optime >= 0.8*game.state.remtime:
4171 prout(_("First Officer Spock- \"Captain, I compute that such"))
4172 proutn(_(" a trip would require approximately %2.0f") %
4173 (100.0*game.optime/game.state.remtime))
4174 prout(_(" percent of our"))
4175 proutn(_(" remaining time. Are you sure this is wise?\" "))
4181 if game.warpfac > 6.0:
4182 # Decide if engine damage will occur
4183 # ESR: Seems wrong. Probability of damage goes *down* with distance?
4184 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
4185 if prob > randreal():
4187 wcourse.distance = randreal(wcourse.distance)
4188 # Decide if time warp will occur
4189 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
4191 if game.idebug and game.warpfac==10 and not twarp:
4193 proutn("=== Force time warp? ")
4197 # If time warp or engine damage, check path
4198 # If it is obstructed, don't do warp or damage
4199 look = wcourse.moves
4203 w = wcourse.sector()
4204 if not w.valid_sector():
4206 if game.quad[w.i][w.j] != '.':
4210 # Activate Warp Engines and pay the cost
4211 imove(wcourse, noattack=False)
4214 game.energy -= wcourse.power(game.warpfac)
4215 if game.energy <= 0:
4217 game.optime = wcourse.time(game.warpfac)
4221 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4223 prout(_("Engineering to bridge--"))
4224 prout(_(" Scott here. The warp engines are damaged."))
4225 prout(_(" We'll have to reduce speed to warp 4."))
4230 "Change the warp factor."
4232 key=scanner.nexttok()
4236 proutn(_("Warp factor- "))
4240 if game.damage[DWARPEN] > 10.0:
4241 prout(_("Warp engines inoperative."))
4243 if damaged(DWARPEN) and scanner.real > 4.0:
4244 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4245 prout(_(" but right now we can only go warp 4.\""))
4247 if scanner.real > 10.0:
4248 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4250 if scanner.real < 1.0:
4251 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4253 oldfac = game.warpfac
4254 game.warpfac = scanner.real
4255 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4256 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4259 if game.warpfac < 8.00:
4260 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4262 if game.warpfac == 10.0:
4263 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4265 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4269 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4271 # is captain on planet?
4273 if damaged(DTRANSP):
4276 prout(_("Scotty rushes to the transporter controls."))
4278 prout(_("But with the shields up it's hopeless."))
4280 prouts(_("His desperate attempt to rescue you . . ."))
4285 prout(_("SUCCEEDS!"))
4288 proutn(_("The crystals mined were "))
4296 # Check to see if captain in shuttle craft
4301 # Inform captain of attempt to reach safety
4305 prouts(_("***RED ALERT! RED ALERT!"))
4307 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4308 prouts(_(" a supernova."))
4310 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4311 prout(_("safely out of quadrant."))
4312 if not damaged(DRADIO):
4313 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4314 # Try to use warp engines
4315 if damaged(DWARPEN):
4317 prout(_("Warp engines damaged."))
4320 game.warpfac = randreal(6.0, 8.0)
4321 prout(_("Warp factor set to %d") % int(game.warpfac))
4322 power = 0.75*game.energy
4323 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4324 dist = max(dist, randreal(math.sqrt(2)))
4325 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4326 game.optime = bugout.time(game.warpfac)
4328 game.inorbit = False
4329 warp(bugout, involuntary=True)
4331 # This is bad news, we didn't leave quadrant.
4335 prout(_("Insufficient energy to leave quadrant."))
4338 # Repeat if another snova
4339 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4341 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4342 finish(FWON) # Snova killed remaining enemy.
4345 "Let's do the time warp again."
4346 prout(_("***TIME WARP ENTERED."))
4347 if game.state.snap and withprob(0.5):
4349 prout(_("You are traveling backwards in time %d stardates.") %
4350 int(game.state.date-game.snapsht.date))
4351 game.state = game.snapsht
4352 game.state.snap = False
4353 if len(game.state.kcmdr):
4354 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4355 schedule(FBATTAK, expran(0.3*game.intime))
4356 schedule(FSNOVA, expran(0.5*game.intime))
4357 # next snapshot will be sooner
4358 schedule(FSNAP, expran(0.25*game.state.remtime))
4360 if game.state.nscrem:
4361 schedule(FSCMOVE, 0.2777)
4365 game.battle.invalidate()
4366 # Make sure Galileo is consistant -- Snapshot may have been taken
4367 # when on planet, which would give us two Galileos!
4369 for l in range(game.inplan):
4370 if game.state.planets[l].known == "shuttle_down":
4372 if game.iscraft == "onship" and game.ship=='E':
4373 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4374 game.iscraft = "offship"
4375 # Likewise, if in the original time the Galileo was abandoned, but
4376 # was on ship earlier, it would have vanished -- let's restore it.
4377 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4378 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4379 game.iscraft = "onship"
4380 # There used to be code to do the actual reconstrction here,
4381 # but the starchart is now part of the snapshotted galaxy state.
4382 prout(_("Spock has reconstructed a correct star chart from memory"))
4384 # Go forward in time
4385 game.optime = expran(0.5*game.intime)
4386 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4387 # cheat to make sure no tractor beams occur during time warp
4388 postpone(FTBEAM, game.optime)
4389 game.damage[DRADIO] += game.optime
4391 events() # Stas Sergeev added this -- do pending events
4394 "Launch deep-space probe."
4395 # New code to launch a deep space probe
4396 if game.nprobes == 0:
4399 if game.ship == 'E':
4400 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4402 prout(_("Ye Faerie Queene has no deep space probes."))
4407 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4409 if is_scheduled(FDSPROB):
4412 if damaged(DRADIO) and game.condition != "docked":
4413 prout(_("Spock- \"Records show the previous probe has not yet"))
4414 prout(_(" reached its destination.\""))
4416 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4418 key = scanner.nexttok()
4420 if game.nprobes == 1:
4421 prout(_("1 probe left."))
4423 prout(_("%d probes left") % game.nprobes)
4424 proutn(_("Are you sure you want to fire a probe? "))
4427 game.isarmed = False
4428 if key == "IHALPHA" and scanner.token == "armed":
4430 key = scanner.nexttok()
4431 elif key == "IHEOL":
4432 proutn(_("Arm NOVAMAX warhead? "))
4434 elif key == "IHREAL": # first element of course
4435 scanner.push(scanner.token)
4437 game.probe = getcourse(isprobe=True)
4441 schedule(FDSPROB, 0.01) # Time to move one sector
4442 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4447 "Yell for help from nearest starbase."
4448 # There's more than one way to move in this game!
4450 # Test for conditions which prevent calling for help
4451 if game.condition == "docked":
4452 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4455 prout(_("Subspace radio damaged."))
4457 if not game.state.baseq:
4458 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4461 prout(_("You must be aboard the %s.") % crmshp())
4463 # OK -- call for help from nearest starbase
4466 # There's one in this quadrant
4467 ddist = (game.base - game.sector).distance()
4469 ibq = None # Force base-quadrant game to persist past loop
4471 for ibq in game.state.baseq:
4472 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4476 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4478 # Since starbase not in quadrant, set up new quadrant
4481 # dematerialize starship
4482 game.quad[game.sector.i][game.sector.j]='.'
4483 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4484 % (game.quadrant, crmshp()))
4485 game.sector.invalidate()
4486 for m in range(1, 5+1):
4487 w = game.base.scatter()
4488 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4489 # found one -- finish up
4492 if not game.sector.is_valid():
4493 prout(_("You have been lost in space..."))
4494 finish(FMATERIALIZE)
4496 # Give starbase three chances to rematerialize starship
4497 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4498 for m in range(1, 3+1):
4499 if m == 1: proutn(_("1st"))
4500 elif m == 2: proutn(_("2nd"))
4501 elif m == 3: proutn(_("3rd"))
4502 proutn(_(" attempt to re-materialize ") + crmshp())
4503 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4506 if randreal() > probf:
4510 curses.delay_output(500)
4512 game.quad[game.sector.i][game.sector.j]='?'
4515 setwnd(message_window)
4516 finish(FMATERIALIZE)
4518 game.quad[game.sector.i][game.sector.j]=game.ship
4520 prout(_("succeeds."))
4524 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4529 if game.condition=="docked":
4531 prout(_("You cannot abandon Ye Faerie Queene."))
4534 # Must take shuttle craft to exit
4535 if game.damage[DSHUTTL]==-1:
4536 prout(_("Ye Faerie Queene has no shuttle craft."))
4538 if game.damage[DSHUTTL]<0:
4539 prout(_("Shuttle craft now serving Big Macs."))
4541 if game.damage[DSHUTTL]>0:
4542 prout(_("Shuttle craft damaged."))
4545 prout(_("You must be aboard the ship."))
4547 if game.iscraft != "onship":
4548 prout(_("Shuttle craft not currently available."))
4550 # Emit abandon ship messages
4552 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4554 prouts(_("***ALL HANDS ABANDON SHIP!"))
4556 prout(_("Captain and crew escape in shuttle craft."))
4557 if not game.state.baseq:
4558 # Oops! no place to go...
4561 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4563 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4564 prout(_("Remainder of ship's complement beam down"))
4565 prout(_("to nearest habitable planet."))
4566 elif q.planet != None and not damaged(DTRANSP):
4567 prout(_("Remainder of ship's complement beam down to %s.") %
4570 prout(_("Entire crew of %d left to die in outer space.") %
4572 game.casual += game.state.crew
4573 game.abandoned += game.state.crew
4574 # If at least one base left, give 'em the Faerie Queene
4576 game.icrystl = False # crystals are lost
4577 game.nprobes = 0 # No probes
4578 prout(_("You are captured by Klingons and released to"))
4579 prout(_("the Federation in a prisoner-of-war exchange."))
4580 nb = randrange(len(game.state.baseq))
4581 # Set up quadrant and position FQ adjacient to base
4582 if not game.quadrant == game.state.baseq[nb]:
4583 game.quadrant = game.state.baseq[nb]
4584 game.sector.i = game.sector.j = 5
4587 # position next to base by trial and error
4588 game.quad[game.sector.i][game.sector.j] = '.'
4590 for l in range(QUADSIZE):
4591 game.sector = game.base.scatter()
4592 if game.sector.valid_sector() and \
4593 game.quad[game.sector.i][game.sector.j] == '.':
4596 break # found a spot
4597 game.sector.i=QUADSIZE/2
4598 game.sector.j=QUADSIZE/2
4600 # Get new commission
4601 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4602 game.state.crew = FULLCREW
4603 prout(_("Starfleet puts you in command of another ship,"))
4604 prout(_("the Faerie Queene, which is antiquated but,"))
4605 prout(_("still useable."))
4607 prout(_("The dilithium crystals have been moved."))
4609 game.iscraft = "offship" # Galileo disappears
4611 game.condition="docked"
4612 for l in range(NDEVICES):
4613 game.damage[l] = 0.0
4614 game.damage[DSHUTTL] = -1
4615 game.energy = game.inenrg = 3000.0
4616 game.shield = game.inshld = 1250.0
4617 game.torps = game.intorps = 6
4618 game.lsupres=game.inlsr=3.0
4621 game.brigfree = game.brigcapacity = 300
4624 # Code from planets.c begins here.
4627 "Abort a lengthy operation if an event interrupts it."
4630 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4635 "Report on (uninhabited) planets in the galaxy."
4639 prout(_("Spock- \"Planet report follows, Captain.\""))
4641 for i in range(game.inplan):
4642 if game.state.planets[i].pclass == "destroyed":
4644 if (game.state.planets[i].known != "unknown" \
4645 and not game.state.planets[i].inhabited) \
4648 if game.idebug and game.state.planets[i].known=="unknown":
4649 proutn("(Unknown) ")
4650 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4651 proutn(_(" class "))
4652 proutn(game.state.planets[i].pclass)
4654 if game.state.planets[i].crystals != "present":
4656 prout(_("dilithium crystals present."))
4657 if game.state.planets[i].known=="shuttle_down":
4658 prout(_(" Shuttle Craft Galileo on surface."))
4660 prout(_("No information available."))
4663 "Enter standard orbit."
4667 prout(_("Already in standard orbit."))
4669 if damaged(DWARPEN) and damaged(DIMPULS):
4670 prout(_("Both warp and impulse engines damaged."))
4672 if not game.plnet.is_valid():
4673 prout("There is no planet in this sector.")
4675 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4676 prout(crmshp() + _(" not adjacent to planet."))
4679 game.optime = randreal(0.02, 0.05)
4680 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4684 game.height = randreal(1400, 8600)
4685 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4690 "Examine planets in this quadrant."
4691 if damaged(DSRSENS):
4692 if game.options & OPTION_TTY:
4693 prout(_("Short range sensors damaged."))
4695 if game.iplnet is None:
4696 if game.options & OPTION_TTY:
4697 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4699 if game.iplnet.known == "unknown":
4700 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4702 prout(_(" Planet at Sector %s is of class %s.") %
4703 (game.plnet, game.iplnet.pclass))
4704 if game.iplnet.known=="shuttle_down":
4705 prout(_(" Sensors show Galileo still on surface."))
4706 proutn(_(" Readings indicate"))
4707 if game.iplnet.crystals != "present":
4709 prout(_(" dilithium crystals present.\""))
4710 if game.iplnet.known == "unknown":
4711 game.iplnet.known = "known"
4712 elif game.iplnet.inhabited:
4713 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4714 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4717 "Use the transporter."
4721 if damaged(DTRANSP):
4722 prout(_("Transporter damaged."))
4723 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4725 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4729 if not game.inorbit:
4730 prout(crmshp() + _(" not in standard orbit."))
4733 prout(_("Impossible to transport through shields."))
4735 if game.iplnet.known=="unknown":
4736 prout(_("Spock- \"Captain, we have no information on this planet"))
4737 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4738 prout(_(" you may not go down.\""))
4740 if not game.landed and game.iplnet.crystals=="absent":
4741 prout(_("Spock- \"Captain, I fail to see the logic in"))
4742 prout(_(" exploring a planet with no dilithium crystals."))
4743 proutn(_(" Are you sure this is wise?\" "))
4747 if not (game.options & OPTION_PLAIN):
4748 nrgneed = 50 * game.skill + game.height / 100.0
4749 if nrgneed > game.energy:
4750 prout(_("Engineering to bridge--"))
4751 prout(_(" Captain, we don't have enough energy for transportation."))
4753 if not game.landed and nrgneed * 2 > game.energy:
4754 prout(_("Engineering to bridge--"))
4755 prout(_(" Captain, we have enough energy only to transport you down to"))
4756 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4757 if game.iplnet.known == "shuttle_down":
4758 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4759 proutn(_(" Are you sure this is wise?\" "))
4764 # Coming from planet
4765 if game.iplnet.known=="shuttle_down":
4766 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4770 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4771 prout(_("Landing party assembled, ready to beam up."))
4773 prout(_("Kirk whips out communicator..."))
4774 prouts(_("BEEP BEEP BEEP"))
4776 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4779 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4781 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4783 prout(_("Kirk- \"Energize.\""))
4786 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4788 if not withprob(0.98):
4789 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4791 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4794 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4795 game.landed = not game.landed
4796 game.energy -= nrgneed
4798 prout(_("Transport complete."))
4799 if game.landed and game.iplnet.known=="shuttle_down":
4800 prout(_("The shuttle craft Galileo is here!"))
4801 if not game.landed and game.imine:
4808 "Strip-mine a world for dilithium."
4812 prout(_("Mining party not on planet."))
4814 if game.iplnet.crystals == "mined":
4815 prout(_("This planet has already been strip-mined for dilithium."))
4817 elif game.iplnet.crystals == "absent":
4818 prout(_("No dilithium crystals on this planet."))
4821 prout(_("You've already mined enough crystals for this trip."))
4823 if game.icrystl and game.cryprob == 0.05:
4824 prout(_("With all those fresh crystals aboard the ") + crmshp())
4825 prout(_("there's no reason to mine more at this time."))
4827 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4830 prout(_("Mining operation complete."))
4831 game.iplnet.crystals = "mined"
4832 game.imine = game.ididit = True
4835 "Use dilithium crystals."
4839 if not game.icrystl:
4840 prout(_("No dilithium crystals available."))
4842 if game.energy >= 1000:
4843 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4844 prout(_(" except when Condition Yellow exists."))
4846 prout(_("Spock- \"Captain, I must warn you that loading"))
4847 prout(_(" raw dilithium crystals into the ship's power"))
4848 prout(_(" system may risk a severe explosion."))
4849 proutn(_(" Are you sure this is wise?\" "))
4854 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4855 prout(_(" Mr. Spock and I will try it.\""))
4857 prout(_("Spock- \"Crystals in place, Sir."))
4858 prout(_(" Ready to activate circuit.\""))
4860 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4862 if withprob(game.cryprob):
4863 prouts(_(" \"Activating now! - - No good! It's***"))
4865 prouts(_("***RED ALERT! RED A*L********************************"))
4868 prouts(_("****************** KA-BOOM!!!! *******************"))
4872 game.energy += randreal(5000.0, 5500.0)
4873 prouts(_(" \"Activating now! - - "))
4874 prout(_("The instruments"))
4875 prout(_(" are going crazy, but I think it's"))
4876 prout(_(" going to work!! Congratulations, Sir!\""))
4881 "Use shuttlecraft for planetary jaunt."
4884 if damaged(DSHUTTL):
4885 if game.damage[DSHUTTL] == -1.0:
4886 if game.inorbit and game.iplnet.known == "shuttle_down":
4887 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4889 prout(_("Ye Faerie Queene had no shuttle craft."))
4890 elif game.damage[DSHUTTL] > 0:
4891 prout(_("The Galileo is damaged."))
4892 else: # game.damage[DSHUTTL] < 0
4893 prout(_("Shuttle craft is now serving Big Macs."))
4895 if not game.inorbit:
4896 prout(crmshp() + _(" not in standard orbit."))
4898 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4899 prout(_("Shuttle craft not currently available."))
4901 if not game.landed and game.iplnet.known=="shuttle_down":
4902 prout(_("You will have to beam down to retrieve the shuttle craft."))
4904 if game.shldup or game.condition == "docked":
4905 prout(_("Shuttle craft cannot pass through shields."))
4907 if game.iplnet.known=="unknown":
4908 prout(_("Spock- \"Captain, we have no information on this planet"))
4909 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4910 prout(_(" you may not fly down.\""))
4912 game.optime = 3.0e-5*game.height
4913 if game.optime >= 0.8*game.state.remtime:
4914 prout(_("First Officer Spock- \"Captain, I compute that such"))
4915 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4916 int(100*game.optime/game.state.remtime))
4917 prout(_("remaining time."))
4918 proutn(_("Are you sure this is wise?\" "))
4924 if game.iscraft == "onship":
4926 if not damaged(DTRANSP):
4927 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4931 proutn(_("Shuttle crew"))
4933 proutn(_("Rescue party"))
4934 prout(_(" boards Galileo and swoops toward planet surface."))
4935 game.iscraft = "offship"
4939 game.iplnet.known="shuttle_down"
4940 prout(_("Trip complete."))
4943 # Ready to go back to ship
4944 prout(_("You and your mining party board the"))
4945 prout(_("shuttle craft for the trip back to the Enterprise."))
4947 prouts(_("The short hop begins . . ."))
4949 game.iplnet.known="known"
4955 game.iscraft = "onship"
4961 prout(_("Trip complete."))
4964 # Kirk on ship and so is Galileo
4965 prout(_("Mining party assembles in the hangar deck,"))
4966 prout(_("ready to board the shuttle craft \"Galileo\"."))
4968 prouts(_("The hangar doors open; the trip begins."))
4971 game.iscraft = "offship"
4974 game.iplnet.known = "shuttle_down"
4977 prout(_("Trip complete."))
4981 "Use the big zapper."
4985 if game.ship != 'E':
4986 prout(_("Ye Faerie Queene has no death ray."))
4988 if len(game.enemies)==0:
4989 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4992 prout(_("Death Ray is damaged."))
4994 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4995 prout(_(" is highly unpredictible. Considering the alternatives,"))
4996 proutn(_(" are you sure this is wise?\" "))
4999 prout(_("Spock- \"Acknowledged.\""))
5002 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
5004 prout(_("Crew scrambles in emergency preparation."))
5005 prout(_("Spock and Scotty ready the death ray and"))
5006 prout(_("prepare to channel all ship's power to the device."))
5008 prout(_("Spock- \"Preparations complete, sir.\""))
5009 prout(_("Kirk- \"Engage!\""))
5011 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
5014 if game.options & OPTION_PLAIN:
5018 prouts(_("Sulu- \"Captain! It's working!\""))
5020 while len(game.enemies) > 0:
5021 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
5022 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
5023 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
5025 if (game.options & OPTION_PLAIN) == 0:
5026 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
5028 prout(_(" is still operational.\""))
5030 prout(_(" has been rendered nonfunctional.\""))
5031 game.damage[DDRAY] = 39.95
5033 r = randreal() # Pick failure method
5035 prouts(_("Sulu- \"Captain! It's working!\""))
5037 prouts(_("***RED ALERT! RED ALERT!"))
5039 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
5041 prouts(_("***RED ALERT! RED A*L********************************"))
5044 prouts(_("****************** KA-BOOM!!!! *******************"))
5049 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
5051 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
5053 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
5054 prout(_(" have apparently been transformed into strange mutations."))
5055 prout(_(" Vulcans do not seem to be affected."))
5057 prout(_("Kirk- \"Raauch! Raauch!\""))
5061 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
5063 proutn(_("Spock- \"I believe the word is"))
5064 prouts(_(" *ASTONISHING*"))
5065 prout(_(" Mr. Sulu."))
5066 for i in range(QUADSIZE):
5067 for j in range(QUADSIZE):
5068 if game.quad[i][j] == '.':
5069 game.quad[i][j] = '?'
5070 prout(_(" Captain, our quadrant is now infested with"))
5071 prouts(_(" - - - - - - *THINGS*."))
5073 prout(_(" I have no logical explanation.\""))
5075 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
5077 prout(_("Scotty- \"There are so many tribbles down here"))
5078 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
5082 # Code from reports.c begins here
5084 def attackreport(curt):
5085 "eport status of bases under attack."
5087 if is_scheduled(FCDBAS):
5088 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
5089 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
5090 elif game.isatb == 1:
5091 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
5092 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
5094 prout(_("No Starbase is currently under attack."))
5096 if is_scheduled(FCDBAS):
5097 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
5099 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
5103 # report on general game status
5105 s1 = (game.thawed and _("thawed ")) or ""
5106 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
5107 s3 = (None, _("novice"), _("fair"),
5108 _("good"), _("expert"), _("emeritus"))[game.skill]
5109 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
5110 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
5111 prout(_("No plaque is allowed."))
5113 prout(_("This is tournament game %d.") % game.tourn)
5114 prout(_("Your secret password is \"%s\"") % game.passwd)
5115 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
5116 (game.inkling + game.incom + game.inscom)))
5117 if game.incom - len(game.state.kcmdr):
5118 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
5119 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
5120 prout(_(", but no Commanders."))
5123 if game.skill > SKILL_FAIR:
5124 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
5125 if len(game.state.baseq) != game.inbase:
5127 if game.inbase-len(game.state.baseq)==1:
5128 proutn(_("has been 1 base"))
5130 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
5131 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
5133 prout(_("There are %d bases.") % game.inbase)
5134 if communicating() or game.iseenit:
5135 # Don't report this if not seen and
5136 # either the radio is dead or not at base!
5140 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
5141 if game.brigcapacity != game.brigfree:
5142 embriggened = brigcapacity-brigfree
5143 if embriggened == 1:
5144 prout(_("1 Klingon in brig"))
5146 prout(_("%d Klingons in brig.") % embriggened)
5147 if game.kcaptured == 0:
5149 elif game.kcaptured == 1:
5150 prout(_("1 captured Klingon turned in to Starfleet."))
5152 prout(_("%d captured Klingons turned in to Star Fleet.") % game.kcaptured)
5154 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
5155 if game.ship == 'E':
5156 proutn(_("You have "))
5158 proutn("%d" % (game.nprobes))
5161 proutn(_(" deep space probe"))
5165 if communicating() and is_scheduled(FDSPROB):
5167 proutn(_("An armed deep space probe is in "))
5169 proutn(_("A deep space probe is in "))
5170 prout("Quadrant %s." % game.probe.quadrant())
5172 if game.cryprob <= .05:
5173 prout(_("Dilithium crystals aboard ship... not yet used."))
5177 while game.cryprob > ai:
5180 prout(_("Dilithium crystals have been used %d time%s.") % \
5181 (i, (_("s"), "")[i==1]))
5185 "Long-range sensor scan."
5186 if damaged(DLRSENS):
5187 # Now allow base's sensors if docked
5188 if game.condition != "docked":
5190 prout(_("LONG-RANGE SENSORS DAMAGED."))
5193 prout(_("Starbase's long-range scan"))
5195 prout(_("Long-range scan"))
5196 for x in range(game.quadrant.i-1, game.quadrant.i+2):
5199 for y in range(game.quadrant.j-1, game.quadrant.j+2):
5200 if not Coord(x, y).valid_quadrant():
5204 if not damaged(DRADIO):
5205 game.state.galaxy[x][y].charted = True
5206 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5207 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5208 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5209 if not silent and game.state.galaxy[x][y].supernova:
5212 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
5220 for i in range(NDEVICES):
5223 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5224 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5226 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5227 game.damage[i]+0.05,
5228 DOCKFAC*game.damage[i]+0.005))
5230 prout(_("All devices functional."))
5233 "Update the chart in the Enterprise's computer from galaxy data."
5234 game.lastchart = game.state.date
5235 for i in range(GALSIZE):
5236 for j in range(GALSIZE):
5237 if game.state.galaxy[i][j].charted:
5238 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5239 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5240 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5243 "Display the star chart."
5245 if (game.options & OPTION_AUTOSCAN):
5247 if not damaged(DRADIO):
5249 if game.lastchart < game.state.date and game.condition == "docked":
5250 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5252 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5253 if game.state.date > game.lastchart:
5254 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5255 prout(" 1 2 3 4 5 6 7 8")
5256 for i in range(GALSIZE):
5257 proutn("%d |" % (i+1))
5258 for j in range(GALSIZE):
5259 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5263 if game.state.galaxy[i][j].supernova:
5265 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5267 elif game.state.galaxy[i][j].charted:
5268 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5272 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5280 def sectscan(goodScan, i, j):
5281 "Light up an individual dot in a sector."
5282 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5283 if game.quad[i][j] in ('E', 'F'):
5286 textcolor({"green":GREEN,
5290 "dead":BROWN}[game.condition])
5292 textcolor({'?':LIGHTMAGENTA,
5298 }.get(game.quad[i][j], DEFAULT))
5299 proutn("%c " % game.quad[i][j])
5305 "Emit status report lines"
5306 if not req or req == 1:
5307 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5308 % (game.state.date, game.state.remtime))
5309 if not req or req == 2:
5310 if game.condition != "docked":
5312 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5313 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5315 prout(_(", CLOAKED"))
5316 if not req or req == 3:
5317 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5318 if not req or req == 4:
5319 if damaged(DLIFSUP):
5320 if game.condition == "docked":
5321 s = _("DAMAGED, Base provides")
5323 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5326 prstat(_("Life Support"), s)
5327 if not req or req == 5:
5328 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5329 if not req or req == 6:
5331 if game.icrystl and (game.options & OPTION_SHOWME):
5332 extra = _(" (have crystals)")
5333 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5334 if not req or req == 7:
5335 prstat(_("Torpedoes"), "%d" % (game.torps))
5336 if not req or req == 8:
5337 if damaged(DSHIELD):
5343 data = _(" %d%% %.1f units") \
5344 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5345 prstat(_("Shields"), s+data)
5346 if not req or req == 9:
5347 prstat(_("Klingons Left"), "%d" \
5348 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5349 if not req or req == 10:
5350 if game.options & OPTION_WORLDS:
5351 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5352 if plnet and plnet.inhabited:
5353 prstat(_("Major system"), plnet.name)
5355 prout(_("Sector is uninhabited"))
5356 elif not req or req == 11:
5357 attackreport(not req)
5360 "Request specified status data, a historical relic from slow TTYs."
5361 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5362 while scanner.nexttok() == "IHEOL":
5363 proutn(_("Information desired? "))
5365 if scanner.token in requests:
5366 status(requests.index(scanner.token))
5368 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5369 prout((" date, condition, position, lsupport, warpfactor,"))
5370 prout((" energy, torpedoes, shields, klingons, system, time."))
5375 if damaged(DSRSENS):
5376 # Allow base's sensors if docked
5377 if game.condition != "docked":
5378 prout(_(" S.R. SENSORS DAMAGED!"))
5381 prout(_(" [Using Base's sensors]"))
5383 prout(_(" Short-range scan"))
5384 if goodScan and not damaged(DRADIO):
5385 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5386 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5387 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5388 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5389 prout(" 1 2 3 4 5 6 7 8 9 10")
5390 if game.condition != "docked":
5392 for i in range(QUADSIZE):
5393 proutn("%2d " % (i+1))
5394 for j in range(QUADSIZE):
5395 sectscan(goodScan, i, j)
5399 "Use computer to get estimated time of arrival for a warp jump."
5400 w1 = Coord(); w2 = Coord()
5402 if damaged(DCOMPTR):
5403 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5406 if scanner.nexttok() != "IHREAL":
5409 proutn(_("Destination quadrant and/or sector? "))
5410 if scanner.nexttok()!="IHREAL":
5413 w1.j = int(scanner.real-0.5)
5414 if scanner.nexttok() != "IHREAL":
5417 w1.i = int(scanner.real-0.5)
5418 if scanner.nexttok() == "IHREAL":
5419 w2.j = int(scanner.real-0.5)
5420 if scanner.nexttok() != "IHREAL":
5423 w2.i = int(scanner.real-0.5)
5425 if game.quadrant.j>w1.i:
5429 if game.quadrant.i>w1.j:
5433 if not w1.valid_quadrant() or not w2.valid_sector():
5436 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5437 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5440 prout(_("Answer \"no\" if you don't know the value:"))
5443 proutn(_("Time or arrival date? "))
5444 if scanner.nexttok()=="IHREAL":
5445 ttime = scanner.real
5446 if ttime > game.state.date:
5447 ttime -= game.state.date # Actually a star date
5448 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5449 if ttime <= 1e-10 or twarp > 10:
5450 prout(_("We'll never make it, sir."))
5457 proutn(_("Warp factor? "))
5458 if scanner.nexttok()== "IHREAL":
5460 twarp = scanner.real
5461 if twarp<1.0 or twarp > 10.0:
5465 prout(_("Captain, certainly you can give me one of these."))
5468 ttime = (10.0*dist)/twarp**2
5469 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5470 if tpower >= game.energy:
5471 prout(_("Insufficient energy, sir."))
5472 if not game.shldup or tpower > game.energy*2.0:
5475 proutn(_("New warp factor to try? "))
5476 if scanner.nexttok() == "IHREAL":
5478 twarp = scanner.real
5479 if twarp<1.0 or twarp > 10.0:
5487 prout(_("But if you lower your shields,"))
5488 proutn(_("remaining"))
5491 proutn(_("Remaining"))
5492 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5494 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5496 prout(_("Any warp speed is adequate."))
5498 prout(_("Minimum warp needed is %.2f,") % (twarp))
5499 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5500 if game.state.remtime < ttime:
5501 prout(_("Unfortunately, the Federation will be destroyed by then."))
5503 prout(_("You'll be taking risks at that speed, Captain"))
5504 if (game.isatb==1 and game.state.kscmdr == w1 and \
5505 scheduled(FSCDBAS)< ttime+game.state.date) or \
5506 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5507 prout(_("The starbase there will be destroyed by then."))
5508 proutn(_("New warp factor to try? "))
5509 if scanner.nexttok() == "IHREAL":
5511 twarp = scanner.real
5512 if twarp<1.0 or twarp > 10.0:
5520 # Code from setup.c begins here
5523 "Issue a historically correct banner."
5525 prout(_("-SUPER- STAR TREK"))
5527 # From the FORTRAN original
5528 # prout(_("Latest update-21 Sept 78"))
5534 scanner.push("emsave.trk")
5535 key = scanner.nexttok()
5537 proutn(_("File name: "))
5538 key = scanner.nexttok()
5539 if key != "IHALPHA":
5542 if '.' not in scanner.token:
5543 scanner.token += ".trk"
5545 fp = open(scanner.token, "wb")
5547 prout(_("Can't freeze game as file %s") % scanner.token)
5549 pickle.dump(game, fp)
5554 "Retrieve saved game."
5557 key = scanner.nexttok()
5559 proutn(_("File name: "))
5560 key = scanner.nexttok()
5561 if key != "IHALPHA":
5564 if '.' not in scanner.token:
5565 scanner.token += ".trk"
5567 fp = open(scanner.token, "rb")
5569 prout(_("Can't thaw game in %s") % scanner.token)
5571 game = pickle.load(fp)
5576 # I used <http://www.memory-alpha.org> to find planets
5577 # with references in ST:TOS. Earth and the Alpha Centauri
5578 # Colony have been omitted.
5580 # Some planets marked Class G and P here will be displayed as class M
5581 # because of the way planets are generated. This is a known bug.
5584 _("Andoria (Fesoan)"), # several episodes
5585 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5586 _("Vulcan (T'Khasi)"), # many episodes
5587 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5588 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5589 _("Ardana"), # TOS: "The Cloud Minders"
5590 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5591 _("Gideon"), # TOS: "The Mark of Gideon"
5592 _("Aldebaran III"), # TOS: "The Deadly Years"
5593 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5594 _("Altair IV"), # TOS: "Amok Time
5595 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5596 _("Benecia"), # TOS: "The Conscience of the King"
5597 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5598 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5599 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5600 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5601 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5602 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5603 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5604 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5605 _("Ingraham B"), # TOS: "Operation: Annihilate"
5606 _("Janus IV"), # TOS: "The Devil in the Dark"
5607 _("Makus III"), # TOS: "The Galileo Seven"
5608 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5609 _("Omega IV"), # TOS: "The Omega Glory"
5610 _("Regulus V"), # TOS: "Amok Time
5611 _("Deneva"), # TOS: "Operation -- Annihilate!"
5612 # Worlds from BSD Trek
5613 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5614 _("Beta III"), # TOS: "The Return of the Archons"
5615 _("Triacus"), # TOS: "And the Children Shall Lead",
5616 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5618 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5619 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5620 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5621 # _("Izar"), # TOS: "Whom Gods Destroy"
5622 # _("Tiburon"), # TOS: "The Way to Eden"
5623 # _("Merak II"), # TOS: "The Cloud Minders"
5624 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5625 # _("Iotia"), # TOS: "A Piece of the Action"
5629 _("S. R. Sensors"), \
5630 _("L. R. Sensors"), \
5632 _("Photon Tubes"), \
5633 _("Life Support"), \
5634 _("Warp Engines"), \
5635 _("Impulse Engines"), \
5637 _("Subspace Radio"), \
5638 _("Shuttle Craft"), \
5640 _("Navigation System"), \
5642 _("Shield Control"), \
5645 _("Cloaking Device"), \
5649 "Prepare to play, set up cosmos."
5651 # Decide how many of everything
5653 return # frozen game
5654 # Prepare the Enterprise
5655 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5657 game.state.crew = FULLCREW
5658 game.energy = game.inenrg = 5000.0
5659 game.shield = game.inshld = 2500.0
5662 game.quadrant = randplace(GALSIZE)
5663 game.sector = randplace(QUADSIZE)
5664 game.torps = game.intorps = 10
5665 game.nprobes = randrange(2, 5)
5667 for i in range(NDEVICES):
5668 game.damage[i] = 0.0
5669 # Set up assorted game parameters
5670 game.battle = Coord()
5671 game.state.date = game.indate = 100.0 * randreal(20, 51)
5672 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5673 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5674 game.isatb = game.state.nplankl = 0
5675 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5676 game.iscraft = "onship"
5681 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5683 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5685 game.state.planets = [] # Planet information
5686 game.state.baseq = [] # Base quadrant coordinates
5687 game.state.kcmdr = [] # Commander quadrant coordinates
5688 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5690 # Starchart is functional but we've never seen it
5691 game.lastchart = FOREVER
5692 # Put stars in the galaxy
5694 for i in range(GALSIZE):
5695 for j in range(GALSIZE):
5696 # Can't have more stars per quadrant than fit in one decimal digit,
5697 # if we do the chart representation will break.
5698 k = randrange(1, min(10, QUADSIZE**2/10))
5700 game.state.galaxy[i][j].stars = k
5701 # Locate star bases in galaxy
5703 prout("=== Allocating %d bases" % game.inbase)
5704 for i in range(game.inbase):
5707 w = randplace(GALSIZE)
5708 if not game.state.galaxy[w.i][w.j].starbase:
5711 # C version: for (j = i-1; j > 0; j--)
5712 # so it did them in the opposite order.
5713 for j in range(1, i):
5714 # Improved placement algorithm to spread out bases
5715 distq = (w - game.state.baseq[j]).distance()
5716 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5719 prout("=== Abandoning base #%d at %s" % (i, w))
5721 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5723 prout("=== Saving base #%d, close to #%d" % (i, j))
5727 prout("=== Placing base #%d in quadrant %s" % (i, w))
5728 game.state.baseq.append(w)
5729 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5730 # Position ordinary Klingon Battle Cruisers
5732 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5733 if klumper > MAXKLQUAD:
5737 klump = (1.0 - r*r)*klumper
5742 w = randplace(GALSIZE)
5743 if not game.state.galaxy[w.i][w.j].supernova and \
5744 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5746 game.state.galaxy[w.i][w.j].klingons += int(klump)
5749 # Position Klingon Commander Ships
5750 for i in range(game.incom):
5752 w = randplace(GALSIZE)
5753 if not welcoming(w) or w in game.state.kcmdr:
5755 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5757 game.state.galaxy[w.i][w.j].klingons += 1
5758 game.state.kcmdr.append(w)
5759 # Locate planets in galaxy
5760 for i in range(game.inplan):
5762 w = randplace(GALSIZE)
5763 if game.state.galaxy[w.i][w.j].planet is None:
5767 new.crystals = "absent"
5768 if (game.options & OPTION_WORLDS) and i < NINHAB:
5769 new.pclass = "M" # All inhabited planets are class M
5770 new.crystals = "absent"
5772 new.name = systnames[i]
5773 new.inhabited = True
5775 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5777 new.crystals = "present"
5778 new.known = "unknown"
5779 new.inhabited = False
5780 game.state.galaxy[w.i][w.j].planet = new
5781 game.state.planets.append(new)
5783 for i in range(game.state.nromrem):
5784 w = randplace(GALSIZE)
5785 game.state.galaxy[w.i][w.j].romulans += 1
5786 # Place the Super-Commander if needed
5787 if game.state.nscrem > 0:
5789 w = randplace(GALSIZE)
5792 game.state.kscmdr = w
5793 game.state.galaxy[w.i][w.j].klingons += 1
5794 # Initialize times for extraneous events
5795 schedule(FSNOVA, expran(0.5 * game.intime))
5796 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5797 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5798 schedule(FBATTAK, expran(0.3*game.intime))
5800 if game.state.nscrem:
5801 schedule(FSCMOVE, 0.2777)
5806 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5807 schedule(FDISTR, expran(1.0 + game.intime))
5812 # Place thing (in tournament game, we don't want one!)
5813 # New in SST2K: never place the Thing near a starbase.
5814 # This makes sense and avoids a special case in the old code.
5816 if game.tourn is None:
5818 thing = randplace(GALSIZE)
5819 if thing not in game.state.baseq:
5822 game.state.snap = False
5823 if game.skill == SKILL_NOVICE:
5824 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5825 prout(_("a deadly Klingon invasion force. As captain of the United"))
5826 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5827 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5828 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5829 prout(_("your mission. As you proceed you may be given more time."))
5831 prout(_("You will have %d supporting starbases.") % (game.inbase))
5832 proutn(_("Starbase locations- "))
5834 prout(_("Stardate %d.") % int(game.state.date))
5836 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5837 prout(_("An unknown number of Romulans."))
5838 if game.state.nscrem:
5839 prout(_("And one (GULP) Super-Commander."))
5840 prout(_("%d stardates.") % int(game.intime))
5841 proutn(_("%d starbases in ") % game.inbase)
5842 for i in range(game.inbase):
5843 proutn(repr(game.state.baseq[i]))
5846 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5847 proutn(_(" Sector %s") % game.sector)
5849 prout(_("Good Luck!"))
5850 if game.state.nscrem:
5851 prout(_(" YOU'LL NEED IT."))
5854 setwnd(message_window)
5856 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5858 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5859 attack(torps_ok=False)
5862 "Choose your game type."
5864 game.tourn = game.length = 0
5866 game.skill = SKILL_NONE
5867 # Do not chew here, we want to use command-line tokens
5868 if not scanner.inqueue: # Can start with command line options
5869 proutn(_("Would you like a regular, tournament, or saved game? "))
5871 if scanner.sees("tournament"):
5872 while scanner.nexttok() == "IHEOL":
5873 proutn(_("Type in tournament number-"))
5874 if scanner.real == 0:
5876 continue # We don't want a blank entry
5877 game.tourn = int(round(scanner.real))
5878 random.seed(scanner.real)
5880 logfp.write("# random.seed(%d)\n" % scanner.real)
5882 if scanner.sees("saved") or scanner.sees("frozen"):
5886 if game.passwd is None:
5888 if not game.alldone:
5889 game.thawed = True # No plaque if not finished
5893 if scanner.sees("regular"):
5895 proutn(_("What is \"%s\"? ") % scanner.token)
5897 while game.length==0 or game.skill==SKILL_NONE:
5898 if scanner.nexttok() == "IHALPHA":
5899 if scanner.sees("short"):
5901 elif scanner.sees("medium"):
5903 elif scanner.sees("long"):
5905 elif scanner.sees("novice"):
5906 game.skill = SKILL_NOVICE
5907 elif scanner.sees("fair"):
5908 game.skill = SKILL_FAIR
5909 elif scanner.sees("good"):
5910 game.skill = SKILL_GOOD
5911 elif scanner.sees("expert"):
5912 game.skill = SKILL_EXPERT
5913 elif scanner.sees("emeritus"):
5914 game.skill = SKILL_EMERITUS
5916 proutn(_("What is \""))
5917 proutn(scanner.token)
5922 proutn(_("Would you like a Short, Medium, or Long game? "))
5923 elif game.skill == SKILL_NONE:
5924 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5925 # Choose game options -- added by ESR for SST2K
5926 if scanner.nexttok() != "IHALPHA":
5928 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5930 if scanner.sees("plain"):
5931 # Approximates the UT FORTRAN version.
5932 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR | OPTION_CAPTURE | OPTION_CLOAK)
5933 game.options |= OPTION_PLAIN
5934 elif scanner.sees("almy"):
5935 # Approximates Tom Almy's version.
5936 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
5937 game.options |= OPTION_ALMY
5938 elif scanner.sees("fancy") or scanner.sees("\n"):
5940 elif len(scanner.token):
5941 proutn(_("What is \"%s\"?") % scanner.token)
5943 if game.passwd == "debug":
5945 prout("=== Debug mode enabled.")
5946 # Use parameters to generate initial values of things
5947 game.damfac = 0.5 * game.skill
5948 game.inbase = randrange(BASEMIN, BASEMAX+1)
5950 if game.options & OPTION_PLANETS:
5951 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5952 if game.options & OPTION_WORLDS:
5953 game.inplan += int(NINHAB)
5954 game.state.nromrem = game.inrom = randrange(2 * game.skill)
5955 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5956 game.state.remtime = 7.0 * game.length
5957 game.intime = game.state.remtime
5958 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5959 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5960 game.state.remres = (game.inkling+4*game.incom)*game.intime
5961 game.inresor = game.state.remres
5962 if game.inkling > 50:
5966 def dropin(iquad=None):
5967 "Drop a feature on a random dot in the current quadrant."
5969 w = randplace(QUADSIZE)
5970 if game.quad[w.i][w.j] == '.':
5972 if iquad is not None:
5973 game.quad[w.i][w.j] = iquad
5977 "Update our alert status."
5978 game.condition = "green"
5979 if game.energy < 1000.0:
5980 game.condition = "yellow"
5981 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5982 game.condition = "red"
5984 game.condition="dead"
5987 "Drop new Klingon into current quadrant."
5988 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5991 "Sort enemies by distance so 'nearest' is meaningful."
5992 game.enemies.sort(key=lambda x: x.kdist)
5995 "Set up a new state of quadrant, for when we enter or re-enter it."
5998 game.neutz = game.inorbit = game.landed = False
5999 game.ientesc = game.iseenit = game.isviolreported = False
6000 # Create a blank quadrant
6001 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
6003 # Attempt to escape Super-commander, so tbeam back!
6006 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
6007 # cope with supernova
6010 game.klhere = q.klingons
6011 game.irhere = q.romulans
6013 game.quad[game.sector.i][game.sector.j] = game.ship
6016 # Position ordinary Klingons
6017 for _i in range(game.klhere):
6019 # If we need a commander, promote a Klingon
6020 for cmdr in game.state.kcmdr:
6021 if cmdr == game.quadrant:
6022 e = game.enemies[game.klhere-1]
6023 game.quad[e.location.i][e.location.j] = 'C'
6024 e.power = randreal(950,1350) + 50.0*game.skill
6026 # If we need a super-commander, promote a Klingon
6027 if game.quadrant == game.state.kscmdr:
6029 game.quad[e.location.i][e.location.j] = 'S'
6030 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
6031 game.iscate = (game.state.remkl > 1)
6032 # Put in Romulans if needed
6033 for _i in range(q.romulans):
6034 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
6035 # If quadrant needs a starbase, put it in
6037 game.base = dropin('B')
6038 # If quadrant needs a planet, put it in
6040 game.iplnet = q.planet
6041 if not q.planet.inhabited:
6042 game.plnet = dropin('P')
6044 game.plnet = dropin('@')
6045 # Check for condition
6048 if game.irhere > 0 and game.klhere == 0:
6050 if not damaged(DRADIO):
6052 prout(_("LT. Uhura- \"Captain, an urgent message."))
6053 prout(_(" I'll put it on audio.\" CLICK"))
6055 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
6056 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
6057 # Put in THING if needed
6058 if thing == game.quadrant:
6059 Enemy(etype='?', loc=dropin(),
6060 power=randreal(6000,6500.0)+250.0*game.skill)
6061 if not damaged(DSRSENS):
6063 prout(_("Mr. Spock- \"Captain, this is most unusual."))
6064 prout(_(" Please examine your short-range scan.\""))
6065 # Decide if quadrant needs a Tholian; lighten up if skill is low
6066 if game.options & OPTION_THOLIAN:
6067 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
6068 (game.skill == SKILL_GOOD and withprob(0.05)) or \
6069 (game.skill > SKILL_GOOD and withprob(0.08)):
6072 w.i = withprob(0.5) * (QUADSIZE-1)
6073 w.j = withprob(0.5) * (QUADSIZE-1)
6074 if game.quad[w.i][w.j] == '.':
6076 game.tholian = Enemy(etype='T', loc=w,
6077 power=randrange(100, 500) + 25.0*game.skill)
6078 # Reserve unoccupied corners
6079 if game.quad[0][0]=='.':
6080 game.quad[0][0] = 'X'
6081 if game.quad[0][QUADSIZE-1]=='.':
6082 game.quad[0][QUADSIZE-1] = 'X'
6083 if game.quad[QUADSIZE-1][0]=='.':
6084 game.quad[QUADSIZE-1][0] = 'X'
6085 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
6086 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
6088 # And finally the stars
6089 for _i in range(q.stars):
6091 # Put in a few black holes
6092 for _i in range(1, 3+1):
6095 # Take out X's in corners if Tholian present
6097 if game.quad[0][0]=='X':
6098 game.quad[0][0] = '.'
6099 if game.quad[0][QUADSIZE-1]=='X':
6100 game.quad[0][QUADSIZE-1] = '.'
6101 if game.quad[QUADSIZE-1][0]=='X':
6102 game.quad[QUADSIZE-1][0] = '.'
6103 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
6104 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
6107 "Set the self-destruct password."
6108 if game.options & OPTION_PLAIN:
6111 proutn(_("Please type in a secret password- "))
6113 game.passwd = scanner.token
6114 if game.passwd != None:
6118 game.passwd += chr(ord('a')+randrange(26))
6119 game.passwd += chr(ord('a')+randrange(26))
6120 game.passwd += chr(ord('a')+randrange(26))
6122 # Code from sst.c begins here
6125 ("SRSCAN", OPTION_TTY),
6126 ("STATUS", OPTION_TTY),
6127 ("REQUEST", OPTION_TTY),
6128 ("LRSCAN", OPTION_TTY),
6140 ("SENSORS", OPTION_PLANETS),
6141 ("ORBIT", OPTION_PLANETS),
6142 ("TRANSPORT", OPTION_PLANETS),
6143 ("MINE", OPTION_PLANETS),
6144 ("CRYSTALS", OPTION_PLANETS),
6145 ("SHUTTLE", OPTION_PLANETS),
6146 ("PLANETS", OPTION_PLANETS),
6151 ("PROBE", OPTION_PROBE),
6153 ("FREEZE", 0), # Synonym for SAVE
6157 ("CAPTURE", OPTION_CAPTURE),
6158 ("CLOAK", OPTION_CLOAK),
6161 ("SOS", 0), # Synonym for MAYDAY
6162 ("CALL", 0), # Synonym for MAYDAY
6170 "Generate a list of legal commands."
6171 prout(_("LEGAL COMMANDS ARE:"))
6173 for (key, opt) in commands:
6174 if not opt or (opt & game.options):
6175 proutn("%-12s " % key)
6177 if emitted % 5 == 4:
6182 "Browse on-line help."
6183 key = scanner.nexttok()
6186 setwnd(prompt_window)
6187 proutn(_("Help on what command? "))
6188 key = scanner.nexttok()
6189 setwnd(message_window)
6192 cmds = [x[0] for x in commands]
6193 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
6200 cmd = scanner.token.upper()
6201 for directory in docpath:
6203 fp = open(os.path.join(directory, "sst.doc"), "r")
6208 prout(_("Spock- \"Captain, that information is missing from the"))
6209 prout(_(" computer. You need to find sst.doc and put it somewhere"))
6210 proutn(_(" in these directories: %s") % ":".join(docpath))
6212 # This used to continue: "You need to find SST.DOC and put
6213 # it in the current directory."
6216 linebuf = fp.readline()
6218 prout(_("Spock- \"Captain, there is no information on that command.\""))
6221 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
6222 linebuf = linebuf[3:].strip()
6223 if cmd.upper() == linebuf:
6226 prout(_("Spock- \"Captain, I've found the following information:\""))
6229 linebuf = fp.readline()
6230 if "******" in linebuf:
6236 "Command-interpretation loop."
6238 if game.irhere and game.state.date >= ALGERON and not game.isviolreported and game.iscloaked:
6239 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
6241 game.isviolreported = True
6242 while True: # command loop
6244 while True: # get a command
6246 game.optime = game.justin = False
6248 setwnd(prompt_window)
6251 if scanner.nexttok() == "IHEOL":
6252 if game.options & OPTION_CURSES:
6255 elif scanner.token == "":
6259 setwnd(message_window)
6261 abandon_passed = False
6262 cmd = "" # Force cmd to persist after loop
6263 opt = 0 # Force opt to persist after loop
6264 for (cmd, opt) in commands:
6265 # commands after ABANDON cannot be abbreviated
6266 if cmd == "ABANDON":
6267 abandon_passed = True
6268 if cmd == scanner.token.upper() or (not abandon_passed \
6269 and cmd.startswith(scanner.token.upper())):
6274 elif opt and not (opt & game.options):
6278 if cmd == "SRSCAN": # srscan
6280 elif cmd == "STATUS": # status
6282 elif cmd == "REQUEST": # status request
6284 elif cmd == "LRSCAN": # long range scan
6285 lrscan(silent=False)
6286 elif cmd == "PHASERS": # phasers
6291 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6296 elif cmd == "MOVE": # move under warp
6297 warp(wcourse=None, involuntary=False)
6298 elif cmd == "SHIELDS": # shields
6299 doshield(shraise=False)
6302 game.shldchg = False
6303 elif cmd == "DOCK": # dock at starbase
6306 attack(torps_ok=False)
6307 elif cmd == "DAMAGES": # damage reports
6309 elif cmd == "CHART": # chart
6311 elif cmd == "IMPULSE": # impulse
6313 elif cmd == "REST": # rest
6317 elif cmd == "WARP": # warp
6319 elif cmd == "SENSORS": # sensors
6321 elif cmd == "ORBIT": # orbit
6325 elif cmd == "TRANSPORT": # transport "beam"
6327 elif cmd == "MINE": # mine
6331 elif cmd == "CRYSTALS": # crystals
6335 elif cmd == "SHUTTLE": # shuttle
6339 elif cmd == "PLANETS": # Planet list
6341 elif cmd == "REPORT": # Game Report
6343 elif cmd == "COMPUTER": # use COMPUTER!
6345 elif cmd == "COMMANDS":
6347 elif cmd == "EMEXIT": # Emergency exit
6348 clrscr() # Hide screen
6349 freeze(True) # forced save
6350 raise SystemExit(1) # And quick exit
6351 elif cmd == "PROBE":
6352 probe() # Launch probe
6355 elif cmd == "ABANDON": # Abandon Ship
6357 elif cmd == "DESTRUCT": # Self Destruct
6359 elif cmd == "SAVE": # Save Game
6362 if game.skill > SKILL_GOOD:
6363 prout(_("WARNING--Saved games produce no plaques!"))
6364 elif cmd == "DEATHRAY": # Try a desparation measure
6368 elif cmd == "CAPTURE":
6370 elif cmd == "CLOAK":
6372 elif cmd == "DEBUGCMD": # What do we want for debug???
6374 elif cmd == "MAYDAY": # Call for help
6379 game.alldone = True # quit the game
6382 elif cmd == "SCORE":
6383 score() # see current score
6386 break # Game has ended
6387 if game.optime != 0.0:
6390 break # Events did us in
6391 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6394 if hitme and not game.justin:
6395 attack(torps_ok=True)
6398 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6409 "Emit the name of an enemy or feature."
6410 if ch == 'R': s = _("Romulan")
6411 elif ch == 'K': s = _("Klingon")
6412 elif ch == 'C': s = _("Commander")
6413 elif ch == 'S': s = _("Super-commander")
6414 elif ch == '*': s = _("Star")
6415 elif ch == 'P': s = _("Planet")
6416 elif ch == 'B': s = _("Starbase")
6417 elif ch == ' ': s = _("Black hole")
6418 elif ch == 'T': s = _("Tholian")
6419 elif ch == '#': s = _("Tholian web")
6420 elif ch == '?': s = _("Stranger")
6421 elif ch == '@': s = _("Inhabited World")
6422 else: s = "Unknown??"
6425 def crmena(loud, enemy, loctype, w):
6426 "Emit the name of an enemy and his location."
6430 buf += cramen(enemy) + _(" at ")
6431 if loctype == "quadrant":
6432 buf += _("Quadrant ")
6433 elif loctype == "sector":
6435 return buf + repr(w)
6438 "Emit our ship name."
6439 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6442 "Emit a line of stars"
6443 prouts("******************************************************")
6447 return -avrage*math.log(1e-7 + randreal())
6449 def randplace(size):
6450 "Choose a random location."
6452 w.i = randrange(size)
6453 w.j = randrange(size)
6463 # Get a token from the user
6466 # Fill the token quue if nothing here
6467 while not self.inqueue:
6469 if curwnd==prompt_window:
6471 setwnd(message_window)
6478 self.inqueue = sline.lstrip().split() + ["\n"]
6479 # From here on in it's all looking at the queue
6480 self.token = self.inqueue.pop(0)
6481 if self.token == "\n":
6485 self.real = float(self.token)
6486 self.type = "IHREAL"
6491 self.token = self.token.lower()
6492 self.type = "IHALPHA"
6495 def append(self, tok):
6496 self.inqueue.append(tok)
6497 def push(self, tok):
6498 self.inqueue.insert(0, tok)
6502 # Demand input for next scan
6504 self.real = self.token = None
6506 # compares s to item and returns true if it matches to the length of s
6507 return s.startswith(self.token)
6509 # Round token value to nearest integer
6510 return int(round(self.real))
6514 if self.type != "IHREAL":
6519 if self.type != "IHREAL":
6525 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6528 "Yes-or-no confirmation."
6532 if scanner.token == 'y':
6534 if scanner.token == 'n':
6537 proutn(_("Please answer with \"y\" or \"n\": "))
6540 "Complain about unparseable input."
6543 prout(_("Beg your pardon, Captain?"))
6546 "Access to the internals for debugging."
6547 proutn("Reset levels? ")
6549 if game.energy < game.inenrg:
6550 game.energy = game.inenrg
6551 game.shield = game.inshld
6552 game.torps = game.intorps
6553 game.lsupres = game.inlsr
6554 proutn("Reset damage? ")
6556 for i in range(NDEVICES):
6557 if game.damage[i] > 0.0:
6558 game.damage[i] = 0.0
6559 proutn("Toggle debug flag? ")
6561 game.idebug = not game.idebug
6563 prout("Debug output ON")
6565 prout("Debug output OFF")
6566 proutn("Cause selective damage? ")
6568 for i in range(NDEVICES):
6569 proutn("Kill %s?" % device[i])
6571 key = scanner.nexttok()
6572 if key == "IHALPHA" and scanner.sees("y"):
6573 game.damage[i] = 10.0
6574 proutn("Examine/change events? ")
6579 FSNOVA: "Supernova ",
6582 FBATTAK: "Base Attack ",
6583 FCDBAS: "Base Destroy ",
6584 FSCMOVE: "SC Move ",
6585 FSCDBAS: "SC Base Destroy ",
6586 FDSPROB: "Probe Move ",
6587 FDISTR: "Distress Call ",
6588 FENSLV: "Enslavement ",
6589 FREPRO: "Klingon Build ",
6591 for i in range(1, NEVENTS):
6594 proutn("%.2f" % (scheduled(i)-game.state.date))
6595 if i == FENSLV or i == FREPRO:
6597 proutn(" in %s" % ev.quadrant)
6602 key = scanner.nexttok()
6606 elif key == "IHREAL":
6607 ev = schedule(i, scanner.real)
6608 if i == FENSLV or i == FREPRO:
6610 proutn("In quadrant- ")
6611 key = scanner.nexttok()
6612 # "IHEOL" says to leave coordinates as they are
6615 prout("Event %d canceled, no x coordinate." % (i))
6618 w.i = int(round(scanner.real))
6619 key = scanner.nexttok()
6621 prout("Event %d canceled, no y coordinate." % (i))
6624 w.j = int(round(scanner.real))
6627 proutn("Induce supernova here? ")
6629 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6632 if __name__ == '__main__':
6634 #global line, thing, game
6638 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6639 if os.getenv("TERM"):
6640 game.options |= OPTION_CURSES
6642 game.options |= OPTION_TTY
6643 seed = int(time.time())
6644 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6646 for (switch, val) in options:
6649 replayfp = open(val, "r")
6651 sys.stderr.write("sst: can't open replay file %s\n" % val)
6654 line = replayfp.readline().strip()
6655 (leader, __, seed) = line.split()
6657 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6658 line = replayfp.readline().strip()
6659 arguments += line.split()[2:]
6662 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6664 game.options |= OPTION_TTY
6665 game.options &=~ OPTION_CURSES
6666 elif switch == '-s':
6668 elif switch == '-t':
6669 game.options |= OPTION_TTY
6670 game.options &=~ OPTION_CURSES
6671 elif switch == '-x':
6673 elif switch == '-V':
6674 print("SST2K", version)
6677 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6679 # where to save the input in case of bugs
6680 if "TMPDIR" in os.environ:
6681 tmpdir = os.environ['TMPDIR']
6685 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6687 sys.stderr.write("sst: warning, can't open logfile\n")
6690 logfp.write("# seed %s\n" % seed)
6691 logfp.write("# options %s\n" % " ".join(arguments))
6692 logfp.write("# SST2K version %s\n" % version)
6693 logfp.write("# recorded by %s@%s on %s\n" % \
6694 (getpass.getuser(),socket.gethostname(),time.ctime()))
6696 scanner = sstscanner()
6697 for arg in arguments:
6701 while True: # Play a game
6702 setwnd(fullscreen_window)
6708 game.alldone = False
6716 if game.tourn and game.alldone:
6717 proutn(_("Do you want your score recorded?"))
6723 proutn(_("Do you want to play again? "))
6727 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6731 except KeyboardInterrupt: