3 sst.py -- Super Star Trek 2K
5 SST2K is a Python translation of a C translation of a FORTRAN
6 original dating back to 1973. Beautiful Python it is not, but it
7 works. Translation by Eric S. Raymond; original game by David Matuszek
8 and Paul Reynolds, with modifications by Don Smith, Tom Almy,
9 Stas Sergeev, and Eric S. Raymond.
11 See the doc/HACKING file in the distribution for designers notes and advice
12 on how to modify (and how not to modify!) this code.
14 import os, sys, math, curses, time, pickle, random, copy, gettext, getpass
15 import getopt, socket, locale
17 # This import only works on Unixes. The intention is to enable
18 # Ctrl-P, Ctrl-N, and friends in Cmd.
24 # Prevent lossage under Python 3
33 docpath = (".", "doc/", "/usr/share/doc/sst/")
36 return gettext.gettext(st)
38 GALSIZE = 8 # Galaxy size in quadrants
39 NINHAB = (GALSIZE * GALSIZE // 2) # Number of inhabited worlds
40 MAXUNINHAB = 10 # Maximum uninhabited worlds
41 QUADSIZE = 10 # Quadrant size in sectors
42 BASEMIN = 2 # Minimum starbases
43 BASEMAX = (GALSIZE * GALSIZE // 12) # Maximum starbases
44 MAXKLGAME = 127 # Maximum Klingons per game
45 MAXKLQUAD = 9 # Maximum Klingons per quadrant
46 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
47 FOREVER = 1e30 # Time for the indefinite future
48 MAXBURST = 3 # Max # of torps you can launch in one turn
49 MINCMDR = 10 # Minimum number of Klingon commanders
50 DOCKFAC = 0.25 # Repair faster when docked
51 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
53 ALGERON = 2311 # Date of the Treaty of Algeron
74 class TrekError(Exception):
77 class JumpOut(Exception):
81 def __init__(self, x=None, y=None):
84 def valid_quadrant(self):
85 return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
86 def valid_sector(self):
87 return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
89 self.i = self.j = None
91 return self.i != None and self.j != None
92 def __eq__(self, other):
93 return other != None and self.i == other.i and self.j == other.j
94 def __ne__(self, other):
95 return other is None or self.i != other.i or self.j != other.j
96 def __add__(self, other):
97 return Coord(self.i+other.i, self.j+other.j)
98 def __sub__(self, other):
99 return Coord(self.i-other.i, self.j-other.j)
100 def __mul__(self, other):
101 return Coord(self.i*other, self.j*other)
102 def __rmul__(self, other):
103 return Coord(self.i*other, self.j*other)
104 def __div__(self, other):
105 return Coord(self.i/other, self.j/other)
106 def __mod__(self, other):
107 return Coord(self.i % other, self.j % other)
108 def __rdiv__(self, other):
109 return Coord(self.i/other, self.j/other)
110 def roundtogrid(self):
111 return Coord(int(round(self.i)), int(round(self.j)))
112 def distance(self, other=None):
115 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
117 return 1.90985*math.atan2(self.j, self.i)
123 s.i = self.i / abs(self.i)
127 s.j = self.j / abs(self.j)
130 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
131 return self.roundtogrid() / QUADSIZE
133 return self.roundtogrid() % QUADSIZE
136 s.i = self.i + randrange(-1, 2)
137 s.j = self.j + randrange(-1, 2)
140 if self.i is None or self.j is None:
142 return "%s - %s" % (self.i+1, self.j+1)
146 "Do not anger the Space Thingy!"
153 return (q.i, q.j) == (self.i, self.j)
157 self.name = None # string-valued if inhabited
158 self.quadrant = Coord() # quadrant located
159 self.pclass = None # could be ""M", "N", "O", or "destroyed"
160 self.crystals = "absent"# could be "mined", "present", "absent"
161 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
162 self.inhabited = False # is it inhabited?
170 self.starbase = False
173 self.supernova = False
175 self.status = "secure" # Could be "secure", "distressed", "enslaved"
180 self.starbase = False
183 return "<%s,%s,%s>" % (self.klingons, self.starbase, self.stars)
185 def fill2d(size, fillfun):
186 "Fill an empty list in 2D."
188 for i in range(size):
190 for j in range(size):
191 lst[i].append(fillfun(i, j))
196 self.snap = False # snapshot taken
197 self.crew = 0 # crew complement
198 self.remkl = 0 # remaining klingons
199 self.nscrem = 0 # remaining super commanders
200 self.starkl = 0 # destroyed stars
201 self.basekl = 0 # destroyed bases
202 self.nromrem = 0 # Romulans remaining
203 self.nplankl = 0 # destroyed uninhabited planets
204 self.nworldkl = 0 # destroyed inhabited planets
205 self.planets = [] # Planet information
206 self.date = 0.0 # stardate
207 self.remres = 0 # remaining resources
208 self.remtime = 0 # remaining time
209 self.baseq = [] # Base quadrant coordinates
210 self.kcmdr = [] # Commander quadrant coordinates
211 self.kscmdr = Coord() # Supercommander quadrant coordinates
213 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
215 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
219 self.date = None # A real number
220 self.quadrant = None # A coord structure
223 OPTION_ALL = 0xffffffff
224 OPTION_TTY = 0x00000001 # old interface
225 OPTION_CURSES = 0x00000002 # new interface
226 OPTION_IOMODES = 0x00000003 # cover both interfaces
227 OPTION_PLANETS = 0x00000004 # planets and mining
228 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
229 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
230 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
231 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
232 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
233 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
234 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
235 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
236 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
237 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
238 OPTION_CAPTURE = 0x00002000 # Enable BSD-Trek capture (Almy, 2013).
239 OPTION_CLOAK = 0x80004000 # Enable BSD-Trek capture (Almy, 2013).
240 OPTION_PLAIN = 0x01000000 # user chose plain game
241 OPTION_ALMY = 0x02000000 # user chose Almy variant
242 OPTION_COLOR = 0x04000000 # enable color display (ESR, 2010)
262 NDEVICES = 17 # Number of devices
272 return (game.damage[dev] != 0.0)
274 return not damaged(DRADIO) or game.condition=="docked"
276 # Define future events
277 FSPY = 0 # Spy event happens always (no future[] entry)
278 # can cause SC to tractor beam Enterprise
279 FSNOVA = 1 # Supernova
280 FTBEAM = 2 # Commander tractor beams Enterprise
281 FSNAP = 3 # Snapshot for time warp
282 FBATTAK = 4 # Commander attacks base
283 FCDBAS = 5 # Commander destroys base
284 FSCMOVE = 6 # Supercommander moves (might attack base)
285 FSCDBAS = 7 # Supercommander destroys base
286 FDSPROB = 8 # Move deep space probe
287 FDISTR = 9 # Emit distress call from an inhabited world
288 FENSLV = 10 # Inhabited word is enslaved */
289 FREPRO = 11 # Klingons build a ship in an enslaved system
292 # Abstract out the event handling -- underlying data structures will change
293 # when we implement stateful events
294 def findevent(evtype):
295 return game.future[evtype]
298 def __init__(self, etype=None, loc=None, power=None):
300 self.location = Coord()
305 self.power = power # enemy energy level
306 game.enemies.append(self)
308 motion = (loc != self.location)
309 if self.location.i is not None and self.location.j is not None:
312 game.quad[self.location.i][self.location.j] = '#'
314 game.quad[self.location.i][self.location.j] = '.'
316 self.location = copy.copy(loc)
317 game.quad[self.location.i][self.location.j] = self.type
318 self.kdist = self.kavgd = (game.sector - loc).distance()
320 self.location = Coord()
321 self.kdist = self.kavgd = None
322 game.enemies.remove(self)
325 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
329 self.options = None # Game options
330 self.state = Snapshot() # A snapshot structure
331 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
332 self.quad = None # contents of our quadrant
333 self.damage = [0.0] * NDEVICES # damage encountered
334 self.future = [] # future events
338 self.future.append(Event())
339 self.passwd = None # Self Destruct password
341 self.quadrant = None # where we are in the large
342 self.sector = None # where we are in the small
343 self.tholian = None # Tholian enemy object
344 self.base = None # position of base in current quadrant
345 self.battle = None # base coordinates being attacked
346 self.plnet = None # location of planet in quadrant
347 self.gamewon = False # Finished!
348 self.ididit = False # action taken -- allows enemy to attack
349 self.alive = False # we are alive (not killed)
350 self.justin = False # just entered quadrant
351 self.shldup = False # shields are up
352 self.shldchg = False # shield is changing (affects efficiency)
353 self.iscate = False # super commander is here
354 self.ientesc = False # attempted escape from supercommander
355 self.resting = False # rest time
356 self.icraft = False # Kirk in Galileo
357 self.landed = False # party on planet (true), on ship (false)
358 self.alldone = False # game is now finished
359 self.neutz = False # Romulan Neutral Zone
360 self.isarmed = False # probe is armed
361 self.inorbit = False # orbiting a planet
362 self.imine = False # mining
363 self.icrystl = False # dilithium crystals aboard
364 self.iseenit = False # seen base attack report
365 self.thawed = False # thawed game
366 self.condition = None # "green", "yellow", "red", "docked", "dead"
367 self.iscraft = None # "onship", "offship", "removed"
368 self.skill = None # Player skill level
369 self.inkling = 0 # initial number of klingons
370 self.inbase = 0 # initial number of bases
371 self.incom = 0 # initial number of commanders
372 self.inscom = 0 # initial number of commanders
373 self.inrom = 0 # initial number of commanders
374 self.instar = 0 # initial stars
375 self.intorps = 0 # initial/max torpedoes
376 self.torps = 0 # number of torpedoes
377 self.ship = 0 # ship type -- 'E' is Enterprise
378 self.abandoned = 0 # count of crew abandoned in space
379 self.length = 0 # length of game
380 self.klhere = 0 # klingons here
381 self.casual = 0 # causalties
382 self.nhelp = 0 # calls for help
383 self.nkinks = 0 # count of energy-barrier crossings
384 self.iplnet = None # planet # in quadrant
385 self.inplan = 0 # initial planets
386 self.irhere = 0 # Romulans in quadrant
387 self.isatb = 0 # =2 if super commander is attacking base
388 self.tourn = None # tournament number
389 self.nprobes = 0 # number of probes available
390 self.inresor = 0.0 # initial resources
391 self.intime = 0.0 # initial time
392 self.inenrg = 0.0 # initial/max energy
393 self.inshld = 0.0 # initial/max shield
394 self.inlsr = 0.0 # initial life support resources
395 self.indate = 0.0 # initial date
396 self.energy = 0.0 # energy level
397 self.shield = 0.0 # shield level
398 self.warpfac = 0.0 # warp speed
399 self.lsupres = 0.0 # life support reserves
400 self.optime = 0.0 # time taken by current operation
401 self.damfac = 0.0 # damage factor
402 self.lastchart = 0.0 # time star chart was last updated
403 self.cryprob = 0.0 # probability that crystal will work
404 self.probe = None # object holding probe course info
405 self.height = 0.0 # height of orbit around planet
406 self.score = 0.0 # overall score
407 self.perdate = 0.0 # rate of kills
408 self.idebug = False # Debugging instrumentation enabled?
409 self.statekscmdr = None # No SuperCommander coordinates yet.
410 self.brigcapacity = 400 # Enterprise brig capacity
411 self.brigfree = 400 # How many klingons can we put in the brig?
412 self.kcaptured = 0 # Total Klingons captured, for scoring.
413 self.iscloaked = False # Cloaking device on?
414 self.ncviol = 0 # Algreon treaty violations
415 self.isviolreported = False # We have been warned
417 # Stas thinks this should be (C expression):
418 # game.state.remkl + len(game.state.kcmdr) > 0 ?
419 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
420 # He says the existing expression is prone to divide-by-zero errors
421 # after killing the last klingon when score is shown -- perhaps also
422 # if the only remaining klingon is SCOM.
423 self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.state.kcmdr))
425 "Are there Klingons remaining?"
426 return self.state.remkl + len(self.state.kcmdr) + self.state.nscrem
453 return random.random() < p
455 def randrange(*args):
456 return random.randrange(*args)
461 v *= args[0] # from [0, args[0])
463 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
466 # Code from ai.c begins here
469 "Would this quadrant welcome another Klingon?"
470 return iq.valid_quadrant() and \
471 not game.state.galaxy[iq.i][iq.j].supernova and \
472 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
474 def tryexit(enemy, look, irun):
475 "A bad guy attempts to bug out."
477 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
478 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
479 if not welcoming(iq):
481 if enemy.type == 'R':
482 return False # Romulans cannot escape!
484 # avoid intruding on another commander's territory
485 if enemy.type == 'C':
486 if iq in game.state.kcmdr:
488 # refuse to leave if currently attacking starbase
489 if game.battle == game.quadrant:
491 # don't leave if over 1000 units of energy
492 if enemy.power > 1000.0:
494 oldloc = copy.copy(enemy.location)
495 # handle local matters related to escape
498 if game.condition != "docked":
500 # Handle global matters related to escape
501 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
502 game.state.galaxy[iq.i][iq.j].klingons += 1
503 if enemy.type == 'S':
507 schedule(FSCMOVE, 0.2777)
509 game.state.kscmdr = iq
511 for cmdr in game.state.kcmdr:
512 if cmdr == game.quadrant:
513 game.state.kcmdr.append(iq)
515 # report move out of quadrant.
516 return [(True, enemy, oldloc, iq)]
518 # The bad-guy movement algorithm:
520 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
521 # If both are operating full strength, force is 1000. If both are damaged,
522 # force is -1000. Having shields down subtracts an additional 1000.
524 # 2. Enemy has forces equal to the energy of the attacker plus
525 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
526 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
528 # Attacker Initial energy levels (nominal):
529 # Klingon Romulan Commander Super-Commander
530 # Novice 400 700 1200
532 # Good 450 800 1300 1750
533 # Expert 475 850 1350 1875
534 # Emeritus 500 900 1400 2000
535 # VARIANCE 75 200 200 200
537 # Enemy vessels only move prior to their attack. In Novice - Good games
538 # only commanders move. In Expert games, all enemy vessels move if there
539 # is a commander present. In Emeritus games all enemy vessels move.
541 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
542 # forces are 1000 greater than Enterprise.
544 # Agressive action on average cuts the distance between the ship and
545 # the enemy to 1/4 the original.
547 # 4. At lower energy advantage, movement units are proportional to the
548 # advantage with a 650 advantage being to hold ground, 800 to move forward
549 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
551 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
552 # retreat, especially at high skill levels.
554 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
556 def movebaddy(enemy):
557 "Tactical movement for the bad guys."
561 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
562 if game.skill >= SKILL_EXPERT:
563 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
565 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
566 old_dist = enemy.kdist
567 mdist = int(old_dist + 0.5) # Nearest integer distance
568 # If SC, check with spy to see if should hi-tail it
569 if enemy.type == 'S' and \
570 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
574 # decide whether to advance, retreat, or hold position
575 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
577 forces += 1000 # Good for enemy if shield is down!
578 if not damaged(DPHASER) or not damaged(DPHOTON):
579 if damaged(DPHASER): # phasers damaged
582 forces -= 0.2*(game.energy - 2500.0)
583 if damaged(DPHOTON): # photon torpedoes damaged
586 forces -= 50.0*game.torps
588 # phasers and photon tubes both out!
591 if forces <= 1000.0 and game.condition != "docked": # Typical situation
592 motion = ((forces + randreal(200))/150.0) - 5.0
594 if forces > 1000.0: # Very strong -- move in for kill
595 motion = (1.0 - randreal())**2 * old_dist + 1.0
596 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
597 motion -= game.skill*(2.0-randreal()**2)
599 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
600 # don't move if no motion
603 # Limit motion according to skill
604 if abs(motion) > game.skill:
609 # calculate preferred number of steps
610 nsteps = abs(int(motion))
611 if motion > 0 and nsteps > mdist:
612 nsteps = mdist # don't overshoot
613 if nsteps > QUADSIZE:
614 nsteps = QUADSIZE # This shouldn't be necessary
616 nsteps = 1 # This shouldn't be necessary
618 proutn("NSTEPS = %d:" % nsteps)
619 # Compute preferred values of delta X and Y
620 m = game.sector - enemy.location
621 if 2.0 * abs(m.i) < abs(m.j):
623 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
625 m = (motion * m).sgn()
626 goto = enemy.location
628 for ll in range(nsteps):
630 proutn(" %d" % (ll+1))
631 # Check if preferred position available
642 attempts = 0 # Settle mysterious hang problem
643 while attempts < 20 and not success:
645 if look.i < 0 or look.i >= QUADSIZE:
647 return tryexit(enemy, look, irun)
648 if krawli == m.i or m.j == 0:
650 look.i = goto.i + krawli
652 elif look.j < 0 or look.j >= QUADSIZE:
654 return tryexit(enemy, look, irun)
655 if krawlj == m.j or m.i == 0:
657 look.j = goto.j + krawlj
659 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
660 # See if enemy should ram ship
661 if game.quad[look.i][look.j] == game.ship and \
662 (enemy.type == 'C' or enemy.type == 'S'):
663 collision(rammed=True, enemy=enemy)
665 if krawli != m.i and m.j != 0:
666 look.i = goto.i + krawli
668 elif krawlj != m.j and m.i != 0:
669 look.j = goto.j + krawlj
672 break # we have failed
683 # Enemy moved, but is still in sector
684 return [(False, enemy, old_dist, goto)]
687 "Sequence Klingon tactical movement."
690 # Figure out which Klingon is the commander (or Supercommander)
693 if game.quadrant in game.state.kcmdr:
694 for enemy in game.enemies:
695 if enemy.type == 'C':
696 tacmoves += movebaddy(enemy)
697 if game.state.kscmdr == game.quadrant:
698 for enemy in game.enemies:
699 if enemy.type == 'S':
700 tacmoves += movebaddy(enemy)
702 # If skill level is high, move other Klingons and Romulans too!
703 # Move these last so they can base their actions on what the
705 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
706 for enemy in game.enemies:
707 if enemy.type in ('K', 'R'):
708 tacmoves += movebaddy(enemy)
711 def movescom(iq, avoid):
712 "Commander movement helper."
713 # Avoid quadrants with bases if we want to avoid Enterprise
714 if not welcoming(iq) or (avoid and iq in game.state.baseq):
716 if game.justin and not game.iscate:
719 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
720 game.state.kscmdr = iq
721 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
722 if game.state.kscmdr == game.quadrant:
723 # SC has scooted, remove him from current quadrant
728 for enemy in game.enemies:
729 if enemy.type == 'S':
732 if game.condition != "docked":
735 # check for a helpful planet
736 for i in range(game.inplan):
737 if game.state.planets[i].quadrant == game.state.kscmdr and \
738 game.state.planets[i].crystals == "present":
740 game.state.planets[i].pclass = "destroyed"
741 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
744 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
745 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
746 prout(_(" by the Super-commander.\""))
748 return True # looks good!
750 def supercommander():
751 "Move the Super Commander."
758 prout("== SUPERCOMMANDER")
759 # Decide on being active or passive
760 avoid = ((game.incom - len(game.state.kcmdr) + game.inkling - game.state.remkl)/(game.state.date+0.01-game.indate) < 0.1*game.skill*(game.skill+1.0) or \
761 (game.state.date-game.indate) < 3.0)
762 if not game.iscate and avoid:
763 # compute move away from Enterprise
764 idelta = game.state.kscmdr-game.quadrant
765 if idelta.distance() > 2.0:
767 idelta.i = game.state.kscmdr.j-game.quadrant.j
768 idelta.j = game.quadrant.i-game.state.kscmdr.i
770 # compute distances to starbases
771 if not game.state.baseq:
775 sc = game.state.kscmdr
776 for (i, base) in enumerate(game.state.baseq):
777 basetbl.append((i, (base - sc).distance()))
778 if game.state.baseq > 1:
779 basetbl.sort(key=lambda x: x[1])
780 # look for nearest base without a commander, no Enterprise, and
781 # without too many Klingons, and not already under attack.
782 ifindit = iwhichb = 0
783 for (i2, base) in enumerate(game.state.baseq):
784 i = basetbl[i2][0] # bug in original had it not finding nearest
785 if base == game.quadrant or base == game.battle or not welcoming(base):
787 # if there is a commander, and no other base is appropriate,
788 # we will take the one with the commander
789 for cmdr in game.state.kcmdr:
790 if base == cmdr and ifindit != 2:
794 else: # no commander -- use this one
799 return # Nothing suitable -- wait until next time
800 ibq = game.state.baseq[iwhichb]
801 # decide how to move toward base
802 idelta = ibq - game.state.kscmdr
803 # Maximum movement is 1 quadrant in either or both axes
804 idelta = idelta.sgn()
805 # try moving in both x and y directions
806 # there was what looked like a bug in the Almy C code here,
807 # but it might be this translation is just wrong.
808 iq = game.state.kscmdr + idelta
809 if not movescom(iq, avoid):
810 # failed -- try some other maneuvers
811 if idelta.i == 0 or idelta.j == 0:
814 iq.j = game.state.kscmdr.j + 1
815 if not movescom(iq, avoid):
816 iq.j = game.state.kscmdr.j - 1
819 iq.i = game.state.kscmdr.i + 1
820 if not movescom(iq, avoid):
821 iq.i = game.state.kscmdr.i - 1
824 # try moving just in x or y
825 iq.j = game.state.kscmdr.j
826 if not movescom(iq, avoid):
827 iq.j = game.state.kscmdr.j + idelta.j
828 iq.i = game.state.kscmdr.i
831 if len(game.state.baseq) == 0:
834 for ibq in game.state.baseq:
835 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
838 return # no, don't attack base!
841 schedule(FSCDBAS, randreal(1.0, 3.0))
842 if is_scheduled(FCDBAS):
843 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
844 if not communicating():
848 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
850 prout(_(" reports that it is under attack from the Klingon Super-commander."))
851 proutn(_(" It can survive until stardate %d.\"") \
852 % int(scheduled(FSCDBAS)))
855 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
859 game.optime = 0.0 # actually finished
861 # Check for intelligence report
862 if not game.idebug and \
864 (not communicating()) or \
865 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
868 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
869 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
874 if not game.tholian or game.justin:
877 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
880 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
883 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
886 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
890 # something is wrong!
891 game.tholian.move(None)
892 prout("***Internal error: Tholian in a bad spot.")
894 # do nothing if we are blocked
895 if game.quad[tid.i][tid.j] not in ('.', '#'):
897 here = copy.copy(game.tholian.location)
898 delta = (tid - game.tholian.location).sgn()
900 while here.i != tid.i:
902 if game.quad[here.i][here.j] == '.':
903 game.tholian.move(here)
905 while here.j != tid.j:
907 if game.quad[here.i][here.j] == '.':
908 game.tholian.move(here)
909 # check to see if all holes plugged
910 for i in range(QUADSIZE):
911 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
913 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
915 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
917 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
919 # All plugged up -- Tholian splits
920 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
922 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
923 game.tholian.move(None)
926 # Code from battle.c begins here
929 "Change cloaking-device status."
931 prout(_("Ye Faerie Queene hath no cloaking device."));
934 key = scanner.nexttok()
941 if scanner.sees("on"):
943 prout(_("The cloaking device has already been switched on."))
946 elif scanner.sees("off"):
947 if not game.iscloaked:
948 prout(_("The cloaking device has already been switched off."))
955 if not game.iscloaked:
956 proutn(_("Switch cloaking device on? "))
961 proutn(_("Switch cloaking device off? "))
968 if action == "CLOFF":
969 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
970 prout(_("Spock- \"Captain, the Treaty of Algeron is in effect.\n Are you sure this is wise?\""))
973 prout("Engineer Scott- \"Aye, Sir.\"");
974 game.iscloaked = False;
975 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
976 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
978 game.isviolreported = True
980 #if (neutz and game.state.date >= ALGERON) finish(FCLOAK);
985 prout(_("Engineer Scott- \"The cloaking device is damaged, Sir.\""))
988 if game.condition == "docked":
989 prout(_("You cannot cloak while docked."))
991 if game.state.date >= ALGERON and not game.isviolreported:
992 prout(_("Spock- \"Captain, using the cloaking device is a violation"))
993 prout(_(" of the Treaty of Algeron. Considering the alternatives,"))
994 proutn(_(" are you sure this is wise? "))
997 prout(_("Engineer Scott- \"Cloaking device has engaging, Sir...\""))
999 prout(_("Engineer Scott- \"Cloaking device has engaged, Sir.\""))
1000 game.iscloaked = True
1002 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
1003 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
1005 game.isviolreported = True
1007 def doshield(shraise):
1008 "Change shield status."
1014 key = scanner.nexttok()
1015 if key == "IHALPHA":
1016 if scanner.sees("transfer"):
1019 if damaged(DSHIELD):
1020 prout(_("Shields damaged and down."))
1022 if scanner.sees("up"):
1024 elif scanner.sees("down"):
1026 if action == "NONE":
1027 proutn(_("Do you wish to change shield energy? "))
1030 elif damaged(DSHIELD):
1031 prout(_("Shields damaged and down."))
1034 proutn(_("Shields are up. Do you want them down? "))
1041 proutn(_("Shields are down. Do you want them up? "))
1047 if action == "SHUP": # raise shields
1049 prout(_("Shields already up."))
1053 if game.condition != "docked":
1055 prout(_("Shields raised."))
1056 if game.energy <= 0:
1058 prout(_("Shields raising uses up last of energy."))
1063 elif action == "SHDN":
1065 prout(_("Shields already down."))
1069 prout(_("Shields lowered."))
1072 elif action == "NRG":
1073 while scanner.nexttok() != "IHREAL":
1075 proutn(_("Energy to transfer to shields- "))
1080 if nrg > game.energy:
1081 prout(_("Insufficient ship energy."))
1084 if game.shield+nrg >= game.inshld:
1085 prout(_("Shield energy maximized."))
1086 if game.shield+nrg > game.inshld:
1087 prout(_("Excess energy requested returned to ship energy"))
1088 game.energy -= game.inshld-game.shield
1089 game.shield = game.inshld
1091 if nrg < 0.0 and game.energy-nrg > game.inenrg:
1092 # Prevent shield drain loophole
1094 prout(_("Engineering to bridge--"))
1095 prout(_(" Scott here. Power circuit problem, Captain."))
1096 prout(_(" I can't drain the shields."))
1099 if game.shield+nrg < 0:
1100 prout(_("All shield energy transferred to ship."))
1101 game.energy += game.shield
1104 proutn(_("Scotty- \""))
1106 prout(_("Transferring energy to shields.\""))
1108 prout(_("Draining energy from shields.\""))
1114 "Choose a device to damage, at random."
1116 105, # DSRSENS: short range scanners 10.5%
1117 105, # DLRSENS: long range scanners 10.5%
1118 120, # DPHASER: phasers 12.0%
1119 120, # DPHOTON: photon torpedoes 12.0%
1120 25, # DLIFSUP: life support 2.5%
1121 65, # DWARPEN: warp drive 6.5%
1122 70, # DIMPULS: impulse engines 6.5%
1123 145, # DSHIELD: deflector shields 14.5%
1124 30, # DRADIO: subspace radio 3.0%
1125 45, # DSHUTTL: shuttle 4.5%
1126 15, # DCOMPTR: computer 1.5%
1127 20, # NAVCOMP: navigation system 2.0%
1128 75, # DTRANSP: transporter 7.5%
1129 20, # DSHCTRL: high-speed shield controller 2.0%
1130 10, # DDRAY: death ray 1.0%
1131 30, # DDSP: deep-space probes 3.0%
1132 0, # DCLOAK: the cloaking device 0.0
1134 assert(sum(weights) == 1000)
1135 idx = randrange(1000)
1137 for (i, w) in enumerate(weights):
1141 return None # we should never get here
1143 def collision(rammed, enemy):
1144 "Collision handling for rammong events."
1145 prouts(_("***RED ALERT! RED ALERT!"))
1147 prout(_("***COLLISION IMMINENT."))
1151 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1153 proutn(_(" rammed by "))
1156 proutn(crmena(False, enemy.type, "sector", enemy.location))
1158 proutn(_(" (original position)"))
1160 deadkl(enemy.location, enemy.type, game.sector)
1161 proutn("***" + crmshp() + " heavily damaged.")
1162 icas = randrange(10, 30)
1163 prout(_("***Sickbay reports %d casualties") % icas)
1165 game.state.crew -= icas
1166 # In the pre-SST2K version, all devices got equiprobably damaged,
1167 # which was silly. Instead, pick up to half the devices at
1168 # random according to our weighting table,
1169 ncrits = randrange(NDEVICES/2)
1173 if game.damage[dev] < 0:
1175 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1176 # Damage for at least time of travel!
1177 game.damage[dev] += game.optime + extradm
1179 prout(_("***Shields are down."))
1180 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1187 def torpedo(origin, bearing, dispersion, number, nburst):
1188 "Let a photon torpedo fly"
1189 if not damaged(DSRSENS) or game.condition == "docked":
1190 setwnd(srscan_window)
1192 setwnd(message_window)
1193 ac = bearing + 0.25*dispersion # dispersion is a random variable
1194 bullseye = (15.0 - bearing)*0.5235988
1195 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1196 bumpto = Coord(0, 0)
1197 # Loop to move a single torpedo
1198 setwnd(message_window)
1199 for step in range(1, QUADSIZE*2):
1200 if not track.nexttok():
1203 if not w.valid_sector():
1205 iquad = game.quad[w.i][w.j]
1206 tracktorpedo(w, step, number, nburst, iquad)
1210 setwnd(message_window)
1211 if not damaged(DSRSENS) or game.condition == "docked":
1212 skip(1) # start new line after text track
1213 if iquad in ('E', 'F'): # Hit our ship
1215 prout(_("Torpedo hits %s.") % crmshp())
1216 hit = 700.0 + randreal(100) - \
1217 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1218 newcnd() # we're blown out of dock
1219 if game.landed or game.condition == "docked":
1220 return hit # Cheat if on a planet
1221 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1222 # is 143 degrees, which is almost exactly 4.8 clockface units
1223 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1224 displacement.nexttok()
1225 bumpto = displacement.sector()
1226 if not bumpto.valid_sector():
1228 if game.quad[bumpto.i][bumpto.j] == ' ':
1231 if game.quad[bumpto.i][bumpto.j] != '.':
1232 # can't move into object
1234 game.sector = bumpto
1236 game.quad[w.i][w.j] = '.'
1237 game.quad[bumpto.i][bumpto.j] = iquad
1238 prout(_(" displaced by blast to Sector %s ") % bumpto)
1239 for enemy in game.enemies:
1240 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1243 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1245 if iquad in ('C', 'S') and withprob(0.05):
1246 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1247 prout(_(" torpedo neutralized."))
1249 for enemy in game.enemies:
1250 if w == enemy.location:
1251 kp = math.fabs(enemy.power)
1252 h1 = 700.0 + randrange(100) - \
1253 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1261 if enemy.power == 0:
1264 proutn(crmena(True, iquad, "sector", w))
1265 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1266 displacement.nexttok()
1267 bumpto = displacement.sector()
1268 if not bumpto.valid_sector():
1269 prout(_(" damaged but not destroyed."))
1271 if game.quad[bumpto.i][bumpto.j] == ' ':
1272 prout(_(" buffeted into black hole."))
1273 deadkl(w, iquad, bumpto)
1274 if game.quad[bumpto.i][bumpto.j] != '.':
1275 prout(_(" damaged but not destroyed."))
1277 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1278 enemy.location = bumpto
1279 game.quad[w.i][w.j] = '.'
1280 game.quad[bumpto.i][bumpto.j] = iquad
1281 for enemy in game.enemies:
1282 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1286 prout("Internal error, no enemy where expected!")
1289 elif iquad == 'B': # Hit a base
1291 prout(_("***STARBASE DESTROYED.."))
1292 game.state.baseq = [x for x in game.state.baseq if x != game.quadrant]
1293 game.quad[w.i][w.j] = '.'
1294 game.base.invalidate()
1295 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
1296 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = False
1297 game.state.basekl += 1
1300 elif iquad == 'P': # Hit a planet
1301 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1302 game.state.nplankl += 1
1303 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1304 game.iplnet.pclass = "destroyed"
1306 game.plnet.invalidate()
1307 game.quad[w.i][w.j] = '.'
1309 # captain perishes on planet
1312 elif iquad == '@': # Hit an inhabited world -- very bad!
1313 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1314 game.state.nworldkl += 1
1315 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1316 game.iplnet.pclass = "destroyed"
1318 game.plnet.invalidate()
1319 game.quad[w.i][w.j] = '.'
1321 # captain perishes on planet
1323 prout(_("The torpedo destroyed an inhabited planet."))
1325 elif iquad == '*': # Hit a star
1329 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1331 elif iquad == '?': # Hit a thingy
1332 if not (game.options & OPTION_THINGY) or withprob(0.3):
1334 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1336 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1338 proutn(_("Mr. Spock-"))
1339 prouts(_(" \"Fascinating!\""))
1343 # Stas Sergeev added the possibility that
1344 # you can shove the Thingy and piss it off.
1345 # It then becomes an enemy and may fire at you.
1348 elif iquad == ' ': # Black hole
1350 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1352 elif iquad == '#': # hit the web
1354 prout(_("***Torpedo absorbed by Tholian web."))
1356 elif iquad == 'T': # Hit a Tholian
1357 h1 = 700.0 + randrange(100) - \
1358 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1361 game.quad[w.i][w.j] = '.'
1366 proutn(crmena(True, 'T', "sector", w))
1368 prout(_(" survives photon blast."))
1370 prout(_(" disappears."))
1371 game.tholian.move(None)
1372 game.quad[w.i][w.j] = '#'
1377 proutn("Don't know how to handle torpedo collision with ")
1378 proutn(crmena(True, iquad, "sector", w))
1383 setwnd(message_window)
1384 prout(_("Torpedo missed."))
1388 "Critical-hit resolution."
1389 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1391 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1392 proutn(_("***CRITICAL HIT--"))
1393 # Select devices and cause damage
1398 # Cheat to prevent shuttle damage unless on ship
1399 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship") or (j == DCLOAK and game.ship != 'E' or j == DDRAY)):
1402 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1403 game.damage[j] += extradm
1406 for (i, j) in enumerate(cdam):
1408 if skipcount % 3 == 2 and i < len(cdam)-1:
1413 prout(_(" damaged."))
1414 if damaged(DSHIELD) and game.shldup:
1415 prout(_("***Shields knocked down."))
1417 if damaged(DCLOAK) and game.iscloaked:
1418 prout(_("***Cloaking device rendered inoperative."))
1419 game.iscloaked = False
1421 def attack(torps_ok):
1422 # bad guy attacks us
1423 # torps_ok == False forces use of phasers in an attack
1426 # game could be over at this point, check
1436 prout("=== ATTACK!")
1437 # Tholian gets to move before attacking
1440 # if you have just entered the RNZ, you'll get a warning
1441 if game.neutz: # The one chance not to be attacked
1444 # commanders get a chance to tac-move towards you
1445 if (((game.quadrant in game.state.kcmdr or game.state.kscmdr == game.quadrant) and not game.justin) or game.skill == SKILL_EMERITUS) and torps_ok:
1446 for (bugout, enemy, old, goto) in moveklings():
1448 # we know about this if either short or long range
1449 # sensors are working
1450 if damaged(DSRSENS) and damaged(DLRSENS) \
1451 and game.condition != "docked":
1452 prout(crmena(True, enemy.type, "sector", old) + \
1453 (_(" escapes to Quadrant %s (and regains strength).") % goto))
1454 else: # Enemy still in-sector
1455 if enemy.move(goto):
1456 if not damaged(DSRSENS) or game.condition == "docked":
1457 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
1458 if enemy.kdist < old:
1459 proutn(_(" advances to "))
1461 proutn(_(" retreats to "))
1462 prout("Sector %s." % goto)
1464 # if no enemies remain after movement, we're done
1465 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered):
1467 # set up partial hits if attack happens during shield status change
1468 pfac = 1.0/game.inshld
1470 chgfac = 0.25 + randreal(0.5)
1472 # message verbosity control
1473 if game.skill <= SKILL_FAIR:
1475 for enemy in game.enemies:
1477 continue # too weak to attack
1478 # compute hit strength and diminish shield power
1480 # Increase chance of photon torpedos if docked or enemy energy is low
1481 if game.condition == "docked":
1483 if enemy.power < 500:
1485 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1487 # different enemies have different probabilities of throwing a torp
1488 usephasers = not torps_ok or \
1489 (enemy.type == 'K' and r > 0.0005) or \
1490 (enemy.type == 'C' and r > 0.015) or \
1491 (enemy.type == 'R' and r > 0.3) or \
1492 (enemy.type == 'S' and r > 0.07) or \
1493 (enemy.type == '?' and r > 0.05)
1494 if usephasers: # Enemy uses phasers
1495 if game.condition == "docked":
1496 continue # Don't waste the effort!
1497 attempt = True # Attempt to attack
1498 dustfac = randreal(0.8, 0.85)
1499 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1501 else: # Enemy uses photon torpedo
1502 # We should be able to make the bearing() method work here
1503 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1505 proutn(_("***TORPEDO INCOMING"))
1506 if not damaged(DSRSENS):
1507 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1510 dispersion = (randreal()+randreal())*0.5 - 0.5
1511 dispersion += 0.002*enemy.power*dispersion
1512 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1513 if game.unwon() == 0:
1514 finish(FWON) # Klingons did themselves in!
1515 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1516 return # Supernova or finished
1519 # incoming phaser or torpedo, shields may dissipate it
1520 if game.shldup or game.shldchg or game.condition == "docked":
1521 # shields will take hits
1522 propor = pfac * game.shield
1523 if game.condition == "docked":
1527 hitsh = propor*chgfac*hit+1.0
1529 if absorb > game.shield:
1530 absorb = game.shield
1531 game.shield -= absorb
1533 # taking a hit blasts us out of a starbase dock
1534 if game.condition == "docked":
1536 # but the shields may take care of it
1537 if propor > 0.1 and hit < 0.005*game.energy:
1539 # hit from this opponent got through shields, so take damage
1541 proutn(_("%d unit hit") % int(hit))
1542 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1543 proutn(_(" on the ") + crmshp())
1544 if not damaged(DSRSENS) and usephasers:
1545 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1547 # Decide if hit is critical
1553 if game.energy <= 0:
1554 # Returning home upon your shield, not with it...
1557 if not attempt and game.condition == "docked":
1558 prout(_("***Enemies decide against attacking your ship."))
1559 percent = 100.0*pfac*game.shield+0.5
1561 # Shields fully protect ship
1562 proutn(_("Enemy attack reduces shield strength to "))
1564 # Emit message if starship suffered hit(s)
1566 proutn(_("Energy left %2d shields ") % int(game.energy))
1569 elif not damaged(DSHIELD):
1572 proutn(_("damaged, "))
1573 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1574 # Check if anyone was hurt
1575 if hitmax >= 200 or hittot >= 500:
1576 icas = randrange(int(hittot * 0.015))
1579 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1580 prout(_(" in that last attack.\""))
1582 game.state.crew -= icas
1583 # After attack, reset average distance to enemies
1584 for enemy in game.enemies:
1585 enemy.kavgd = enemy.kdist
1589 def deadkl(w, etype, mv):
1590 "Kill a Klingon, Tholian, Romulan, or Thingy."
1591 # Added mv to allow enemy to "move" before dying
1592 proutn(crmena(True, etype, "sector", mv))
1593 # Decide what kind of enemy it is and update appropriately
1595 # Chalk up a Romulan
1596 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1598 game.state.nromrem -= 1
1607 # Killed some type of Klingon
1608 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1611 game.state.kcmdr.remove(game.quadrant)
1613 if game.state.kcmdr:
1614 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1615 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1618 game.state.remkl -= 1
1620 game.state.nscrem -= 1
1621 game.state.kscmdr.invalidate()
1626 # For each kind of enemy, finish message to player
1627 prout(_(" destroyed."))
1628 if game.unwon() == 0:
1631 # Remove enemy ship from arrays describing local conditions
1632 for e in game.enemies:
1639 "Return None if target is invalid, otherwise return a course angle."
1640 if not w.valid_sector():
1644 # C code this was translated from is wacky -- why the sign reversal?
1645 delta.j = (w.j - game.sector.j)
1646 delta.i = (game.sector.i - w.i)
1647 if delta == Coord(0, 0):
1649 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1650 prout(_(" I recommend an immediate review of"))
1651 prout(_(" the Captain's psychological profile.\""))
1654 return delta.bearing()
1657 "Launch photon torpedo salvo."
1660 if damaged(DPHOTON):
1661 prout(_("Photon tubes damaged."))
1665 prout(_("No torpedoes left."))
1668 # First, get torpedo count
1671 if scanner.token == "IHALPHA":
1674 elif scanner.token == "IHEOL" or not scanner.waiting():
1675 prout(_("%d torpedoes left.") % game.torps)
1677 proutn(_("Number of torpedoes to fire- "))
1678 continue # Go back around to get a number
1679 else: # key == "IHREAL"
1681 if n <= 0: # abort command
1686 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1689 scanner.chew() # User requested more torps than available
1690 continue # Go back around
1691 break # All is good, go to next stage
1695 key = scanner.nexttok()
1696 if i == 0 and key == "IHEOL":
1697 break # no coordinate waiting, we will try prompting
1698 if i == 1 and key == "IHEOL":
1699 # direct all torpedoes at one target
1701 target.append(target[0])
1702 tcourse.append(tcourse[0])
1705 scanner.push(scanner.token)
1706 target.append(scanner.getcoord())
1707 if target[-1] is None:
1709 tcourse.append(targetcheck(target[-1]))
1710 if tcourse[-1] is None:
1713 if len(target) == 0:
1714 # prompt for each one
1716 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1718 target.append(scanner.getcoord())
1719 if target[-1] is None:
1721 tcourse.append(targetcheck(target[-1]))
1722 if tcourse[-1] is None:
1725 # Loop for moving <n> torpedoes
1727 if game.condition != "docked":
1729 dispersion = (randreal()+randreal())*0.5 -0.5
1730 if math.fabs(dispersion) >= 0.47:
1732 dispersion *= randreal(1.2, 2.2)
1734 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1736 prouts(_("***TORPEDO MISFIRES."))
1739 prout(_(" Remainder of burst aborted."))
1741 prout(_("***Photon tubes damaged by misfire."))
1742 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1746 elif game.shldup or game.condition == "docked":
1747 dispersion *= 1.0 + 0.0001*game.shield
1748 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1749 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1755 "Check for phasers overheating."
1757 checkburn = (rpow-1500.0)*0.00038
1758 if withprob(checkburn):
1759 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1760 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1762 def checkshctrl(rpow):
1763 "Check shield control."
1766 prout(_("Shields lowered."))
1768 # Something bad has happened
1769 prouts(_("***RED ALERT! RED ALERT!"))
1771 hit = rpow*game.shield/game.inshld
1772 game.energy -= rpow+hit*0.8
1773 game.shield -= hit*0.2
1774 if game.energy <= 0.0:
1775 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1780 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1782 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1783 icas = randrange(int(hit*0.012))
1788 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1789 prout(_(" %d casualties so far.\"") % icas)
1791 game.state.crew -= icas
1793 prout(_("Phaser energy dispersed by shields."))
1794 prout(_("Enemy unaffected."))
1799 "Register a phaser hit on Klingons and Romulans."
1806 dustfac = randreal(0.9, 1.0)
1807 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1808 kpini = game.enemies[kk].power
1809 kp = math.fabs(kpini)
1810 if PHASEFAC*hit < kp:
1812 if game.enemies[kk].power < 0:
1813 game.enemies[kk].power -= -kp
1815 game.enemies[kk].power -= kp
1816 kpow = game.enemies[kk].power
1817 w = game.enemies[kk].location
1819 if not damaged(DSRSENS):
1821 proutn(_("%d unit hit on ") % int(hit))
1823 proutn(_("Very small hit on "))
1824 ienm = game.quad[w.i][w.j]
1827 proutn(crmena(False, ienm, "sector", w))
1836 else: # decide whether or not to emasculate klingon
1837 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1838 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1839 prout(_(" has just lost its firepower.\""))
1840 game.enemies[kk].power = -kpow
1845 "Fire phasers at bad guys."
1849 irec = 0 # Cheating inhibitor
1858 # SR sensors and Computer are needed for automode
1859 if damaged(DSRSENS) or damaged(DCOMPTR):
1861 if game.condition == "docked":
1862 prout(_("Phasers can't be fired through base shields."))
1865 if damaged(DPHASER):
1866 prout(_("Phaser control damaged."))
1870 if damaged(DSHCTRL):
1871 prout(_("High speed shield control damaged."))
1874 if game.energy <= 200.0:
1875 prout(_("Insufficient energy to activate high-speed shield control."))
1878 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1880 # Original code so convoluted, I re-did it all
1881 # (That was Tom Almy talking about the C code, I think -- ESR)
1882 while automode == "NOTSET":
1883 key = scanner.nexttok()
1884 if key == "IHALPHA":
1885 if scanner.sees("manual"):
1886 if len(game.enemies)==0:
1887 prout(_("There is no enemy present to select."))
1890 automode = "AUTOMATIC"
1893 key = scanner.nexttok()
1894 elif scanner.sees("automatic"):
1895 if (not itarg) and len(game.enemies) != 0:
1896 automode = "FORCEMAN"
1898 if len(game.enemies)==0:
1899 prout(_("Energy will be expended into space."))
1900 automode = "AUTOMATIC"
1901 key = scanner.nexttok()
1902 elif scanner.sees("no"):
1907 elif key == "IHREAL":
1908 if len(game.enemies)==0:
1909 prout(_("Energy will be expended into space."))
1910 automode = "AUTOMATIC"
1912 automode = "FORCEMAN"
1914 automode = "AUTOMATIC"
1917 if len(game.enemies)==0:
1918 prout(_("Energy will be expended into space."))
1919 automode = "AUTOMATIC"
1921 automode = "FORCEMAN"
1923 proutn(_("Manual or automatic? "))
1928 if automode == "AUTOMATIC":
1929 if key == "IHALPHA" and scanner.sees("no"):
1931 key = scanner.nexttok()
1932 if key != "IHREAL" and len(game.enemies) != 0:
1933 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1938 for i in range(len(game.enemies)):
1939 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1941 proutn(_("%d units required. ") % irec)
1943 proutn(_("Units to fire= "))
1944 key = scanner.nexttok()
1949 proutn(_("Energy available= %.2f") % avail)
1952 if not rpow > avail:
1958 key = scanner.nexttok()
1959 if key == "IHALPHA" and scanner.sees("no"):
1962 game.energy -= 200 # Go and do it!
1963 if checkshctrl(rpow):
1968 if len(game.enemies):
1971 for i in range(len(game.enemies)):
1975 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1976 over = randreal(1.01, 1.06) * hits[i]
1978 powrem -= hits[i] + over
1979 if powrem <= 0 and temp < hits[i]:
1988 if extra > 0 and not game.alldone:
1990 proutn(_("*** Tholian web absorbs "))
1991 if len(game.enemies)>0:
1992 proutn(_("excess "))
1993 prout(_("phaser energy."))
1995 prout(_("%d expended on empty space.") % int(extra))
1996 elif automode == "FORCEMAN":
1999 if damaged(DCOMPTR):
2000 prout(_("Battle computer damaged, manual fire only."))
2003 prouts(_("---WORKING---"))
2005 prout(_("Short-range-sensors-damaged"))
2006 prout(_("Insufficient-data-for-automatic-phaser-fire"))
2007 prout(_("Manual-fire-must-be-used"))
2009 elif automode == "MANUAL":
2011 for k in range(len(game.enemies)):
2012 aim = game.enemies[k].location
2013 ienm = game.quad[aim.i][aim.j]
2015 proutn(_("Energy available= %.2f") % (avail-0.006))
2019 if damaged(DSRSENS) and \
2020 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
2021 prout(cramen(ienm) + _(" can't be located without short range scan."))
2024 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
2029 if itarg and k > kz:
2030 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
2033 if not damaged(DCOMPTR):
2038 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
2039 key = scanner.nexttok()
2040 if key == "IHALPHA" and scanner.sees("no"):
2042 key = scanner.nexttok()
2044 if key == "IHALPHA":
2048 if k == 1: # Let me say I'm baffled by this
2051 if scanner.real < 0:
2055 hits[k] = scanner.real
2056 rpow += scanner.real
2057 # If total requested is too much, inform and start over
2059 prout(_("Available energy exceeded -- try again."))
2062 key = scanner.nexttok() # scan for next value
2065 # zero energy -- abort
2068 if key == "IHALPHA" and scanner.sees("no"):
2073 game.energy -= 200.0
2074 if checkshctrl(rpow):
2078 # Say shield raised or malfunction, if necessary
2085 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
2086 prouts(_(" CLICK CLICK POP . . ."))
2087 prout(_(" No response, sir!"))
2090 prout(_("Shields raised."))
2097 game.ididit = False # Nothing if we fail
2100 # Make sure there is room in the brig */
2101 if game.brigfree == 0:
2102 prout(_("Security reports the brig is already full."))
2106 prout(_("Uhura- \"We have no subspace radio communication, sir.\""))
2109 if damaged(DTRANSP):
2110 prout(_("Scotty- \"Transporter damaged, sir.\""))
2113 # find out if there are any at all
2115 prout(_("Uhura- \"Getting no response, sir.\""))
2118 # if there is more than one Klingon, find out which one */
2119 # Cruddy, just takes one at random. Should ask the captain.
2120 # Nah, just select the weakest one since it is most likely to
2121 # surrender (Tom Almy mod)
2122 klingons = [e for e in game.enemies if e.type == 'K']
2123 weakest = sorted(klingons, key=lambda e: e.power)[0]
2124 game.optime = 0.05 # This action will take some time
2125 game.ididit = True # So any others can strike back
2127 # check out that Klingon
2128 # The algorithm isn't that great and could use some more
2129 # intelligent design
2130 # x = 300 + 25*skill;
2131 x = game.energy / (weakest.power * len(klingons))
2132 #prout(_("Stats: energy = %s, kpower = %s, klingons = %s")
2133 # % (game.energy, weakest.power, len(klingons)))
2134 x *= 2.5 # would originally have been equivalent of 1.4,
2135 # but we want command to work more often, more humanely */
2136 #prout(_("Prob = %.4f" % x))
2137 # x = 100; // For testing, of course!
2138 if x < randreal(100):
2139 # guess what, he surrendered!!! */
2140 prout(_("Klingon captain at %s surrenders.") % weakest.location)
2143 prout(_("%d Klingons commit suicide rather than be taken captive.") % (200 - i))
2144 if i > game.brigfree:
2145 prout(_("%d Klingons die because there is no room for them in the brig.") % (i-brigfree))
2148 prout(_("%d captives taken") % i)
2149 deadkl(weakest.location, weakest.type, game.sector)
2154 # big surprise, he refuses to surrender */
2155 prout(_("Fat chance, captain!"))
2157 # Code from events.c begins here.
2159 # This isn't a real event queue a la BSD Trek yet -- you can only have one
2160 # event of each type active at any given time. Mostly these means we can
2161 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
2162 # BSD Trek, from which we swiped the idea, can have up to 5.
2164 def unschedule(evtype):
2165 "Remove an event from the schedule."
2166 game.future[evtype].date = FOREVER
2167 return game.future[evtype]
2169 def is_scheduled(evtype):
2170 "Is an event of specified type scheduled."
2171 return game.future[evtype].date != FOREVER
2173 def scheduled(evtype):
2174 "When will this event happen?"
2175 return game.future[evtype].date
2177 def schedule(evtype, offset):
2178 "Schedule an event of specified type."
2179 game.future[evtype].date = game.state.date + offset
2180 return game.future[evtype]
2182 def postpone(evtype, offset):
2183 "Postpone a scheduled event."
2184 game.future[evtype].date += offset
2187 "Rest period is interrupted by event."
2190 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2192 game.resting = False
2198 "Run through the event queue looking for things to do."
2200 fintim = game.state.date + game.optime
2209 def tractorbeam(yank):
2210 "Tractor-beaming cases merge here."
2212 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2214 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2215 # If Kirk & Co. screwing around on planet, handle
2216 atover(True) # atover(true) is Grab
2219 if game.icraft: # Caught in Galileo?
2222 # Check to see if shuttle is aboard
2223 if game.iscraft == "offship":
2226 prout(_("Galileo, left on the planet surface, is captured"))
2227 prout(_("by aliens and made into a flying McDonald's."))
2228 game.damage[DSHUTTL] = -10
2229 game.iscraft = "removed"
2231 prout(_("Galileo, left on the planet surface, is well hidden."))
2233 game.quadrant = game.state.kscmdr
2235 game.quadrant = game.state.kcmdr[i]
2236 game.sector = randplace(QUADSIZE)
2237 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2238 % (game.quadrant, game.sector))
2240 prout(_("(Remainder of rest/repair period cancelled.)"))
2241 game.resting = False
2243 if not damaged(DSHIELD) and game.shield > 0:
2244 doshield(shraise=True) # raise shields
2245 game.shldchg = False
2247 prout(_("(Shields not currently useable.)"))
2249 # Adjust finish time to time of tractor beaming?
2250 # fintim = game.state.date+game.optime
2251 attack(torps_ok=False)
2252 if not game.state.kcmdr:
2255 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2258 "Code merges here for any commander destroying a starbase."
2259 # Not perfect, but will have to do
2260 # Handle case where base is in same quadrant as starship
2261 if game.battle == game.quadrant:
2262 game.state.chart[game.battle.i][game.battle.j].starbase = False
2263 game.quad[game.base.i][game.base.j] = '.'
2264 game.base.invalidate()
2267 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2268 elif game.state.baseq and communicating():
2269 # Get word via subspace radio
2272 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2273 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2275 prout(_("the Klingon Super-Commander"))
2277 prout(_("a Klingon Commander"))
2278 game.state.chart[game.battle.i][game.battle.j].starbase = False
2279 # Remove Starbase from galaxy
2280 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2281 game.state.baseq = [x for x in game.state.baseq if x != game.battle]
2283 # reinstate a commander's base attack
2287 game.battle.invalidate()
2289 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2290 for i in range(1, NEVENTS):
2291 if i == FSNOVA: proutn("=== Supernova ")
2292 elif i == FTBEAM: proutn("=== T Beam ")
2293 elif i == FSNAP: proutn("=== Snapshot ")
2294 elif i == FBATTAK: proutn("=== Base Attack ")
2295 elif i == FCDBAS: proutn("=== Base Destroy ")
2296 elif i == FSCMOVE: proutn("=== SC Move ")
2297 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2298 elif i == FDSPROB: proutn("=== Probe Move ")
2299 elif i == FDISTR: proutn("=== Distress Call ")
2300 elif i == FENSLV: proutn("=== Enslavement ")
2301 elif i == FREPRO: proutn("=== Klingon Build ")
2303 prout("%.2f" % (scheduled(i)))
2306 radio_was_broken = damaged(DRADIO)
2309 # Select earliest extraneous event, evcode==0 if no events
2314 for l in range(1, NEVENTS):
2315 if game.future[l].date < datemin:
2318 prout("== Event %d fires" % evcode)
2319 datemin = game.future[l].date
2320 xtime = datemin-game.state.date
2322 game.energy -= xtime*500.0
2323 if game.energy <= 0:
2326 game.state.date = datemin
2327 # Decrement Federation resources and recompute remaining time
2328 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2330 if game.state.remtime <= 0:
2333 # Any crew left alive?
2334 if game.state.crew <= 0:
2337 # Is life support adequate?
2338 if damaged(DLIFSUP) and game.condition != "docked":
2339 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2342 game.lsupres -= xtime
2343 if game.damage[DLIFSUP] <= xtime:
2344 game.lsupres = game.inlsr
2347 if game.condition == "docked":
2349 # Don't fix Deathray here
2350 for l in range(NDEVICES):
2351 if game.damage[l] > 0.0 and l != DDRAY:
2352 if game.damage[l]-repair > 0.0:
2353 game.damage[l] -= repair
2355 game.damage[l] = 0.0
2356 # If radio repaired, update star chart and attack reports
2357 if radio_was_broken and not damaged(DRADIO):
2358 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2359 prout(_(" surveillance reports are coming in."))
2361 if not game.iseenit:
2365 prout(_(" The star chart is now up to date.\""))
2367 # Cause extraneous event EVCODE to occur
2368 game.optime -= xtime
2369 if evcode == FSNOVA: # Supernova
2372 schedule(FSNOVA, expran(0.5*game.intime))
2373 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2375 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2376 if game.state.nscrem == 0 or game.iscloaked or \
2377 ictbeam or istract or \
2378 game.condition == "docked" or game.isatb == 1 or game.iscate:
2380 if game.ientesc or \
2381 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2382 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2383 (damaged(DSHIELD) and \
2384 (game.energy < 2500 or damaged(DPHASER)) and \
2385 (game.torps < 5 or damaged(DPHOTON))):
2387 istract = ictbeam = True
2388 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2391 elif evcode == FTBEAM: # Tractor beam
2392 if not game.state.kcmdr:
2395 i = randrange(len(game.state.kcmdr))
2396 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2397 if istract or game.condition == "docked" or game.iscloaked or yank == 0:
2398 # Drats! Have to reschedule
2400 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2404 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2405 game.snapsht = copy.deepcopy(game.state)
2406 game.state.snap = True
2407 schedule(FSNAP, expran(0.5 * game.intime))
2408 elif evcode == FBATTAK: # Commander attacks starbase
2409 if not game.state.kcmdr or not game.state.baseq:
2414 ibq = None # Force battle location to persist past loop
2416 for ibq in game.state.baseq:
2417 for cmdr in game.state.kcmdr:
2418 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2420 # no match found -- try later
2421 schedule(FBATTAK, expran(0.3*game.intime))
2426 # commander + starbase combination found -- launch attack
2428 schedule(FCDBAS, randreal(1.0, 4.0))
2429 if game.isatb: # extra time if SC already attacking
2430 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2431 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2432 game.iseenit = False
2433 if not communicating():
2434 continue # No warning :-(
2438 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2439 prout(_(" reports that it is under attack and that it can"))
2440 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2443 elif evcode == FSCDBAS: # Supercommander destroys base
2446 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2447 continue # WAS RETURN!
2449 game.battle = game.state.kscmdr
2451 elif evcode == FCDBAS: # Commander succeeds in destroying base
2452 if evcode == FCDBAS:
2454 if not game.state.baseq() \
2455 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2456 game.battle.invalidate()
2458 # find the lucky pair
2459 for cmdr in game.state.kcmdr:
2460 if cmdr == game.battle:
2463 # No action to take after all
2466 elif evcode == FSCMOVE: # Supercommander moves
2467 schedule(FSCMOVE, 0.2777)
2468 if not game.ientesc and not istract and game.isatb != 1 and \
2469 (not game.iscate or not game.justin):
2471 elif evcode == FDSPROB: # Move deep space probe
2472 schedule(FDSPROB, 0.01)
2473 if not game.probe.nexttok():
2474 if not game.probe.quadrant().valid_quadrant() or \
2475 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2476 # Left galaxy or ran into supernova
2480 proutn(_("Lt. Uhura- \"The deep space probe "))
2481 if not game.probe.quadrant().valid_quadrant():
2482 prout(_("has left the galaxy.\""))
2484 prout(_("is no longer transmitting.\""))
2490 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2491 pquad = game.probe.quadrant()
2492 pdest = game.state.galaxy[pquad.i][pquad.j]
2494 game.state.chart[pquad.i][pquad.j].klingons = pdest.klingons
2495 game.state.chart[pquad.i][pquad.j].starbase = pdest.starbase
2496 game.state.chart[pquad.i][pquad.j].stars = pdest.stars
2497 pdest.charted = True
2498 game.probe.moves -= 1 # One less to travel
2499 if game.probe.arrived() and game.isarmed and pdest.stars:
2500 supernova(game.probe) # fire in the hole!
2502 if game.state.galaxy[pquad.i][pquad.j].supernova:
2504 elif evcode == FDISTR: # inhabited system issues distress call
2506 # try a whole bunch of times to find something suitable
2507 for i in range(100):
2508 # need a quadrant which is not the current one,
2509 # which has some stars which are inhabited and
2510 # not already under attack, which is not
2511 # supernova'ed, and which has some Klingons in it
2512 w = randplace(GALSIZE)
2513 q = game.state.galaxy[w.i][w.j]
2514 if not (game.quadrant == w or q.planet is None or \
2515 not q.planet.inhabited or \
2516 q.supernova or q.status!="secure" or q.klingons<=0):
2519 # can't seem to find one; ignore this call
2521 prout("=== Couldn't find location for distress event.")
2523 # got one!! Schedule its enslavement
2524 ev = schedule(FENSLV, expran(game.intime))
2526 q.status = "distressed"
2527 # tell the captain about it if we can
2529 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2530 % (q.planet, repr(w)))
2531 prout(_("by a Klingon invasion fleet."))
2534 elif evcode == FENSLV: # starsystem is enslaved
2535 ev = unschedule(FENSLV)
2536 # see if current distress call still active
2537 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2541 q.status = "enslaved"
2543 # play stork and schedule the first baby
2544 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2545 ev2.quadrant = ev.quadrant
2547 # report the disaster if we can
2549 prout(_("Uhura- We've lost contact with starsystem %s") % \
2551 prout(_("in Quadrant %s.\n") % ev.quadrant)
2552 elif evcode == FREPRO: # Klingon reproduces
2553 # If we ever switch to a real event queue, we'll need to
2554 # explicitly retrieve and restore the x and y.
2555 ev = schedule(FREPRO, expran(1.0 * game.intime))
2556 # see if current distress call still active
2557 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2561 if game.state.remkl >= MAXKLGAME:
2562 continue # full right now
2563 # reproduce one Klingon
2566 if game.klhere >= MAXKLQUAD:
2568 # this quadrant not ok, pick an adjacent one
2569 for m.i in range(w.i - 1, w.i + 2):
2570 for m.j in range(w.j - 1, w.j + 2):
2571 if not m.valid_quadrant():
2573 q = game.state.galaxy[m.i][m.j]
2574 # check for this quad ok (not full & no snova)
2575 if q.klingons >= MAXKLQUAD or q.supernova:
2578 # search for eligible quadrant failed
2583 game.state.remkl += 1
2585 if game.quadrant == w:
2587 game.enemies.append(newkling())
2588 # recompute time left
2591 if game.quadrant == w:
2592 prout(_("Spock- sensors indicate the Klingons have"))
2593 prout(_("launched a warship from %s.") % q.planet)
2595 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2596 if q.planet != None:
2597 proutn(_("near %s ") % q.planet)
2598 prout(_("in Quadrant %s.") % w)
2604 key = scanner.nexttok()
2607 proutn(_("How long? "))
2612 origTime = delay = scanner.real
2615 if delay >= game.state.remtime or len(game.enemies) != 0:
2616 proutn(_("Are you sure? "))
2619 # Alternate resting periods (events) with attacks
2623 game.resting = False
2624 if not game.resting:
2625 prout(_("%d stardates left.") % int(game.state.remtime))
2627 temp = game.optime = delay
2628 if len(game.enemies):
2629 rtime = randreal(1.0, 2.0)
2633 if game.optime < delay:
2634 attack(torps_ok=False)
2642 # Repair Deathray if long rest at starbase
2643 if origTime-delay >= 9.99 and game.condition == "docked":
2644 game.damage[DDRAY] = 0.0
2645 # leave if quadrant supernovas
2646 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2648 game.resting = False
2653 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2654 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2656 # Wow! We've supernova'ed
2657 supernova(game.quadrant)
2659 # handle initial nova
2660 game.quad[nov.i][nov.j] = '.'
2661 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2662 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2663 game.state.starkl += 1
2664 # Set up queue to recursively trigger adjacent stars
2670 for offset.i in range(-1, 1+1):
2671 for offset.j in range(-1, 1+1):
2672 if offset.j == 0 and offset.i == 0:
2674 neighbor = start + offset
2675 if not neighbor.valid_sector():
2677 iquad = game.quad[neighbor.i][neighbor.j]
2678 # Empty space ends reaction
2679 if iquad in ('.', '?', ' ', 'T', '#'):
2681 elif iquad == '*': # Affect another star
2683 # This star supernovas
2684 supernova(game.quadrant)
2687 hits.append(neighbor)
2688 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2689 game.state.starkl += 1
2690 proutn(crmena(True, '*', "sector", neighbor))
2692 game.quad[neighbor.i][neighbor.j] = '.'
2694 elif iquad in ('P', '@'): # Destroy planet
2695 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2697 game.state.nplankl += 1
2699 game.state.nworldkl += 1
2700 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2701 game.iplnet.pclass = "destroyed"
2703 game.plnet.invalidate()
2707 game.quad[neighbor.i][neighbor.j] = '.'
2708 elif iquad == 'B': # Destroy base
2709 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2710 game.state.baseq = [x for x in game.state.baseq if x!= game.quadrant]
2711 game.base.invalidate()
2712 game.state.basekl += 1
2714 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2715 game.quad[neighbor.i][neighbor.j] = '.'
2716 elif iquad in ('E', 'F'): # Buffet ship
2717 prout(_("***Starship buffeted by nova."))
2719 if game.shield >= 2000.0:
2720 game.shield -= 2000.0
2722 diff = 2000.0 - game.shield
2726 prout(_("***Shields knocked out."))
2727 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2729 game.energy -= 2000.0
2730 if game.energy <= 0:
2733 # add in course nova contributes to kicking starship
2734 bump += (game.sector-hits[-1]).sgn()
2735 elif iquad == 'K': # kill klingon
2736 deadkl(neighbor, iquad, neighbor)
2737 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2739 for ll in range(len(game.enemies)):
2740 if game.enemies[ll].location == neighbor:
2741 target = game.enemies[ll]
2743 if target is not None:
2744 target.power -= 800.0 # If firepower is lost, die
2745 if target.power <= 0.0:
2746 deadkl(neighbor, iquad, neighbor)
2747 continue # neighbor loop
2748 # Else enemy gets flung by the blast wave
2749 newc = neighbor + neighbor - hits[-1]
2750 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2751 if not newc.valid_sector():
2752 # can't leave quadrant
2755 iquad1 = game.quad[newc.i][newc.j]
2757 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2759 deadkl(neighbor, iquad, newc)
2762 # can't move into something else
2765 proutn(_(", buffeted to Sector %s") % newc)
2766 game.quad[neighbor.i][neighbor.j] = '.'
2767 game.quad[newc.i][newc.j] = iquad
2769 # Starship affected by nova -- kick it away.
2771 direc = ncourse[3*(bump.i+1)+bump.j+2]
2776 scourse = course(bearing=direc, distance=dist)
2777 game.optime = scourse.time(w=4)
2779 prout(_("Force of nova displaces starship."))
2780 imove(scourse, noattack=True)
2781 game.optime = scourse.time(w=4)
2785 "Star goes supernova."
2790 # Scheduled supernova -- select star at random.
2793 for nq.i in range(GALSIZE):
2794 for nq.j in range(GALSIZE):
2795 nstars += game.state.galaxy[nq.i][nq.j].stars
2797 return # nothing to supernova exists
2798 num = randrange(nstars) + 1
2799 for nq.i in range(GALSIZE):
2800 for nq.j in range(GALSIZE):
2801 num -= game.state.galaxy[nq.i][nq.j].stars
2807 proutn("=== Super nova here?")
2810 if not nq == game.quadrant or game.justin:
2811 # it isn't here, or we just entered (treat as enroute)
2814 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2815 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2818 # we are in the quadrant!
2819 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2820 for ns.i in range(QUADSIZE):
2821 for ns.j in range(QUADSIZE):
2822 if game.quad[ns.i][ns.j]=='*':
2829 prouts(_("***RED ALERT! RED ALERT!"))
2831 prout(_("***Incipient supernova detected at Sector %s") % ns)
2832 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2833 proutn(_("Emergency override attempts t"))
2834 prouts("***************")
2838 # destroy any Klingons in supernovaed quadrant
2839 kldead = game.state.galaxy[nq.i][nq.j].klingons
2840 game.state.galaxy[nq.i][nq.j].klingons = 0
2841 if nq == game.state.kscmdr:
2842 # did in the Supercommander!
2843 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2847 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2848 comkills = len(game.state.kcmdr) - len(survivors)
2849 game.state.kcmdr = survivors
2851 if not game.state.kcmdr:
2853 game.state.remkl -= kldead
2854 # destroy Romulans and planets in supernovaed quadrant
2855 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2856 game.state.galaxy[nq.i][nq.j].romulans = 0
2857 game.state.nromrem -= nrmdead
2859 for loop in range(game.inplan):
2860 if game.state.planets[loop].quadrant == nq:
2861 game.state.planets[loop].pclass = "destroyed"
2863 # Destroy any base in supernovaed quadrant
2864 game.state.baseq = [x for x in game.state.baseq if x != nq]
2865 # If starship caused supernova, tally up destruction
2867 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2868 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2869 game.state.nplankl += npdead
2870 # mark supernova in galaxy and in star chart
2871 if game.quadrant == nq or communicating():
2872 game.state.galaxy[nq.i][nq.j].supernova = True
2873 # If supernova destroys last Klingons give special message
2874 if game.unwon()==0 and not nq == game.quadrant:
2877 prout(_("Lucky you!"))
2878 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2881 # if some Klingons remain, continue or die in supernova
2886 # Code from finish.c ends here.
2889 "Self-destruct maneuver. Finish with a BANG!"
2891 if damaged(DCOMPTR):
2892 prout(_("Computer damaged; cannot execute destruct sequence."))
2894 prouts(_("---WORKING---")); skip(1)
2895 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2896 prouts(" 10"); skip(1)
2897 prouts(" 9"); skip(1)
2898 prouts(" 8"); skip(1)
2899 prouts(" 7"); skip(1)
2900 prouts(" 6"); skip(1)
2902 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2904 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2906 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2909 if game.passwd != scanner.token:
2910 prouts(_("PASSWORD-REJECTED;"))
2912 prouts(_("CONTINUITY-EFFECTED"))
2915 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2916 prouts(" 5"); skip(1)
2917 prouts(" 4"); skip(1)
2918 prouts(" 3"); skip(1)
2919 prouts(" 2"); skip(1)
2920 prouts(" 1"); skip(1)
2922 prouts(_("GOODBYE-CRUEL-WORLD"))
2930 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2934 if len(game.enemies) != 0:
2935 whammo = 25.0 * game.energy
2936 for l in range(len(game.enemies)):
2937 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2938 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2942 "Compute our rate of kils over time."
2943 elapsed = game.state.date - game.indate
2944 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2947 starting = (game.inkling + game.incom + game.inscom)
2948 remaining = game.unwon()
2949 return (starting - remaining)/elapsed
2953 badpt = 5.0*game.state.starkl + \
2955 10.0*game.state.nplankl + \
2956 300*game.state.nworldkl + \
2958 100.0*game.state.basekl +\
2959 3.0*game.abandoned +\
2961 if game.ship == 'F':
2963 elif game.ship is None:
2968 # end the game, with appropriate notifications
2972 prout(_("It is stardate %.1f.") % game.state.date)
2974 if ifin == FWON: # Game has been won
2975 if game.state.nromrem != 0:
2976 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2979 prout(_("You have smashed the Klingon invasion fleet and saved"))
2980 prout(_("the Federation."))
2981 if game.alive and game.brigcapacity-game.brigfree > 0:
2982 game.kcaptured += game.brigcapacity-game.brigfree
2983 prout(_("The %d captured Klingons are transferred to Star Fleet Command.") % (game.brigcapacity-game.brigfree))
2988 badpt = 0.0 # Close enough!
2989 # killsPerDate >= RateMax
2990 if game.state.date-game.indate < 5.0 or \
2991 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2993 prout(_("In fact, you have done so well that Starfleet Command"))
2994 if game.skill == SKILL_NOVICE:
2995 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2996 elif game.skill == SKILL_FAIR:
2997 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2998 elif game.skill == SKILL_GOOD:
2999 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
3000 elif game.skill == SKILL_EXPERT:
3001 prout(_("promotes you to Commodore Emeritus."))
3003 prout(_("Now that you think you're really good, try playing"))
3004 prout(_("the \"Emeritus\" game. It will splatter your ego."))
3005 elif game.skill == SKILL_EMERITUS:
3007 proutn(_("Computer- "))
3008 prouts(_("ERROR-ERROR-ERROR-ERROR"))
3010 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
3012 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3014 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3016 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3018 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
3020 prout(_("Now you can retire and write your own Star Trek game!"))
3022 elif game.skill >= SKILL_EXPERT:
3023 if game.thawed and not game.idebug:
3024 prout(_("You cannot get a citation, so..."))
3026 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
3030 # Only grant long life if alive (original didn't!)
3032 prout(_("LIVE LONG AND PROSPER."))
3037 elif ifin == FDEPLETE: # Federation Resources Depleted
3038 prout(_("Your time has run out and the Federation has been"))
3039 prout(_("conquered. Your starship is now Klingon property,"))
3040 prout(_("and you are put on trial as a war criminal. On the"))
3041 proutn(_("basis of your record, you are "))
3042 if game.unwon()*3.0 > (game.inkling + game.incom + game.inscom):
3043 prout(_("acquitted."))
3045 prout(_("LIVE LONG AND PROSPER."))
3047 prout(_("found guilty and"))
3048 prout(_("sentenced to death by slow torture."))
3052 elif ifin == FLIFESUP:
3053 prout(_("Your life support reserves have run out, and"))
3054 prout(_("you die of thirst, starvation, and asphyxiation."))
3055 prout(_("Your starship is a derelict in space."))
3057 prout(_("Your energy supply is exhausted."))
3059 prout(_("Your starship is a derelict in space."))
3060 elif ifin == FBATTLE:
3061 prout(_("The %s has been destroyed in battle.") % crmshp())
3063 prout(_("Dulce et decorum est pro patria mori."))
3065 prout(_("You have made three attempts to cross the negative energy"))
3066 prout(_("barrier which surrounds the galaxy."))
3068 prout(_("Your navigation is abominable."))
3071 prout(_("Your starship has been destroyed by a nova."))
3072 prout(_("That was a great shot."))
3074 elif ifin == FSNOVAED:
3075 prout(_("The %s has been fried by a supernova.") % crmshp())
3076 prout(_("...Not even cinders remain..."))
3077 elif ifin == FABANDN:
3078 prout(_("You have been captured by the Klingons. If you still"))
3079 prout(_("had a starbase to be returned to, you would have been"))
3080 prout(_("repatriated and given another chance. Since you have"))
3081 prout(_("no starbases, you will be mercilessly tortured to death."))
3082 elif ifin == FDILITHIUM:
3083 prout(_("Your starship is now an expanding cloud of subatomic particles"))
3084 elif ifin == FMATERIALIZE:
3085 prout(_("Starbase was unable to re-materialize your starship."))
3086 prout(_("Sic transit gloria mundi"))
3087 elif ifin == FPHASER:
3088 prout(_("The %s has been cremated by its own phasers.") % crmshp())
3090 prout(_("You and your landing party have been"))
3091 prout(_("converted to energy, dissipating through space."))
3092 elif ifin == FMINING:
3093 prout(_("You are left with your landing party on"))
3094 prout(_("a wild jungle planet inhabited by primitive cannibals."))
3096 prout(_("They are very fond of \"Captain Kirk\" soup."))
3098 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3099 elif ifin == FDPLANET:
3100 prout(_("You and your mining party perish."))
3102 prout(_("That was a great shot."))
3105 prout(_("The Galileo is instantly annihilated by the supernova."))
3106 prout(_("You and your mining party are atomized."))
3108 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3109 prout(_("joins the Romulans, wreaking terror on the Federation."))
3110 elif ifin == FPNOVA:
3111 prout(_("You and your mining party are atomized."))
3113 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3114 prout(_("joins the Romulans, wreaking terror on the Federation."))
3115 elif ifin == FSTRACTOR:
3116 prout(_("The shuttle craft Galileo is also caught,"))
3117 prout(_("and breaks up under the strain."))
3119 prout(_("Your debris is scattered for millions of miles."))
3120 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3122 prout(_("The mutants attack and kill Spock."))
3123 prout(_("Your ship is captured by Klingons, and"))
3124 prout(_("your crew is put on display in a Klingon zoo."))
3125 elif ifin == FTRIBBLE:
3126 prout(_("Tribbles consume all remaining water,"))
3127 prout(_("food, and oxygen on your ship."))
3129 prout(_("You die of thirst, starvation, and asphyxiation."))
3130 prout(_("Your starship is a derelict in space."))
3132 prout(_("Your ship is drawn to the center of the black hole."))
3133 prout(_("You are crushed into extremely dense matter."))
3134 elif ifin == FCLOAK:
3136 prout(_("You have violated the Treaty of Algeron."))
3137 prout(_("The Romulan Empire can never trust you again."))
3139 prout(_("Your last crew member has died."))
3140 if ifin != FWON and ifin != FCLOAK and game.iscloaked:
3141 prout(_("Your ship was cloaked so your subspace radio did not receive anything."))
3142 prout(_("You may have missed some warning messages."))
3144 if game.ship == 'F':
3146 elif game.ship == 'E':
3149 if game.unwon() != 0:
3150 goodies = game.state.remres/game.inresor
3151 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
3152 if goodies/baddies >= randreal(1.0, 1.5):
3153 prout(_("As a result of your actions, a treaty with the Klingon"))
3154 prout(_("Empire has been signed. The terms of the treaty are"))
3155 if goodies/baddies >= randreal(3.0):
3156 prout(_("favorable to the Federation."))
3158 prout(_("Congratulations!"))
3160 prout(_("highly unfavorable to the Federation."))
3162 prout(_("The Federation will be destroyed."))
3164 prout(_("Since you took the last Klingon with you, you are a"))
3165 prout(_("martyr and a hero. Someday maybe they'll erect a"))
3166 prout(_("statue in your memory. Rest in peace, and try not"))
3167 prout(_("to think about pigeons."))
3170 scanner.chew() # Clean up leftovers
3173 "Compute player's score."
3174 timused = game.state.date - game.indate
3175 if (timused == 0 or game.unwon() != 0) and timused < 5.0:
3177 game.perdate = killrate()
3178 ithperd = 500*game.perdate + 0.5
3181 iwon = 100*game.skill
3182 if game.ship == 'E':
3184 elif game.ship == 'F':
3188 game.score = 10*(game.inkling - game.state.remkl) \
3189 + 50*(game.incom - len(game.state.kcmdr)) \
3191 + 20*(game.inrom - game.state.nromrem) \
3192 + 200*(game.inscom - game.state.nscrem) \
3193 - game.state.nromrem \
3194 + 3 * game.kcaptured \
3199 prout(_("Your score --"))
3200 if game.inrom - game.state.nromrem:
3201 prout(_("%6d Romulans destroyed %5d") %
3202 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
3203 if game.state.nromrem and game.gamewon:
3204 prout(_("%6d Romulans captured %5d") %
3205 (game.state.nromrem, game.state.nromrem))
3206 if game.inkling - game.state.remkl:
3207 prout(_("%6d ordinary Klingons destroyed %5d") %
3208 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
3209 if game.incom - len(game.state.kcmdr):
3210 prout(_("%6d Klingon commanders destroyed %5d") %
3211 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3213 prout(_("%d Klingons captured %5d") %
3214 (game.kcaptured, 3 * game.kcaptured))
3215 if game.inscom - game.state.nscrem:
3216 prout(_("%6d Super-Commander destroyed %5d") %
3217 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3219 prout(_("%6.2f Klingons per stardate %5d") %
3220 (game.perdate, ithperd))
3221 if game.state.starkl:
3222 prout(_("%6d stars destroyed by your action %5d") %
3223 (game.state.starkl, -5*game.state.starkl))
3224 if game.state.nplankl:
3225 prout(_("%6d planets destroyed by your action %5d") %
3226 (game.state.nplankl, -10*game.state.nplankl))
3227 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3228 prout(_("%6d inhabited planets destroyed by your action %5d") %
3229 (game.state.nworldkl, -300*game.state.nworldkl))
3230 if game.state.basekl:
3231 prout(_("%6d bases destroyed by your action %5d") %
3232 (game.state.basekl, -100*game.state.basekl))
3234 prout(_("%6d calls for help from starbase %5d") %
3235 (game.nhelp, -45*game.nhelp))
3237 prout(_("%6d casualties incurred %5d") %
3238 (game.casual, -game.casual))
3240 prout(_("%6d crew abandoned in space %5d") %
3241 (game.abandoned, -3*game.abandoned))
3243 prout(_("%6d ship(s) lost or destroyed %5d") %
3244 (klship, -100*klship))
3247 prout(_("1 Treaty of Algeron violation -100"))
3249 prout(_("%6d Treaty of Algeron violations %5d\n") %
3250 (ncviol, -100*ncviol))
3252 prout(_("Penalty for getting yourself killed -200"))
3254 proutn(_("Bonus for winning "))
3255 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3256 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3257 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3258 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3259 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3260 prout(" %5d" % iwon)
3262 prout(_("TOTAL SCORE %5d") % game.score)
3265 "Emit winner's commemmorative plaque."
3268 proutn(_("File or device name for your plaque: "))
3271 fp = open(winner, "w")
3274 prout(_("Invalid name."))
3276 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3278 # The 38 below must be 64 for 132-column paper
3279 nskip = 38 - len(winner)/2
3280 fp.write("\n\n\n\n")
3281 # --------DRAW ENTERPRISE PICTURE.
3282 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3283 fp.write(" EEE E : : : E\n" )
3284 fp.write(" EE EEE E : : NCC-1701 : E\n")
3285 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3286 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3287 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3288 fp.write(" EEEEEEE EEEEE E E E E\n")
3289 fp.write(" EEE E E E E\n")
3290 fp.write(" E E E E\n")
3291 fp.write(" EEEEEEEEEEEEE E E\n")
3292 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3293 fp.write(" :E : EEEE E\n")
3294 fp.write(" .-E -:----- E\n")
3295 fp.write(" :E : E\n")
3296 fp.write(" EE : EEEEEEEE\n")
3297 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3299 fp.write(_(" U. S. S. ENTERPRISE\n"))
3300 fp.write("\n\n\n\n")
3301 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3303 fp.write(_(" Starfleet Command bestows to you\n"))
3305 fp.write("%*s%s\n\n" % (nskip, "", winner))
3306 fp.write(_(" the rank of\n\n"))
3307 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3309 if game.skill == SKILL_EXPERT:
3310 fp.write(_(" Expert level\n\n"))
3311 elif game.skill == SKILL_EMERITUS:
3312 fp.write(_("Emeritus level\n\n"))
3314 fp.write(_(" Cheat level\n\n"))
3315 timestring = time.ctime()
3316 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3317 (timestring+4, timestring+20, timestring+11))
3318 fp.write(_(" Your score: %d\n\n") % game.score)
3319 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3322 # Code from io.c begins here
3324 rows = linecount = 0 # for paging
3327 fullscreen_window = None
3328 srscan_window = None # Short range scan
3329 report_window = None # Report legends for status window
3330 status_window = None # The status window itself
3331 lrscan_window = None # Long range scan
3332 message_window = None # Main window for scrolling text
3333 prompt_window = None # Prompt window at bottom of display
3338 # for some recent versions of python2, the following enables UTF8
3339 # for the older ones we probably need to set C locale, and python3
3340 # has no problems at all
3341 if sys.version_info[0] < 3:
3342 locale.setlocale(locale.LC_ALL, "")
3343 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3344 gettext.textdomain("sst")
3345 if not (game.options & OPTION_CURSES):
3346 ln_env = os.getenv("LINES")
3352 stdscr = curses.initscr()
3356 if game.options & OPTION_COLOR:
3357 curses.start_color()
3358 curses.use_default_colors()
3359 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3360 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3361 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3362 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3363 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3364 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3365 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3366 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3367 global fullscreen_window, srscan_window, report_window, status_window
3368 global lrscan_window, message_window, prompt_window
3369 (rows, _columns) = stdscr.getmaxyx()
3370 fullscreen_window = stdscr
3371 srscan_window = curses.newwin(12, 25, 0, 0)
3372 report_window = curses.newwin(11, 0, 1, 25)
3373 status_window = curses.newwin(10, 0, 1, 39)
3374 lrscan_window = curses.newwin(5, 0, 0, 64)
3375 message_window = curses.newwin(0, 0, 12, 0)
3376 prompt_window = curses.newwin(1, 0, rows-2, 0)
3377 message_window.scrollok(True)
3378 setwnd(fullscreen_window)
3382 if game.options & OPTION_CURSES:
3383 stdscr.keypad(False)
3389 "Wait for user action -- OK to do nothing if on a TTY"
3390 if game.options & OPTION_CURSES:
3395 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3399 if game.skill > SKILL_FAIR:
3400 prompt = _("[CONTINUE?]")
3402 prompt = _("[PRESS ENTER TO CONTINUE]")
3404 if game.options & OPTION_CURSES:
3406 setwnd(prompt_window)
3407 prompt_window.clear()
3408 prompt_window.addstr(prompt)
3409 prompt_window.getstr()
3410 prompt_window.clear()
3411 prompt_window.refresh()
3412 setwnd(message_window)
3415 sys.stdout.write('\n')
3419 sys.stdout.write('\n' * rows)
3423 "Skip i lines. Pause game if this would cause a scrolling event."
3424 for _dummy in range(i):
3425 if game.options & OPTION_CURSES:
3426 (y, _x) = curwnd.getyx()
3429 except curses.error:
3434 if rows and linecount >= rows:
3437 sys.stdout.write('\n')
3439 def proutn(proutntline):
3440 "Utter a line with no following line feed."
3441 if game.options & OPTION_CURSES:
3442 (y, x) = curwnd.getyx()
3443 (my, _mx) = curwnd.getmaxyx()
3444 if curwnd == message_window and y >= my - 2:
3447 # Uncomment this to debug curses problems
3449 logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(proutntline)))
3450 curwnd.addstr(proutntline)
3453 sys.stdout.write(proutntline)
3456 def prout(proutline):
3460 def prouts(proutsline):
3462 for c in proutsline:
3463 if not replayfp or replayfp.closed: # Don't slow down replays
3466 if game.options & OPTION_CURSES:
3470 if not replayfp or replayfp.closed:
3474 "Get a line of input."
3475 if game.options & OPTION_CURSES:
3476 linein = curwnd.getstr() + "\n"
3479 if replayfp and not replayfp.closed:
3481 linein = replayfp.readline()
3484 prout("*** Replay finished")
3487 elif linein[0] != "#":
3491 linein = my_input() + "\n"
3500 "Change windows -- OK for this to be a no-op in tty mode."
3502 if game.options & OPTION_CURSES:
3503 # Uncomment this to debug curses problems
3505 if wnd == fullscreen_window:
3506 legend = "fullscreen"
3507 elif wnd == srscan_window:
3509 elif wnd == report_window:
3511 elif wnd == status_window:
3513 elif wnd == lrscan_window:
3515 elif wnd == message_window:
3517 elif wnd == prompt_window:
3521 logfp.write("#curses: setwnd(%s)\n" % legend)
3523 # Some curses implementations get confused when you try this.
3525 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3526 except curses.error:
3530 "Clear to end of line -- can be a no-op in tty mode"
3531 if game.options & OPTION_CURSES:
3536 "Clear screen -- can be a no-op in tty mode."
3538 if game.options & OPTION_CURSES:
3544 def textcolor(color=DEFAULT):
3545 if (game.options & OPTION_COLOR) and (game.options & OPTION_CURSES):
3546 if color == DEFAULT:
3548 elif color == BLACK:
3549 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3551 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3552 elif color == GREEN:
3553 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3555 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3557 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3558 elif color == MAGENTA:
3559 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3560 elif color == BROWN:
3561 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3562 elif color == LIGHTGRAY:
3563 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3564 elif color == DARKGRAY:
3565 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3566 elif color == LIGHTBLUE:
3567 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3568 elif color == LIGHTGREEN:
3569 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3570 elif color == LIGHTCYAN:
3571 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3572 elif color == LIGHTRED:
3573 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3574 elif color == LIGHTMAGENTA:
3575 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3576 elif color == YELLOW:
3577 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3578 elif color == WHITE:
3579 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3582 if (game.options & OPTION_COLOR) and (game.options & OPTION_CURSES):
3583 curwnd.attron(curses.A_REVERSE)
3586 # Things past this point have policy implications.
3590 "Hook to be called after moving to redraw maps."
3591 if game.options & OPTION_CURSES:
3594 setwnd(srscan_window)
3598 setwnd(status_window)
3599 status_window.clear()
3600 status_window.move(0, 0)
3601 setwnd(report_window)
3602 report_window.clear()
3603 report_window.move(0, 0)
3605 setwnd(lrscan_window)
3606 lrscan_window.clear()
3607 lrscan_window.move(0, 0)
3608 lrscan(silent=False)
3610 def put_srscan_sym(w, sym):
3611 "Emit symbol for short-range scan."
3612 srscan_window.move(w.i+1, w.j*2+2)
3613 srscan_window.addch(sym)
3614 srscan_window.refresh()
3617 "Enemy fall down, go boom."
3618 if game.options & OPTION_CURSES:
3620 setwnd(srscan_window)
3621 srscan_window.attron(curses.A_REVERSE)
3622 put_srscan_sym(w, game.quad[w.i][w.j])
3626 srscan_window.attroff(curses.A_REVERSE)
3627 put_srscan_sym(w, game.quad[w.i][w.j])
3628 curses.delay_output(500)
3629 setwnd(message_window)
3632 "Sound and visual effects for teleportation."
3633 if game.options & OPTION_CURSES:
3635 setwnd(message_window)
3637 prouts(" . . . . . ")
3638 if game.options & OPTION_CURSES:
3639 #curses.delay_output(1000)
3643 def tracktorpedo(w, step, i, n, iquad):
3644 "Torpedo-track animation."
3645 if not game.options & OPTION_CURSES:
3649 proutn(_("Track for torpedo number %d- ") % (i+1))
3652 proutn(_("Torpedo track- "))
3653 elif step==4 or step==9:
3657 if not damaged(DSRSENS) or game.condition=="docked":
3658 if i != 0 and step == 1:
3661 if (iquad=='.') or (iquad==' '):
3662 put_srscan_sym(w, '+')
3666 put_srscan_sym(w, iquad)
3668 curwnd.attron(curses.A_REVERSE)
3669 put_srscan_sym(w, iquad)
3673 curwnd.attroff(curses.A_REVERSE)
3674 put_srscan_sym(w, iquad)
3679 "Display the current galaxy chart."
3680 if game.options & OPTION_CURSES:
3681 setwnd(message_window)
3682 message_window.clear()
3684 if game.options & OPTION_TTY:
3689 def prstat(txt, data):
3691 if game.options & OPTION_CURSES:
3693 setwnd(status_window)
3695 proutn(" " * (NSYM - len(txt)))
3698 if game.options & OPTION_CURSES:
3699 setwnd(report_window)
3701 # Code from moving.c begins here
3703 def imove(icourse=None, noattack=False):
3704 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3707 def newquadrant(noattack):
3708 # Leaving quadrant -- allow final enemy attack
3709 # Don't set up attack if being pushed by nova or cloaked
3710 if len(game.enemies) != 0 and not noattack and not game.iscloaked:
3712 for enemy in game.enemies:
3713 finald = (w - enemy.location).distance()
3714 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3715 # Stas Sergeev added the condition
3716 # that attacks only happen if Klingons
3717 # are present and your skill is good.
3718 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3719 attack(torps_ok=False)
3722 # check for edge of galaxy
3728 if icourse.final.i < 0:
3729 icourse.final.i = -icourse.final.i
3731 if icourse.final.j < 0:
3732 icourse.final.j = -icourse.final.j
3734 if icourse.final.i >= GALSIZE*QUADSIZE:
3735 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3737 if icourse.final.j >= GALSIZE*QUADSIZE:
3738 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3746 if game.nkinks == 3:
3747 # Three strikes -- you're out!
3751 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3752 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3753 prout(_("YOU WILL BE DESTROYED."))
3754 # Compute final position in new quadrant
3755 if trbeam: # Don't bother if we are to be beamed
3757 game.quadrant = icourse.final.quadrant()
3758 game.sector = icourse.final.sector()
3760 prout(_("Entering Quadrant %s.") % game.quadrant)
3761 game.quad[game.sector.i][game.sector.j] = game.ship
3763 if game.skill>SKILL_NOVICE:
3764 attack(torps_ok=False)
3766 def check_collision(h):
3767 iquad = game.quad[h.i][h.j]
3769 # object encountered in flight path
3770 stopegy = 50.0*icourse.distance/game.optime
3771 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3772 for enemy in game.enemies:
3773 if enemy.location == game.sector:
3774 collision(rammed=False, enemy=enemy)
3776 # This should not happen
3777 prout(_("Which way did he go?"))
3781 prouts(_("***RED ALERT! RED ALERT!"))
3783 proutn("***" + crmshp())
3784 proutn(_(" pulled into black hole at Sector %s") % h)
3785 # Getting pulled into a black hole was certain
3786 # death in Almy's original. Stas Sergeev added a
3787 # possibility that you'll get timewarped instead.
3789 for m in range(NDEVICES):
3790 if game.damage[m]>0:
3792 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3793 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3803 prout(_(" encounters Tholian web at %s;") % h)
3805 prout(_(" blocked by object at %s;") % h)
3806 proutn(_("Emergency stop required "))
3807 prout(_("%2d units of energy.") % int(stopegy))
3808 game.energy -= stopegy
3809 if game.energy <= 0:
3816 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3817 game.inorbit = False
3818 # If tractor beam is to occur, don't move full distance
3819 if game.state.date+game.optime >= scheduled(FTBEAM):
3821 # We can't be tractor beamed if cloaked,
3822 # so move the event into the future
3823 postpone(FTBEAM, game.optime + expran(1.5*game.intime/len(game.kcmdr)))
3827 game.condition = "red"
3828 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3829 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3831 game.quad[game.sector.i][game.sector.j] = '.'
3832 for _m in range(icourse.moves):
3834 w = icourse.sector()
3835 if icourse.origin.quadrant() != icourse.location.quadrant():
3836 newquadrant(noattack)
3838 elif check_collision(w):
3839 print("Collision detected")
3843 # We're in destination quadrant -- compute new average enemy distances
3844 game.quad[game.sector.i][game.sector.j] = game.ship
3846 for enemy in game.enemies:
3847 finald = (w-enemy.location).distance()
3848 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3849 enemy.kdist = finald
3851 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3852 attack(torps_ok=False)
3853 for enemy in game.enemies:
3854 enemy.kavgd = enemy.kdist
3857 setwnd(message_window)
3861 "Dock our ship at a starbase."
3863 if game.condition == "docked" and verbose:
3864 prout(_("Already docked."))
3867 prout(_("You must first leave standard orbit."))
3869 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3870 prout(crmshp() + _(" not adjacent to base."))
3873 prout(_("You cannot dock while cloaked."))
3875 game.condition = "docked"
3879 if game.energy < game.inenrg:
3880 game.energy = game.inenrg
3881 game.shield = game.inshld
3882 game.torps = game.intorps
3883 game.lsupres = game.inlsr
3884 game.state.crew = FULLCREW
3885 if game.brigcapacity-game.brigfree > 0:
3886 prout(_("%d captured Klingons transferred to base") % (game.brigcapacity-game.brigfree))
3887 game.kcaptured += game.brigcapacity-game.brigfree
3888 game.brigfree = game.brigcapacity
3889 if communicating() and \
3890 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3891 # get attack report from base
3892 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3896 def cartesian(loc1=None, loc2=None):
3898 return game.quadrant * QUADSIZE + game.sector
3900 return game.quadrant * QUADSIZE + loc1
3902 return loc1 * QUADSIZE + loc2
3904 def getcourse(isprobe):
3905 "Get a course and distance from the user."
3907 dquad = copy.copy(game.quadrant)
3908 navmode = "unspecified"
3912 if game.landed and not isprobe:
3913 prout(_("Dummy! You can't leave standard orbit until you"))
3914 proutn(_("are back aboard the ship."))
3917 while navmode == "unspecified":
3918 if damaged(DNAVSYS):
3920 prout(_("Computer damaged; manual navigation only"))
3922 prout(_("Computer damaged; manual movement only"))
3927 key = scanner.nexttok()
3929 proutn(_("Manual or automatic- "))
3932 elif key == "IHALPHA":
3933 if scanner.sees("manual"):
3935 key = scanner.nexttok()
3937 elif scanner.sees("automatic"):
3938 navmode = "automatic"
3939 key = scanner.nexttok()
3947 prout(_("(Manual navigation assumed.)"))
3949 prout(_("(Manual movement assumed.)"))
3953 if navmode == "automatic":
3954 while key == "IHEOL":
3956 proutn(_("Target quadrant or quadrant§or- "))
3958 proutn(_("Destination sector or quadrant§or- "))
3961 key = scanner.nexttok()
3965 xi = int(round(scanner.real))-1
3966 key = scanner.nexttok()
3970 xj = int(round(scanner.real))-1
3971 key = scanner.nexttok()
3973 # both quadrant and sector specified
3974 xk = int(round(scanner.real))-1
3975 key = scanner.nexttok()
3979 xl = int(round(scanner.real))-1
3985 # only one pair of numbers was specified
3987 # only quadrant specified -- go to center of dest quad
3990 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3992 # only sector specified
3996 if not dquad.valid_quadrant() or not dsect.valid_sector():
4003 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
4005 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
4006 # the actual deltas get computed here
4007 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
4008 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
4010 while key == "IHEOL":
4011 proutn(_("X and Y displacements- "))
4014 key = scanner.nexttok()
4017 delta.j = scanner.real
4021 key = scanner.nexttok()
4023 delta.i = scanner.real
4024 elif key == "IHEOL":
4030 # Check for zero movement
4031 if delta.i == 0 and delta.j == 0:
4034 if itemp == "verbose" and not isprobe:
4036 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
4038 return course(bearing=delta.bearing(), distance=delta.distance())
4041 def __init__(self, bearing, distance, origin=None):
4042 self.distance = distance
4043 self.bearing = bearing
4045 self.origin = cartesian(game.quadrant, game.sector)
4047 self.origin = origin
4048 # The bearing() code we inherited from FORTRAN is actually computing
4049 # clockface directions!
4050 if self.bearing < 0.0:
4051 self.bearing += 12.0
4052 self.angle = ((15.0 - self.bearing) * 0.5235988)
4053 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
4054 bigger = max(abs(self.increment.i), abs(self.increment.j))
4055 self.increment /= bigger
4056 self.moves = int(round(10*self.distance*bigger))
4058 self.final = (self.location + self.moves*self.increment).roundtogrid()
4059 self.location = self.origin
4060 self.nextlocation = None
4062 self.location = self.origin
4065 return self.location.roundtogrid() == self.final
4067 "Next step on course."
4069 self.nextlocation = self.location + self.increment
4070 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
4071 self.location = self.nextlocation
4074 return self.location.quadrant()
4076 return self.location.sector()
4078 return self.distance*(w**3)*(game.shldup+1)
4080 return 10.0*self.distance/w**2
4083 "Move under impulse power."
4085 if damaged(DIMPULS):
4088 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4090 if game.energy > 30.0:
4092 icourse = getcourse(isprobe=False)
4095 power = 20.0 + 100.0*icourse.distance
4098 if power >= game.energy:
4099 # Insufficient power for trip
4101 prout(_("First Officer Spock- \"Captain, the impulse engines"))
4102 prout(_("require 20.0 units to engage, plus 100.0 units per"))
4103 if game.energy > 30:
4104 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
4105 int(0.01 * (game.energy-20.0)-0.05))
4106 prout(_(" quadrants.\""))
4108 prout(_("quadrant. They are, therefore, useless.\""))
4111 # Make sure enough time is left for the trip
4112 game.optime = icourse.distance/0.095
4113 if game.optime >= game.state.remtime:
4114 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
4115 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
4116 proutn(_("we dare spend the time?\" "))
4119 # Activate impulse engines and pay the cost
4120 imove(icourse, noattack=False)
4124 power = 20.0 + 100.0*icourse.distance
4125 game.energy -= power
4126 game.optime = icourse.distance/0.095
4127 if game.energy <= 0:
4131 def warp(wcourse, involuntary):
4132 "ove under warp drive."
4133 blooey = False; twarp = False
4134 if not involuntary: # Not WARPX entry
4139 prout(_("Engineer Scott- \"The warp engines can not be used while cloaked, Sir.\""))
4141 if game.damage[DWARPEN] > 10.0:
4144 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
4146 if damaged(DWARPEN) and game.warpfac > 4.0:
4149 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4150 prout(_(" is repaired, I can only give you warp 4.\""))
4152 # Read in course and distance
4155 wcourse = getcourse(isprobe=False)
4158 # Make sure starship has enough energy for the trip
4159 # Note: this formula is slightly different from the C version,
4160 # and lets you skate a bit closer to the edge.
4161 if wcourse.power(game.warpfac) >= game.energy:
4162 # Insufficient power for trip
4165 prout(_("Engineering to bridge--"))
4166 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
4167 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
4169 prout(_("We can't do it, Captain. We don't have enough energy."))
4171 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4174 prout(_("if you'll lower the shields."))
4178 prout(_("We haven't the energy to go that far with the shields up."))
4180 # Make sure enough time is left for the trip
4181 game.optime = wcourse.time(game.warpfac)
4182 if game.optime >= 0.8*game.state.remtime:
4184 prout(_("First Officer Spock- \"Captain, I compute that such"))
4185 proutn(_(" a trip would require approximately %2.0f") %
4186 (100.0*game.optime/game.state.remtime))
4187 prout(_(" percent of our"))
4188 proutn(_(" remaining time. Are you sure this is wise?\" "))
4194 if game.warpfac > 6.0:
4195 # Decide if engine damage will occur
4196 # ESR: Seems wrong. Probability of damage goes *down* with distance?
4197 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
4198 if prob > randreal():
4200 wcourse.distance = randreal(wcourse.distance)
4201 # Decide if time warp will occur
4202 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
4204 if game.idebug and game.warpfac==10 and not twarp:
4206 proutn("=== Force time warp? ")
4210 # If time warp or engine damage, check path
4211 # If it is obstructed, don't do warp or damage
4212 look = wcourse.moves
4216 w = wcourse.sector()
4217 if not w.valid_sector():
4219 if game.quad[w.i][w.j] != '.':
4223 # Activate Warp Engines and pay the cost
4224 imove(wcourse, noattack=False)
4227 game.energy -= wcourse.power(game.warpfac)
4228 if game.energy <= 0:
4230 game.optime = wcourse.time(game.warpfac)
4234 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4236 prout(_("Engineering to bridge--"))
4237 prout(_(" Scott here. The warp engines are damaged."))
4238 prout(_(" We'll have to reduce speed to warp 4."))
4243 "Change the warp factor."
4245 key=scanner.nexttok()
4249 proutn(_("Warp factor- "))
4253 if game.damage[DWARPEN] > 10.0:
4254 prout(_("Warp engines inoperative."))
4256 if damaged(DWARPEN) and scanner.real > 4.0:
4257 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4258 prout(_(" but right now we can only go warp 4.\""))
4260 if scanner.real > 10.0:
4261 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4263 if scanner.real < 1.0:
4264 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4266 oldfac = game.warpfac
4267 game.warpfac = scanner.real
4268 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4269 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4272 if game.warpfac < 8.00:
4273 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4275 if game.warpfac == 10.0:
4276 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4278 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4282 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4284 # is captain on planet?
4286 if damaged(DTRANSP):
4289 prout(_("Scotty rushes to the transporter controls."))
4291 prout(_("But with the shields up it's hopeless."))
4293 prouts(_("His desperate attempt to rescue you . . ."))
4298 prout(_("SUCCEEDS!"))
4301 proutn(_("The crystals mined were "))
4309 # Check to see if captain in shuttle craft
4314 # Inform captain of attempt to reach safety
4318 prouts(_("***RED ALERT! RED ALERT!"))
4320 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4321 prouts(_(" a supernova."))
4323 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4324 prout(_("safely out of quadrant."))
4325 if not damaged(DRADIO):
4326 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4327 # Try to use warp engines
4328 if damaged(DWARPEN):
4330 prout(_("Warp engines damaged."))
4333 game.warpfac = randreal(6.0, 8.0)
4334 prout(_("Warp factor set to %d") % int(game.warpfac))
4335 power = 0.75*game.energy
4336 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4337 dist = max(dist, randreal(math.sqrt(2)))
4338 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4339 game.optime = bugout.time(game.warpfac)
4341 game.inorbit = False
4342 warp(bugout, involuntary=True)
4344 # This is bad news, we didn't leave quadrant.
4348 prout(_("Insufficient energy to leave quadrant."))
4351 # Repeat if another snova
4352 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4355 finish(FWON) # Snova killed remaining enemy.
4358 "Let's do the time warp again."
4359 prout(_("***TIME WARP ENTERED."))
4360 if game.state.snap and withprob(0.5):
4362 prout(_("You are traveling backwards in time %d stardates.") %
4363 int(game.state.date-game.snapsht.date))
4364 game.state = game.snapsht
4365 game.state.snap = False
4366 if len(game.state.kcmdr):
4367 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4368 schedule(FBATTAK, expran(0.3*game.intime))
4369 schedule(FSNOVA, expran(0.5*game.intime))
4370 # next snapshot will be sooner
4371 schedule(FSNAP, expran(0.25*game.state.remtime))
4373 if game.state.nscrem:
4374 schedule(FSCMOVE, 0.2777)
4378 game.battle.invalidate()
4379 # Make sure Galileo is consistant -- Snapshot may have been taken
4380 # when on planet, which would give us two Galileos!
4382 for l in range(game.inplan):
4383 if game.state.planets[l].known == "shuttle_down":
4385 if game.iscraft == "onship" and game.ship=='E':
4386 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4387 game.iscraft = "offship"
4388 # Likewise, if in the original time the Galileo was abandoned, but
4389 # was on ship earlier, it would have vanished -- let's restore it.
4390 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4391 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4392 game.iscraft = "onship"
4393 # There used to be code to do the actual reconstrction here,
4394 # but the starchart is now part of the snapshotted galaxy state.
4395 prout(_("Spock has reconstructed a correct star chart from memory"))
4397 # Go forward in time
4398 game.optime = expran(0.5*game.intime)
4399 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4400 # cheat to make sure no tractor beams occur during time warp
4401 postpone(FTBEAM, game.optime)
4402 game.damage[DRADIO] += game.optime
4404 events() # Stas Sergeev added this -- do pending events
4407 "Launch deep-space probe."
4408 # New code to launch a deep space probe
4409 if game.nprobes == 0:
4412 if game.ship == 'E':
4413 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4415 prout(_("Ye Faerie Queene has no deep space probes."))
4420 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4422 if is_scheduled(FDSPROB):
4425 if damaged(DRADIO) and game.condition != "docked":
4426 prout(_("Spock- \"Records show the previous probe has not yet"))
4427 prout(_(" reached its destination.\""))
4429 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4431 key = scanner.nexttok()
4433 if game.nprobes == 1:
4434 prout(_("1 probe left."))
4436 prout(_("%d probes left") % game.nprobes)
4437 proutn(_("Are you sure you want to fire a probe? "))
4440 game.isarmed = False
4441 if key == "IHALPHA" and scanner.token == "armed":
4443 key = scanner.nexttok()
4444 elif key == "IHEOL":
4445 proutn(_("Arm NOVAMAX warhead? "))
4447 elif key == "IHREAL": # first element of course
4448 scanner.push(scanner.token)
4450 game.probe = getcourse(isprobe=True)
4454 schedule(FDSPROB, 0.01) # Time to move one sector
4455 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4460 "Yell for help from nearest starbase."
4461 # There's more than one way to move in this game!
4463 # Test for conditions which prevent calling for help
4464 if game.condition == "docked":
4465 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4468 prout(_("Subspace radio damaged."))
4470 if not game.state.baseq:
4471 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4474 prout(_("You must be aboard the %s.") % crmshp())
4476 # OK -- call for help from nearest starbase
4479 # There's one in this quadrant
4480 ddist = (game.base - game.sector).distance()
4482 ibq = None # Force base-quadrant game to persist past loop
4484 for ibq in game.state.baseq:
4485 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4489 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4491 # Since starbase not in quadrant, set up new quadrant
4494 # dematerialize starship
4495 game.quad[game.sector.i][game.sector.j]='.'
4496 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4497 % (game.quadrant, crmshp()))
4498 game.sector.invalidate()
4499 for m in range(1, 5+1):
4500 w = game.base.scatter()
4501 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4502 # found one -- finish up
4505 if not game.sector.is_valid():
4506 prout(_("You have been lost in space..."))
4507 finish(FMATERIALIZE)
4509 # Give starbase three chances to rematerialize starship
4510 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4511 for m in range(1, 3+1):
4512 if m == 1: proutn(_("1st"))
4513 elif m == 2: proutn(_("2nd"))
4514 elif m == 3: proutn(_("3rd"))
4515 proutn(_(" attempt to re-materialize ") + crmshp())
4516 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4519 if randreal() > probf:
4523 curses.delay_output(500)
4525 game.quad[game.sector.i][game.sector.j]='?'
4528 setwnd(message_window)
4529 finish(FMATERIALIZE)
4531 game.quad[game.sector.i][game.sector.j]=game.ship
4533 prout(_("succeeds."))
4537 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4542 if game.condition=="docked":
4544 prout(_("You cannot abandon Ye Faerie Queene."))
4547 # Must take shuttle craft to exit
4548 if game.damage[DSHUTTL]==-1:
4549 prout(_("Ye Faerie Queene has no shuttle craft."))
4551 if game.damage[DSHUTTL]<0:
4552 prout(_("Shuttle craft now serving Big Macs."))
4554 if game.damage[DSHUTTL]>0:
4555 prout(_("Shuttle craft damaged."))
4558 prout(_("You must be aboard the ship."))
4560 if game.iscraft != "onship":
4561 prout(_("Shuttle craft not currently available."))
4563 # Emit abandon ship messages
4565 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4567 prouts(_("***ALL HANDS ABANDON SHIP!"))
4569 prout(_("Captain and crew escape in shuttle craft."))
4570 if not game.state.baseq:
4571 # Oops! no place to go...
4574 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4576 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4577 prout(_("Remainder of ship's complement beam down"))
4578 prout(_("to nearest habitable planet."))
4579 elif q.planet != None and not damaged(DTRANSP):
4580 prout(_("Remainder of ship's complement beam down to %s.") %
4583 prout(_("Entire crew of %d left to die in outer space.") %
4585 game.casual += game.state.crew
4586 game.abandoned += game.state.crew
4587 # If at least one base left, give 'em the Faerie Queene
4589 game.icrystl = False # crystals are lost
4590 game.nprobes = 0 # No probes
4591 prout(_("You are captured by Klingons and released to"))
4592 prout(_("the Federation in a prisoner-of-war exchange."))
4593 nb = randrange(len(game.state.baseq))
4594 # Set up quadrant and position FQ adjacient to base
4595 if not game.quadrant == game.state.baseq[nb]:
4596 game.quadrant = game.state.baseq[nb]
4597 game.sector.i = game.sector.j = 5
4600 # position next to base by trial and error
4601 game.quad[game.sector.i][game.sector.j] = '.'
4603 for l in range(QUADSIZE):
4604 game.sector = game.base.scatter()
4605 if game.sector.valid_sector() and \
4606 game.quad[game.sector.i][game.sector.j] == '.':
4609 break # found a spot
4610 game.sector.i=QUADSIZE/2
4611 game.sector.j=QUADSIZE/2
4613 # Get new commission
4614 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4615 game.state.crew = FULLCREW
4616 prout(_("Starfleet puts you in command of another ship,"))
4617 prout(_("the Faerie Queene, which is antiquated but,"))
4618 prout(_("still useable."))
4620 prout(_("The dilithium crystals have been moved."))
4622 game.iscraft = "offship" # Galileo disappears
4624 game.condition="docked"
4625 for l in range(NDEVICES):
4626 game.damage[l] = 0.0
4627 game.damage[DSHUTTL] = -1
4628 game.energy = game.inenrg = 3000.0
4629 game.shield = game.inshld = 1250.0
4630 game.torps = game.intorps = 6
4631 game.lsupres=game.inlsr=3.0
4634 game.brigfree = game.brigcapacity = 300
4637 # Code from planets.c begins here.
4640 "Abort a lengthy operation if an event interrupts it."
4643 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4648 "Report on (uninhabited) planets in the galaxy."
4652 prout(_("Spock- \"Planet report follows, Captain.\""))
4654 for i in range(game.inplan):
4655 if game.state.planets[i].pclass == "destroyed":
4657 if (game.state.planets[i].known != "unknown" \
4658 and not game.state.planets[i].inhabited) \
4661 if game.idebug and game.state.planets[i].known=="unknown":
4662 proutn("(Unknown) ")
4663 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4664 proutn(_(" class "))
4665 proutn(game.state.planets[i].pclass)
4667 if game.state.planets[i].crystals != "present":
4669 prout(_("dilithium crystals present."))
4670 if game.state.planets[i].known=="shuttle_down":
4671 prout(_(" Shuttle Craft Galileo on surface."))
4673 prout(_("No information available."))
4676 "Enter standard orbit."
4680 prout(_("Already in standard orbit."))
4682 if damaged(DWARPEN) and damaged(DIMPULS):
4683 prout(_("Both warp and impulse engines damaged."))
4685 if not game.plnet.is_valid():
4686 prout("There is no planet in this sector.")
4688 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4689 prout(crmshp() + _(" not adjacent to planet."))
4692 game.optime = randreal(0.02, 0.05)
4693 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4697 game.height = randreal(1400, 8600)
4698 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4703 "Examine planets in this quadrant."
4704 if damaged(DSRSENS):
4705 if game.options & OPTION_TTY:
4706 prout(_("Short range sensors damaged."))
4708 if game.iplnet is None:
4709 if game.options & OPTION_TTY:
4710 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4712 if game.iplnet.known == "unknown":
4713 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4715 prout(_(" Planet at Sector %s is of class %s.") %
4716 (game.plnet, game.iplnet.pclass))
4717 if game.iplnet.known=="shuttle_down":
4718 prout(_(" Sensors show Galileo still on surface."))
4719 proutn(_(" Readings indicate"))
4720 if game.iplnet.crystals != "present":
4722 prout(_(" dilithium crystals present.\""))
4723 if game.iplnet.known == "unknown":
4724 game.iplnet.known = "known"
4725 elif game.iplnet.inhabited:
4726 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4727 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4730 "Use the transporter."
4734 if damaged(DTRANSP):
4735 prout(_("Transporter damaged."))
4736 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4738 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4742 if not game.inorbit:
4743 prout(crmshp() + _(" not in standard orbit."))
4746 prout(_("Impossible to transport through shields."))
4748 if game.iplnet.known=="unknown":
4749 prout(_("Spock- \"Captain, we have no information on this planet"))
4750 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4751 prout(_(" you may not go down.\""))
4753 if not game.landed and game.iplnet.crystals=="absent":
4754 prout(_("Spock- \"Captain, I fail to see the logic in"))
4755 prout(_(" exploring a planet with no dilithium crystals."))
4756 proutn(_(" Are you sure this is wise?\" "))
4760 if not (game.options & OPTION_PLAIN):
4761 nrgneed = 50 * game.skill + game.height / 100.0
4762 if nrgneed > game.energy:
4763 prout(_("Engineering to bridge--"))
4764 prout(_(" Captain, we don't have enough energy for transportation."))
4766 if not game.landed and nrgneed * 2 > game.energy:
4767 prout(_("Engineering to bridge--"))
4768 prout(_(" Captain, we have enough energy only to transport you down to"))
4769 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4770 if game.iplnet.known == "shuttle_down":
4771 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4772 proutn(_(" Are you sure this is wise?\" "))
4777 # Coming from planet
4778 if game.iplnet.known=="shuttle_down":
4779 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4783 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4784 prout(_("Landing party assembled, ready to beam up."))
4786 prout(_("Kirk whips out communicator..."))
4787 prouts(_("BEEP BEEP BEEP"))
4789 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4792 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4794 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4796 prout(_("Kirk- \"Energize.\""))
4799 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4801 if not withprob(0.98):
4802 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4804 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4807 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4808 game.landed = not game.landed
4809 game.energy -= nrgneed
4811 prout(_("Transport complete."))
4812 if game.landed and game.iplnet.known=="shuttle_down":
4813 prout(_("The shuttle craft Galileo is here!"))
4814 if not game.landed and game.imine:
4821 "Strip-mine a world for dilithium."
4825 prout(_("Mining party not on planet."))
4827 if game.iplnet.crystals == "mined":
4828 prout(_("This planet has already been strip-mined for dilithium."))
4830 elif game.iplnet.crystals == "absent":
4831 prout(_("No dilithium crystals on this planet."))
4834 prout(_("You've already mined enough crystals for this trip."))
4836 if game.icrystl and game.cryprob == 0.05:
4837 prout(_("With all those fresh crystals aboard the ") + crmshp())
4838 prout(_("there's no reason to mine more at this time."))
4840 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4843 prout(_("Mining operation complete."))
4844 game.iplnet.crystals = "mined"
4845 game.imine = game.ididit = True
4848 "Use dilithium crystals."
4852 if not game.icrystl:
4853 prout(_("No dilithium crystals available."))
4855 if game.energy >= 1000:
4856 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4857 prout(_(" except when Condition Yellow exists."))
4859 prout(_("Spock- \"Captain, I must warn you that loading"))
4860 prout(_(" raw dilithium crystals into the ship's power"))
4861 prout(_(" system may risk a severe explosion."))
4862 proutn(_(" Are you sure this is wise?\" "))
4867 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4868 prout(_(" Mr. Spock and I will try it.\""))
4870 prout(_("Spock- \"Crystals in place, Sir."))
4871 prout(_(" Ready to activate circuit.\""))
4873 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4875 if withprob(game.cryprob):
4876 prouts(_(" \"Activating now! - - No good! It's***"))
4878 prouts(_("***RED ALERT! RED A*L********************************"))
4881 prouts(_("****************** KA-BOOM!!!! *******************"))
4885 game.energy += randreal(5000.0, 5500.0)
4886 prouts(_(" \"Activating now! - - "))
4887 prout(_("The instruments"))
4888 prout(_(" are going crazy, but I think it's"))
4889 prout(_(" going to work!! Congratulations, Sir!\""))
4894 "Use shuttlecraft for planetary jaunt."
4897 if damaged(DSHUTTL):
4898 if game.damage[DSHUTTL] == -1.0:
4899 if game.inorbit and game.iplnet.known == "shuttle_down":
4900 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4902 prout(_("Ye Faerie Queene had no shuttle craft."))
4903 elif game.damage[DSHUTTL] > 0:
4904 prout(_("The Galileo is damaged."))
4905 else: # game.damage[DSHUTTL] < 0
4906 prout(_("Shuttle craft is now serving Big Macs."))
4908 if not game.inorbit:
4909 prout(crmshp() + _(" not in standard orbit."))
4911 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4912 prout(_("Shuttle craft not currently available."))
4914 if not game.landed and game.iplnet.known=="shuttle_down":
4915 prout(_("You will have to beam down to retrieve the shuttle craft."))
4917 if game.shldup or game.condition == "docked":
4918 prout(_("Shuttle craft cannot pass through shields."))
4920 if game.iplnet.known=="unknown":
4921 prout(_("Spock- \"Captain, we have no information on this planet"))
4922 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4923 prout(_(" you may not fly down.\""))
4925 game.optime = 3.0e-5*game.height
4926 if game.optime >= 0.8*game.state.remtime:
4927 prout(_("First Officer Spock- \"Captain, I compute that such"))
4928 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4929 int(100*game.optime/game.state.remtime))
4930 prout(_("remaining time."))
4931 proutn(_("Are you sure this is wise?\" "))
4937 if game.iscraft == "onship":
4939 if not damaged(DTRANSP):
4940 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4944 proutn(_("Shuttle crew"))
4946 proutn(_("Rescue party"))
4947 prout(_(" boards Galileo and swoops toward planet surface."))
4948 game.iscraft = "offship"
4952 game.iplnet.known="shuttle_down"
4953 prout(_("Trip complete."))
4956 # Ready to go back to ship
4957 prout(_("You and your mining party board the"))
4958 prout(_("shuttle craft for the trip back to the Enterprise."))
4960 prouts(_("The short hop begins . . ."))
4962 game.iplnet.known="known"
4968 game.iscraft = "onship"
4974 prout(_("Trip complete."))
4977 # Kirk on ship and so is Galileo
4978 prout(_("Mining party assembles in the hangar deck,"))
4979 prout(_("ready to board the shuttle craft \"Galileo\"."))
4981 prouts(_("The hangar doors open; the trip begins."))
4984 game.iscraft = "offship"
4987 game.iplnet.known = "shuttle_down"
4990 prout(_("Trip complete."))
4994 "Use the big zapper."
4998 if game.ship != 'E':
4999 prout(_("Ye Faerie Queene has no death ray."))
5001 if len(game.enemies)==0:
5002 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
5005 prout(_("Death Ray is damaged."))
5007 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
5008 prout(_(" is highly unpredictible. Considering the alternatives,"))
5009 proutn(_(" are you sure this is wise?\" "))
5012 prout(_("Spock- \"Acknowledged.\""))
5015 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
5017 prout(_("Crew scrambles in emergency preparation."))
5018 prout(_("Spock and Scotty ready the death ray and"))
5019 prout(_("prepare to channel all ship's power to the device."))
5021 prout(_("Spock- \"Preparations complete, sir.\""))
5022 prout(_("Kirk- \"Engage!\""))
5024 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
5027 if game.options & OPTION_PLAIN:
5031 prouts(_("Sulu- \"Captain! It's working!\""))
5033 while len(game.enemies) > 0:
5034 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
5035 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
5036 if game.unwon() == 0:
5038 if (game.options & OPTION_PLAIN) == 0:
5039 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
5041 prout(_(" is still operational.\""))
5043 prout(_(" has been rendered nonfunctional.\""))
5044 game.damage[DDRAY] = 39.95
5046 r = randreal() # Pick failure method
5048 prouts(_("Sulu- \"Captain! It's working!\""))
5050 prouts(_("***RED ALERT! RED ALERT!"))
5052 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
5054 prouts(_("***RED ALERT! RED A*L********************************"))
5057 prouts(_("****************** KA-BOOM!!!! *******************"))
5062 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
5064 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
5066 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
5067 prout(_(" have apparently been transformed into strange mutations."))
5068 prout(_(" Vulcans do not seem to be affected."))
5070 prout(_("Kirk- \"Raauch! Raauch!\""))
5074 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
5076 proutn(_("Spock- \"I believe the word is"))
5077 prouts(_(" *ASTONISHING*"))
5078 prout(_(" Mr. Sulu."))
5079 for i in range(QUADSIZE):
5080 for j in range(QUADSIZE):
5081 if game.quad[i][j] == '.':
5082 game.quad[i][j] = '?'
5083 prout(_(" Captain, our quadrant is now infested with"))
5084 prouts(_(" - - - - - - *THINGS*."))
5086 prout(_(" I have no logical explanation.\""))
5088 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
5090 prout(_("Scotty- \"There are so many tribbles down here"))
5091 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
5095 # Code from reports.c begins here
5097 def attackreport(curt):
5098 "eport status of bases under attack."
5100 if is_scheduled(FCDBAS):
5101 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
5102 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
5103 elif game.isatb == 1:
5104 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
5105 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
5107 prout(_("No Starbase is currently under attack."))
5109 if is_scheduled(FCDBAS):
5110 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
5112 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
5116 # report on general game status
5118 s1 = (game.thawed and _("thawed ")) or ""
5119 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
5120 s3 = (None, _("novice"), _("fair"),
5121 _("good"), _("expert"), _("emeritus"))[game.skill]
5122 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
5123 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
5124 prout(_("No plaque is allowed."))
5126 prout(_("This is tournament game %d.") % game.tourn)
5127 prout(_("Your secret password is \"%s\"") % game.passwd)
5128 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - game.unwon()),
5129 (game.inkling + game.incom + game.inscom)))
5130 if game.incom - len(game.state.kcmdr):
5131 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
5132 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
5133 prout(_(", but no Commanders."))
5136 if game.skill > SKILL_FAIR:
5137 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
5138 if len(game.state.baseq) != game.inbase:
5140 if game.inbase-len(game.state.baseq)==1:
5141 proutn(_("has been 1 base"))
5143 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
5144 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
5146 prout(_("There are %d bases.") % game.inbase)
5147 if communicating() or game.iseenit:
5148 # Don't report this if not seen and
5149 # either the radio is dead or not at base!
5153 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
5154 if game.brigcapacity != game.brigfree:
5155 embriggened = brigcapacity-brigfree
5156 if embriggened == 1:
5157 prout(_("1 Klingon in brig"))
5159 prout(_("%d Klingons in brig.") % embriggened)
5160 if game.kcaptured == 0:
5162 elif game.kcaptured == 1:
5163 prout(_("1 captured Klingon turned in to Starfleet."))
5165 prout(_("%d captured Klingons turned in to Star Fleet.") % game.kcaptured)
5167 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
5168 if game.ship == 'E':
5169 proutn(_("You have "))
5171 proutn("%d" % (game.nprobes))
5174 proutn(_(" deep space probe"))
5178 if communicating() and is_scheduled(FDSPROB):
5180 proutn(_("An armed deep space probe is in "))
5182 proutn(_("A deep space probe is in "))
5183 prout("Quadrant %s." % game.probe.quadrant())
5185 if game.cryprob <= .05:
5186 prout(_("Dilithium crystals aboard ship... not yet used."))
5190 while game.cryprob > ai:
5193 prout(_("Dilithium crystals have been used %d time%s.") % \
5194 (i, (_("s"), "")[i==1]))
5198 "Long-range sensor scan."
5199 if damaged(DLRSENS):
5200 # Now allow base's sensors if docked
5201 if game.condition != "docked":
5203 prout(_("LONG-RANGE SENSORS DAMAGED."))
5206 prout(_("Starbase's long-range scan"))
5208 prout(_("Long-range scan"))
5209 for x in range(game.quadrant.i-1, game.quadrant.i+2):
5212 for y in range(game.quadrant.j-1, game.quadrant.j+2):
5213 if not Coord(x, y).valid_quadrant():
5217 if not damaged(DRADIO):
5218 game.state.galaxy[x][y].charted = True
5219 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5220 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5221 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5222 if not silent and game.state.galaxy[x][y].supernova:
5225 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
5233 for i in range(NDEVICES):
5236 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5237 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5239 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5240 game.damage[i]+0.05,
5241 DOCKFAC*game.damage[i]+0.005))
5243 prout(_("All devices functional."))
5246 "Update the chart in the Enterprise's computer from galaxy data."
5247 game.lastchart = game.state.date
5248 for i in range(GALSIZE):
5249 for j in range(GALSIZE):
5250 if game.state.galaxy[i][j].charted:
5251 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5252 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5253 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5256 "Display the star chart."
5258 if (game.options & OPTION_AUTOSCAN):
5262 if game.lastchart < game.state.date and game.condition == "docked":
5263 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5265 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5266 if game.state.date > game.lastchart:
5267 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5268 prout(" 1 2 3 4 5 6 7 8")
5269 for i in range(GALSIZE):
5270 proutn("%d |" % (i+1))
5271 for j in range(GALSIZE):
5272 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5276 if game.state.galaxy[i][j].supernova:
5278 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5280 elif game.state.galaxy[i][j].charted:
5281 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5285 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5293 def sectscan(goodScan, i, j):
5294 "Light up an individual dot in a sector."
5295 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5296 if game.quad[i][j] in ('E', 'F'):
5299 textcolor({"green":GREEN,
5303 "dead":BROWN}[game.condition])
5305 textcolor({'?':LIGHTMAGENTA,
5311 }.get(game.quad[i][j], DEFAULT))
5312 proutn("%c " % game.quad[i][j])
5318 "Emit status report lines"
5319 if not req or req == 1:
5320 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5321 % (game.state.date, game.state.remtime))
5322 if not req or req == 2:
5323 if game.condition != "docked":
5325 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5326 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5328 prout(_(", CLOAKED"))
5329 if not req or req == 3:
5330 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5331 if not req or req == 4:
5332 if damaged(DLIFSUP):
5333 if game.condition == "docked":
5334 s = _("DAMAGED, Base provides")
5336 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5339 prstat(_("Life Support"), s)
5340 if not req or req == 5:
5341 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5342 if not req or req == 6:
5344 if game.icrystl and (game.options & OPTION_SHOWME):
5345 extra = _(" (have crystals)")
5346 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5347 if not req or req == 7:
5348 prstat(_("Torpedoes"), "%d" % (game.torps))
5349 if not req or req == 8:
5350 if damaged(DSHIELD):
5356 data = _(" %d%% %.1f units") \
5357 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5358 prstat(_("Shields"), s+data)
5359 if not req or req == 9:
5360 prstat(_("Klingons Left"), "%d" % game.unwon())
5361 if not req or req == 10:
5362 if game.options & OPTION_WORLDS:
5363 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5364 if plnet and plnet.inhabited:
5365 prstat(_("Major system"), plnet.name)
5367 prout(_("Sector is uninhabited"))
5368 elif not req or req == 11:
5369 attackreport(not req)
5372 "Request specified status data, a historical relic from slow TTYs."
5373 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5374 while scanner.nexttok() == "IHEOL":
5375 proutn(_("Information desired? "))
5377 if scanner.token in requests:
5378 status(requests.index(scanner.token))
5380 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5381 prout((" date, condition, position, lsupport, warpfactor,"))
5382 prout((" energy, torpedoes, shields, klingons, system, time."))
5387 if damaged(DSRSENS):
5388 # Allow base's sensors if docked
5389 if game.condition != "docked":
5390 prout(_(" S.R. SENSORS DAMAGED!"))
5393 prout(_(" [Using Base's sensors]"))
5395 prout(_(" Short-range scan"))
5396 if goodScan and communicating():
5397 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5398 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5399 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5400 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5401 prout(" 1 2 3 4 5 6 7 8 9 10")
5402 if game.condition != "docked":
5404 for i in range(QUADSIZE):
5405 proutn("%2d " % (i+1))
5406 for j in range(QUADSIZE):
5407 sectscan(goodScan, i, j)
5411 "Use computer to get estimated time of arrival for a warp jump."
5412 w1 = Coord(); w2 = Coord()
5414 if damaged(DCOMPTR):
5415 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5418 if scanner.nexttok() != "IHREAL":
5421 proutn(_("Destination quadrant and/or sector? "))
5422 if scanner.nexttok()!="IHREAL":
5425 w1.j = int(scanner.real-0.5)
5426 if scanner.nexttok() != "IHREAL":
5429 w1.i = int(scanner.real-0.5)
5430 if scanner.nexttok() == "IHREAL":
5431 w2.j = int(scanner.real-0.5)
5432 if scanner.nexttok() != "IHREAL":
5435 w2.i = int(scanner.real-0.5)
5437 if game.quadrant.j>w1.i:
5441 if game.quadrant.i>w1.j:
5445 if not w1.valid_quadrant() or not w2.valid_sector():
5448 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5449 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5452 prout(_("Answer \"no\" if you don't know the value:"))
5455 proutn(_("Time or arrival date? "))
5456 if scanner.nexttok()=="IHREAL":
5457 ttime = scanner.real
5458 if ttime > game.state.date:
5459 ttime -= game.state.date # Actually a star date
5460 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5461 if ttime <= 1e-10 or twarp > 10:
5462 prout(_("We'll never make it, sir."))
5469 proutn(_("Warp factor? "))
5470 if scanner.nexttok()== "IHREAL":
5472 twarp = scanner.real
5473 if twarp<1.0 or twarp > 10.0:
5477 prout(_("Captain, certainly you can give me one of these."))
5480 ttime = (10.0*dist)/twarp**2
5481 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5482 if tpower >= game.energy:
5483 prout(_("Insufficient energy, sir."))
5484 if not game.shldup or tpower > game.energy*2.0:
5487 proutn(_("New warp factor to try? "))
5488 if scanner.nexttok() == "IHREAL":
5490 twarp = scanner.real
5491 if twarp<1.0 or twarp > 10.0:
5499 prout(_("But if you lower your shields,"))
5500 proutn(_("remaining"))
5503 proutn(_("Remaining"))
5504 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5506 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5508 prout(_("Any warp speed is adequate."))
5510 prout(_("Minimum warp needed is %.2f,") % (twarp))
5511 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5512 if game.state.remtime < ttime:
5513 prout(_("Unfortunately, the Federation will be destroyed by then."))
5515 prout(_("You'll be taking risks at that speed, Captain"))
5516 if (game.isatb==1 and game.state.kscmdr == w1 and \
5517 scheduled(FSCDBAS)< ttime+game.state.date) or \
5518 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5519 prout(_("The starbase there will be destroyed by then."))
5520 proutn(_("New warp factor to try? "))
5521 if scanner.nexttok() == "IHREAL":
5523 twarp = scanner.real
5524 if twarp<1.0 or twarp > 10.0:
5532 # Code from setup.c begins here
5535 "Issue a historically correct banner."
5537 prout(_("-SUPER- STAR TREK"))
5539 # From the FORTRAN original
5540 # prout(_("Latest update-21 Sept 78"))
5546 scanner.push("emsave.trk")
5547 key = scanner.nexttok()
5549 proutn(_("File name: "))
5550 key = scanner.nexttok()
5551 if key != "IHALPHA":
5554 if '.' not in scanner.token:
5555 scanner.token += ".trk"
5557 fp = open(scanner.token, "wb")
5559 prout(_("Can't freeze game as file %s") % scanner.token)
5561 pickle.dump(game, fp)
5566 "Retrieve saved game."
5569 key = scanner.nexttok()
5571 proutn(_("File name: "))
5572 key = scanner.nexttok()
5573 if key != "IHALPHA":
5576 if '.' not in scanner.token:
5577 scanner.token += ".trk"
5579 fp = open(scanner.token, "rb")
5581 prout(_("Can't thaw game in %s") % scanner.token)
5583 game = pickle.load(fp)
5588 # I used <http://www.memory-alpha.org> to find planets
5589 # with references in ST:TOS. Earth and the Alpha Centauri
5590 # Colony have been omitted.
5592 # Some planets marked Class G and P here will be displayed as class M
5593 # because of the way planets are generated. This is a known bug.
5596 _("Andoria (Fesoan)"), # several episodes
5597 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5598 _("Vulcan (T'Khasi)"), # many episodes
5599 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5600 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5601 _("Ardana"), # TOS: "The Cloud Minders"
5602 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5603 _("Gideon"), # TOS: "The Mark of Gideon"
5604 _("Aldebaran III"), # TOS: "The Deadly Years"
5605 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5606 _("Altair IV"), # TOS: "Amok Time
5607 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5608 _("Benecia"), # TOS: "The Conscience of the King"
5609 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5610 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5611 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5612 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5613 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5614 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5615 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5616 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5617 _("Ingraham B"), # TOS: "Operation: Annihilate"
5618 _("Janus IV"), # TOS: "The Devil in the Dark"
5619 _("Makus III"), # TOS: "The Galileo Seven"
5620 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5621 _("Omega IV"), # TOS: "The Omega Glory"
5622 _("Regulus V"), # TOS: "Amok Time
5623 _("Deneva"), # TOS: "Operation -- Annihilate!"
5624 # Worlds from BSD Trek
5625 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5626 _("Beta III"), # TOS: "The Return of the Archons"
5627 _("Triacus"), # TOS: "And the Children Shall Lead",
5628 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5630 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5631 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5632 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5633 # _("Izar"), # TOS: "Whom Gods Destroy"
5634 # _("Tiburon"), # TOS: "The Way to Eden"
5635 # _("Merak II"), # TOS: "The Cloud Minders"
5636 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5637 # _("Iotia"), # TOS: "A Piece of the Action"
5641 _("S. R. Sensors"), \
5642 _("L. R. Sensors"), \
5644 _("Photon Tubes"), \
5645 _("Life Support"), \
5646 _("Warp Engines"), \
5647 _("Impulse Engines"), \
5649 _("Subspace Radio"), \
5650 _("Shuttle Craft"), \
5652 _("Navigation System"), \
5654 _("Shield Control"), \
5657 _("Cloaking Device"), \
5661 "Prepare to play, set up cosmos."
5663 # Decide how many of everything
5665 return # frozen game
5666 # Prepare the Enterprise
5667 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5669 game.state.crew = FULLCREW
5670 game.energy = game.inenrg = 5000.0
5671 game.shield = game.inshld = 2500.0
5674 game.quadrant = randplace(GALSIZE)
5675 game.sector = randplace(QUADSIZE)
5676 game.torps = game.intorps = 10
5677 game.nprobes = randrange(2, 5)
5679 for i in range(NDEVICES):
5680 game.damage[i] = 0.0
5681 # Set up assorted game parameters
5682 game.battle = Coord()
5683 game.state.date = game.indate = 100.0 * randreal(20, 51)
5684 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5685 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5686 game.isatb = game.state.nplankl = 0
5687 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5688 game.iscraft = "onship"
5693 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5695 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5697 game.state.planets = [] # Planet information
5698 game.state.baseq = [] # Base quadrant coordinates
5699 game.state.kcmdr = [] # Commander quadrant coordinates
5700 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5702 # Starchart is functional but we've never seen it
5703 game.lastchart = FOREVER
5704 # Put stars in the galaxy
5706 for i in range(GALSIZE):
5707 for j in range(GALSIZE):
5708 # Can't have more stars per quadrant than fit in one decimal digit,
5709 # if we do the chart representation will break.
5710 k = randrange(1, min(10, QUADSIZE**2/10))
5712 game.state.galaxy[i][j].stars = k
5713 # Locate star bases in galaxy
5715 prout("=== Allocating %d bases" % game.inbase)
5716 for i in range(game.inbase):
5719 w = randplace(GALSIZE)
5720 if not game.state.galaxy[w.i][w.j].starbase:
5723 # C version: for (j = i-1; j > 0; j--)
5724 # so it did them in the opposite order.
5725 for j in range(1, i):
5726 # Improved placement algorithm to spread out bases
5727 distq = (w - game.state.baseq[j]).distance()
5728 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5731 prout("=== Abandoning base #%d at %s" % (i, w))
5733 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5735 prout("=== Saving base #%d, close to #%d" % (i, j))
5739 prout("=== Placing base #%d in quadrant %s" % (i, w))
5740 game.state.baseq.append(w)
5741 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5742 # Position ordinary Klingon Battle Cruisers
5744 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5745 if klumper > MAXKLQUAD:
5749 klump = (1.0 - r*r)*klumper
5754 w = randplace(GALSIZE)
5755 if not game.state.galaxy[w.i][w.j].supernova and \
5756 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5758 game.state.galaxy[w.i][w.j].klingons += int(klump)
5761 # Position Klingon Commander Ships
5762 for i in range(game.incom):
5764 w = randplace(GALSIZE)
5765 if not welcoming(w) or w in game.state.kcmdr:
5767 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5769 game.state.galaxy[w.i][w.j].klingons += 1
5770 game.state.kcmdr.append(w)
5771 # Locate planets in galaxy
5772 for i in range(game.inplan):
5774 w = randplace(GALSIZE)
5775 if game.state.galaxy[w.i][w.j].planet is None:
5779 new.crystals = "absent"
5780 if (game.options & OPTION_WORLDS) and i < NINHAB:
5781 new.pclass = "M" # All inhabited planets are class M
5782 new.crystals = "absent"
5784 new.name = systnames[i]
5785 new.inhabited = True
5787 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5789 new.crystals = "present"
5790 new.known = "unknown"
5791 new.inhabited = False
5792 game.state.galaxy[w.i][w.j].planet = new
5793 game.state.planets.append(new)
5795 for i in range(game.state.nromrem):
5796 w = randplace(GALSIZE)
5797 game.state.galaxy[w.i][w.j].romulans += 1
5798 # Place the Super-Commander if needed
5799 if game.state.nscrem > 0:
5801 w = randplace(GALSIZE)
5804 game.state.kscmdr = w
5805 game.state.galaxy[w.i][w.j].klingons += 1
5806 # Initialize times for extraneous events
5807 schedule(FSNOVA, expran(0.5 * game.intime))
5808 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5809 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5810 schedule(FBATTAK, expran(0.3*game.intime))
5812 if game.state.nscrem:
5813 schedule(FSCMOVE, 0.2777)
5818 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5819 schedule(FDISTR, expran(1.0 + game.intime))
5824 # Place thing (in tournament game, we don't want one!)
5825 # New in SST2K: never place the Thing near a starbase.
5826 # This makes sense and avoids a special case in the old code.
5828 if game.tourn is None:
5830 thing = randplace(GALSIZE)
5831 if thing not in game.state.baseq:
5834 game.state.snap = False
5835 if game.skill == SKILL_NOVICE:
5836 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5837 prout(_("a deadly Klingon invasion force. As captain of the United"))
5838 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5839 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5840 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5841 prout(_("your mission. As you proceed you may be given more time."))
5843 prout(_("You will have %d supporting starbases.") % (game.inbase))
5844 proutn(_("Starbase locations- "))
5846 prout(_("Stardate %d.") % int(game.state.date))
5848 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5849 prout(_("An unknown number of Romulans."))
5850 if game.state.nscrem:
5851 prout(_("And one (GULP) Super-Commander."))
5852 prout(_("%d stardates.") % int(game.intime))
5853 proutn(_("%d starbases in ") % game.inbase)
5854 for i in range(game.inbase):
5855 proutn(repr(game.state.baseq[i]))
5858 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5859 proutn(_(" Sector %s") % game.sector)
5861 prout(_("Good Luck!"))
5862 if game.state.nscrem:
5863 prout(_(" YOU'LL NEED IT."))
5866 setwnd(message_window)
5868 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5870 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5871 attack(torps_ok=False)
5874 "Choose your game type."
5876 game.tourn = game.length = 0
5878 game.skill = SKILL_NONE
5879 # Do not chew here, we want to use command-line tokens
5880 if not scanner.inqueue: # Can start with command line options
5881 proutn(_("Would you like a regular, tournament, or saved game? "))
5883 if scanner.sees("tournament"):
5884 while scanner.nexttok() == "IHEOL":
5885 proutn(_("Type in tournament number-"))
5886 if scanner.real == 0:
5888 continue # We don't want a blank entry
5889 game.tourn = int(round(scanner.real))
5890 random.seed(scanner.real)
5892 logfp.write("# random.seed(%d)\n" % scanner.real)
5894 if scanner.sees("saved") or scanner.sees("frozen"):
5898 if game.passwd is None:
5900 if not game.alldone:
5901 game.thawed = True # No plaque if not finished
5905 if scanner.sees("regular"):
5907 proutn(_("What is \"%s\"? ") % scanner.token)
5909 while game.length==0 or game.skill==SKILL_NONE:
5910 if scanner.nexttok() == "IHALPHA":
5911 if scanner.sees("short"):
5913 elif scanner.sees("medium"):
5915 elif scanner.sees("long"):
5917 elif scanner.sees("novice"):
5918 game.skill = SKILL_NOVICE
5919 elif scanner.sees("fair"):
5920 game.skill = SKILL_FAIR
5921 elif scanner.sees("good"):
5922 game.skill = SKILL_GOOD
5923 elif scanner.sees("expert"):
5924 game.skill = SKILL_EXPERT
5925 elif scanner.sees("emeritus"):
5926 game.skill = SKILL_EMERITUS
5928 proutn(_("What is \""))
5929 proutn(scanner.token)
5934 proutn(_("Would you like a Short, Medium, or Long game? "))
5935 elif game.skill == SKILL_NONE:
5936 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5937 # Choose game options -- added by ESR for SST2K
5938 if scanner.nexttok() != "IHALPHA":
5940 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5942 if scanner.sees("plain"):
5943 # Approximates the UT FORTRAN version.
5944 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)
5945 game.options |= OPTION_PLAIN
5946 elif scanner.sees("almy"):
5947 # Approximates Tom Almy's version.
5948 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
5949 game.options |= OPTION_ALMY
5950 elif scanner.sees("fancy") or scanner.sees("\n"):
5952 elif len(scanner.token):
5953 proutn(_("What is \"%s\"?") % scanner.token)
5955 if game.passwd == "debug":
5957 prout("=== Debug mode enabled.")
5958 # Use parameters to generate initial values of things
5959 game.damfac = 0.5 * game.skill
5960 game.inbase = randrange(BASEMIN, BASEMAX+1)
5962 if game.options & OPTION_PLANETS:
5963 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5964 if game.options & OPTION_WORLDS:
5965 game.inplan += int(NINHAB)
5966 game.state.nromrem = game.inrom = randrange(2 * game.skill)
5967 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5968 game.state.remtime = 7.0 * game.length
5969 game.intime = game.state.remtime
5970 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5971 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5972 game.state.remres = (game.inkling+4*game.incom)*game.intime
5973 game.inresor = game.state.remres
5974 if game.inkling > 50:
5978 def dropin(iquad=None):
5979 "Drop a feature on a random dot in the current quadrant."
5981 w = randplace(QUADSIZE)
5982 if game.quad[w.i][w.j] == '.':
5984 if iquad is not None:
5985 game.quad[w.i][w.j] = iquad
5989 "Update our alert status."
5990 game.condition = "green"
5991 if game.energy < 1000.0:
5992 game.condition = "yellow"
5993 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5994 game.condition = "red"
5996 game.condition="dead"
5999 "Drop new Klingon into current quadrant."
6000 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
6003 "Sort enemies by distance so 'nearest' is meaningful."
6004 game.enemies.sort(key=lambda x: x.kdist)
6007 "Set up a new state of quadrant, for when we enter or re-enter it."
6010 game.neutz = game.inorbit = game.landed = False
6011 game.ientesc = game.iseenit = game.isviolreported = False
6012 # Create a blank quadrant
6013 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
6015 # Attempt to escape Super-commander, so tbeam back!
6018 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
6019 # cope with supernova
6022 game.klhere = q.klingons
6023 game.irhere = q.romulans
6025 game.quad[game.sector.i][game.sector.j] = game.ship
6028 # Position ordinary Klingons
6029 for _i in range(game.klhere):
6031 # If we need a commander, promote a Klingon
6032 for cmdr in game.state.kcmdr:
6033 if cmdr == game.quadrant:
6034 e = game.enemies[game.klhere-1]
6035 game.quad[e.location.i][e.location.j] = 'C'
6036 e.power = randreal(950,1350) + 50.0*game.skill
6038 # If we need a super-commander, promote a Klingon
6039 if game.quadrant == game.state.kscmdr:
6041 game.quad[e.location.i][e.location.j] = 'S'
6042 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
6043 game.iscate = (game.state.remkl > 1)
6044 # Put in Romulans if needed
6045 for _i in range(q.romulans):
6046 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
6047 # If quadrant needs a starbase, put it in
6049 game.base = dropin('B')
6050 # If quadrant needs a planet, put it in
6052 game.iplnet = q.planet
6053 if not q.planet.inhabited:
6054 game.plnet = dropin('P')
6056 game.plnet = dropin('@')
6057 # Check for condition
6060 if game.irhere > 0 and game.klhere == 0:
6062 if not damaged(DRADIO):
6064 prout(_("LT. Uhura- \"Captain, an urgent message."))
6065 prout(_(" I'll put it on audio.\" CLICK"))
6067 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
6068 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
6069 # Put in THING if needed
6070 if thing == game.quadrant:
6071 Enemy(etype='?', loc=dropin(),
6072 power=randreal(6000,6500.0)+250.0*game.skill)
6073 if not damaged(DSRSENS):
6075 prout(_("Mr. Spock- \"Captain, this is most unusual."))
6076 prout(_(" Please examine your short-range scan.\""))
6077 # Decide if quadrant needs a Tholian; lighten up if skill is low
6078 if game.options & OPTION_THOLIAN:
6079 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
6080 (game.skill == SKILL_GOOD and withprob(0.05)) or \
6081 (game.skill > SKILL_GOOD and withprob(0.08)):
6084 w.i = withprob(0.5) * (QUADSIZE-1)
6085 w.j = withprob(0.5) * (QUADSIZE-1)
6086 if game.quad[w.i][w.j] == '.':
6088 game.tholian = Enemy(etype='T', loc=w,
6089 power=randrange(100, 500) + 25.0*game.skill)
6090 # Reserve unoccupied corners
6091 if game.quad[0][0]=='.':
6092 game.quad[0][0] = 'X'
6093 if game.quad[0][QUADSIZE-1]=='.':
6094 game.quad[0][QUADSIZE-1] = 'X'
6095 if game.quad[QUADSIZE-1][0]=='.':
6096 game.quad[QUADSIZE-1][0] = 'X'
6097 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
6098 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
6100 # And finally the stars
6101 for _i in range(q.stars):
6103 # Put in a few black holes
6104 for _i in range(1, 3+1):
6107 # Take out X's in corners if Tholian present
6109 if game.quad[0][0]=='X':
6110 game.quad[0][0] = '.'
6111 if game.quad[0][QUADSIZE-1]=='X':
6112 game.quad[0][QUADSIZE-1] = '.'
6113 if game.quad[QUADSIZE-1][0]=='X':
6114 game.quad[QUADSIZE-1][0] = '.'
6115 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
6116 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
6119 "Set the self-destruct password."
6120 if game.options & OPTION_PLAIN:
6123 proutn(_("Please type in a secret password- "))
6125 game.passwd = scanner.token
6126 if game.passwd != None:
6130 game.passwd += chr(ord('a')+randrange(26))
6131 game.passwd += chr(ord('a')+randrange(26))
6132 game.passwd += chr(ord('a')+randrange(26))
6134 # Code from sst.c begins here
6137 ("SRSCAN", OPTION_TTY),
6138 ("STATUS", OPTION_TTY),
6139 ("REQUEST", OPTION_TTY),
6140 ("LRSCAN", OPTION_TTY),
6152 ("SENSORS", OPTION_PLANETS),
6153 ("ORBIT", OPTION_PLANETS),
6154 ("TRANSPORT", OPTION_PLANETS),
6155 ("MINE", OPTION_PLANETS),
6156 ("CRYSTALS", OPTION_PLANETS),
6157 ("SHUTTLE", OPTION_PLANETS),
6158 ("PLANETS", OPTION_PLANETS),
6163 ("PROBE", OPTION_PROBE),
6165 ("FREEZE", 0), # Synonym for SAVE
6169 ("CAPTURE", OPTION_CAPTURE),
6170 ("CLOAK", OPTION_CLOAK),
6173 ("SOS", 0), # Synonym for MAYDAY
6174 ("CALL", 0), # Synonym for MAYDAY
6182 "Generate a list of legal commands."
6183 prout(_("LEGAL COMMANDS ARE:"))
6185 for (key, opt) in commands:
6186 if not opt or (opt & game.options):
6187 proutn("%-12s " % key)
6189 if emitted % 5 == 4:
6194 "Browse on-line help."
6195 key = scanner.nexttok()
6198 setwnd(prompt_window)
6199 proutn(_("Help on what command? "))
6200 key = scanner.nexttok()
6201 setwnd(message_window)
6204 cmds = [x[0] for x in commands]
6205 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
6212 cmd = scanner.token.upper()
6213 for directory in docpath:
6215 fp = open(os.path.join(directory, "sst.doc"), "r")
6220 prout(_("Spock- \"Captain, that information is missing from the"))
6221 prout(_(" computer. You need to find sst.doc and put it somewhere"))
6222 proutn(_(" in these directories: %s") % ":".join(docpath))
6224 # This used to continue: "You need to find SST.DOC and put
6225 # it in the current directory."
6228 linebuf = fp.readline()
6230 prout(_("Spock- \"Captain, there is no information on that command.\""))
6233 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
6234 linebuf = linebuf[3:].strip()
6235 if cmd.upper() == linebuf:
6238 prout(_("Spock- \"Captain, I've found the following information:\""))
6241 linebuf = fp.readline()
6242 if "******" in linebuf:
6248 "Command-interpretation loop."
6250 if game.irhere and game.state.date >= ALGERON and not game.isviolreported and game.iscloaked:
6251 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
6253 game.isviolreported = True
6254 while True: # command loop
6256 while True: # get a command
6258 game.optime = game.justin = False
6260 setwnd(prompt_window)
6263 if scanner.nexttok() == "IHEOL":
6264 if game.options & OPTION_CURSES:
6267 elif scanner.token == "":
6271 setwnd(message_window)
6273 abandon_passed = False
6274 cmd = "" # Force cmd to persist after loop
6275 opt = 0 # Force opt to persist after loop
6276 for (cmd, opt) in commands:
6277 # commands after ABANDON cannot be abbreviated
6278 if cmd == "ABANDON":
6279 abandon_passed = True
6280 if cmd == scanner.token.upper() or (not abandon_passed \
6281 and cmd.startswith(scanner.token.upper())):
6286 elif opt and not (opt & game.options):
6290 if game.options & OPTION_CURSES:
6291 prout("COMMAND> %s" % cmd)
6292 if cmd == "SRSCAN": # srscan
6294 elif cmd == "STATUS": # status
6296 elif cmd == "REQUEST": # status request
6298 elif cmd == "LRSCAN": # long range scan
6299 lrscan(silent=False)
6300 elif cmd == "PHASERS": # phasers
6305 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6310 elif cmd == "MOVE": # move under warp
6311 warp(wcourse=None, involuntary=False)
6312 elif cmd == "SHIELDS": # shields
6313 doshield(shraise=False)
6316 game.shldchg = False
6317 elif cmd == "DOCK": # dock at starbase
6320 attack(torps_ok=False)
6321 elif cmd == "DAMAGES": # damage reports
6323 elif cmd == "CHART": # chart
6325 elif cmd == "IMPULSE": # impulse
6327 elif cmd == "REST": # rest
6331 elif cmd == "WARP": # warp
6333 elif cmd == "SENSORS": # sensors
6335 elif cmd == "ORBIT": # orbit
6339 elif cmd == "TRANSPORT": # transport "beam"
6341 elif cmd == "MINE": # mine
6345 elif cmd == "CRYSTALS": # crystals
6349 elif cmd == "SHUTTLE": # shuttle
6353 elif cmd == "PLANETS": # Planet list
6355 elif cmd == "REPORT": # Game Report
6357 elif cmd == "COMPUTER": # use COMPUTER!
6359 elif cmd == "COMMANDS":
6361 elif cmd == "EMEXIT": # Emergency exit
6362 clrscr() # Hide screen
6363 freeze(True) # forced save
6364 raise SystemExit(1) # And quick exit
6365 elif cmd == "PROBE":
6366 probe() # Launch probe
6369 elif cmd == "ABANDON": # Abandon Ship
6371 elif cmd == "DESTRUCT": # Self Destruct
6373 elif cmd == "SAVE": # Save Game
6376 if game.skill > SKILL_GOOD:
6377 prout(_("WARNING--Saved games produce no plaques!"))
6378 elif cmd == "DEATHRAY": # Try a desparation measure
6382 elif cmd == "CAPTURE":
6384 elif cmd == "CLOAK":
6386 elif cmd == "DEBUGCMD": # What do we want for debug???
6388 elif cmd == "MAYDAY": # Call for help
6393 game.alldone = True # quit the game
6396 elif cmd == "SCORE":
6397 score() # see current score
6400 break # Game has ended
6401 if game.optime != 0.0:
6404 break # Events did us in
6405 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6408 if hitme and not game.justin:
6409 attack(torps_ok=True)
6412 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6423 "Emit the name of an enemy or feature."
6424 if ch == 'R': s = _("Romulan")
6425 elif ch == 'K': s = _("Klingon")
6426 elif ch == 'C': s = _("Commander")
6427 elif ch == 'S': s = _("Super-commander")
6428 elif ch == '*': s = _("Star")
6429 elif ch == 'P': s = _("Planet")
6430 elif ch == 'B': s = _("Starbase")
6431 elif ch == ' ': s = _("Black hole")
6432 elif ch == 'T': s = _("Tholian")
6433 elif ch == '#': s = _("Tholian web")
6434 elif ch == '?': s = _("Stranger")
6435 elif ch == '@': s = _("Inhabited World")
6436 else: s = "Unknown??"
6439 def crmena(loud, enemy, loctype, w):
6440 "Emit the name of an enemy and his location."
6444 buf += cramen(enemy) + _(" at ")
6445 if loctype == "quadrant":
6446 buf += _("Quadrant ")
6447 elif loctype == "sector":
6449 return buf + repr(w)
6452 "Emit our ship name."
6453 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6456 "Emit a line of stars"
6457 prouts("******************************************************")
6461 return -avrage*math.log(1e-7 + randreal())
6463 def randplace(size):
6464 "Choose a random location."
6466 w.i = randrange(size)
6467 w.j = randrange(size)
6477 # Get a token from the user
6480 # Fill the token quue if nothing here
6481 while not self.inqueue:
6483 if curwnd==prompt_window:
6485 setwnd(message_window)
6492 self.inqueue = sline.lstrip().split() + ["\n"]
6493 # From here on in it's all looking at the queue
6494 self.token = self.inqueue.pop(0)
6495 if self.token == "\n":
6499 self.real = float(self.token)
6500 self.type = "IHREAL"
6505 self.token = self.token.lower()
6506 self.type = "IHALPHA"
6509 def append(self, tok):
6510 self.inqueue.append(tok)
6511 def push(self, tok):
6512 self.inqueue.insert(0, tok)
6516 # Demand input for next scan
6518 self.real = self.token = None
6520 # compares s to item and returns true if it matches to the length of s
6521 return s.startswith(self.token)
6523 # Round token value to nearest integer
6524 return int(round(self.real))
6528 if self.type != "IHREAL":
6533 if self.type != "IHREAL":
6539 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6542 "Yes-or-no confirmation."
6546 if scanner.token == 'y':
6548 if scanner.token == 'n':
6551 proutn(_("Please answer with \"y\" or \"n\": "))
6554 "Complain about unparseable input."
6557 prout(_("Beg your pardon, Captain?"))
6560 "Access to the internals for debugging."
6561 proutn("Reset levels? ")
6563 if game.energy < game.inenrg:
6564 game.energy = game.inenrg
6565 game.shield = game.inshld
6566 game.torps = game.intorps
6567 game.lsupres = game.inlsr
6568 proutn("Reset damage? ")
6570 for i in range(NDEVICES):
6571 if game.damage[i] > 0.0:
6572 game.damage[i] = 0.0
6573 proutn("Toggle debug flag? ")
6575 game.idebug = not game.idebug
6577 prout("Debug output ON")
6579 prout("Debug output OFF")
6580 proutn("Cause selective damage? ")
6582 for i in range(NDEVICES):
6583 proutn("Kill %s?" % device[i])
6585 key = scanner.nexttok()
6586 if key == "IHALPHA" and scanner.sees("y"):
6587 game.damage[i] = 10.0
6588 proutn("Examine/change events? ")
6593 FSNOVA: "Supernova ",
6596 FBATTAK: "Base Attack ",
6597 FCDBAS: "Base Destroy ",
6598 FSCMOVE: "SC Move ",
6599 FSCDBAS: "SC Base Destroy ",
6600 FDSPROB: "Probe Move ",
6601 FDISTR: "Distress Call ",
6602 FENSLV: "Enslavement ",
6603 FREPRO: "Klingon Build ",
6605 for i in range(1, NEVENTS):
6608 proutn("%.2f" % (scheduled(i)-game.state.date))
6609 if i == FENSLV or i == FREPRO:
6611 proutn(" in %s" % ev.quadrant)
6616 key = scanner.nexttok()
6620 elif key == "IHREAL":
6621 ev = schedule(i, scanner.real)
6622 if i == FENSLV or i == FREPRO:
6624 proutn("In quadrant- ")
6625 key = scanner.nexttok()
6626 # "IHEOL" says to leave coordinates as they are
6629 prout("Event %d canceled, no x coordinate." % (i))
6632 w.i = int(round(scanner.real))
6633 key = scanner.nexttok()
6635 prout("Event %d canceled, no y coordinate." % (i))
6638 w.j = int(round(scanner.real))
6641 proutn("Induce supernova here? ")
6643 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6646 if __name__ == '__main__':
6648 #global line, thing, game
6652 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6653 if os.getenv("TERM"):
6654 game.options |= OPTION_CURSES
6656 game.options |= OPTION_TTY
6657 seed = int(time.time())
6658 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6660 for (switch, val) in options:
6663 replayfp = open(val, "r")
6665 sys.stderr.write("sst: can't open replay file %s\n" % val)
6668 line = replayfp.readline().strip()
6669 (leader, __, seed) = line.split()
6671 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6672 line = replayfp.readline().strip()
6673 arguments += line.split()[2:]
6676 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6678 game.options |= OPTION_TTY
6679 game.options &=~ OPTION_CURSES
6680 elif switch == '-s':
6682 elif switch == '-t':
6683 game.options |= OPTION_TTY
6684 game.options &=~ OPTION_CURSES
6685 elif switch == '-x':
6687 elif switch == '-V':
6688 print("SST2K", version)
6691 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6693 # where to save the input in case of bugs
6694 if "TMPDIR" in os.environ:
6695 tmpdir = os.environ['TMPDIR']
6699 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6701 sys.stderr.write("sst: warning, can't open logfile\n")
6704 logfp.write("# seed %s\n" % seed)
6705 logfp.write("# options %s\n" % " ".join(arguments))
6706 logfp.write("# SST2K version %s\n" % version)
6707 logfp.write("# recorded by %s@%s on %s\n" % \
6708 (getpass.getuser(),socket.gethostname(),time.ctime()))
6710 scanner = sstscanner()
6711 for arg in arguments:
6715 while True: # Play a game
6716 setwnd(fullscreen_window)
6722 game.alldone = False
6730 if game.tourn and game.alldone:
6731 proutn(_("Do you want your score recorded?"))
6737 proutn(_("Do you want to play again? "))
6741 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6745 except KeyboardInterrupt: