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()
4019 delta.j = scanner.real
4020 key = scanner.nexttok()
4024 delta.i = scanner.real
4025 # Check for zero movement
4026 if delta.i == 0 and delta.j == 0:
4029 if itemp == "verbose" and not isprobe:
4031 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
4033 return course(bearing=delta.bearing(), distance=delta.distance())
4036 def __init__(self, bearing, distance, origin=None):
4037 self.distance = distance
4038 self.bearing = bearing
4040 self.origin = cartesian(game.quadrant, game.sector)
4042 self.origin = origin
4043 # The bearing() code we inherited from FORTRAN is actually computing
4044 # clockface directions!
4045 if self.bearing < 0.0:
4046 self.bearing += 12.0
4047 self.angle = ((15.0 - self.bearing) * 0.5235988)
4048 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
4049 bigger = max(abs(self.increment.i), abs(self.increment.j))
4050 self.increment /= bigger
4051 self.moves = int(round(10*self.distance*bigger))
4053 self.final = (self.location + self.moves*self.increment).roundtogrid()
4054 self.location = self.origin
4055 self.nextlocation = None
4057 self.location = self.origin
4060 return self.location.roundtogrid() == self.final
4062 "Next step on course."
4064 self.nextlocation = self.location + self.increment
4065 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
4066 self.location = self.nextlocation
4069 return self.location.quadrant()
4071 return self.location.sector()
4073 return self.distance*(w**3)*(game.shldup+1)
4075 return 10.0*self.distance/w**2
4078 "Move under impulse power."
4080 if damaged(DIMPULS):
4083 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4085 if game.energy > 30.0:
4087 icourse = getcourse(isprobe=False)
4090 power = 20.0 + 100.0*icourse.distance
4093 if power >= game.energy:
4094 # Insufficient power for trip
4096 prout(_("First Officer Spock- \"Captain, the impulse engines"))
4097 prout(_("require 20.0 units to engage, plus 100.0 units per"))
4098 if game.energy > 30:
4099 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
4100 int(0.01 * (game.energy-20.0)-0.05))
4101 prout(_(" quadrants.\""))
4103 prout(_("quadrant. They are, therefore, useless.\""))
4106 # Make sure enough time is left for the trip
4107 game.optime = icourse.distance/0.095
4108 if game.optime >= game.state.remtime:
4109 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
4110 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
4111 proutn(_("we dare spend the time?\" "))
4114 # Activate impulse engines and pay the cost
4115 imove(icourse, noattack=False)
4119 power = 20.0 + 100.0*icourse.distance
4120 game.energy -= power
4121 game.optime = icourse.distance/0.095
4122 if game.energy <= 0:
4126 def warp(wcourse, involuntary):
4127 "ove under warp drive."
4128 blooey = False; twarp = False
4129 if not involuntary: # Not WARPX entry
4134 prout(_("Engineer Scott- \"The warp engines can not be used while cloaked, Sir.\""))
4136 if game.damage[DWARPEN] > 10.0:
4139 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
4141 if damaged(DWARPEN) and game.warpfac > 4.0:
4144 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4145 prout(_(" is repaired, I can only give you warp 4.\""))
4147 # Read in course and distance
4150 wcourse = getcourse(isprobe=False)
4153 # Make sure starship has enough energy for the trip
4154 # Note: this formula is slightly different from the C version,
4155 # and lets you skate a bit closer to the edge.
4156 if wcourse.power(game.warpfac) >= game.energy:
4157 # Insufficient power for trip
4160 prout(_("Engineering to bridge--"))
4161 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
4162 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
4164 prout(_("We can't do it, Captain. We don't have enough energy."))
4166 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4169 prout(_("if you'll lower the shields."))
4173 prout(_("We haven't the energy to go that far with the shields up."))
4175 # Make sure enough time is left for the trip
4176 game.optime = wcourse.time(game.warpfac)
4177 if game.optime >= 0.8*game.state.remtime:
4179 prout(_("First Officer Spock- \"Captain, I compute that such"))
4180 proutn(_(" a trip would require approximately %2.0f") %
4181 (100.0*game.optime/game.state.remtime))
4182 prout(_(" percent of our"))
4183 proutn(_(" remaining time. Are you sure this is wise?\" "))
4189 if game.warpfac > 6.0:
4190 # Decide if engine damage will occur
4191 # ESR: Seems wrong. Probability of damage goes *down* with distance?
4192 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
4193 if prob > randreal():
4195 wcourse.distance = randreal(wcourse.distance)
4196 # Decide if time warp will occur
4197 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
4199 if game.idebug and game.warpfac==10 and not twarp:
4201 proutn("=== Force time warp? ")
4205 # If time warp or engine damage, check path
4206 # If it is obstructed, don't do warp or damage
4207 look = wcourse.moves
4211 w = wcourse.sector()
4212 if not w.valid_sector():
4214 if game.quad[w.i][w.j] != '.':
4218 # Activate Warp Engines and pay the cost
4219 imove(wcourse, noattack=False)
4222 game.energy -= wcourse.power(game.warpfac)
4223 if game.energy <= 0:
4225 game.optime = wcourse.time(game.warpfac)
4229 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4231 prout(_("Engineering to bridge--"))
4232 prout(_(" Scott here. The warp engines are damaged."))
4233 prout(_(" We'll have to reduce speed to warp 4."))
4238 "Change the warp factor."
4240 key=scanner.nexttok()
4244 proutn(_("Warp factor- "))
4248 if game.damage[DWARPEN] > 10.0:
4249 prout(_("Warp engines inoperative."))
4251 if damaged(DWARPEN) and scanner.real > 4.0:
4252 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4253 prout(_(" but right now we can only go warp 4.\""))
4255 if scanner.real > 10.0:
4256 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4258 if scanner.real < 1.0:
4259 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4261 oldfac = game.warpfac
4262 game.warpfac = scanner.real
4263 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4264 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4267 if game.warpfac < 8.00:
4268 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4270 if game.warpfac == 10.0:
4271 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4273 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4277 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4279 # is captain on planet?
4281 if damaged(DTRANSP):
4284 prout(_("Scotty rushes to the transporter controls."))
4286 prout(_("But with the shields up it's hopeless."))
4288 prouts(_("His desperate attempt to rescue you . . ."))
4293 prout(_("SUCCEEDS!"))
4296 proutn(_("The crystals mined were "))
4304 # Check to see if captain in shuttle craft
4309 # Inform captain of attempt to reach safety
4313 prouts(_("***RED ALERT! RED ALERT!"))
4315 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4316 prouts(_(" a supernova."))
4318 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4319 prout(_("safely out of quadrant."))
4320 if not damaged(DRADIO):
4321 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4322 # Try to use warp engines
4323 if damaged(DWARPEN):
4325 prout(_("Warp engines damaged."))
4328 game.warpfac = randreal(6.0, 8.0)
4329 prout(_("Warp factor set to %d") % int(game.warpfac))
4330 power = 0.75*game.energy
4331 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4332 dist = max(dist, randreal(math.sqrt(2)))
4333 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4334 game.optime = bugout.time(game.warpfac)
4336 game.inorbit = False
4337 warp(bugout, involuntary=True)
4339 # This is bad news, we didn't leave quadrant.
4343 prout(_("Insufficient energy to leave quadrant."))
4346 # Repeat if another snova
4347 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4350 finish(FWON) # Snova killed remaining enemy.
4353 "Let's do the time warp again."
4354 prout(_("***TIME WARP ENTERED."))
4355 if game.state.snap and withprob(0.5):
4357 prout(_("You are traveling backwards in time %d stardates.") %
4358 int(game.state.date-game.snapsht.date))
4359 game.state = game.snapsht
4360 game.state.snap = False
4361 if len(game.state.kcmdr):
4362 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4363 schedule(FBATTAK, expran(0.3*game.intime))
4364 schedule(FSNOVA, expran(0.5*game.intime))
4365 # next snapshot will be sooner
4366 schedule(FSNAP, expran(0.25*game.state.remtime))
4368 if game.state.nscrem:
4369 schedule(FSCMOVE, 0.2777)
4373 game.battle.invalidate()
4374 # Make sure Galileo is consistant -- Snapshot may have been taken
4375 # when on planet, which would give us two Galileos!
4377 for l in range(game.inplan):
4378 if game.state.planets[l].known == "shuttle_down":
4380 if game.iscraft == "onship" and game.ship=='E':
4381 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4382 game.iscraft = "offship"
4383 # Likewise, if in the original time the Galileo was abandoned, but
4384 # was on ship earlier, it would have vanished -- let's restore it.
4385 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4386 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4387 game.iscraft = "onship"
4388 # There used to be code to do the actual reconstrction here,
4389 # but the starchart is now part of the snapshotted galaxy state.
4390 prout(_("Spock has reconstructed a correct star chart from memory"))
4392 # Go forward in time
4393 game.optime = expran(0.5*game.intime)
4394 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4395 # cheat to make sure no tractor beams occur during time warp
4396 postpone(FTBEAM, game.optime)
4397 game.damage[DRADIO] += game.optime
4399 events() # Stas Sergeev added this -- do pending events
4402 "Launch deep-space probe."
4403 # New code to launch a deep space probe
4404 if game.nprobes == 0:
4407 if game.ship == 'E':
4408 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4410 prout(_("Ye Faerie Queene has no deep space probes."))
4415 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4417 if is_scheduled(FDSPROB):
4420 if damaged(DRADIO) and game.condition != "docked":
4421 prout(_("Spock- \"Records show the previous probe has not yet"))
4422 prout(_(" reached its destination.\""))
4424 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4426 key = scanner.nexttok()
4428 if game.nprobes == 1:
4429 prout(_("1 probe left."))
4431 prout(_("%d probes left") % game.nprobes)
4432 proutn(_("Are you sure you want to fire a probe? "))
4435 game.isarmed = False
4436 if key == "IHALPHA" and scanner.token == "armed":
4438 key = scanner.nexttok()
4439 elif key == "IHEOL":
4440 proutn(_("Arm NOVAMAX warhead? "))
4442 elif key == "IHREAL": # first element of course
4443 scanner.push(scanner.token)
4445 game.probe = getcourse(isprobe=True)
4449 schedule(FDSPROB, 0.01) # Time to move one sector
4450 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4455 "Yell for help from nearest starbase."
4456 # There's more than one way to move in this game!
4458 # Test for conditions which prevent calling for help
4459 if game.condition == "docked":
4460 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4463 prout(_("Subspace radio damaged."))
4465 if not game.state.baseq:
4466 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4469 prout(_("You must be aboard the %s.") % crmshp())
4471 # OK -- call for help from nearest starbase
4474 # There's one in this quadrant
4475 ddist = (game.base - game.sector).distance()
4477 ibq = None # Force base-quadrant game to persist past loop
4479 for ibq in game.state.baseq:
4480 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4484 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4486 # Since starbase not in quadrant, set up new quadrant
4489 # dematerialize starship
4490 game.quad[game.sector.i][game.sector.j]='.'
4491 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4492 % (game.quadrant, crmshp()))
4493 game.sector.invalidate()
4494 for m in range(1, 5+1):
4495 w = game.base.scatter()
4496 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4497 # found one -- finish up
4500 if not game.sector.is_valid():
4501 prout(_("You have been lost in space..."))
4502 finish(FMATERIALIZE)
4504 # Give starbase three chances to rematerialize starship
4505 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4506 for m in range(1, 3+1):
4507 if m == 1: proutn(_("1st"))
4508 elif m == 2: proutn(_("2nd"))
4509 elif m == 3: proutn(_("3rd"))
4510 proutn(_(" attempt to re-materialize ") + crmshp())
4511 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4514 if randreal() > probf:
4518 curses.delay_output(500)
4520 game.quad[game.sector.i][game.sector.j]='?'
4523 setwnd(message_window)
4524 finish(FMATERIALIZE)
4526 game.quad[game.sector.i][game.sector.j]=game.ship
4528 prout(_("succeeds."))
4532 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4537 if game.condition=="docked":
4539 prout(_("You cannot abandon Ye Faerie Queene."))
4542 # Must take shuttle craft to exit
4543 if game.damage[DSHUTTL]==-1:
4544 prout(_("Ye Faerie Queene has no shuttle craft."))
4546 if game.damage[DSHUTTL]<0:
4547 prout(_("Shuttle craft now serving Big Macs."))
4549 if game.damage[DSHUTTL]>0:
4550 prout(_("Shuttle craft damaged."))
4553 prout(_("You must be aboard the ship."))
4555 if game.iscraft != "onship":
4556 prout(_("Shuttle craft not currently available."))
4558 # Emit abandon ship messages
4560 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4562 prouts(_("***ALL HANDS ABANDON SHIP!"))
4564 prout(_("Captain and crew escape in shuttle craft."))
4565 if not game.state.baseq:
4566 # Oops! no place to go...
4569 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4571 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4572 prout(_("Remainder of ship's complement beam down"))
4573 prout(_("to nearest habitable planet."))
4574 elif q.planet != None and not damaged(DTRANSP):
4575 prout(_("Remainder of ship's complement beam down to %s.") %
4578 prout(_("Entire crew of %d left to die in outer space.") %
4580 game.casual += game.state.crew
4581 game.abandoned += game.state.crew
4582 # If at least one base left, give 'em the Faerie Queene
4584 game.icrystl = False # crystals are lost
4585 game.nprobes = 0 # No probes
4586 prout(_("You are captured by Klingons and released to"))
4587 prout(_("the Federation in a prisoner-of-war exchange."))
4588 nb = randrange(len(game.state.baseq))
4589 # Set up quadrant and position FQ adjacient to base
4590 if not game.quadrant == game.state.baseq[nb]:
4591 game.quadrant = game.state.baseq[nb]
4592 game.sector.i = game.sector.j = 5
4595 # position next to base by trial and error
4596 game.quad[game.sector.i][game.sector.j] = '.'
4598 for l in range(QUADSIZE):
4599 game.sector = game.base.scatter()
4600 if game.sector.valid_sector() and \
4601 game.quad[game.sector.i][game.sector.j] == '.':
4604 break # found a spot
4605 game.sector.i=QUADSIZE/2
4606 game.sector.j=QUADSIZE/2
4608 # Get new commission
4609 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4610 game.state.crew = FULLCREW
4611 prout(_("Starfleet puts you in command of another ship,"))
4612 prout(_("the Faerie Queene, which is antiquated but,"))
4613 prout(_("still useable."))
4615 prout(_("The dilithium crystals have been moved."))
4617 game.iscraft = "offship" # Galileo disappears
4619 game.condition="docked"
4620 for l in range(NDEVICES):
4621 game.damage[l] = 0.0
4622 game.damage[DSHUTTL] = -1
4623 game.energy = game.inenrg = 3000.0
4624 game.shield = game.inshld = 1250.0
4625 game.torps = game.intorps = 6
4626 game.lsupres=game.inlsr=3.0
4629 game.brigfree = game.brigcapacity = 300
4632 # Code from planets.c begins here.
4635 "Abort a lengthy operation if an event interrupts it."
4638 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4643 "Report on (uninhabited) planets in the galaxy."
4647 prout(_("Spock- \"Planet report follows, Captain.\""))
4649 for i in range(game.inplan):
4650 if game.state.planets[i].pclass == "destroyed":
4652 if (game.state.planets[i].known != "unknown" \
4653 and not game.state.planets[i].inhabited) \
4656 if game.idebug and game.state.planets[i].known=="unknown":
4657 proutn("(Unknown) ")
4658 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4659 proutn(_(" class "))
4660 proutn(game.state.planets[i].pclass)
4662 if game.state.planets[i].crystals != "present":
4664 prout(_("dilithium crystals present."))
4665 if game.state.planets[i].known=="shuttle_down":
4666 prout(_(" Shuttle Craft Galileo on surface."))
4668 prout(_("No information available."))
4671 "Enter standard orbit."
4675 prout(_("Already in standard orbit."))
4677 if damaged(DWARPEN) and damaged(DIMPULS):
4678 prout(_("Both warp and impulse engines damaged."))
4680 if not game.plnet.is_valid():
4681 prout("There is no planet in this sector.")
4683 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4684 prout(crmshp() + _(" not adjacent to planet."))
4687 game.optime = randreal(0.02, 0.05)
4688 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4692 game.height = randreal(1400, 8600)
4693 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4698 "Examine planets in this quadrant."
4699 if damaged(DSRSENS):
4700 if game.options & OPTION_TTY:
4701 prout(_("Short range sensors damaged."))
4703 if game.iplnet is None:
4704 if game.options & OPTION_TTY:
4705 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4707 if game.iplnet.known == "unknown":
4708 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4710 prout(_(" Planet at Sector %s is of class %s.") %
4711 (game.plnet, game.iplnet.pclass))
4712 if game.iplnet.known=="shuttle_down":
4713 prout(_(" Sensors show Galileo still on surface."))
4714 proutn(_(" Readings indicate"))
4715 if game.iplnet.crystals != "present":
4717 prout(_(" dilithium crystals present.\""))
4718 if game.iplnet.known == "unknown":
4719 game.iplnet.known = "known"
4720 elif game.iplnet.inhabited:
4721 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4722 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4725 "Use the transporter."
4729 if damaged(DTRANSP):
4730 prout(_("Transporter damaged."))
4731 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4733 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4737 if not game.inorbit:
4738 prout(crmshp() + _(" not in standard orbit."))
4741 prout(_("Impossible to transport through shields."))
4743 if game.iplnet.known=="unknown":
4744 prout(_("Spock- \"Captain, we have no information on this planet"))
4745 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4746 prout(_(" you may not go down.\""))
4748 if not game.landed and game.iplnet.crystals=="absent":
4749 prout(_("Spock- \"Captain, I fail to see the logic in"))
4750 prout(_(" exploring a planet with no dilithium crystals."))
4751 proutn(_(" Are you sure this is wise?\" "))
4755 if not (game.options & OPTION_PLAIN):
4756 nrgneed = 50 * game.skill + game.height / 100.0
4757 if nrgneed > game.energy:
4758 prout(_("Engineering to bridge--"))
4759 prout(_(" Captain, we don't have enough energy for transportation."))
4761 if not game.landed and nrgneed * 2 > game.energy:
4762 prout(_("Engineering to bridge--"))
4763 prout(_(" Captain, we have enough energy only to transport you down to"))
4764 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4765 if game.iplnet.known == "shuttle_down":
4766 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4767 proutn(_(" Are you sure this is wise?\" "))
4772 # Coming from planet
4773 if game.iplnet.known=="shuttle_down":
4774 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4778 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4779 prout(_("Landing party assembled, ready to beam up."))
4781 prout(_("Kirk whips out communicator..."))
4782 prouts(_("BEEP BEEP BEEP"))
4784 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4787 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4789 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4791 prout(_("Kirk- \"Energize.\""))
4794 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4796 if not withprob(0.98):
4797 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4799 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4802 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4803 game.landed = not game.landed
4804 game.energy -= nrgneed
4806 prout(_("Transport complete."))
4807 if game.landed and game.iplnet.known=="shuttle_down":
4808 prout(_("The shuttle craft Galileo is here!"))
4809 if not game.landed and game.imine:
4816 "Strip-mine a world for dilithium."
4820 prout(_("Mining party not on planet."))
4822 if game.iplnet.crystals == "mined":
4823 prout(_("This planet has already been strip-mined for dilithium."))
4825 elif game.iplnet.crystals == "absent":
4826 prout(_("No dilithium crystals on this planet."))
4829 prout(_("You've already mined enough crystals for this trip."))
4831 if game.icrystl and game.cryprob == 0.05:
4832 prout(_("With all those fresh crystals aboard the ") + crmshp())
4833 prout(_("there's no reason to mine more at this time."))
4835 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4838 prout(_("Mining operation complete."))
4839 game.iplnet.crystals = "mined"
4840 game.imine = game.ididit = True
4843 "Use dilithium crystals."
4847 if not game.icrystl:
4848 prout(_("No dilithium crystals available."))
4850 if game.energy >= 1000:
4851 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4852 prout(_(" except when Condition Yellow exists."))
4854 prout(_("Spock- \"Captain, I must warn you that loading"))
4855 prout(_(" raw dilithium crystals into the ship's power"))
4856 prout(_(" system may risk a severe explosion."))
4857 proutn(_(" Are you sure this is wise?\" "))
4862 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4863 prout(_(" Mr. Spock and I will try it.\""))
4865 prout(_("Spock- \"Crystals in place, Sir."))
4866 prout(_(" Ready to activate circuit.\""))
4868 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4870 if withprob(game.cryprob):
4871 prouts(_(" \"Activating now! - - No good! It's***"))
4873 prouts(_("***RED ALERT! RED A*L********************************"))
4876 prouts(_("****************** KA-BOOM!!!! *******************"))
4880 game.energy += randreal(5000.0, 5500.0)
4881 prouts(_(" \"Activating now! - - "))
4882 prout(_("The instruments"))
4883 prout(_(" are going crazy, but I think it's"))
4884 prout(_(" going to work!! Congratulations, Sir!\""))
4889 "Use shuttlecraft for planetary jaunt."
4892 if damaged(DSHUTTL):
4893 if game.damage[DSHUTTL] == -1.0:
4894 if game.inorbit and game.iplnet.known == "shuttle_down":
4895 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4897 prout(_("Ye Faerie Queene had no shuttle craft."))
4898 elif game.damage[DSHUTTL] > 0:
4899 prout(_("The Galileo is damaged."))
4900 else: # game.damage[DSHUTTL] < 0
4901 prout(_("Shuttle craft is now serving Big Macs."))
4903 if not game.inorbit:
4904 prout(crmshp() + _(" not in standard orbit."))
4906 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4907 prout(_("Shuttle craft not currently available."))
4909 if not game.landed and game.iplnet.known=="shuttle_down":
4910 prout(_("You will have to beam down to retrieve the shuttle craft."))
4912 if game.shldup or game.condition == "docked":
4913 prout(_("Shuttle craft cannot pass through shields."))
4915 if game.iplnet.known=="unknown":
4916 prout(_("Spock- \"Captain, we have no information on this planet"))
4917 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4918 prout(_(" you may not fly down.\""))
4920 game.optime = 3.0e-5*game.height
4921 if game.optime >= 0.8*game.state.remtime:
4922 prout(_("First Officer Spock- \"Captain, I compute that such"))
4923 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4924 int(100*game.optime/game.state.remtime))
4925 prout(_("remaining time."))
4926 proutn(_("Are you sure this is wise?\" "))
4932 if game.iscraft == "onship":
4934 if not damaged(DTRANSP):
4935 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4939 proutn(_("Shuttle crew"))
4941 proutn(_("Rescue party"))
4942 prout(_(" boards Galileo and swoops toward planet surface."))
4943 game.iscraft = "offship"
4947 game.iplnet.known="shuttle_down"
4948 prout(_("Trip complete."))
4951 # Ready to go back to ship
4952 prout(_("You and your mining party board the"))
4953 prout(_("shuttle craft for the trip back to the Enterprise."))
4955 prouts(_("The short hop begins . . ."))
4957 game.iplnet.known="known"
4963 game.iscraft = "onship"
4969 prout(_("Trip complete."))
4972 # Kirk on ship and so is Galileo
4973 prout(_("Mining party assembles in the hangar deck,"))
4974 prout(_("ready to board the shuttle craft \"Galileo\"."))
4976 prouts(_("The hangar doors open; the trip begins."))
4979 game.iscraft = "offship"
4982 game.iplnet.known = "shuttle_down"
4985 prout(_("Trip complete."))
4989 "Use the big zapper."
4993 if game.ship != 'E':
4994 prout(_("Ye Faerie Queene has no death ray."))
4996 if len(game.enemies)==0:
4997 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
5000 prout(_("Death Ray is damaged."))
5002 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
5003 prout(_(" is highly unpredictible. Considering the alternatives,"))
5004 proutn(_(" are you sure this is wise?\" "))
5007 prout(_("Spock- \"Acknowledged.\""))
5010 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
5012 prout(_("Crew scrambles in emergency preparation."))
5013 prout(_("Spock and Scotty ready the death ray and"))
5014 prout(_("prepare to channel all ship's power to the device."))
5016 prout(_("Spock- \"Preparations complete, sir.\""))
5017 prout(_("Kirk- \"Engage!\""))
5019 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
5022 if game.options & OPTION_PLAIN:
5026 prouts(_("Sulu- \"Captain! It's working!\""))
5028 while len(game.enemies) > 0:
5029 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
5030 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
5031 if game.unwon() == 0:
5033 if (game.options & OPTION_PLAIN) == 0:
5034 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
5036 prout(_(" is still operational.\""))
5038 prout(_(" has been rendered nonfunctional.\""))
5039 game.damage[DDRAY] = 39.95
5041 r = randreal() # Pick failure method
5043 prouts(_("Sulu- \"Captain! It's working!\""))
5045 prouts(_("***RED ALERT! RED ALERT!"))
5047 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
5049 prouts(_("***RED ALERT! RED A*L********************************"))
5052 prouts(_("****************** KA-BOOM!!!! *******************"))
5057 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
5059 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
5061 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
5062 prout(_(" have apparently been transformed into strange mutations."))
5063 prout(_(" Vulcans do not seem to be affected."))
5065 prout(_("Kirk- \"Raauch! Raauch!\""))
5069 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
5071 proutn(_("Spock- \"I believe the word is"))
5072 prouts(_(" *ASTONISHING*"))
5073 prout(_(" Mr. Sulu."))
5074 for i in range(QUADSIZE):
5075 for j in range(QUADSIZE):
5076 if game.quad[i][j] == '.':
5077 game.quad[i][j] = '?'
5078 prout(_(" Captain, our quadrant is now infested with"))
5079 prouts(_(" - - - - - - *THINGS*."))
5081 prout(_(" I have no logical explanation.\""))
5083 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
5085 prout(_("Scotty- \"There are so many tribbles down here"))
5086 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
5090 # Code from reports.c begins here
5092 def attackreport(curt):
5093 "eport status of bases under attack."
5095 if is_scheduled(FCDBAS):
5096 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
5097 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
5098 elif game.isatb == 1:
5099 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
5100 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
5102 prout(_("No Starbase is currently under attack."))
5104 if is_scheduled(FCDBAS):
5105 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
5107 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
5111 # report on general game status
5113 s1 = (game.thawed and _("thawed ")) or ""
5114 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
5115 s3 = (None, _("novice"), _("fair"),
5116 _("good"), _("expert"), _("emeritus"))[game.skill]
5117 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
5118 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
5119 prout(_("No plaque is allowed."))
5121 prout(_("This is tournament game %d.") % game.tourn)
5122 prout(_("Your secret password is \"%s\"") % game.passwd)
5123 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - game.unwon()),
5124 (game.inkling + game.incom + game.inscom)))
5125 if game.incom - len(game.state.kcmdr):
5126 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
5127 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
5128 prout(_(", but no Commanders."))
5131 if game.skill > SKILL_FAIR:
5132 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
5133 if len(game.state.baseq) != game.inbase:
5135 if game.inbase-len(game.state.baseq)==1:
5136 proutn(_("has been 1 base"))
5138 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
5139 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
5141 prout(_("There are %d bases.") % game.inbase)
5142 if communicating() or game.iseenit:
5143 # Don't report this if not seen and
5144 # either the radio is dead or not at base!
5148 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
5149 if game.brigcapacity != game.brigfree:
5150 embriggened = brigcapacity-brigfree
5151 if embriggened == 1:
5152 prout(_("1 Klingon in brig"))
5154 prout(_("%d Klingons in brig.") % embriggened)
5155 if game.kcaptured == 0:
5157 elif game.kcaptured == 1:
5158 prout(_("1 captured Klingon turned in to Starfleet."))
5160 prout(_("%d captured Klingons turned in to Star Fleet.") % game.kcaptured)
5162 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
5163 if game.ship == 'E':
5164 proutn(_("You have "))
5166 proutn("%d" % (game.nprobes))
5169 proutn(_(" deep space probe"))
5173 if communicating() and is_scheduled(FDSPROB):
5175 proutn(_("An armed deep space probe is in "))
5177 proutn(_("A deep space probe is in "))
5178 prout("Quadrant %s." % game.probe.quadrant())
5180 if game.cryprob <= .05:
5181 prout(_("Dilithium crystals aboard ship... not yet used."))
5185 while game.cryprob > ai:
5188 prout(_("Dilithium crystals have been used %d time%s.") % \
5189 (i, (_("s"), "")[i==1]))
5193 "Long-range sensor scan."
5194 if damaged(DLRSENS):
5195 # Now allow base's sensors if docked
5196 if game.condition != "docked":
5198 prout(_("LONG-RANGE SENSORS DAMAGED."))
5201 prout(_("Starbase's long-range scan"))
5203 prout(_("Long-range scan"))
5204 for x in range(game.quadrant.i-1, game.quadrant.i+2):
5207 for y in range(game.quadrant.j-1, game.quadrant.j+2):
5208 if not Coord(x, y).valid_quadrant():
5212 if not damaged(DRADIO):
5213 game.state.galaxy[x][y].charted = True
5214 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5215 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5216 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5217 if not silent and game.state.galaxy[x][y].supernova:
5220 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
5228 for i in range(NDEVICES):
5231 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5232 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5234 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5235 game.damage[i]+0.05,
5236 DOCKFAC*game.damage[i]+0.005))
5238 prout(_("All devices functional."))
5241 "Update the chart in the Enterprise's computer from galaxy data."
5242 game.lastchart = game.state.date
5243 for i in range(GALSIZE):
5244 for j in range(GALSIZE):
5245 if game.state.galaxy[i][j].charted:
5246 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5247 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5248 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5251 "Display the star chart."
5253 if (game.options & OPTION_AUTOSCAN):
5257 if game.lastchart < game.state.date and game.condition == "docked":
5258 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5260 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5261 if game.state.date > game.lastchart:
5262 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5263 prout(" 1 2 3 4 5 6 7 8")
5264 for i in range(GALSIZE):
5265 proutn("%d |" % (i+1))
5266 for j in range(GALSIZE):
5267 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5271 if game.state.galaxy[i][j].supernova:
5273 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5275 elif game.state.galaxy[i][j].charted:
5276 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5280 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5288 def sectscan(goodScan, i, j):
5289 "Light up an individual dot in a sector."
5290 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5291 if game.quad[i][j] in ('E', 'F'):
5294 textcolor({"green":GREEN,
5298 "dead":BROWN}[game.condition])
5300 textcolor({'?':LIGHTMAGENTA,
5306 }.get(game.quad[i][j], DEFAULT))
5307 proutn("%c " % game.quad[i][j])
5313 "Emit status report lines"
5314 if not req or req == 1:
5315 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5316 % (game.state.date, game.state.remtime))
5317 if not req or req == 2:
5318 if game.condition != "docked":
5320 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5321 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5323 prout(_(", CLOAKED"))
5324 if not req or req == 3:
5325 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5326 if not req or req == 4:
5327 if damaged(DLIFSUP):
5328 if game.condition == "docked":
5329 s = _("DAMAGED, Base provides")
5331 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5334 prstat(_("Life Support"), s)
5335 if not req or req == 5:
5336 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5337 if not req or req == 6:
5339 if game.icrystl and (game.options & OPTION_SHOWME):
5340 extra = _(" (have crystals)")
5341 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5342 if not req or req == 7:
5343 prstat(_("Torpedoes"), "%d" % (game.torps))
5344 if not req or req == 8:
5345 if damaged(DSHIELD):
5351 data = _(" %d%% %.1f units") \
5352 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5353 prstat(_("Shields"), s+data)
5354 if not req or req == 9:
5355 prstat(_("Klingons Left"), "%d" % game.unwon())
5356 if not req or req == 10:
5357 if game.options & OPTION_WORLDS:
5358 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5359 if plnet and plnet.inhabited:
5360 prstat(_("Major system"), plnet.name)
5362 prout(_("Sector is uninhabited"))
5363 elif not req or req == 11:
5364 attackreport(not req)
5367 "Request specified status data, a historical relic from slow TTYs."
5368 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5369 while scanner.nexttok() == "IHEOL":
5370 proutn(_("Information desired? "))
5372 if scanner.token in requests:
5373 status(requests.index(scanner.token))
5375 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5376 prout((" date, condition, position, lsupport, warpfactor,"))
5377 prout((" energy, torpedoes, shields, klingons, system, time."))
5382 if damaged(DSRSENS):
5383 # Allow base's sensors if docked
5384 if game.condition != "docked":
5385 prout(_(" S.R. SENSORS DAMAGED!"))
5388 prout(_(" [Using Base's sensors]"))
5390 prout(_(" Short-range scan"))
5391 if goodScan and communicating():
5392 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5393 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5394 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5395 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5396 prout(" 1 2 3 4 5 6 7 8 9 10")
5397 if game.condition != "docked":
5399 for i in range(QUADSIZE):
5400 proutn("%2d " % (i+1))
5401 for j in range(QUADSIZE):
5402 sectscan(goodScan, i, j)
5406 "Use computer to get estimated time of arrival for a warp jump."
5407 w1 = Coord(); w2 = Coord()
5409 if damaged(DCOMPTR):
5410 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5413 if scanner.nexttok() != "IHREAL":
5416 proutn(_("Destination quadrant and/or sector? "))
5417 if scanner.nexttok()!="IHREAL":
5420 w1.j = int(scanner.real-0.5)
5421 if scanner.nexttok() != "IHREAL":
5424 w1.i = int(scanner.real-0.5)
5425 if scanner.nexttok() == "IHREAL":
5426 w2.j = int(scanner.real-0.5)
5427 if scanner.nexttok() != "IHREAL":
5430 w2.i = int(scanner.real-0.5)
5432 if game.quadrant.j>w1.i:
5436 if game.quadrant.i>w1.j:
5440 if not w1.valid_quadrant() or not w2.valid_sector():
5443 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5444 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5447 prout(_("Answer \"no\" if you don't know the value:"))
5450 proutn(_("Time or arrival date? "))
5451 if scanner.nexttok()=="IHREAL":
5452 ttime = scanner.real
5453 if ttime > game.state.date:
5454 ttime -= game.state.date # Actually a star date
5455 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5456 if ttime <= 1e-10 or twarp > 10:
5457 prout(_("We'll never make it, sir."))
5464 proutn(_("Warp factor? "))
5465 if scanner.nexttok()== "IHREAL":
5467 twarp = scanner.real
5468 if twarp<1.0 or twarp > 10.0:
5472 prout(_("Captain, certainly you can give me one of these."))
5475 ttime = (10.0*dist)/twarp**2
5476 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5477 if tpower >= game.energy:
5478 prout(_("Insufficient energy, sir."))
5479 if not game.shldup or tpower > game.energy*2.0:
5482 proutn(_("New warp factor to try? "))
5483 if scanner.nexttok() == "IHREAL":
5485 twarp = scanner.real
5486 if twarp<1.0 or twarp > 10.0:
5494 prout(_("But if you lower your shields,"))
5495 proutn(_("remaining"))
5498 proutn(_("Remaining"))
5499 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5501 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5503 prout(_("Any warp speed is adequate."))
5505 prout(_("Minimum warp needed is %.2f,") % (twarp))
5506 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5507 if game.state.remtime < ttime:
5508 prout(_("Unfortunately, the Federation will be destroyed by then."))
5510 prout(_("You'll be taking risks at that speed, Captain"))
5511 if (game.isatb==1 and game.state.kscmdr == w1 and \
5512 scheduled(FSCDBAS)< ttime+game.state.date) or \
5513 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5514 prout(_("The starbase there will be destroyed by then."))
5515 proutn(_("New warp factor to try? "))
5516 if scanner.nexttok() == "IHREAL":
5518 twarp = scanner.real
5519 if twarp<1.0 or twarp > 10.0:
5527 # Code from setup.c begins here
5530 "Issue a historically correct banner."
5532 prout(_("-SUPER- STAR TREK"))
5534 # From the FORTRAN original
5535 # prout(_("Latest update-21 Sept 78"))
5541 scanner.push("emsave.trk")
5542 key = scanner.nexttok()
5544 proutn(_("File name: "))
5545 key = scanner.nexttok()
5546 if key != "IHALPHA":
5549 if '.' not in scanner.token:
5550 scanner.token += ".trk"
5552 fp = open(scanner.token, "wb")
5554 prout(_("Can't freeze game as file %s") % scanner.token)
5556 pickle.dump(game, fp)
5561 "Retrieve saved game."
5564 key = scanner.nexttok()
5566 proutn(_("File name: "))
5567 key = scanner.nexttok()
5568 if key != "IHALPHA":
5571 if '.' not in scanner.token:
5572 scanner.token += ".trk"
5574 fp = open(scanner.token, "rb")
5576 prout(_("Can't thaw game in %s") % scanner.token)
5578 game = pickle.load(fp)
5583 # I used <http://www.memory-alpha.org> to find planets
5584 # with references in ST:TOS. Earth and the Alpha Centauri
5585 # Colony have been omitted.
5587 # Some planets marked Class G and P here will be displayed as class M
5588 # because of the way planets are generated. This is a known bug.
5591 _("Andoria (Fesoan)"), # several episodes
5592 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5593 _("Vulcan (T'Khasi)"), # many episodes
5594 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5595 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5596 _("Ardana"), # TOS: "The Cloud Minders"
5597 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5598 _("Gideon"), # TOS: "The Mark of Gideon"
5599 _("Aldebaran III"), # TOS: "The Deadly Years"
5600 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5601 _("Altair IV"), # TOS: "Amok Time
5602 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5603 _("Benecia"), # TOS: "The Conscience of the King"
5604 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5605 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5606 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5607 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5608 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5609 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5610 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5611 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5612 _("Ingraham B"), # TOS: "Operation: Annihilate"
5613 _("Janus IV"), # TOS: "The Devil in the Dark"
5614 _("Makus III"), # TOS: "The Galileo Seven"
5615 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5616 _("Omega IV"), # TOS: "The Omega Glory"
5617 _("Regulus V"), # TOS: "Amok Time
5618 _("Deneva"), # TOS: "Operation -- Annihilate!"
5619 # Worlds from BSD Trek
5620 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5621 _("Beta III"), # TOS: "The Return of the Archons"
5622 _("Triacus"), # TOS: "And the Children Shall Lead",
5623 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5625 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5626 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5627 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5628 # _("Izar"), # TOS: "Whom Gods Destroy"
5629 # _("Tiburon"), # TOS: "The Way to Eden"
5630 # _("Merak II"), # TOS: "The Cloud Minders"
5631 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5632 # _("Iotia"), # TOS: "A Piece of the Action"
5636 _("S. R. Sensors"), \
5637 _("L. R. Sensors"), \
5639 _("Photon Tubes"), \
5640 _("Life Support"), \
5641 _("Warp Engines"), \
5642 _("Impulse Engines"), \
5644 _("Subspace Radio"), \
5645 _("Shuttle Craft"), \
5647 _("Navigation System"), \
5649 _("Shield Control"), \
5652 _("Cloaking Device"), \
5656 "Prepare to play, set up cosmos."
5658 # Decide how many of everything
5660 return # frozen game
5661 # Prepare the Enterprise
5662 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5664 game.state.crew = FULLCREW
5665 game.energy = game.inenrg = 5000.0
5666 game.shield = game.inshld = 2500.0
5669 game.quadrant = randplace(GALSIZE)
5670 game.sector = randplace(QUADSIZE)
5671 game.torps = game.intorps = 10
5672 game.nprobes = randrange(2, 5)
5674 for i in range(NDEVICES):
5675 game.damage[i] = 0.0
5676 # Set up assorted game parameters
5677 game.battle = Coord()
5678 game.state.date = game.indate = 100.0 * randreal(20, 51)
5679 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5680 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5681 game.isatb = game.state.nplankl = 0
5682 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5683 game.iscraft = "onship"
5688 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5690 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5692 game.state.planets = [] # Planet information
5693 game.state.baseq = [] # Base quadrant coordinates
5694 game.state.kcmdr = [] # Commander quadrant coordinates
5695 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5697 # Starchart is functional but we've never seen it
5698 game.lastchart = FOREVER
5699 # Put stars in the galaxy
5701 for i in range(GALSIZE):
5702 for j in range(GALSIZE):
5703 # Can't have more stars per quadrant than fit in one decimal digit,
5704 # if we do the chart representation will break.
5705 k = randrange(1, min(10, QUADSIZE**2/10))
5707 game.state.galaxy[i][j].stars = k
5708 # Locate star bases in galaxy
5710 prout("=== Allocating %d bases" % game.inbase)
5711 for i in range(game.inbase):
5714 w = randplace(GALSIZE)
5715 if not game.state.galaxy[w.i][w.j].starbase:
5718 # C version: for (j = i-1; j > 0; j--)
5719 # so it did them in the opposite order.
5720 for j in range(1, i):
5721 # Improved placement algorithm to spread out bases
5722 distq = (w - game.state.baseq[j]).distance()
5723 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5726 prout("=== Abandoning base #%d at %s" % (i, w))
5728 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5730 prout("=== Saving base #%d, close to #%d" % (i, j))
5734 prout("=== Placing base #%d in quadrant %s" % (i, w))
5735 game.state.baseq.append(w)
5736 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5737 # Position ordinary Klingon Battle Cruisers
5739 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5740 if klumper > MAXKLQUAD:
5744 klump = (1.0 - r*r)*klumper
5749 w = randplace(GALSIZE)
5750 if not game.state.galaxy[w.i][w.j].supernova and \
5751 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5753 game.state.galaxy[w.i][w.j].klingons += int(klump)
5756 # Position Klingon Commander Ships
5757 for i in range(game.incom):
5759 w = randplace(GALSIZE)
5760 if not welcoming(w) or w in game.state.kcmdr:
5762 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5764 game.state.galaxy[w.i][w.j].klingons += 1
5765 game.state.kcmdr.append(w)
5766 # Locate planets in galaxy
5767 for i in range(game.inplan):
5769 w = randplace(GALSIZE)
5770 if game.state.galaxy[w.i][w.j].planet is None:
5774 new.crystals = "absent"
5775 if (game.options & OPTION_WORLDS) and i < NINHAB:
5776 new.pclass = "M" # All inhabited planets are class M
5777 new.crystals = "absent"
5779 new.name = systnames[i]
5780 new.inhabited = True
5782 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5784 new.crystals = "present"
5785 new.known = "unknown"
5786 new.inhabited = False
5787 game.state.galaxy[w.i][w.j].planet = new
5788 game.state.planets.append(new)
5790 for i in range(game.state.nromrem):
5791 w = randplace(GALSIZE)
5792 game.state.galaxy[w.i][w.j].romulans += 1
5793 # Place the Super-Commander if needed
5794 if game.state.nscrem > 0:
5796 w = randplace(GALSIZE)
5799 game.state.kscmdr = w
5800 game.state.galaxy[w.i][w.j].klingons += 1
5801 # Initialize times for extraneous events
5802 schedule(FSNOVA, expran(0.5 * game.intime))
5803 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5804 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5805 schedule(FBATTAK, expran(0.3*game.intime))
5807 if game.state.nscrem:
5808 schedule(FSCMOVE, 0.2777)
5813 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5814 schedule(FDISTR, expran(1.0 + game.intime))
5819 # Place thing (in tournament game, we don't want one!)
5820 # New in SST2K: never place the Thing near a starbase.
5821 # This makes sense and avoids a special case in the old code.
5823 if game.tourn is None:
5825 thing = randplace(GALSIZE)
5826 if thing not in game.state.baseq:
5829 game.state.snap = False
5830 if game.skill == SKILL_NOVICE:
5831 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5832 prout(_("a deadly Klingon invasion force. As captain of the United"))
5833 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5834 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5835 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5836 prout(_("your mission. As you proceed you may be given more time."))
5838 prout(_("You will have %d supporting starbases.") % (game.inbase))
5839 proutn(_("Starbase locations- "))
5841 prout(_("Stardate %d.") % int(game.state.date))
5843 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5844 prout(_("An unknown number of Romulans."))
5845 if game.state.nscrem:
5846 prout(_("And one (GULP) Super-Commander."))
5847 prout(_("%d stardates.") % int(game.intime))
5848 proutn(_("%d starbases in ") % game.inbase)
5849 for i in range(game.inbase):
5850 proutn(repr(game.state.baseq[i]))
5853 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5854 proutn(_(" Sector %s") % game.sector)
5856 prout(_("Good Luck!"))
5857 if game.state.nscrem:
5858 prout(_(" YOU'LL NEED IT."))
5861 setwnd(message_window)
5863 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5865 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5866 attack(torps_ok=False)
5869 "Choose your game type."
5871 game.tourn = game.length = 0
5873 game.skill = SKILL_NONE
5874 # Do not chew here, we want to use command-line tokens
5875 if not scanner.inqueue: # Can start with command line options
5876 proutn(_("Would you like a regular, tournament, or saved game? "))
5878 if scanner.sees("tournament"):
5879 while scanner.nexttok() == "IHEOL":
5880 proutn(_("Type in tournament number-"))
5881 if scanner.real == 0:
5883 continue # We don't want a blank entry
5884 game.tourn = int(round(scanner.real))
5885 random.seed(scanner.real)
5887 logfp.write("# random.seed(%d)\n" % scanner.real)
5889 if scanner.sees("saved") or scanner.sees("frozen"):
5893 if game.passwd is None:
5895 if not game.alldone:
5896 game.thawed = True # No plaque if not finished
5900 if scanner.sees("regular"):
5902 proutn(_("What is \"%s\"? ") % scanner.token)
5904 while game.length==0 or game.skill==SKILL_NONE:
5905 if scanner.nexttok() == "IHALPHA":
5906 if scanner.sees("short"):
5908 elif scanner.sees("medium"):
5910 elif scanner.sees("long"):
5912 elif scanner.sees("novice"):
5913 game.skill = SKILL_NOVICE
5914 elif scanner.sees("fair"):
5915 game.skill = SKILL_FAIR
5916 elif scanner.sees("good"):
5917 game.skill = SKILL_GOOD
5918 elif scanner.sees("expert"):
5919 game.skill = SKILL_EXPERT
5920 elif scanner.sees("emeritus"):
5921 game.skill = SKILL_EMERITUS
5923 proutn(_("What is \""))
5924 proutn(scanner.token)
5929 proutn(_("Would you like a Short, Medium, or Long game? "))
5930 elif game.skill == SKILL_NONE:
5931 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5932 # Choose game options -- added by ESR for SST2K
5933 if scanner.nexttok() != "IHALPHA":
5935 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5937 if scanner.sees("plain"):
5938 # Approximates the UT FORTRAN version.
5939 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)
5940 game.options |= OPTION_PLAIN
5941 elif scanner.sees("almy"):
5942 # Approximates Tom Almy's version.
5943 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
5944 game.options |= OPTION_ALMY
5945 elif scanner.sees("fancy") or scanner.sees("\n"):
5947 elif len(scanner.token):
5948 proutn(_("What is \"%s\"?") % scanner.token)
5950 if game.passwd == "debug":
5952 prout("=== Debug mode enabled.")
5953 # Use parameters to generate initial values of things
5954 game.damfac = 0.5 * game.skill
5955 game.inbase = randrange(BASEMIN, BASEMAX+1)
5957 if game.options & OPTION_PLANETS:
5958 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5959 if game.options & OPTION_WORLDS:
5960 game.inplan += int(NINHAB)
5961 game.state.nromrem = game.inrom = randrange(2 * game.skill)
5962 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5963 game.state.remtime = 7.0 * game.length
5964 game.intime = game.state.remtime
5965 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5966 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5967 game.state.remres = (game.inkling+4*game.incom)*game.intime
5968 game.inresor = game.state.remres
5969 if game.inkling > 50:
5973 def dropin(iquad=None):
5974 "Drop a feature on a random dot in the current quadrant."
5976 w = randplace(QUADSIZE)
5977 if game.quad[w.i][w.j] == '.':
5979 if iquad is not None:
5980 game.quad[w.i][w.j] = iquad
5984 "Update our alert status."
5985 game.condition = "green"
5986 if game.energy < 1000.0:
5987 game.condition = "yellow"
5988 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5989 game.condition = "red"
5991 game.condition="dead"
5994 "Drop new Klingon into current quadrant."
5995 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5998 "Sort enemies by distance so 'nearest' is meaningful."
5999 game.enemies.sort(key=lambda x: x.kdist)
6002 "Set up a new state of quadrant, for when we enter or re-enter it."
6005 game.neutz = game.inorbit = game.landed = False
6006 game.ientesc = game.iseenit = game.isviolreported = False
6007 # Create a blank quadrant
6008 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
6010 # Attempt to escape Super-commander, so tbeam back!
6013 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
6014 # cope with supernova
6017 game.klhere = q.klingons
6018 game.irhere = q.romulans
6020 game.quad[game.sector.i][game.sector.j] = game.ship
6023 # Position ordinary Klingons
6024 for _i in range(game.klhere):
6026 # If we need a commander, promote a Klingon
6027 for cmdr in game.state.kcmdr:
6028 if cmdr == game.quadrant:
6029 e = game.enemies[game.klhere-1]
6030 game.quad[e.location.i][e.location.j] = 'C'
6031 e.power = randreal(950,1350) + 50.0*game.skill
6033 # If we need a super-commander, promote a Klingon
6034 if game.quadrant == game.state.kscmdr:
6036 game.quad[e.location.i][e.location.j] = 'S'
6037 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
6038 game.iscate = (game.state.remkl > 1)
6039 # Put in Romulans if needed
6040 for _i in range(q.romulans):
6041 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
6042 # If quadrant needs a starbase, put it in
6044 game.base = dropin('B')
6045 # If quadrant needs a planet, put it in
6047 game.iplnet = q.planet
6048 if not q.planet.inhabited:
6049 game.plnet = dropin('P')
6051 game.plnet = dropin('@')
6052 # Check for condition
6055 if game.irhere > 0 and game.klhere == 0:
6057 if not damaged(DRADIO):
6059 prout(_("LT. Uhura- \"Captain, an urgent message."))
6060 prout(_(" I'll put it on audio.\" CLICK"))
6062 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
6063 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
6064 # Put in THING if needed
6065 if thing == game.quadrant:
6066 Enemy(etype='?', loc=dropin(),
6067 power=randreal(6000,6500.0)+250.0*game.skill)
6068 if not damaged(DSRSENS):
6070 prout(_("Mr. Spock- \"Captain, this is most unusual."))
6071 prout(_(" Please examine your short-range scan.\""))
6072 # Decide if quadrant needs a Tholian; lighten up if skill is low
6073 if game.options & OPTION_THOLIAN:
6074 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
6075 (game.skill == SKILL_GOOD and withprob(0.05)) or \
6076 (game.skill > SKILL_GOOD and withprob(0.08)):
6079 w.i = withprob(0.5) * (QUADSIZE-1)
6080 w.j = withprob(0.5) * (QUADSIZE-1)
6081 if game.quad[w.i][w.j] == '.':
6083 game.tholian = Enemy(etype='T', loc=w,
6084 power=randrange(100, 500) + 25.0*game.skill)
6085 # Reserve unoccupied corners
6086 if game.quad[0][0]=='.':
6087 game.quad[0][0] = 'X'
6088 if game.quad[0][QUADSIZE-1]=='.':
6089 game.quad[0][QUADSIZE-1] = 'X'
6090 if game.quad[QUADSIZE-1][0]=='.':
6091 game.quad[QUADSIZE-1][0] = 'X'
6092 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
6093 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
6095 # And finally the stars
6096 for _i in range(q.stars):
6098 # Put in a few black holes
6099 for _i in range(1, 3+1):
6102 # Take out X's in corners if Tholian present
6104 if game.quad[0][0]=='X':
6105 game.quad[0][0] = '.'
6106 if game.quad[0][QUADSIZE-1]=='X':
6107 game.quad[0][QUADSIZE-1] = '.'
6108 if game.quad[QUADSIZE-1][0]=='X':
6109 game.quad[QUADSIZE-1][0] = '.'
6110 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
6111 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
6114 "Set the self-destruct password."
6115 if game.options & OPTION_PLAIN:
6118 proutn(_("Please type in a secret password- "))
6120 game.passwd = scanner.token
6121 if game.passwd != None:
6125 game.passwd += chr(ord('a')+randrange(26))
6126 game.passwd += chr(ord('a')+randrange(26))
6127 game.passwd += chr(ord('a')+randrange(26))
6129 # Code from sst.c begins here
6132 ("SRSCAN", OPTION_TTY),
6133 ("STATUS", OPTION_TTY),
6134 ("REQUEST", OPTION_TTY),
6135 ("LRSCAN", OPTION_TTY),
6147 ("SENSORS", OPTION_PLANETS),
6148 ("ORBIT", OPTION_PLANETS),
6149 ("TRANSPORT", OPTION_PLANETS),
6150 ("MINE", OPTION_PLANETS),
6151 ("CRYSTALS", OPTION_PLANETS),
6152 ("SHUTTLE", OPTION_PLANETS),
6153 ("PLANETS", OPTION_PLANETS),
6158 ("PROBE", OPTION_PROBE),
6160 ("FREEZE", 0), # Synonym for SAVE
6164 ("CAPTURE", OPTION_CAPTURE),
6165 ("CLOAK", OPTION_CLOAK),
6168 ("SOS", 0), # Synonym for MAYDAY
6169 ("CALL", 0), # Synonym for MAYDAY
6177 "Generate a list of legal commands."
6178 prout(_("LEGAL COMMANDS ARE:"))
6180 for (key, opt) in commands:
6181 if not opt or (opt & game.options):
6182 proutn("%-12s " % key)
6184 if emitted % 5 == 4:
6189 "Browse on-line help."
6190 key = scanner.nexttok()
6193 setwnd(prompt_window)
6194 proutn(_("Help on what command? "))
6195 key = scanner.nexttok()
6196 setwnd(message_window)
6199 cmds = [x[0] for x in commands]
6200 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
6207 cmd = scanner.token.upper()
6208 for directory in docpath:
6210 fp = open(os.path.join(directory, "sst.doc"), "r")
6215 prout(_("Spock- \"Captain, that information is missing from the"))
6216 prout(_(" computer. You need to find sst.doc and put it somewhere"))
6217 proutn(_(" in these directories: %s") % ":".join(docpath))
6219 # This used to continue: "You need to find SST.DOC and put
6220 # it in the current directory."
6223 linebuf = fp.readline()
6225 prout(_("Spock- \"Captain, there is no information on that command.\""))
6228 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
6229 linebuf = linebuf[3:].strip()
6230 if cmd.upper() == linebuf:
6233 prout(_("Spock- \"Captain, I've found the following information:\""))
6236 linebuf = fp.readline()
6237 if "******" in linebuf:
6243 "Command-interpretation loop."
6245 if game.irhere and game.state.date >= ALGERON and not game.isviolreported and game.iscloaked:
6246 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
6248 game.isviolreported = True
6249 while True: # command loop
6251 while True: # get a command
6253 game.optime = game.justin = False
6255 setwnd(prompt_window)
6258 if scanner.nexttok() == "IHEOL":
6259 if game.options & OPTION_CURSES:
6262 elif scanner.token == "":
6266 setwnd(message_window)
6268 abandon_passed = False
6269 cmd = "" # Force cmd to persist after loop
6270 opt = 0 # Force opt to persist after loop
6271 for (cmd, opt) in commands:
6272 # commands after ABANDON cannot be abbreviated
6273 if cmd == "ABANDON":
6274 abandon_passed = True
6275 if cmd == scanner.token.upper() or (not abandon_passed \
6276 and cmd.startswith(scanner.token.upper())):
6281 elif opt and not (opt & game.options):
6285 if game.options & OPTION_CURSES:
6286 prout("COMMAND> %s" % cmd)
6287 if cmd == "SRSCAN": # srscan
6289 elif cmd == "STATUS": # status
6291 elif cmd == "REQUEST": # status request
6293 elif cmd == "LRSCAN": # long range scan
6294 lrscan(silent=False)
6295 elif cmd == "PHASERS": # phasers
6300 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6305 elif cmd == "MOVE": # move under warp
6306 warp(wcourse=None, involuntary=False)
6307 elif cmd == "SHIELDS": # shields
6308 doshield(shraise=False)
6311 game.shldchg = False
6312 elif cmd == "DOCK": # dock at starbase
6315 attack(torps_ok=False)
6316 elif cmd == "DAMAGES": # damage reports
6318 elif cmd == "CHART": # chart
6320 elif cmd == "IMPULSE": # impulse
6322 elif cmd == "REST": # rest
6326 elif cmd == "WARP": # warp
6328 elif cmd == "SENSORS": # sensors
6330 elif cmd == "ORBIT": # orbit
6334 elif cmd == "TRANSPORT": # transport "beam"
6336 elif cmd == "MINE": # mine
6340 elif cmd == "CRYSTALS": # crystals
6344 elif cmd == "SHUTTLE": # shuttle
6348 elif cmd == "PLANETS": # Planet list
6350 elif cmd == "REPORT": # Game Report
6352 elif cmd == "COMPUTER": # use COMPUTER!
6354 elif cmd == "COMMANDS":
6356 elif cmd == "EMEXIT": # Emergency exit
6357 clrscr() # Hide screen
6358 freeze(True) # forced save
6359 raise SystemExit(1) # And quick exit
6360 elif cmd == "PROBE":
6361 probe() # Launch probe
6364 elif cmd == "ABANDON": # Abandon Ship
6366 elif cmd == "DESTRUCT": # Self Destruct
6368 elif cmd == "SAVE": # Save Game
6371 if game.skill > SKILL_GOOD:
6372 prout(_("WARNING--Saved games produce no plaques!"))
6373 elif cmd == "DEATHRAY": # Try a desparation measure
6377 elif cmd == "CAPTURE":
6379 elif cmd == "CLOAK":
6381 elif cmd == "DEBUGCMD": # What do we want for debug???
6383 elif cmd == "MAYDAY": # Call for help
6388 game.alldone = True # quit the game
6391 elif cmd == "SCORE":
6392 score() # see current score
6395 break # Game has ended
6396 if game.optime != 0.0:
6399 break # Events did us in
6400 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6403 if hitme and not game.justin:
6404 attack(torps_ok=True)
6407 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6418 "Emit the name of an enemy or feature."
6419 if ch == 'R': s = _("Romulan")
6420 elif ch == 'K': s = _("Klingon")
6421 elif ch == 'C': s = _("Commander")
6422 elif ch == 'S': s = _("Super-commander")
6423 elif ch == '*': s = _("Star")
6424 elif ch == 'P': s = _("Planet")
6425 elif ch == 'B': s = _("Starbase")
6426 elif ch == ' ': s = _("Black hole")
6427 elif ch == 'T': s = _("Tholian")
6428 elif ch == '#': s = _("Tholian web")
6429 elif ch == '?': s = _("Stranger")
6430 elif ch == '@': s = _("Inhabited World")
6431 else: s = "Unknown??"
6434 def crmena(loud, enemy, loctype, w):
6435 "Emit the name of an enemy and his location."
6439 buf += cramen(enemy) + _(" at ")
6440 if loctype == "quadrant":
6441 buf += _("Quadrant ")
6442 elif loctype == "sector":
6444 return buf + repr(w)
6447 "Emit our ship name."
6448 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6451 "Emit a line of stars"
6452 prouts("******************************************************")
6456 return -avrage*math.log(1e-7 + randreal())
6458 def randplace(size):
6459 "Choose a random location."
6461 w.i = randrange(size)
6462 w.j = randrange(size)
6472 # Get a token from the user
6475 # Fill the token quue if nothing here
6476 while not self.inqueue:
6478 if curwnd==prompt_window:
6480 setwnd(message_window)
6487 self.inqueue = sline.lstrip().split() + ["\n"]
6488 # From here on in it's all looking at the queue
6489 self.token = self.inqueue.pop(0)
6490 if self.token == "\n":
6494 self.real = float(self.token)
6495 self.type = "IHREAL"
6500 self.token = self.token.lower()
6501 self.type = "IHALPHA"
6504 def append(self, tok):
6505 self.inqueue.append(tok)
6506 def push(self, tok):
6507 self.inqueue.insert(0, tok)
6511 # Demand input for next scan
6513 self.real = self.token = None
6515 # compares s to item and returns true if it matches to the length of s
6516 return s.startswith(self.token)
6518 # Round token value to nearest integer
6519 return int(round(self.real))
6523 if self.type != "IHREAL":
6528 if self.type != "IHREAL":
6534 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6537 "Yes-or-no confirmation."
6541 if scanner.token == 'y':
6543 if scanner.token == 'n':
6546 proutn(_("Please answer with \"y\" or \"n\": "))
6549 "Complain about unparseable input."
6552 prout(_("Beg your pardon, Captain?"))
6555 "Access to the internals for debugging."
6556 proutn("Reset levels? ")
6558 if game.energy < game.inenrg:
6559 game.energy = game.inenrg
6560 game.shield = game.inshld
6561 game.torps = game.intorps
6562 game.lsupres = game.inlsr
6563 proutn("Reset damage? ")
6565 for i in range(NDEVICES):
6566 if game.damage[i] > 0.0:
6567 game.damage[i] = 0.0
6568 proutn("Toggle debug flag? ")
6570 game.idebug = not game.idebug
6572 prout("Debug output ON")
6574 prout("Debug output OFF")
6575 proutn("Cause selective damage? ")
6577 for i in range(NDEVICES):
6578 proutn("Kill %s?" % device[i])
6580 key = scanner.nexttok()
6581 if key == "IHALPHA" and scanner.sees("y"):
6582 game.damage[i] = 10.0
6583 proutn("Examine/change events? ")
6588 FSNOVA: "Supernova ",
6591 FBATTAK: "Base Attack ",
6592 FCDBAS: "Base Destroy ",
6593 FSCMOVE: "SC Move ",
6594 FSCDBAS: "SC Base Destroy ",
6595 FDSPROB: "Probe Move ",
6596 FDISTR: "Distress Call ",
6597 FENSLV: "Enslavement ",
6598 FREPRO: "Klingon Build ",
6600 for i in range(1, NEVENTS):
6603 proutn("%.2f" % (scheduled(i)-game.state.date))
6604 if i == FENSLV or i == FREPRO:
6606 proutn(" in %s" % ev.quadrant)
6611 key = scanner.nexttok()
6615 elif key == "IHREAL":
6616 ev = schedule(i, scanner.real)
6617 if i == FENSLV or i == FREPRO:
6619 proutn("In quadrant- ")
6620 key = scanner.nexttok()
6621 # "IHEOL" says to leave coordinates as they are
6624 prout("Event %d canceled, no x coordinate." % (i))
6627 w.i = int(round(scanner.real))
6628 key = scanner.nexttok()
6630 prout("Event %d canceled, no y coordinate." % (i))
6633 w.j = int(round(scanner.real))
6636 proutn("Induce supernova here? ")
6638 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6641 if __name__ == '__main__':
6643 #global line, thing, game
6647 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6648 if os.getenv("TERM"):
6649 game.options |= OPTION_CURSES
6651 game.options |= OPTION_TTY
6652 seed = int(time.time())
6653 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6655 for (switch, val) in options:
6658 replayfp = open(val, "r")
6660 sys.stderr.write("sst: can't open replay file %s\n" % val)
6663 line = replayfp.readline().strip()
6664 (leader, __, seed) = line.split()
6666 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6667 line = replayfp.readline().strip()
6668 arguments += line.split()[2:]
6671 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6673 game.options |= OPTION_TTY
6674 game.options &=~ OPTION_CURSES
6675 elif switch == '-s':
6677 elif switch == '-t':
6678 game.options |= OPTION_TTY
6679 game.options &=~ OPTION_CURSES
6680 elif switch == '-x':
6682 elif switch == '-V':
6683 print("SST2K", version)
6686 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6688 # where to save the input in case of bugs
6689 if "TMPDIR" in os.environ:
6690 tmpdir = os.environ['TMPDIR']
6694 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6696 sys.stderr.write("sst: warning, can't open logfile\n")
6699 logfp.write("# seed %s\n" % seed)
6700 logfp.write("# options %s\n" % " ".join(arguments))
6701 logfp.write("# SST2K version %s\n" % version)
6702 logfp.write("# recorded by %s@%s on %s\n" % \
6703 (getpass.getuser(),socket.gethostname(),time.ctime()))
6705 scanner = sstscanner()
6706 for arg in arguments:
6710 while True: # Play a game
6711 setwnd(fullscreen_window)
6717 game.alldone = False
6725 if game.tourn and game.alldone:
6726 proutn(_("Do you want your score recorded?"))
6732 proutn(_("Do you want to play again? "))
6736 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6740 except KeyboardInterrupt: