3 sst.py =-- Super Star Trek in Python
5 This code is a Python translation of a C translation of a FORTRAN
6 original dating back to 1973. Beautiful Python it is not. But it
11 SRSCAN, MOVE, PHASERS, CALL, STATUS, IMPULSE, PHOTONS, ABANDON,
12 LRSCAN, WARP, SHIELDS, DESTRUCT, CHART, REST, DOCK, QUIT, and DAMAGE
13 were in the original non-"super" version of UT FORTRAN Star Trek.
15 Tholians were not in the original. Dave is dubious about their merits.
16 (They are now controlled by OPTION_THOLIAN and turned off if the game
19 Planets and dilithium crystals were not in the original. Dave is OK
20 with this idea. (It's now controlled by OPTION_PLANETS and turned
21 off if the game type is "plain".)
23 Dave says the bit about the Galileo getting turned into a
24 McDonald's is "consistant with our original vision". (This has been
25 left permanently enabled, as it can only happen if OPTION_PLANETS
28 Dave also says the Space Thingy should not be preserved across saved
29 games, so you can't prove to others that you've seen it. He says it
30 shouldn't fire back, either. It should do nothing except scream and
31 disappear when hit by photon torpedos. It's OK that it may move
32 when attacked, but it didn't in the original. (Whether the Thingy
33 can fire back is now controlled by OPTION_THINGY and turned off if the
34 game type is "plain" or "almy". The no-save behavior has been restored.)
36 The Faerie Queen, black holes, and time warping were in the original.
38 Here are Tom Almy's changes:
40 In early 1997, I got the bright idea to look for references to
41 "Super Star Trek" on the World Wide Web. There weren't many hits,
42 but there was one that came up with 1979 Fortran sources! This
43 version had a few additional features that mine didn't have,
44 however mine had some feature it didn't have. So I merged its
45 features that I liked. I also took a peek at the DECUS version (a
46 port, less sources, to the PDP-10), and some other variations.
48 1, Compared to the original UT version, I've changed the "help"
49 command to "call" and the "terminate" command to "quit" to better
50 match user expectations. The DECUS version apparently made those
51 changes as well as changing "freeze" to "save". However I like
52 "freeze". (Both "freeze" and "save" work in SST2K.)
54 2. The experimental deathray originally had only a 5% chance of
55 success, but could be used repeatedly. I guess after a couple
56 years of use, it was less "experimental" because the 1979
57 version had a 70% success rate. However it was prone to breaking
58 after use. I upgraded the deathray, but kept the original set of
59 failure modes (great humor!). (Now controlled by OPTION_DEATHRAY
60 and turned off if game type is "plain".)
62 3. The 1979 version also mentions srscan and lrscan working when
63 docked (using the starbase's scanners), so I made some changes here
64 to do this (and indicating that fact to the player), and then realized
65 the base would have a subspace radio as well -- doing a Chart when docked
66 updates the star chart, and all radio reports will be heard. The Dock
67 command will also give a report if a base is under attack.
69 4. Tholian Web from the 1979 version. (Now controlled by
70 OPTION_THOLIAN and turned off if game type is "plain".)
72 5. Enemies can ram the Enterprise. (Now controlled by OPTION_RAMMING
73 and turned off if game type is "plain".)
75 6. Regular Klingons and Romulans can move in Expert and Emeritus games.
76 This code could use improvement. (Now controlled by OPTION_MVBADDY
77 and turned off if game type is "plain".)
79 7. The deep-space probe feature from the DECUS version. (Now controlled
80 by OPTION_PROBE and turned off if game type is "plain").
82 8. 'emexit' command from the 1979 version.
84 9. Bugfix: Klingon commander movements are no longer reported if long-range
87 10. Bugfix: Better base positioning at startup (more spread out).
88 That made sense to add because most people abort games with
91 In June 2002, I fixed two known bugs and a documentation typo.
92 In June 2004 I fixed a number of bugs involving: 1) parsing invalid
93 numbers, 2) manual phasers when SR scan is damaged and commander is
94 present, 3) time warping into the future, 4) hang when moving
95 klingons in crowded quadrants. (These fixes are in SST2K.)
97 Here are Stas Sergeev's changes:
99 1. The Space Thingy can be shoved, if you ram it, and can fire back if
100 fired upon. (Now controlled by OPTION_THINGY and turned off if game
101 type is "plain" or "almy".)
103 2. When you are docked, base covers you with an almost invincible shield.
104 (A commander can still ram you, or a Romulan can destroy the base,
105 or a SCom can even succeed with direct attack IIRC, but this rarely
106 happens.) (Now controlled by OPTION_BASE and turned off if game
107 type is "plain" or "almy".)
109 3. Ramming a black hole is no longer instant death. There is a
110 chance you might get timewarped instead. (Now controlled by
111 OPTION_BLKHOLE and turned off if game type is "plain" or "almy".)
113 4. The Tholian can be hit with phasers.
115 5. SCom can't escape from you if no more enemies remain
116 (without this, chasing SCom can take an eternity).
118 6. Probe target you enter is now the destination quadrant. Before I don't
119 remember what it was, but it was something I had difficulty using.
121 7. Secret password is now autogenerated.
123 8. "Plaque" is adjusted for A4 paper :-)
125 9. Phasers now tells you how much energy needed, but only if the computer
128 10. Planets are auto-scanned when you enter the quadrant.
130 11. Mining or using crystals in presense of enemy now yields an attack.
131 There are other minor adjustments to what yields an attack
134 12. "freeze" command reverts to "save", most people will understand this
135 better anyway. (SST2K recognizes both.)
137 13. Screen-oriented interface, with sensor scans always up. (SST2K
138 supports both screen-oriented and TTY modes.)
140 Eric Raymond's changes:
142 Mainly, I translated this C code out of FORTRAN into C -- created #defines
143 for a lot of magic numbers and refactored the heck out of it.
145 1. "sos" and "call" becomes "mayday", "freeze" and "save" are both good.
147 2. Status report now indicates when dilithium crystals are on board.
149 3. Per Dave Matuszek's remarks, Thingy state is never saved across games.
151 4. Added game option selection so you can play a close (but not bug-for-
152 bug identical) approximation of older versions.
154 5. Half the quadrants now have inhabited planets, from which one
155 cannot mine dilithium (there will still be the same additional number
156 of dilithium-bearing planets). Torpedoing an inhabited world is *bad*.
157 There is BSD-Trek-like logic for Klingons to attack and enslave
158 inhabited worlds, producing more ships (only is skill is 'good' or
159 better). (Controlled by OPTION_WORLDS and turned off if game
160 type is "plain" or "almy".)
162 6. User input is now logged so we can do regression testing.
164 7. More BSD-Trek features: You can now lose if your entire crew
165 dies in battle. When abandoning ship in a game with inhabited
166 worlds enabled, they must have one in the quadrant to beam down
167 to; otherwise they die in space and this counts heavily against
168 your score. Docking at a starbase replenishes your crew.
170 8. Still more BSD-Trek: we now have a weighted damage table.
171 Also, the nav subsystem (enabling automatic course
172 setting) can be damaged separately from the main computer (which
173 handles weapons targeting, ETA calculation, and self-destruct).
175 After these features were added, I translated this into Python and added
178 9. A long-range scan is done silently whenever you call CHART; thus
179 the LRSCAN command is no longer needed. (Controlled by OPTION_AUTOSCAN
180 and turned off if game type is "plain" or "almy".)
182 import os, sys, math, curses, time, readline, cPickle, random, copy, gettext
184 SSTDOC = "/usr/share/doc/sst/sst.doc"
187 def _(str): return gettext.gettext(str)
191 NINHAB = (GALSIZE * GALSIZE / 2)
193 PLNETMAX = (NINHAB + MAXUNINHAB)
196 BASEMAX = (GALSIZE * GALSIZE / 12)
199 FULLCREW = 428 # BSD Trek was 387, that's wrong
204 # How to represent features
228 def __init__(self, x=None, y=None):
231 def valid_quadrant(self):
232 return self.i>=0 and self.i<GALSIZE and self.j>=0 and self.j<GALSIZE
233 def valid_sector(self):
234 return self.i>=0 and self.i<QUADSIZE and self.j>=0 and self.j<QUADSIZE
235 def invalidate(self):
236 self.i = self.j = None
238 return self.i != None and self.j != None
239 def __eq__(self, other):
240 return other != None and self.i == other.i and self.j == other.j
241 def __ne__(self, other):
242 return other == None or self.i != other.i or self.j != other.j
243 def __add__(self, other):
244 return coord(self.i+other.i, self.j+other.j)
245 def __sub__(self, other):
246 return coord(self.i-other.i, self.j-other.j)
247 def __mul__(self, other):
248 return coord(self.i*other, self.j*other)
249 def __rmul__(self, other):
250 return coord(self.i*other, self.j*other)
251 def __div__(self, other):
252 return coord(self.i/other, self.j/other)
253 def __mod__(self, other):
254 return coord(self.i % other, self.j % other)
255 def __rdiv__(self, other):
256 return coord(self.i/other, self.j/other)
257 def roundtogrid(self):
258 return coord(int(round(self.i)), int(round(self.j)))
259 def distance(self, other=None):
260 if not other: other = coord(0, 0)
261 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
263 return 1.90985*math.atan2(self.j, self.i)
269 s.i = self.i / abs(self.i)
273 s.j = self.j / abs(self.j)
276 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
277 return self.roundtogrid() / QUADSIZE
279 return self.roundtogrid() % QUADSIZE
282 s.i = self.i + randrange(-1, 2)
283 s.j = self.j + randrange(-1, 2)
286 if self.i == None or self.j == None:
288 return "%s - %s" % (self.i+1, self.j+1)
293 self.name = None # string-valued if inhabited
294 self.quadrant = coord() # quadrant located
295 self.pclass = None # could be ""M", "N", "O", or "destroyed"
296 self.crystals = "absent"# could be "mined", "present", "absent"
297 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
298 self.inhabited = False # is it inhabites?
306 self.starbase = False
309 self.supernova = False
311 self.status = "secure" # Could be "secure", "distressed", "enslaved"
319 def fill2d(size, fillfun):
320 "Fill an empty list in 2D."
322 for i in range(size):
324 for j in range(size):
325 lst[i].append(fillfun(i, j))
330 self.snap = False # snapshot taken
331 self.crew = 0 # crew complement
332 self.remkl = 0 # remaining klingons
333 self.nscrem = 0 # remaining super commanders
334 self.starkl = 0 # destroyed stars
335 self.basekl = 0 # destroyed bases
336 self.nromrem = 0 # Romulans remaining
337 self.nplankl = 0 # destroyed uninhabited planets
338 self.nworldkl = 0 # destroyed inhabited planets
339 self.planets = [] # Planet information
340 self.date = 0.0 # stardate
341 self.remres = 0 # remaining resources
342 self.remtime = 0 # remaining time
343 self.baseq = [] # Base quadrant coordinates
344 self.kcmdr = [] # Commander quadrant coordinates
345 self.kscmdr = coord() # Supercommander quadrant coordinates
347 self.galaxy = fill2d(GALSIZE, lambda i, j: quadrant())
349 self.chart = fill2d(GALSIZE, lambda i, j: page())
353 self.date = None # A real number
354 self.quadrant = None # A coord structure
357 OPTION_ALL = 0xffffffff
358 OPTION_TTY = 0x00000001 # old interface
359 OPTION_CURSES = 0x00000002 # new interface
360 OPTION_IOMODES = 0x00000003 # cover both interfaces
361 OPTION_PLANETS = 0x00000004 # planets and mining
362 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
363 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
364 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
365 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
366 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
367 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
368 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
369 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
370 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
371 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
372 OPTION_PLAIN = 0x01000000 # user chose plain game
373 OPTION_ALMY = 0x02000000 # user chose Almy variant
392 NDEVICES= 16 # Number of devices
401 def damaged(dev): return (game.damage[dev] != 0.0)
402 def communicating(): return not damaged(DRADIO) or game.condition=="docked"
404 # Define future events
405 FSPY = 0 # Spy event happens always (no future[] entry)
406 # can cause SC to tractor beam Enterprise
407 FSNOVA = 1 # Supernova
408 FTBEAM = 2 # Commander tractor beams Enterprise
409 FSNAP = 3 # Snapshot for time warp
410 FBATTAK = 4 # Commander attacks base
411 FCDBAS = 5 # Commander destroys base
412 FSCMOVE = 6 # Supercommander moves (might attack base)
413 FSCDBAS = 7 # Supercommander destroys base
414 FDSPROB = 8 # Move deep space probe
415 FDISTR = 9 # Emit distress call from an inhabited world
416 FENSLV = 10 # Inhabited word is enslaved */
417 FREPRO = 11 # Klingons build a ship in an enslaved system
421 # abstract out the event handling -- underlying data structures will change
422 # when we implement stateful events
424 def findevent(evtype): return game.future[evtype]
427 def __init__(self, type=None, loc=None, power=None):
432 self.kpower = power # enemy energy level
433 game.enemies.append(self)
435 motion = (loc != self.kloc)
436 if self.kloc.i is not None and self.kloc.j is not None:
439 game.quad[self.kloc.i][self.kloc.j] = IHWEB
441 game.quad[self.kloc.i][self.kloc.j] = IHDOT
443 self.kloc = copy.copy(loc)
444 game.quad[self.kloc.i][self.kloc.j] = self.type
445 self.kdist = self.kavgd = (game.sector - loc).distance()
448 self.kdist = self.kavgd = None
449 game.enemies.remove(self)
452 return "<%s,%s.%f>" % (self.type, self.kloc, self.kpower) # For debugging
456 self.options = None # Game options
457 self.state = snapshot() # A snapshot structure
458 self.snapsht = snapshot() # Last snapshot taken for time-travel purposes
459 self.quad = None # contents of our quadrant
460 self.damage = [0.0] * NDEVICES # damage encountered
461 self.future = [] # future events
462 for i in range(NEVENTS):
463 self.future.append(event())
464 self.passwd = None; # Self Destruct password
466 self.quadrant = None # where we are in the large
467 self.sector = None # where we are in the small
468 self.tholian = None # Tholian enemy object
469 self.base = None # position of base in current quadrant
470 self.battle = None # base coordinates being attacked
471 self.plnet = None # location of planet in quadrant
472 self.gamewon = False # Finished!
473 self.ididit = False # action taken -- allows enemy to attack
474 self.alive = False # we are alive (not killed)
475 self.justin = False # just entered quadrant
476 self.shldup = False # shields are up
477 self.shldchg = False # shield is changing (affects efficiency)
478 self.iscate = False # super commander is here
479 self.ientesc = False # attempted escape from supercommander
480 self.resting = False # rest time
481 self.icraft = False # Kirk in Galileo
482 self.landed = False # party on planet (true), on ship (false)
483 self.alldone = False # game is now finished
484 self.neutz = False # Romulan Neutral Zone
485 self.isarmed = False # probe is armed
486 self.inorbit = False # orbiting a planet
487 self.imine = False # mining
488 self.icrystl = False # dilithium crystals aboard
489 self.iseenit = False # seen base attack report
490 self.thawed = False # thawed game
491 self.condition = None # "green", "yellow", "red", "docked", "dead"
492 self.iscraft = None # "onship", "offship", "removed"
493 self.skill = None # Player skill level
494 self.inkling = 0 # initial number of klingons
495 self.inbase = 0 # initial number of bases
496 self.incom = 0 # initial number of commanders
497 self.inscom = 0 # initial number of commanders
498 self.inrom = 0 # initial number of commanders
499 self.instar = 0 # initial stars
500 self.intorps = 0 # initial/max torpedoes
501 self.torps = 0 # number of torpedoes
502 self.ship = 0 # ship type -- 'E' is Enterprise
503 self.abandoned = 0 # count of crew abandoned in space
504 self.length = 0 # length of game
505 self.klhere = 0 # klingons here
506 self.casual = 0 # causalties
507 self.nhelp = 0 # calls for help
508 self.nkinks = 0 # count of energy-barrier crossings
509 self.iplnet = None # planet # in quadrant
510 self.inplan = 0 # initial planets
511 self.irhere = 0 # Romulans in quadrant
512 self.isatb = 0 # =1 if super commander is attacking base
513 self.tourn = None # tournament number
514 self.nprobes = 0 # number of probes available
515 self.inresor = 0.0 # initial resources
516 self.intime = 0.0 # initial time
517 self.inenrg = 0.0 # initial/max energy
518 self.inshld = 0.0 # initial/max shield
519 self.inlsr = 0.0 # initial life support resources
520 self.indate = 0.0 # initial date
521 self.energy = 0.0 # energy level
522 self.shield = 0.0 # shield level
523 self.warpfac = 0.0 # warp speed
524 self.wfacsq = 0.0 # squared warp factor
525 self.lsupres = 0.0 # life support reserves
526 self.optime = 0.0 # time taken by current operation
527 self.docfac = 0.0 # repair factor when docking (constant?)
528 self.damfac = 0.0 # damage factor
529 self.lastchart = 0.0 # time star chart was last updated
530 self.cryprob = 0.0 # probability that crystal will work
531 self.probe = None # object holding probe course info
532 self.height = 0.0 # height of orbit around planet
534 # Stas thinks this should be (C expression):
535 # game.state.remkl + len(game.state.kcmdr) > 0 ?
536 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
537 # He says the existing expression is prone to divide-by-zero errors
538 # after killing the last klingon when score is shown -- perhaps also
539 # if the only remaining klingon is SCOM.
540 game.state.remtime = game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr))
586 #logfp.write("# withprob(%s) -> %f (%s) at %s\n" % (p, v, v<p, traceback.extract_stack()[-2][1:]))
589 def randrange(*args):
590 v = random.randrange(*args)
591 #logfp.write("# randrange%s -> %s at %s\n" % (args, v, traceback.extract_stack()[-2][1:]))
597 v *= args[0] # returns from [0, args[0])
599 v = args[0] + v*(args[1]-args[0]) # returns from [args[0], args[1])
600 #logfp.write("# randreal%s -> %s at %s\n" % (args, v, traceback.extract_stack()[-2][1:]))
603 # Code from ai.c begins here
606 "Would this quadrant welcome another Klingon?"
607 return iq.valid_quadrant() and \
608 not game.state.galaxy[iq.i][iq.j].supernova and \
609 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
611 def tryexit(enemy, look, irun):
612 "A bad guy attempts to bug out."
614 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
615 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
616 if not welcoming(iq):
618 if enemy.type == IHR:
619 return False; # Romulans cannot escape!
621 # avoid intruding on another commander's territory
622 if enemy.type == IHC:
623 if iq in game.state.kcmdr:
625 # refuse to leave if currently attacking starbase
626 if game.battle == game.quadrant:
628 # don't leave if over 1000 units of energy
629 if enemy.kpower > 1000.0:
631 # emit escape message and move out of quadrant.
632 # we know this if either short or long range sensors are working
633 if not damaged(DSRSENS) or not damaged(DLRSENS) or \
634 game.condition == "docked":
635 prout(crmena(True, enemy.type, "sector", enemy.kloc) + \
636 (_(" escapes to Quadrant %s (and regains strength).") % q))
637 # handle local matters related to escape
640 if game.condition != "docked":
642 # Handle global matters related to escape
643 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
644 game.state.galaxy[iq.i][iq.j].klingons += 1
649 schedule(FSCMOVE, 0.2777)
653 for cmdr in game.state.kcmdr:
654 if cmdr == game.quadrant:
655 game.state.kcmdr[n] = iq
657 return True; # success
659 # The bad-guy movement algorithm:
661 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
662 # If both are operating full strength, force is 1000. If both are damaged,
663 # force is -1000. Having shields down subtracts an additional 1000.
665 # 2. Enemy has forces equal to the energy of the attacker plus
666 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
667 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
669 # Attacker Initial energy levels (nominal):
670 # Klingon Romulan Commander Super-Commander
671 # Novice 400 700 1200
673 # Good 450 800 1300 1750
674 # Expert 475 850 1350 1875
675 # Emeritus 500 900 1400 2000
676 # VARIANCE 75 200 200 200
678 # Enemy vessels only move prior to their attack. In Novice - Good games
679 # only commanders move. In Expert games, all enemy vessels move if there
680 # is a commander present. In Emeritus games all enemy vessels move.
682 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
683 # forces are 1000 greater than Enterprise.
685 # Agressive action on average cuts the distance between the ship and
686 # the enemy to 1/4 the original.
688 # 4. At lower energy advantage, movement units are proportional to the
689 # advantage with a 650 advantage being to hold ground, 800 to move forward
690 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
692 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
693 # retreat, especially at high skill levels.
695 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
697 def movebaddy(enemy):
698 "Tactical movement for the bad guys."
699 next = coord(); look = coord()
701 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
702 if game.skill >= SKILL_EXPERT:
703 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
705 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
707 mdist = int(dist1 + 0.5); # Nearest integer distance
708 # If SC, check with spy to see if should hi-tail it
709 if enemy.type==IHS and \
710 (enemy.kpower <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
714 # decide whether to advance, retreat, or hold position
715 forces = enemy.kpower+100.0*len(game.enemies)+400*(nbaddys-1)
717 forces += 1000; # Good for enemy if shield is down!
718 if not damaged(DPHASER) or not damaged(DPHOTON):
719 if damaged(DPHASER): # phasers damaged
722 forces -= 0.2*(game.energy - 2500.0)
723 if damaged(DPHOTON): # photon torpedoes damaged
726 forces -= 50.0*game.torps
728 # phasers and photon tubes both out!
731 if forces <= 1000.0 and game.condition != "docked": # Typical situation
732 motion = ((forces + randreal(200))/150.0) - 5.0
734 if forces > 1000.0: # Very strong -- move in for kill
735 motion = (1.0 - randreal())**2 * dist1 + 1.0
736 if game.condition=="docked" and (game.options & OPTION_BASE): # protected by base -- back off !
737 motion -= game.skill*(2.0-randreal()**2)
739 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
740 # don't move if no motion
743 # Limit motion according to skill
744 if abs(motion) > game.skill:
749 # calculate preferred number of steps
750 nsteps = abs(int(motion))
751 if motion > 0 and nsteps > mdist:
752 nsteps = mdist; # don't overshoot
753 if nsteps > QUADSIZE:
754 nsteps = QUADSIZE; # This shouldn't be necessary
756 nsteps = 1; # This shouldn't be necessary
758 proutn("NSTEPS = %d:" % nsteps)
759 # Compute preferred values of delta X and Y
760 m = game.sector - enemy.kloc
761 if 2.0 * abs(m.i) < abs(m.j):
763 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.kloc.i):
765 m = (motion * m).sgn()
768 for ll in range(nsteps):
770 proutn(" %d" % (ll+1))
771 # Check if preferred position available
782 attempts = 0; # Settle mysterious hang problem
783 while attempts < 20 and not success:
785 if look.i < 0 or look.i >= QUADSIZE:
786 if motion < 0 and tryexit(enemy, look, irun):
788 if krawli == m.i or m.j == 0:
790 look.i = next.i + krawli
792 elif look.j < 0 or look.j >= QUADSIZE:
793 if motion < 0 and tryexit(enemy, look, irun):
795 if krawlj == m.j or m.i == 0:
797 look.j = next.j + krawlj
799 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != IHDOT:
800 # See if enemy should ram ship
801 if game.quad[look.i][look.j] == game.ship and \
802 (enemy.type == IHC or enemy.type == IHS):
803 collision(rammed=True, enemy=enemy)
805 if krawli != m.i and m.j != 0:
806 look.i = next.i + krawli
808 elif krawlj != m.j and m.i != 0:
809 look.j = next.j + krawlj
812 break; # we have failed
824 if not damaged(DSRSENS) or game.condition == "docked":
825 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.kloc))
826 if enemy.kdist < dist1:
827 proutn(_(" advances to "))
829 proutn(_(" retreats to "))
830 prout("Sector %s." % next)
833 "Sequence Klingon tactical movement."
836 # Figure out which Klingon is the commander (or Supercommander)
838 if game.quadrant in game.state.kcmdr:
839 for enemy in game.enemies:
840 if enemy.type == IHC:
842 if game.state.kscmdr==game.quadrant:
843 for enemy in game.enemies:
844 if enemy.type == IHS:
847 # If skill level is high, move other Klingons and Romulans too!
848 # Move these last so they can base their actions on what the
850 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
851 for enemy in game.enemies:
852 if enemy.type in (IHK, IHR):
854 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
856 def movescom(iq, avoid):
857 "Commander movement helper."
858 # Avoid quadrants with bases if we want to avoid Enterprise
859 if not welcoming(iq) or (avoid and iq in game.state.baseq):
861 if game.justin and not game.iscate:
864 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
865 game.state.kscmdr = iq
866 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
867 if game.state.kscmdr==game.quadrant:
868 # SC has scooted, Remove him from current quadrant
873 for enemy in game.enemies:
874 if enemy.type == IHS:
878 if game.condition != "docked":
880 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
881 # check for a helpful planet
882 for i in range(game.inplan):
883 if game.state.planets[i].quadrant == game.state.kscmdr and \
884 game.state.planets[i].crystals == "present":
886 game.state.planets[i].pclass = "destroyed"
887 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
890 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
891 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
892 prout(_(" by the Super-commander.\""))
894 return True; # looks good!
896 def supercommander():
897 "Move the Super Commander."
898 iq = coord(); sc = coord(); ibq = coord(); idelta = coord()
901 prout("== SUPERCOMMANDER")
902 # Decide on being active or passive
903 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 \
904 (game.state.date-game.indate) < 3.0)
905 if not game.iscate and avoid:
906 # compute move away from Enterprise
907 idelta = game.state.kscmdr-game.quadrant
908 if idelta.distance() > 2.0:
910 idelta.i = game.state.kscmdr.j-game.quadrant.j
911 idelta.j = game.quadrant.i-game.state.kscmdr.i
913 # compute distances to starbases
914 if not game.state.baseq:
918 sc = game.state.kscmdr
919 for base in game.state.baseq:
920 basetbl.append((i, (base - sc).distance()))
921 if game.state.baseq > 1:
922 basetbl.sort(lambda x, y: cmp(x[1]. y[1]))
923 # look for nearest base without a commander, no Enterprise, and
924 # without too many Klingons, and not already under attack.
925 ifindit = iwhichb = 0
926 for (i2, base) in enumerate(game.state.baseq):
927 i = basetbl[i2][0]; # bug in original had it not finding nearest
928 if base==game.quadrant or base==game.battle or not welcoming(base):
930 # if there is a commander, and no other base is appropriate,
931 # we will take the one with the commander
932 for cmdr in game.state.kcmdr:
933 if base == cmdr and ifindit != 2:
937 else: # no commander -- use this one
942 return # Nothing suitable -- wait until next time
943 ibq = game.state.baseq[iwhichb]
944 # decide how to move toward base
945 idelta = ibq - game.state.kscmdr
946 # Maximum movement is 1 quadrant in either or both axes
947 idelta = idelta.sgn()
948 # try moving in both x and y directions
949 # there was what looked like a bug in the Almy C code here,
950 # but it might be this translation is just wrong.
951 iq = game.state.kscmdr + idelta
952 if not movescom(iq, avoid):
953 # failed -- try some other maneuvers
954 if idelta.i==0 or idelta.j==0:
957 iq.j = game.state.kscmdr.j + 1
958 if not movescom(iq, avoid):
959 iq.j = game.state.kscmdr.j - 1
962 iq.i = game.state.kscmdr.i + 1
963 if not movescom(iq, avoid):
964 iq.i = game.state.kscmdr.i - 1
967 # try moving just in x or y
968 iq.j = game.state.kscmdr.j
969 if not movescom(iq, avoid):
970 iq.j = game.state.kscmdr.j + idelta.j
971 iq.i = game.state.kscmdr.i
974 if len(game.state.baseq) == 0:
977 for ibq in game.state.baseq:
978 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
981 return # no, don't attack base!
984 schedule(FSCDBAS, randreal(1.0, 3.0))
985 if is_scheduled(FCDBAS):
986 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
987 if not communicating():
991 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
993 prout(_(" reports that it is under attack from the Klingon Super-commander."))
994 proutn(_(" It can survive until stardate %d.\"") \
995 % int(scheduled(FSCDBAS)))
998 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
1001 game.resting = False
1002 game.optime = 0.0; # actually finished
1004 # Check for intelligence report
1007 (not communicating()) or \
1008 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
1011 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
1012 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
1017 if not game.tholian or game.justin:
1020 if game.tholian.kloc.i == 0 and game.tholian.kloc.j == 0:
1021 id.i = 0; id.j = QUADSIZE-1
1022 elif game.tholian.kloc.i == 0 and game.tholian.kloc.j == QUADSIZE-1:
1023 id.i = QUADSIZE-1; id.j = QUADSIZE-1
1024 elif game.tholian.kloc.i == QUADSIZE-1 and game.tholian.kloc.j == QUADSIZE-1:
1025 id.i = QUADSIZE-1; id.j = 0
1026 elif game.tholian.kloc.i == QUADSIZE-1 and game.tholian.kloc.j == 0:
1029 # something is wrong!
1030 game.tholian.move(None)
1031 prout("***Internal error: Tholian in a bad spot.")
1033 # do nothing if we are blocked
1034 if game.quad[id.i][id.j] not in (IHDOT, IHWEB):
1036 here = copy.copy(game.tholian.kloc)
1037 delta = (id - game.tholian.kloc).sgn()
1039 while here.i != id.i:
1041 if game.quad[here.i][here.j]==IHDOT:
1042 game.tholian.move(here)
1044 while here.j != id.j:
1046 if game.quad[here.i][here.j]==IHDOT:
1047 game.tholian.move(here)
1048 # check to see if all holes plugged
1049 for i in range(QUADSIZE):
1050 if game.quad[0][i]!=IHWEB and game.quad[0][i]!=IHT:
1052 if game.quad[QUADSIZE-1][i]!=IHWEB and game.quad[QUADSIZE-1][i]!=IHT:
1054 if game.quad[i][0]!=IHWEB and game.quad[i][0]!=IHT:
1056 if game.quad[i][QUADSIZE-1]!=IHWEB and game.quad[i][QUADSIZE-1]!=IHT:
1058 # All plugged up -- Tholian splits
1059 game.quad[game.tholian.kloc.i][game.tholian.kloc.j]=IHWEB
1061 prout(crmena(True, IHT, "sector", game.tholian) + _(" completes web."))
1062 game.tholian.move(None)
1065 # Code from battle.c begins here
1067 def doshield(shraise):
1068 "Change shield status."
1074 key = scanner.next()
1075 if key == "IHALPHA":
1076 if scanner.sees("transfer"):
1079 if damaged(DSHIELD):
1080 prout(_("Shields damaged and down."))
1082 if scanner.sees("up"):
1084 elif scanner.sees("down"):
1087 proutn(_("Do you wish to change shield energy? "))
1089 proutn(_("Energy to transfer to shields- "))
1091 elif damaged(DSHIELD):
1092 prout(_("Shields damaged and down."))
1095 proutn(_("Shields are up. Do you want them down? "))
1102 proutn(_("Shields are down. Do you want them up? "))
1108 if action == "SHUP": # raise shields
1110 prout(_("Shields already up."))
1114 if game.condition != "docked":
1116 prout(_("Shields raised."))
1117 if game.energy <= 0:
1119 prout(_("Shields raising uses up last of energy."))
1124 elif action == "SHDN":
1126 prout(_("Shields already down."))
1130 prout(_("Shields lowered."))
1133 elif action == "NRG":
1134 while scanner.next() != "IHREAL":
1136 proutn(_("Energy to transfer to shields- "))
1138 if scanner.real == 0:
1140 if scanner.real > game.energy:
1141 prout(_("Insufficient ship energy."))
1144 if game.shield+scanner.real >= game.inshld:
1145 prout(_("Shield energy maximized."))
1146 if game.shield+scanner.real > game.inshld:
1147 prout(_("Excess energy requested returned to ship energy"))
1148 game.energy -= game.inshld-game.shield
1149 game.shield = game.inshld
1151 if scanner.real < 0.0 and game.energy-scanner.real > game.inenrg:
1152 # Prevent shield drain loophole
1154 prout(_("Engineering to bridge--"))
1155 prout(_(" Scott here. Power circuit problem, Captain."))
1156 prout(_(" I can't drain the shields."))
1159 if game.shield+scanner.real < 0:
1160 prout(_("All shield energy transferred to ship."))
1161 game.energy += game.shield
1164 proutn(_("Scotty- \""))
1165 if scanner.real > 0:
1166 prout(_("Transferring energy to shields.\""))
1168 prout(_("Draining energy from shields.\""))
1169 game.shield += scanner.real
1170 game.energy -= scanner.real
1174 "Choose a device to damage, at random."
1175 # Quoth Eric Allman in the code of BSD-Trek:
1176 # "Under certain conditions you can get a critical hit. This
1177 # sort of hit damages devices. The probability that a given
1178 # device is damaged depends on the device. Well protected
1179 # devices (such as the computer, which is in the core of the
1180 # ship and has considerable redundancy) almost never get
1181 # damaged, whereas devices which are exposed (such as the
1182 # warp engines) or which are particularly delicate (such as
1183 # the transporter) have a much higher probability of being
1186 # This is one place where OPTION_PLAIN does not restore the
1187 # original behavior, which was equiprobable damage across
1188 # all devices. If we wanted that, we'd return randrange(NDEVICES)
1189 # and have done with it. Also, in the original game, DNAVYS
1190 # and DCOMPTR were the same device.
1192 # Instead, we use a table of weights similar to the one from BSD Trek.
1193 # BSD doesn't have the shuttle, shield controller, death ray, or probes.
1194 # We don't have a cloaking device. The shuttle got the allocation
1195 # for the cloaking device, then we shaved a half-percent off
1196 # everything to have some weight to give DSHCTRL/DDRAY/DDSP.
1198 105, # DSRSENS: short range scanners 10.5%
1199 105, # DLRSENS: long range scanners 10.5%
1200 120, # DPHASER: phasers 12.0%
1201 120, # DPHOTON: photon torpedoes 12.0%
1202 25, # DLIFSUP: life support 2.5%
1203 65, # DWARPEN: warp drive 6.5%
1204 70, # DIMPULS: impulse engines 6.5%
1205 145, # DSHIELD: deflector shields 14.5%
1206 30, # DRADIO: subspace radio 3.0%
1207 45, # DSHUTTL: shuttle 4.5%
1208 15, # DCOMPTR: computer 1.5%
1209 20, # NAVCOMP: navigation system 2.0%
1210 75, # DTRANSP: transporter 7.5%
1211 20, # DSHCTRL: high-speed shield controller 2.0%
1212 10, # DDRAY: death ray 1.0%
1213 30, # DDSP: deep-space probes 3.0%
1215 idx = randrange(1000) # weights must sum to 1000
1217 for (i, w) in enumerate(weights):
1221 return None; # we should never get here
1223 def collision(rammed, enemy):
1224 "Collision handling fot rammong events."
1225 prouts(_("***RED ALERT! RED ALERT!"))
1227 prout(_("***COLLISION IMMINENT."))
1231 hardness = {IHR:1.5, IHC:2.0, IHS:2.5, IHT:0.5, IHQUEST:4.0}.get(enemy.type, 1.0)
1233 proutn(_(" rammed by "))
1236 proutn(crmena(False, enemy.type, "sector", enemy.kloc))
1238 proutn(_(" (original position)"))
1240 deadkl(enemy.kloc, enemy.type, game.sector)
1241 proutn("***" + crmship() + " heavily damaged.")
1242 icas = randrange(10, 30)
1243 prout(_("***Sickbay reports %d casualties"), icas)
1245 game.state.crew -= icas
1246 # In the pre-SST2K version, all devices got equiprobably damaged,
1247 # which was silly. Instead, pick up to half the devices at
1248 # random according to our weighting table,
1249 ncrits = randrange(NDEVICES/2)
1250 for m in range(ncrits):
1252 if game.damage[dev] < 0:
1254 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1255 # Damage for at least time of travel!
1256 game.damage[dev] += game.optime + extradm
1258 prout(_("***Shields are down."))
1259 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1266 def torpedo(origin, bearing, dispersion, number, nburst):
1267 "Let a photon torpedo fly"
1268 if not damaged(DSRSENS) or game.condition=="docked":
1269 setwnd(srscan_window)
1271 setwnd(message_window)
1272 ac = bearing + 0.25*dispersion # dispersion is a random variable
1273 bullseye = (15.0 - bearing)*0.5235988
1274 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1275 bumpto = coord(0, 0)
1276 # Loop to move a single torpedo
1277 setwnd(message_window)
1278 for step in range(1, QUADSIZE*2):
1279 if not track.next(): break
1281 if not w.valid_sector():
1283 iquad=game.quad[w.i][w.j]
1284 tracktorpedo(origin, w, step, number, nburst, iquad)
1288 if not damaged(DSRSENS) or game.condition == "docked":
1289 skip(1); # start new line after text track
1290 if iquad in (IHE, IHF): # Hit our ship
1292 prout(_("Torpedo hits %s.") % crmshp())
1293 hit = 700.0 + randreal(100) - \
1294 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1295 newcnd(); # we're blown out of dock
1296 if game.landed or game.condition=="docked":
1297 return hit # Cheat if on a planet
1298 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1299 # is 143 degrees, which is almost exactly 4.8 clockface units
1300 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1302 bumpto = displacement.sector()
1303 if not bumpto.valid_sector():
1305 if game.quad[bumpto.i][bumpto.j]==IHBLANK:
1308 if game.quad[bumpto.i][bumpto.j]!=IHDOT:
1309 # can't move into object
1311 game.sector = bumpto
1313 game.quad[w.i][w.j]=IHDOT
1314 game.quad[bumpto.i][bumpto.j]=iquad
1315 prout(_(" displaced by blast to Sector %s ") % bumpto)
1316 for enemy in game.enemies:
1317 enemy.kdist = enemy.kavgd = (game.sector-enemy.kloc).distance()
1318 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1320 elif iquad in (IHC, IHS, IHR, IHK): # Hit a regular enemy
1322 if iquad in (IHC, IHS) and withprob(0.05):
1323 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1324 prout(_(" torpedo neutralized."))
1326 for enemy in game.enemies:
1329 kp = math.fabs(enemy.kpower)
1330 h1 = 700.0 + randrange(100) - \
1331 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1335 if enemy.kpower < 0:
1339 if enemy.kpower == 0:
1342 proutn(crmena(True, iquad, "sector", w))
1343 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1345 bumpto = displacement.sector()
1346 if not bumpto.valid_sector():
1347 prout(_(" damaged but not destroyed."))
1349 if game.quad[bumpto.i][bumpto.j] == IHBLANK:
1350 prout(_(" buffeted into black hole."))
1351 deadkl(w, iquad, bumpto)
1352 if game.quad[bumpto.i][bumpto.j] != IHDOT:
1353 prout(_(" damaged but not destroyed."))
1355 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1357 game.quad[w.i][w.j]=IHDOT
1358 game.quad[bumpto.i][bumpto.j]=iquad
1359 for enemy in game.enemies:
1360 enemy.kdist = enemy.kavgd = (game.sector-enemy.kloc).distance()
1361 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1363 elif iquad == IHB: # Hit a base
1365 prout(_("***STARBASE DESTROYED.."))
1366 game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
1367 game.quad[w.i][w.j]=IHDOT
1368 game.base.invalidate()
1369 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1
1370 game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1
1371 game.state.basekl += 1
1374 elif iquad == IHP: # Hit a planet
1375 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1376 game.state.nplankl += 1
1377 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1378 game.iplnet.pclass = "destroyed"
1380 game.plnet.invalidate()
1381 game.quad[w.i][w.j] = IHDOT
1383 # captain perishes on planet
1386 elif iquad == IHW: # Hit an inhabited world -- very bad!
1387 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1388 game.state.nworldkl += 1
1389 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1390 game.iplnet.pclass = "destroyed"
1392 game.plnet.invalidate()
1393 game.quad[w.i][w.j] = IHDOT
1395 # captain perishes on planet
1397 prout(_("The torpedo destroyed an inhabited planet."))
1399 elif iquad == IHSTAR: # Hit a star
1403 prout(crmena(True, IHSTAR, "sector", w) + _(" unaffected by photon blast."))
1405 elif iquad == IHQUEST: # Hit a thingy
1406 if not (game.options & OPTION_THINGY) or withprob(0.3):
1408 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1410 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1412 proutn(_("Mr. Spock-"))
1413 prouts(_(" \"Fascinating!\""))
1417 # Stas Sergeev added the possibility that
1418 # you can shove the Thingy and piss it off.
1419 # It then becomes an enemy and may fire at you.
1423 elif iquad == IHBLANK: # Black hole
1425 prout(crmena(True, IHBLANK, "sector", w) + _(" swallows torpedo."))
1427 elif iquad == IHWEB: # hit the web
1429 prout(_("***Torpedo absorbed by Tholian web."))
1431 elif iquad == IHT: # Hit a Tholian
1432 h1 = 700.0 + randrange(100) - \
1433 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle))
1436 game.quad[w.i][w.j] = IHDOT
1441 proutn(crmena(True, IHT, "sector", w))
1443 prout(_(" survives photon blast."))
1445 prout(_(" disappears."))
1446 game.tholian.move(None)
1447 game.quad[w.i][w.j] = IHWEB
1452 proutn("Don't know how to handle torpedo collision with ")
1453 proutn(crmena(True, iquad, "sector", w))
1458 prout(_("Torpedo missed."))
1462 "Critical-hit resolution."
1463 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1465 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1466 proutn(_("***CRITICAL HIT--"))
1467 # Select devices and cause damage
1469 for loop1 in range(ncrit):
1472 # Cheat to prevent shuttle damage unless on ship
1473 if not (game.damage[j]<0.0 or (j==DSHUTTL and game.iscraft != "onship")):
1476 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1477 game.damage[j] += extradm
1479 for (i, j) in enumerate(cdam):
1481 if skipcount % 3 == 2 and i < len(cdam)-1:
1486 prout(_(" damaged."))
1487 if damaged(DSHIELD) and game.shldup:
1488 prout(_("***Shields knocked down."))
1491 def attack(torps_ok):
1492 # bad guy attacks us
1493 # torps_ok == False forces use of phasers in an attack
1494 # game could be over at this point, check
1497 attempt = False; ihurt = False;
1498 hitmax=0.0; hittot=0.0; chgfac=1.0
1501 prout("=== ATTACK!")
1502 # Tholian gets to move before attacking
1505 # if you have just entered the RNZ, you'll get a warning
1506 if game.neutz: # The one chance not to be attacked
1509 # commanders get a chance to tac-move towards you
1510 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:
1512 # if no enemies remain after movement, we're done
1513 if len(game.enemies)==0 or (len(game.enemies)==1 and thing == game.quadrant and not thing.angry):
1515 # set up partial hits if attack happens during shield status change
1516 pfac = 1.0/game.inshld
1518 chgfac = 0.25 + randreal(0.5)
1520 # message verbosity control
1521 if game.skill <= SKILL_FAIR:
1523 for enemy in game.enemies:
1524 if enemy.kpower < 0:
1525 continue; # too weak to attack
1526 # compute hit strength and diminish shield power
1528 # Increase chance of photon torpedos if docked or enemy energy is low
1529 if game.condition == "docked":
1531 if enemy.kpower < 500:
1533 if enemy.type==IHT or (enemy.type==IHQUEST and not thing.angry):
1535 # different enemies have different probabilities of throwing a torp
1536 usephasers = not torps_ok or \
1537 (enemy.type == IHK and r > 0.0005) or \
1538 (enemy.type==IHC and r > 0.015) or \
1539 (enemy.type==IHR and r > 0.3) or \
1540 (enemy.type==IHS and r > 0.07) or \
1541 (enemy.type==IHQUEST and r > 0.05)
1542 if usephasers: # Enemy uses phasers
1543 if game.condition == "docked":
1544 continue; # Don't waste the effort!
1545 attempt = True; # Attempt to attack
1546 dustfac = randreal(0.8, 0.85)
1547 hit = enemy.kpower*math.pow(dustfac,enemy.kavgd)
1548 enemy.kpower *= 0.75
1549 else: # Enemy uses photon torpedo
1550 # We should be able to make the bearing() method work here
1551 course = 1.90985*math.atan2(game.sector.j-enemy.kloc.j, enemy.kloc.i-game.sector.i)
1553 proutn(_("***TORPEDO INCOMING"))
1554 if not damaged(DSRSENS):
1555 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.kloc))
1558 dispersion = (randreal()+randreal())*0.5 - 0.5
1559 dispersion += 0.002*enemy.kpower*dispersion
1560 hit = torpedo(enemy.kloc, course, dispersion, number=1, nburst=1)
1561 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1562 finish(FWON); # Klingons did themselves in!
1563 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1564 return # Supernova or finished
1567 # incoming phaser or torpedo, shields may dissipate it
1568 if game.shldup or game.shldchg or game.condition=="docked":
1569 # shields will take hits
1570 propor = pfac * game.shield
1571 if game.condition =="docked":
1575 hitsh = propor*chgfac*hit+1.0
1577 if absorb > game.shield:
1578 absorb = game.shield
1579 game.shield -= absorb
1581 # taking a hit blasts us out of a starbase dock
1582 if game.condition == "docked":
1584 # but the shields may take care of it
1585 if propor > 0.1 and hit < 0.005*game.energy:
1587 # hit from this opponent got through shields, so take damage
1589 proutn(_("%d unit hit") % int(hit))
1590 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1591 proutn(_(" on the ") + crmshp())
1592 if not damaged(DSRSENS) and usephasers:
1593 prout(_(" from ") + crmena(False, enemy.type, where, enemy.kloc))
1595 # Decide if hit is critical
1601 if game.energy <= 0:
1602 # Returning home upon your shield, not with it...
1605 if not attempt and game.condition == "docked":
1606 prout(_("***Enemies decide against attacking your ship."))
1607 percent = 100.0*pfac*game.shield+0.5
1609 # Shields fully protect ship
1610 proutn(_("Enemy attack reduces shield strength to "))
1612 # Emit message if starship suffered hit(s)
1614 proutn(_("Energy left %2d shields ") % int(game.energy))
1617 elif not damaged(DSHIELD):
1620 proutn(_("damaged, "))
1621 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1622 # Check if anyone was hurt
1623 if hitmax >= 200 or hittot >= 500:
1624 icas = randrange(int(hittot * 0.015))
1627 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1628 prout(_(" in that last attack.\""))
1630 game.state.crew -= icas
1631 # After attack, reset average distance to enemies
1632 for enemy in game.enemies:
1633 enemy.kavgd = enemy.kdist
1634 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1637 def deadkl(w, type, mv):
1638 "Kill a Klingon, Tholian, Romulan, or Thingy."
1639 # Added mv to allow enemy to "move" before dying
1640 proutn(crmena(True, type, "sector", mv))
1641 # Decide what kind of enemy it is and update appropriately
1643 # Chalk up a Romulan
1644 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1646 game.state.nromrem -= 1
1650 elif type == IHQUEST:
1655 # Killed some type of Klingon
1656 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1659 game.state.kcmdr.remove(game.quadrant)
1661 if game.state.kcmdr:
1662 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1663 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1666 game.state.remkl -= 1
1668 game.state.nscrem -= 1
1669 game.state.kscmdr.invalidate()
1674 # For each kind of enemy, finish message to player
1675 prout(_(" destroyed."))
1676 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1679 # Remove enemy ship from arrays describing local conditions
1680 for e in game.enemies:
1687 "Return None if target is invalid, otherwise return a course angle."
1688 if not w.valid_sector():
1692 # FIXME: C code this was translated from is wacky -- why the sign reversal?
1693 delta.j = (w.j - game.sector.j);
1694 delta.i = (game.sector.i - w.i);
1695 if delta == coord(0, 0):
1697 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1698 prout(_(" I recommend an immediate review of"))
1699 prout(_(" the Captain's psychological profile.\""))
1702 return delta.bearing()
1705 "Launch photon torpedo."
1708 if damaged(DPHOTON):
1709 prout(_("Photon tubes damaged."))
1713 prout(_("No torpedoes left."))
1716 # First, get torpedo count
1719 if scanner.token == "IHALPHA":
1722 elif scanner.token == "IHEOL" or not scanner.waiting():
1723 prout(_("%d torpedoes left.") % game.torps)
1725 proutn(_("Number of torpedoes to fire- "))
1726 continue # Go back around to get a number
1727 else: # key == "IHREAL"
1729 if n <= 0: # abort command
1734 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1737 scanner.chew() # User requested more torps than available
1738 continue # Go back around
1739 break # All is good, go to next stage
1743 key = scanner.next()
1744 if i==0 and key == "IHEOL":
1745 break; # no coordinate waiting, we will try prompting
1746 if i==1 and key == "IHEOL":
1747 # direct all torpedoes at one target
1749 target.append(target[0])
1750 course.append(course[0])
1753 scanner.push(scanner.token)
1754 target.append(scanner.getcoord())
1755 if target[-1] == None:
1757 course.append(targetcheck(target[-1]))
1758 if course[-1] == None:
1761 if len(target) == 0:
1762 # prompt for each one
1764 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1766 target.append(scanner.getcoord())
1767 if target[-1] == None:
1769 course.append(targetcheck(target[-1]))
1770 if course[-1] == None:
1773 # Loop for moving <n> torpedoes
1775 if game.condition != "docked":
1777 dispersion = (randreal()+randreal())*0.5 -0.5
1778 if math.fabs(dispersion) >= 0.47:
1780 dispersion *= randreal(1.2, 2.2)
1782 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1784 prouts(_("***TORPEDO MISFIRES."))
1787 prout(_(" Remainder of burst aborted."))
1789 prout(_("***Photon tubes damaged by misfire."))
1790 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1792 if game.shldup or game.condition == "docked":
1793 dispersion *= 1.0 + 0.0001*game.shield
1794 torpedo(game.sector, course[i], dispersion, number=i, nburst=n)
1795 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1797 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1801 "Check for phasers overheating."
1803 checkburn = (rpow-1500.0)*0.00038
1804 if withprob(checkburn):
1805 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1806 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1808 def checkshctrl(rpow):
1809 "Check shield control."
1812 prout(_("Shields lowered."))
1814 # Something bad has happened
1815 prouts(_("***RED ALERT! RED ALERT!"))
1817 hit = rpow*game.shield/game.inshld
1818 game.energy -= rpow+hit*0.8
1819 game.shield -= hit*0.2
1820 if game.energy <= 0.0:
1821 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1826 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1828 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1829 icas = randrange(int(hit*0.012))
1834 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1835 prout(_(" %d casualties so far.\"") % icas)
1837 game.state.crew -= icas
1839 prout(_("Phaser energy dispersed by shields."))
1840 prout(_("Enemy unaffected."))
1845 "Register a phaser hit on Klingons and Romulans."
1846 nenhr2 = len(game.enemies); kk=0
1849 for (k, wham) in enumerate(hits):
1852 dustfac = randreal(0.9, 1.0)
1853 hit = wham*math.pow(dustfac,game.enemies[kk].kdist)
1854 kpini = game.enemies[kk].kpower
1855 kp = math.fabs(kpini)
1856 if PHASEFAC*hit < kp:
1858 if game.enemies[kk].kpower < 0:
1859 game.enemies[kk].kpower -= -kp
1861 game.enemies[kk].kpower -= kp
1862 kpow = game.enemies[kk].kpower
1863 w = game.enemies[kk].kloc
1865 if not damaged(DSRSENS):
1867 proutn(_("%d unit hit on ") % int(hit))
1869 proutn(_("Very small hit on "))
1870 ienm = game.quad[w.i][w.j]
1873 proutn(crmena(False, ienm, "sector", w))
1877 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1881 kk -= 1 # don't do the increment
1883 else: # decide whether or not to emasculate klingon
1884 if kpow>0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1885 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1886 prout(_(" has just lost its firepower.\""))
1887 game.enemies[kk].kpower = -kpow
1892 "Fire phasers at bad guys."
1894 kz = 0; k = 1; irec=0 # Cheating inhibitor
1895 ifast = False; no = False; itarg = True; msgflag = True; rpow=0
1899 # SR sensors and Computer are needed for automode
1900 if damaged(DSRSENS) or damaged(DCOMPTR):
1902 if game.condition == "docked":
1903 prout(_("Phasers can't be fired through base shields."))
1906 if damaged(DPHASER):
1907 prout(_("Phaser control damaged."))
1911 if damaged(DSHCTRL):
1912 prout(_("High speed shield control damaged."))
1915 if game.energy <= 200.0:
1916 prout(_("Insufficient energy to activate high-speed shield control."))
1919 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1921 # Original code so convoluted, I re-did it all
1922 # (That was Tom Almy talking about the C code, I think -- ESR)
1923 while automode=="NOTSET":
1925 if key == "IHALPHA":
1926 if scanner.sees("manual"):
1927 if len(game.enemies)==0:
1928 prout(_("There is no enemy present to select."))
1931 automode="AUTOMATIC"
1934 key = scanner.next()
1935 elif scanner.sees("automatic"):
1936 if (not itarg) and len(game.enemies) != 0:
1937 automode = "FORCEMAN"
1939 if len(game.enemies)==0:
1940 prout(_("Energy will be expended into space."))
1941 automode = "AUTOMATIC"
1942 key = scanner.next()
1943 elif scanner.sees("no"):
1948 elif key == "IHREAL":
1949 if len(game.enemies)==0:
1950 prout(_("Energy will be expended into space."))
1951 automode = "AUTOMATIC"
1953 automode = "FORCEMAN"
1955 automode = "AUTOMATIC"
1958 if len(game.enemies)==0:
1959 prout(_("Energy will be expended into space."))
1960 automode = "AUTOMATIC"
1962 automode = "FORCEMAN"
1964 proutn(_("Manual or automatic? "))
1969 if automode == "AUTOMATIC":
1970 if key == "IHALPHA" and scanner.sees("no"):
1972 key = scanner.next()
1973 if key != "IHREAL" and len(game.enemies) != 0:
1974 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1979 for i in range(len(game.enemies)):
1980 irec += math.fabs(game.enemies[i].kpower)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1982 proutn(_("%d units required. ") % irec)
1984 proutn(_("Units to fire= "))
1985 key = scanner.next()
1990 proutn(_("Energy available= %.2f") % avail)
1993 if not rpow > avail:
2000 if key == "IHALPHA" and scanner.sees("no"):
2003 game.energy -= 200; # Go and do it!
2004 if checkshctrl(rpow):
2009 if len(game.enemies):
2012 for i in range(len(game.enemies)):
2016 hits[i] = math.fabs(game.enemies[i].kpower)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))
2017 over = randreal(1.01, 1.06) * hits[i]
2019 powrem -= hits[i] + over
2020 if powrem <= 0 and temp < hits[i]:
2029 if extra > 0 and not game.alldone:
2031 proutn(_("*** Tholian web absorbs "))
2032 if len(game.enemies)>0:
2033 proutn(_("excess "))
2034 prout(_("phaser energy."))
2036 prout(_("%d expended on empty space.") % int(extra))
2037 elif automode == "FORCEMAN":
2040 if damaged(DCOMPTR):
2041 prout(_("Battle computer damaged, manual fire only."))
2044 prouts(_("---WORKING---"))
2046 prout(_("Short-range-sensors-damaged"))
2047 prout(_("Insufficient-data-for-automatic-phaser-fire"))
2048 prout(_("Manual-fire-must-be-used"))
2050 elif automode == "MANUAL":
2052 for k in range(len(game.enemies)):
2053 aim = game.enemies[k].kloc
2054 ienm = game.quad[aim.i][aim.j]
2056 proutn(_("Energy available= %.2f") % (avail-0.006))
2060 if damaged(DSRSENS) and \
2061 not game.sector.distance(aim)<2**0.5 and ienm in (IHC, IHS):
2062 prout(cramen(ienm) + _(" can't be located without short range scan."))
2065 hits[k] = 0; # prevent overflow -- thanks to Alexei Voitenko
2070 if itarg and k > kz:
2071 irec=(abs(game.enemies[k].kpower)/(PHASEFAC*math.pow(0.9,game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
2074 if not damaged(DCOMPTR):
2079 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
2080 key = scanner.next()
2081 if key == "IHALPHA" and scanner.sees("no"):
2083 key = scanner.next()
2085 if key == "IHALPHA":
2089 if k==1: # Let me say I'm baffled by this
2092 if scanner.real < 0:
2096 hits[k] = scanner.real
2097 rpow += scanner.real
2098 # If total requested is too much, inform and start over
2100 prout(_("Available energy exceeded -- try again."))
2103 key = scanner.next(); # scan for next value
2106 # zero energy -- abort
2109 if key == "IHALPHA" and scanner.sees("no"):
2114 game.energy -= 200.0
2115 if checkshctrl(rpow):
2119 # Say shield raised or malfunction, if necessary
2126 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
2127 prouts(_(" CLICK CLICK POP . . ."))
2128 prout(_(" No response, sir!"))
2131 prout(_("Shields raised."))
2136 # Code from events,c begins here.
2138 # This isn't a real event queue a la BSD Trek yet -- you can only have one
2139 # event of each type active at any given time. Mostly these means we can
2140 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
2141 # BSD Trek, from which we swiped the idea, can have up to 5.
2143 def unschedule(evtype):
2144 "Remove an event from the schedule."
2145 game.future[evtype].date = FOREVER
2146 return game.future[evtype]
2148 def is_scheduled(evtype):
2149 "Is an event of specified type scheduled."
2150 return game.future[evtype].date != FOREVER
2152 def scheduled(evtype):
2153 "When will this event happen?"
2154 return game.future[evtype].date
2156 def schedule(evtype, offset):
2157 "Schedule an event of specified type."
2158 game.future[evtype].date = game.state.date + offset
2159 return game.future[evtype]
2161 def postpone(evtype, offset):
2162 "Postpone a scheduled event."
2163 game.future[evtype].date += offset
2166 "Rest period is interrupted by event."
2169 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2171 game.resting = False
2177 "Run through the event queue looking for things to do."
2179 fintim = game.state.date + game.optime; yank=0
2180 ictbeam = False; istract = False
2181 w = coord(); hold = coord()
2182 ev = event(); ev2 = event()
2184 def tractorbeam(yank):
2185 "Tractor-beaming cases merge here."
2187 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2189 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2190 # If Kirk & Co. screwing around on planet, handle
2191 atover(True) # atover(true) is Grab
2194 if game.icraft: # Caught in Galileo?
2197 # Check to see if shuttle is aboard
2198 if game.iscraft == "offship":
2201 prout(_("Galileo, left on the planet surface, is captured"))
2202 prout(_("by aliens and made into a flying McDonald's."))
2203 game.damage[DSHUTTL] = -10
2204 game.iscraft = "removed"
2206 prout(_("Galileo, left on the planet surface, is well hidden."))
2208 game.quadrant = game.state.kscmdr
2210 game.quadrant = game.state.kcmdr[i]
2211 game.sector = randplace(QUADSIZE)
2212 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2213 % (game.quadrant, game.sector))
2215 prout(_("(Remainder of rest/repair period cancelled.)"))
2216 game.resting = False
2218 if not damaged(DSHIELD) and game.shield > 0:
2219 doshield(shraise=True) # raise shields
2220 game.shldchg = False
2222 prout(_("(Shields not currently useable.)"))
2224 # Adjust finish time to time of tractor beaming
2225 fintim = game.state.date+game.optime
2226 attack(torps_ok=False)
2227 if not game.state.kcmdr:
2230 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2233 "Code merges here for any commander destroying a starbase."
2234 # Not perfect, but will have to do
2235 # Handle case where base is in same quadrant as starship
2236 if game.battle == game.quadrant:
2237 game.state.chart[game.battle.i][game.battle.j].starbase = False
2238 game.quad[game.base.i][game.base.j] = IHDOT
2239 game.base.invalidate()
2242 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2243 elif game.state.baseq and communicating():
2244 # Get word via subspace radio
2247 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2248 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2250 prout(_("the Klingon Super-Commander"))
2252 prout(_("a Klingon Commander"))
2253 game.state.chart[game.battle.i][game.battle.j].starbase = False
2254 # Remove Starbase from galaxy
2255 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2256 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2258 # reinstate a commander's base attack
2262 game.battle.invalidate()
2264 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2265 for i in range(1, NEVENTS):
2266 if i == FSNOVA: proutn("=== Supernova ")
2267 elif i == FTBEAM: proutn("=== T Beam ")
2268 elif i == FSNAP: proutn("=== Snapshot ")
2269 elif i == FBATTAK: proutn("=== Base Attack ")
2270 elif i == FCDBAS: proutn("=== Base Destroy ")
2271 elif i == FSCMOVE: proutn("=== SC Move ")
2272 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2273 elif i == FDSPROB: proutn("=== Probe Move ")
2274 elif i == FDISTR: proutn("=== Distress Call ")
2275 elif i == FENSLV: proutn("=== Enslavement ")
2276 elif i == FREPRO: proutn("=== Klingon Build ")
2278 prout("%.2f" % (scheduled(i)))
2281 radio_was_broken = damaged(DRADIO)
2284 # Select earliest extraneous event, evcode==0 if no events
2289 for l in range(1, NEVENTS):
2290 if game.future[l].date < datemin:
2293 prout("== Event %d fires" % evcode)
2294 datemin = game.future[l].date
2295 xtime = datemin-game.state.date
2296 game.state.date = datemin
2297 # Decrement Federation resources and recompute remaining time
2298 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2300 if game.state.remtime <=0:
2303 # Any crew left alive?
2304 if game.state.crew <=0:
2307 # Is life support adequate?
2308 if damaged(DLIFSUP) and game.condition != "docked":
2309 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2312 game.lsupres -= xtime
2313 if game.damage[DLIFSUP] <= xtime:
2314 game.lsupres = game.inlsr
2317 if game.condition == "docked":
2318 repair /= game.docfac
2319 # Don't fix Deathray here
2320 for l in range(NDEVICES):
2321 if game.damage[l] > 0.0 and l != DDRAY:
2322 if game.damage[l]-repair > 0.0:
2323 game.damage[l] -= repair
2325 game.damage[l] = 0.0
2326 # If radio repaired, update star chart and attack reports
2327 if radio_was_broken and not damaged(DRADIO):
2328 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2329 prout(_(" surveillance reports are coming in."))
2331 if not game.iseenit:
2335 prout(_(" The star chart is now up to date.\""))
2337 # Cause extraneous event EVCODE to occur
2338 game.optime -= xtime
2339 if evcode == FSNOVA: # Supernova
2342 schedule(FSNOVA, expran(0.5*game.intime))
2343 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2345 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2346 if game.state.nscrem == 0 or \
2347 ictbeam or istract or \
2348 game.condition=="docked" or game.isatb==1 or game.iscate:
2350 if game.ientesc or \
2351 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2352 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2353 (damaged(DSHIELD) and \
2354 (game.energy < 2500 or damaged(DPHASER)) and \
2355 (game.torps < 5 or damaged(DPHOTON))):
2357 istract = ictbeam = True
2358 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2361 elif evcode == FTBEAM: # Tractor beam
2362 if not game.state.kcmdr:
2365 i = randrange(len(game.state.kcmdr))
2366 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2367 if istract or game.condition == "docked" or yank == 0:
2368 # Drats! Have to reschedule
2370 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2374 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2375 game.snapsht = copy.deepcopy(game.state)
2376 game.state.snap = True
2377 schedule(FSNAP, expran(0.5 * game.intime))
2378 elif evcode == FBATTAK: # Commander attacks starbase
2379 if not game.state.kcmdr or not game.state.baseq:
2385 for ibq in game.state.baseq:
2386 for cmdr in game.state.kcmdr:
2387 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2390 # no match found -- try later
2391 schedule(FBATTAK, expran(0.3*game.intime))
2396 # commander + starbase combination found -- launch attack
2398 schedule(FCDBAS, randreal(1.0, 4.0))
2399 if game.isatb: # extra time if SC already attacking
2400 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2401 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2402 game.iseenit = False
2403 if not communicating():
2404 continue # No warning :-(
2408 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2409 prout(_(" reports that it is under attack and that it can"))
2410 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2413 elif evcode == FSCDBAS: # Supercommander destroys base
2416 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2417 continue # WAS RETURN!
2419 game.battle = game.state.kscmdr
2421 elif evcode == FCDBAS: # Commander succeeds in destroying base
2424 if not game.state.baseq() \
2425 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2426 game.battle.invalidate()
2428 # find the lucky pair
2429 for cmdr in game.state.kcmdr:
2430 if cmdr == game.battle:
2433 # No action to take after all
2436 elif evcode == FSCMOVE: # Supercommander moves
2437 schedule(FSCMOVE, 0.2777)
2438 if not game.ientesc and not istract and game.isatb != 1 and \
2439 (not game.iscate or not game.justin):
2441 elif evcode == FDSPROB: # Move deep space probe
2442 schedule(FDSPROB, 0.01)
2443 if not game.probe.next():
2444 if not game.probe.quadrant().valid_quadrant() or \
2445 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2446 # Left galaxy or ran into supernova
2450 proutn(_("Lt. Uhura- \"The deep space probe "))
2451 if not game.probe.quadrant().valid_quadrant():
2452 prout(_("has left the galaxy.\""))
2454 prout(_("is no longer transmitting.\""))
2460 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2461 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2463 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2464 chp.klingons = pdest.klingons
2465 chp.starbase = pdest.starbase
2466 chp.stars = pdest.stars
2467 pdest.charted = True
2468 game.probe.moves -= 1 # One less to travel
2469 if game.probe.arrived() and game.isarmed and pdest.stars:
2470 supernova(game.probe) # fire in the hole!
2472 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2474 elif evcode == FDISTR: # inhabited system issues distress call
2476 # try a whole bunch of times to find something suitable
2477 for i in range(100):
2478 # need a quadrant which is not the current one,
2479 # which has some stars which are inhabited and
2480 # not already under attack, which is not
2481 # supernova'ed, and which has some Klingons in it
2482 w = randplace(GALSIZE)
2483 q = game.state.galaxy[w.i][w.j]
2484 if not (game.quadrant == w or q.planet == None or \
2485 not q.planet.inhabited or \
2486 q.supernova or q.status!="secure" or q.klingons<=0):
2489 # can't seem to find one; ignore this call
2491 prout("=== Couldn't find location for distress event.")
2493 # got one!! Schedule its enslavement
2494 ev = schedule(FENSLV, expran(game.intime))
2496 q.status = "distressed"
2497 # tell the captain about it if we can
2499 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2501 prout(_("by a Klingon invasion fleet."))
2504 elif evcode == FENSLV: # starsystem is enslaved
2505 ev = unschedule(FENSLV)
2506 # see if current distress call still active
2507 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2511 q.status = "enslaved"
2513 # play stork and schedule the first baby
2514 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2515 ev2.quadrant = ev.quadrant
2517 # report the disaster if we can
2519 prout(_("Uhura- We've lost contact with starsystem %s") % \
2521 prout(_("in Quadrant %s.\n") % ev.quadrant)
2522 elif evcode == FREPRO: # Klingon reproduces
2523 # If we ever switch to a real event queue, we'll need to
2524 # explicitly retrieve and restore the x and y.
2525 ev = schedule(FREPRO, expran(1.0 * game.intime))
2526 # see if current distress call still active
2527 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2531 if game.state.remkl >=MAXKLGAME:
2532 continue # full right now
2533 # reproduce one Klingon
2536 if game.klhere >= MAXKLQUAD:
2538 # this quadrant not ok, pick an adjacent one
2539 for m.i in range(w.i - 1, w.i + 2):
2540 for m.j in range(w.j - 1, w.j + 2):
2541 if not m.valid_quadrant():
2543 q = game.state.galaxy[m.i][m.j]
2544 # check for this quad ok (not full & no snova)
2545 if q.klingons >= MAXKLQUAD or q.supernova:
2549 continue # search for eligible quadrant failed
2553 game.state.remkl += 1
2555 if game.quadrant == w:
2557 game.enemies.append(newkling())
2558 # recompute time left
2561 if game.quadrant == w:
2562 prout(_("Spock- sensors indicate the Klingons have"))
2563 prout(_("launched a warship from %s.") % q.planet)
2565 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2566 if q.planet != None:
2567 proutn(_("near %s") % q.planet)
2568 prout(_("in Quadrant %s.") % w)
2574 key = scanner.next()
2577 proutn(_("How long? "))
2582 origTime = delay = scanner.real
2585 if delay >= game.state.remtime or len(game.enemies) != 0:
2586 proutn(_("Are you sure? "))
2589 # Alternate resting periods (events) with attacks
2593 game.resting = False
2594 if not game.resting:
2595 prout(_("%d stardates left.") % int(game.state.remtime))
2597 temp = game.optime = delay
2598 if len(game.enemies):
2599 rtime = randreal(1.0, 2.0)
2603 if game.optime < delay:
2604 attack(torps_ok=False)
2612 # Repair Deathray if long rest at starbase
2613 if origTime-delay >= 9.99 and game.condition == "docked":
2614 game.damage[DDRAY] = 0.0
2615 # leave if quadrant supernovas
2616 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2618 game.resting = False
2623 course = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2624 newc = coord(); neighbor = coord(); bump = coord(0, 0)
2626 # Wow! We've supernova'ed
2627 supernova(game.quadrant)
2629 # handle initial nova
2630 game.quad[nov.i][nov.j] = IHDOT
2631 prout(crmena(False, IHSTAR, "sector", nov) + _(" novas."))
2632 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2633 game.state.starkl += 1
2634 # Set up queue to recursively trigger adjacent stars
2640 for offset.i in range(-1, 1+1):
2641 for offset.j in range(-1, 1+1):
2642 if offset.j==0 and offset.i==0:
2644 neighbor = start + offset
2645 if not neighbor.valid_sector():
2647 iquad = game.quad[neighbor.i][neighbor.j]
2648 # Empty space ends reaction
2649 if iquad in (IHDOT, IHQUEST, IHBLANK, IHT, IHWEB):
2651 elif iquad == IHSTAR: # Affect another star
2653 # This star supernovas
2654 supernova(game.quadrant)
2657 hits.append(neighbor)
2658 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2659 game.state.starkl += 1
2660 proutn(crmena(True, IHSTAR, "sector", neighbor))
2662 game.quad[neighbor.i][neighbor.j] = IHDOT
2664 elif iquad in (IHP, IHW): # Destroy planet
2665 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2667 game.state.nplankl += 1
2669 game.state.worldkl += 1
2670 prout(crmena(True, IHB, "sector", neighbor) + _(" destroyed."))
2671 game.iplnet.pclass = "destroyed"
2673 game.plnet.invalidate()
2677 game.quad[neighbor.i][neighbor.j] = IHDOT
2678 elif iquad == IHB: # Destroy base
2679 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2680 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2681 game.base.invalidate()
2682 game.state.basekl += 1
2684 prout(crmena(True, IHB, "sector", neighbor) + _(" destroyed."))
2685 game.quad[neighbor.i][neighbor.j] = IHDOT
2686 elif iquad in (IHE, IHF): # Buffet ship
2687 prout(_("***Starship buffeted by nova."))
2689 if game.shield >= 2000.0:
2690 game.shield -= 2000.0
2692 diff = 2000.0 - game.shield
2696 prout(_("***Shields knocked out."))
2697 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2699 game.energy -= 2000.0
2700 if game.energy <= 0:
2703 # add in course nova contributes to kicking starship
2704 bump += (game.sector-hits[mm]).sgn()
2705 elif iquad == IHK: # kill klingon
2706 deadkl(neighbor, iquad, neighbor)
2707 elif iquad in (IHC,IHS,IHR): # Damage/destroy big enemies
2708 for ll in range(len(game.enemies)):
2709 if game.enemies[ll].kloc == neighbor:
2711 game.enemies[ll].kpower -= 800.0 # If firepower is lost, die
2712 if game.enemies[ll].kpower <= 0.0:
2713 deadkl(neighbor, iquad, neighbor)
2715 newc = neighbor + neighbor - hits[mm]
2716 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2717 if not newc.valid_sector():
2718 # can't leave quadrant
2721 iquad1 = game.quad[newc.i][newc.j]
2722 if iquad1 == IHBLANK:
2723 proutn(_(", blasted into ") + crmena(False, IHBLANK, "sector", newc))
2725 deadkl(neighbor, iquad, newc)
2728 # can't move into something else
2731 proutn(_(", buffeted to Sector %s") % newc)
2732 game.quad[neighbor.i][neighbor.j] = IHDOT
2733 game.quad[newc.i][newc.j] = iquad
2734 game.enemies[ll].move(newc)
2735 # Starship affected by nova -- kick it away.
2737 direc = course[3*(bump.i+1)+bump.j+2]
2742 course = course(bearing=direc, distance=dist)
2743 game.optime = course.time(warp=4)
2745 prout(_("Force of nova displaces starship."))
2746 imove(course, noattack=True)
2747 game.optime = course.time(warp=4)
2751 "Star goes supernova."
2756 # Scheduled supernova -- select star at random.
2759 for nq.i in range(GALSIZE):
2760 for nq.j in range(GALSIZE):
2761 stars += game.state.galaxy[nq.i][nq.j].stars
2763 return # nothing to supernova exists
2764 num = randrange(stars) + 1
2765 for nq.i in range(GALSIZE):
2766 for nq.j in range(GALSIZE):
2767 num -= game.state.galaxy[nq.i][nq.j].stars
2773 proutn("=== Super nova here?")
2776 if not nq == game.quadrant or game.justin:
2777 # it isn't here, or we just entered (treat as enroute)
2780 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2781 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2784 # we are in the quadrant!
2785 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2786 for ns.i in range(QUADSIZE):
2787 for ns.j in range(QUADSIZE):
2788 if game.quad[ns.i][ns.j]==IHSTAR:
2795 prouts(_("***RED ALERT! RED ALERT!"))
2797 prout(_("***Incipient supernova detected at Sector %s") % ns)
2798 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2799 proutn(_("Emergency override attempts t"))
2800 prouts("***************")
2804 # destroy any Klingons in supernovaed quadrant
2805 kldead = game.state.galaxy[nq.i][nq.j].klingons
2806 game.state.galaxy[nq.i][nq.j].klingons = 0
2807 if nq == game.state.kscmdr:
2808 # did in the Supercommander!
2809 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2813 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2814 comkills = len(game.state.kcmdr) - len(survivors)
2815 game.state.kcmdr = survivors
2817 if not game.state.kcmdr:
2819 game.state.remkl -= kldead
2820 # destroy Romulans and planets in supernovaed quadrant
2821 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2822 game.state.galaxy[nq.i][nq.j].romulans = 0
2823 game.state.nromrem -= nrmdead
2825 for loop in range(game.inplan):
2826 if game.state.planets[loop].quadrant == nq:
2827 game.state.planets[loop].pclass = "destroyed"
2829 # Destroy any base in supernovaed quadrant
2830 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2831 # If starship caused supernova, tally up destruction
2833 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2834 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2835 game.state.nplankl += npdead
2836 # mark supernova in galaxy and in star chart
2837 if game.quadrant == nq or communicating():
2838 game.state.galaxy[nq.i][nq.j].supernova = True
2839 # If supernova destroys last Klingons give special message
2840 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2843 prout(_("Lucky you!"))
2844 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2847 # if some Klingons remain, continue or die in supernova
2852 # Code from finish.c ends here.
2855 "Self-destruct maneuver. Finish with a BANG!"
2857 if damaged(DCOMPTR):
2858 prout(_("Computer damaged; cannot execute destruct sequence."))
2860 prouts(_("---WORKING---")); skip(1)
2861 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2862 prouts(" 10"); skip(1)
2863 prouts(" 9"); skip(1)
2864 prouts(" 8"); skip(1)
2865 prouts(" 7"); skip(1)
2866 prouts(" 6"); skip(1)
2868 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2870 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2872 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2876 if game.passwd != scanner.token:
2877 prouts(_("PASSWORD-REJECTED;"))
2879 prouts(_("CONTINUITY-EFFECTED"))
2882 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2883 prouts(" 5"); skip(1)
2884 prouts(" 4"); skip(1)
2885 prouts(" 3"); skip(1)
2886 prouts(" 2"); skip(1)
2887 prouts(" 1"); skip(1)
2889 prouts(_("GOODBYE-CRUEL-WORLD"))
2897 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2901 if len(game.enemies) != 0:
2902 whammo = 25.0 * game.energy
2904 while l <= len(game.enemies):
2905 if game.enemies[l].kpower*game.enemies[l].kdist <= whammo:
2906 deadkl(game.enemies[l].kloc, game.quad[game.enemies[l].kloc.i][game.enemies[l].kloc.j], game.enemies[l].kloc)
2911 "Compute our rate of kils over time."
2912 elapsed = game.state.date - game.indate
2913 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2916 starting = (game.inkling + game.incom + game.inscom)
2917 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2918 return (starting - remaining)/elapsed
2922 badpt = 5.0*game.state.starkl + \
2924 10.0*game.state.nplankl + \
2925 300*game.state.nworldkl + \
2927 100.0*game.state.basekl +\
2929 if game.ship == IHF:
2931 elif game.ship == None:
2936 # end the game, with appropriate notfications
2940 prout(_("It is stardate %.1f.") % game.state.date)
2942 if ifin == FWON: # Game has been won
2943 if game.state.nromrem != 0:
2944 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2947 prout(_("You have smashed the Klingon invasion fleet and saved"))
2948 prout(_("the Federation."))
2953 badpt = 0.0 # Close enough!
2954 # killsPerDate >= RateMax
2955 if game.state.date-game.indate < 5.0 or \
2956 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2958 prout(_("In fact, you have done so well that Starfleet Command"))
2959 if game.skill == SKILL_NOVICE:
2960 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2961 elif game.skill == SKILL_FAIR:
2962 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2963 elif game.skill == SKILL_GOOD:
2964 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2965 elif game.skill == SKILL_EXPERT:
2966 prout(_("promotes you to Commodore Emeritus."))
2968 prout(_("Now that you think you're really good, try playing"))
2969 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2970 elif game.skill == SKILL_EMERITUS:
2972 proutn(_("Computer- "))
2973 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2975 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2977 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2979 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2981 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2983 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2985 prout(_("Now you can retire and write your own Star Trek game!"))
2987 elif game.skill >= SKILL_EXPERT:
2988 if game.thawed and not idebug:
2989 prout(_("You cannot get a citation, so..."))
2991 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2995 # Only grant long life if alive (original didn't!)
2997 prout(_("LIVE LONG AND PROSPER."))
3002 elif ifin == FDEPLETE: # Federation Resources Depleted
3003 prout(_("Your time has run out and the Federation has been"))
3004 prout(_("conquered. Your starship is now Klingon property,"))
3005 prout(_("and you are put on trial as a war criminal. On the"))
3006 proutn(_("basis of your record, you are "))
3007 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
3008 prout(_("acquitted."))
3010 prout(_("LIVE LONG AND PROSPER."))
3012 prout(_("found guilty and"))
3013 prout(_("sentenced to death by slow torture."))
3017 elif ifin == FLIFESUP:
3018 prout(_("Your life support reserves have run out, and"))
3019 prout(_("you die of thirst, starvation, and asphyxiation."))
3020 prout(_("Your starship is a derelict in space."))
3022 prout(_("Your energy supply is exhausted."))
3024 prout(_("Your starship is a derelict in space."))
3025 elif ifin == FBATTLE:
3026 prout(_("The %s has been destroyed in battle.") % crmshp())
3028 prout(_("Dulce et decorum est pro patria mori."))
3030 prout(_("You have made three attempts to cross the negative energy"))
3031 prout(_("barrier which surrounds the galaxy."))
3033 prout(_("Your navigation is abominable."))
3036 prout(_("Your starship has been destroyed by a nova."))
3037 prout(_("That was a great shot."))
3039 elif ifin == FSNOVAED:
3040 prout(_("The %s has been fried by a supernova.") % crmshp())
3041 prout(_("...Not even cinders remain..."))
3042 elif ifin == FABANDN:
3043 prout(_("You have been captured by the Klingons. If you still"))
3044 prout(_("had a starbase to be returned to, you would have been"))
3045 prout(_("repatriated and given another chance. Since you have"))
3046 prout(_("no starbases, you will be mercilessly tortured to death."))
3047 elif ifin == FDILITHIUM:
3048 prout(_("Your starship is now an expanding cloud of subatomic particles"))
3049 elif ifin == FMATERIALIZE:
3050 prout(_("Starbase was unable to re-materialize your starship."))
3051 prout(_("Sic transit gloria mundi"))
3052 elif ifin == FPHASER:
3053 prout(_("The %s has been cremated by its own phasers.") % crmshp())
3055 prout(_("You and your landing party have been"))
3056 prout(_("converted to energy, disipating through space."))
3057 elif ifin == FMINING:
3058 prout(_("You are left with your landing party on"))
3059 prout(_("a wild jungle planet inhabited by primitive cannibals."))
3061 prout(_("They are very fond of \"Captain Kirk\" soup."))
3063 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3064 elif ifin == FDPLANET:
3065 prout(_("You and your mining party perish."))
3067 prout(_("That was a great shot."))
3070 prout(_("The Galileo is instantly annihilated by the supernova."))
3071 prout(_("You and your mining party are atomized."))
3073 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3074 prout(_("joins the Romulans, wreaking terror on the Federation."))
3075 elif ifin == FPNOVA:
3076 prout(_("You and your mining party are atomized."))
3078 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3079 prout(_("joins the Romulans, wreaking terror on the Federation."))
3080 elif ifin == FSTRACTOR:
3081 prout(_("The shuttle craft Galileo is also caught,"))
3082 prout(_("and breaks up under the strain."))
3084 prout(_("Your debris is scattered for millions of miles."))
3085 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3087 prout(_("The mutants attack and kill Spock."))
3088 prout(_("Your ship is captured by Klingons, and"))
3089 prout(_("your crew is put on display in a Klingon zoo."))
3090 elif ifin == FTRIBBLE:
3091 prout(_("Tribbles consume all remaining water,"))
3092 prout(_("food, and oxygen on your ship."))
3094 prout(_("You die of thirst, starvation, and asphyxiation."))
3095 prout(_("Your starship is a derelict in space."))
3097 prout(_("Your ship is drawn to the center of the black hole."))
3098 prout(_("You are crushed into extremely dense matter."))
3100 prout(_("Your last crew member has died."))
3101 if game.ship == IHF:
3103 elif game.ship == IHE:
3106 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
3107 goodies = game.state.remres/game.inresor
3108 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
3109 if goodies/baddies >= randreal(1.0, 1.5):
3110 prout(_("As a result of your actions, a treaty with the Klingon"))
3111 prout(_("Empire has been signed. The terms of the treaty are"))
3112 if goodies/baddies >= randreal(3.0):
3113 prout(_("favorable to the Federation."))
3115 prout(_("Congratulations!"))
3117 prout(_("highly unfavorable to the Federation."))
3119 prout(_("The Federation will be destroyed."))
3121 prout(_("Since you took the last Klingon with you, you are a"))
3122 prout(_("martyr and a hero. Someday maybe they'll erect a"))
3123 prout(_("statue in your memory. Rest in peace, and try not"))
3124 prout(_("to think about pigeons."))
3129 "Compute player's score."
3130 timused = game.state.date - game.indate
3132 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
3134 perdate = killrate()
3135 ithperd = 500*perdate + 0.5
3138 iwon = 100*game.skill
3139 if game.ship == IHE:
3141 elif game.ship == IHF:
3145 if not game.gamewon:
3146 game.state.nromrem = 0 # None captured if no win
3147 iscore = 10*(game.inkling - game.state.remkl) \
3148 + 50*(game.incom - len(game.state.kcmdr)) \
3150 + 20*(game.inrom - game.state.nromrem) \
3151 + 200*(game.inscom - game.state.nscrem) \
3152 - game.state.nromrem \
3157 prout(_("Your score --"))
3158 if game.inrom - game.state.nromrem:
3159 prout(_("%6d Romulans destroyed %5d") %
3160 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
3161 if game.state.nromrem:
3162 prout(_("%6d Romulans captured %5d") %
3163 (game.state.nromrem, game.state.nromrem))
3164 if game.inkling - game.state.remkl:
3165 prout(_("%6d ordinary Klingons destroyed %5d") %
3166 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
3167 if game.incom - len(game.state.kcmdr):
3168 prout(_("%6d Klingon commanders destroyed %5d") %
3169 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3170 if game.inscom - game.state.nscrem:
3171 prout(_("%6d Super-Commander destroyed %5d") %
3172 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3174 prout(_("%6.2f Klingons per stardate %5d") %
3176 if game.state.starkl:
3177 prout(_("%6d stars destroyed by your action %5d") %
3178 (game.state.starkl, -5*game.state.starkl))
3179 if game.state.nplankl:
3180 prout(_("%6d planets destroyed by your action %5d") %
3181 (game.state.nplankl, -10*game.state.nplankl))
3182 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3183 prout(_("%6d inhabited planets destroyed by your action %5d") %
3184 (game.state.nplankl, -300*game.state.nworldkl))
3185 if game.state.basekl:
3186 prout(_("%6d bases destroyed by your action %5d") %
3187 (game.state.basekl, -100*game.state.basekl))
3189 prout(_("%6d calls for help from starbase %5d") %
3190 (game.nhelp, -45*game.nhelp))
3192 prout(_("%6d casualties incurred %5d") %
3193 (game.casual, -game.casual))
3195 prout(_("%6d crew abandoned in space %5d") %
3196 (game.abandoned, -3*game.abandoned))
3198 prout(_("%6d ship(s) lost or destroyed %5d") %
3199 (klship, -100*klship))
3201 prout(_("Penalty for getting yourself killed -200"))
3203 proutn(_("Bonus for winning "))
3204 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3205 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3206 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3207 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3208 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3209 prout(" %5d" % iwon)
3211 prout(_("TOTAL SCORE %5d") % iscore)
3214 "Emit winner's commemmorative plaque."
3217 proutn(_("File or device name for your plaque: "))
3220 fp = open(winner, "w")
3223 prout(_("Invalid name."))
3225 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3227 # The 38 below must be 64 for 132-column paper
3228 nskip = 38 - len(winner)/2
3229 fp.write("\n\n\n\n")
3230 # --------DRAW ENTERPRISE PICTURE.
3231 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3232 fp.write(" EEE E : : : E\n" )
3233 fp.write(" EE EEE E : : NCC-1701 : E\n")
3234 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3235 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3236 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3237 fp.write(" EEEEEEE EEEEE E E E E\n")
3238 fp.write(" EEE E E E E\n")
3239 fp.write(" E E E E\n")
3240 fp.write(" EEEEEEEEEEEEE E E\n")
3241 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3242 fp.write(" :E : EEEE E\n")
3243 fp.write(" .-E -:----- E\n")
3244 fp.write(" :E : E\n")
3245 fp.write(" EE : EEEEEEEE\n")
3246 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3248 fp.write(_(" U. S. S. ENTERPRISE\n"))
3249 fp.write("\n\n\n\n")
3250 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3252 fp.write(_(" Starfleet Command bestows to you\n"))
3254 fp.write("%*s%s\n\n" % (nskip, "", winner))
3255 fp.write(_(" the rank of\n\n"))
3256 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3258 if game.skill == SKILL_EXPERT:
3259 fp.write(_(" Expert level\n\n"))
3260 elif game.skill == SKILL_EMERITUS:
3261 fp.write(_("Emeritus level\n\n"))
3263 fp.write(_(" Cheat level\n\n"))
3264 timestring = time.ctime()
3265 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3266 (timestring+4, timestring+20, timestring+11))
3267 fp.write(_(" Your score: %d\n\n") % iscore)
3268 fp.write(_(" Klingons per stardate: %.2f\n") % perdate)
3271 # Code from io.c begins here
3273 rows = linecount = 0 # for paging
3276 fullscreen_window = None
3277 srscan_window = None
3278 report_window = None
3279 status_window = None
3280 lrscan_window = None
3281 message_window = None
3282 prompt_window = None
3287 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3288 gettext.textdomain("sst")
3289 if not (game.options & OPTION_CURSES):
3290 ln_env = os.getenv("LINES")
3296 stdscr = curses.initscr()
3300 global fullscreen_window, srscan_window, report_window, status_window
3301 global lrscan_window, message_window, prompt_window
3302 (rows, columns) = stdscr.getmaxyx()
3303 fullscreen_window = stdscr
3304 srscan_window = curses.newwin(12, 25, 0, 0)
3305 report_window = curses.newwin(11, 0, 1, 25)
3306 status_window = curses.newwin(10, 0, 1, 39)
3307 lrscan_window = curses.newwin(5, 0, 0, 64)
3308 message_window = curses.newwin(0, 0, 12, 0)
3309 prompt_window = curses.newwin(1, 0, rows-2, 0)
3310 message_window.scrollok(True)
3311 setwnd(fullscreen_window)
3315 if game.options & OPTION_CURSES:
3316 stdscr.keypad(False)
3322 "Wait for user action -- OK to do nothing if on a TTY"
3323 if game.options & OPTION_CURSES:
3328 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3332 if game.skill > SKILL_FAIR:
3333 prompt = _("[CONTINUE?]")
3335 prompt = _("[PRESS ENTER TO CONTINUE]")
3337 if game.options & OPTION_CURSES:
3339 setwnd(prompt_window)
3340 prompt_window.clear()
3341 prompt_window.addstr(prompt)
3342 prompt_window.getstr()
3343 prompt_window.clear()
3344 prompt_window.refresh()
3345 setwnd(message_window)
3348 sys.stdout.write('\n')
3351 for j in range(rows):
3352 sys.stdout.write('\n')
3356 "Skip i lines. Pause game if this would cause a scrolling event."
3357 for dummy in range(i):
3358 if game.options & OPTION_CURSES:
3359 (y, x) = curwnd.getyx()
3360 (my, mx) = curwnd.getmaxyx()
3361 if curwnd == message_window and y >= my - 3:
3367 except curses.error:
3372 if rows and linecount >= rows:
3375 sys.stdout.write('\n')
3378 "Utter a line with no following line feed."
3379 if game.options & OPTION_CURSES:
3383 sys.stdout.write(line)
3393 if not replayfp or replayfp.closed: # Don't slow down replays
3396 if game.options & OPTION_CURSES:
3400 if not replayfp or replayfp.closed:
3404 "Get a line of input."
3405 if game.options & OPTION_CURSES:
3406 line = curwnd.getstr() + "\n"
3409 if replayfp and not replayfp.closed:
3411 line = replayfp.readline()
3414 prout("*** Replay finished")
3417 elif line[0] != "#":
3420 line = raw_input() + "\n"
3426 "Change windows -- OK for this to be a no-op in tty mode."
3428 if game.options & OPTION_CURSES:
3430 curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window)
3433 "Clear to end of line -- can be a no-op in tty mode"
3434 if game.options & OPTION_CURSES:
3439 "Clear screen -- can be a no-op in tty mode."
3441 if game.options & OPTION_CURSES:
3448 "Set highlight video, if this is reasonable."
3449 if game.options & OPTION_CURSES:
3450 curwnd.attron(curses.A_REVERSE)
3453 # Things past this point have policy implications.
3457 "Hook to be called after moving to redraw maps."
3458 if game.options & OPTION_CURSES:
3461 setwnd(srscan_window)
3465 setwnd(status_window)
3466 status_window.clear()
3467 status_window.move(0, 0)
3468 setwnd(report_window)
3469 report_window.clear()
3470 report_window.move(0, 0)
3472 setwnd(lrscan_window)
3473 lrscan_window.clear()
3474 lrscan_window.move(0, 0)
3475 lrscan(silent=False)
3477 def put_srscan_sym(w, sym):
3478 "Emit symbol for short-range scan."
3479 srscan_window.move(w.i+1, w.j*2+2)
3480 srscan_window.addch(sym)
3481 srscan_window.refresh()
3484 "Enemy fall down, go boom."
3485 if game.options & OPTION_CURSES:
3487 setwnd(srscan_window)
3488 srscan_window.attron(curses.A_REVERSE)
3489 put_srscan_sym(w, game.quad[w.i][w.j])
3493 srscan_window.attroff(curses.A_REVERSE)
3494 put_srscan_sym(w, game.quad[w.i][w.j])
3495 curses.delay_output(500)
3496 setwnd(message_window)
3499 "Sound and visual effects for teleportation."
3500 if game.options & OPTION_CURSES:
3502 setwnd(message_window)
3504 prouts(" . . . . . ")
3505 if game.options & OPTION_CURSES:
3506 #curses.delay_output(1000)
3510 def tracktorpedo(origin, w, step, i, n, iquad):
3511 "Torpedo-track animation."
3512 if not game.options & OPTION_CURSES:
3516 proutn(_("Track for torpedo number %d- ") % (i+1))
3519 proutn(_("Torpedo track- "))
3520 elif step==4 or step==9:
3524 if not damaged(DSRSENS) or game.condition=="docked":
3525 if i != 0 and step == 1:
3528 if (iquad==IHDOT) or (iquad==IHBLANK):
3529 put_srscan_sym(w, '+')
3533 put_srscan_sym(w, iquad)
3535 curwnd.attron(curses.A_REVERSE)
3536 put_srscan_sym(w, iquad)
3540 curwnd.attroff(curses.A_REVERSE)
3541 put_srscan_sym(w, iquad)
3546 "Display the current galaxy chart."
3547 if game.options & OPTION_CURSES:
3548 setwnd(message_window)
3549 message_window.clear()
3551 if game.options & OPTION_TTY:
3556 def prstat(txt, data):
3558 if game.options & OPTION_CURSES:
3560 setwnd(status_window)
3562 proutn(" " * (NSYM - len(txt)))
3565 if game.options & OPTION_CURSES:
3566 setwnd(report_window)
3568 # Code from moving.c begins here
3570 def imove(course=None, noattack=False):
3571 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3574 def newquadrant(noattack):
3575 # Leaving quadrant -- allow final enemy attack
3576 # Don't do it if being pushed by Nova
3577 if len(game.enemies) != 0 and not noattack:
3579 for enemy in game.enemies:
3580 finald = (w - enemy.kloc).distance()
3581 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3582 # Stas Sergeev added the condition
3583 # that attacks only happen if Klingons
3584 # are present and your skill is good.
3585 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3586 attack(torps_ok=False)
3589 # check for edge of galaxy
3593 if course.final.i < 0:
3594 course.final.i = -course.final.i
3596 if course.final.j < 0:
3597 course.final.j = -course.final.j
3599 if course.final.i >= GALSIZE*QUADSIZE:
3600 course.final.i = (GALSIZE*QUADSIZE*2) - course.final.i
3602 if course.final.j >= GALSIZE*QUADSIZE:
3603 course.final.j = (GALSIZE*QUADSIZE*2) - course.final.j
3611 if game.nkinks == 3:
3612 # Three strikes -- you're out!
3616 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3617 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3618 prout(_("YOU WILL BE DESTROYED."))
3619 # Compute final position in new quadrant
3620 if trbeam: # Don't bother if we are to be beamed
3622 game.quadrant = course.final.quadrant()
3623 game.sector = course.final.sector()
3625 prout(_("Entering Quadrant %s.") % game.quadrant)
3626 game.quad[game.sector.i][game.sector.j] = game.ship
3628 if game.skill>SKILL_NOVICE:
3629 attack(torps_ok=False)
3631 def check_collision(h):
3632 iquad = game.quad[h.i][h.j]
3634 # object encountered in flight path
3635 stopegy = 50.0*course.distance/game.optime
3636 if iquad in (IHT, IHK, IHC, IHS, IHR, IHQUEST):
3637 for enemy in game.enemies:
3638 if enemy.kloc == game.sector:
3640 collision(rammed=False, enemy=enemy)
3642 elif iquad == IHBLANK:
3644 prouts(_("***RED ALERT! RED ALERT!"))
3646 proutn("***" + crmshp())
3647 proutn(_(" pulled into black hole at Sector %s") % h)
3648 # Getting pulled into a black hole was certain
3649 # death in Almy's original. Stas Sergeev added a
3650 # possibility that you'll get timewarped instead.
3652 for m in range(NDEVICES):
3653 if game.damage[m]>0:
3655 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3656 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3666 prout(_(" encounters Tholian web at %s;") % h)
3668 prout(_(" blocked by object at %s;") % h)
3669 proutn(_("Emergency stop required "))
3670 prout(_("%2d units of energy.") % int(stopegy))
3671 game.energy -= stopegy
3672 if game.energy <= 0:
3679 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3680 game.inorbit = False
3681 # If tractor beam is to occur, don't move full distance
3682 if game.state.date+game.optime >= scheduled(FTBEAM):
3684 game.condition = "red"
3685 course.distance = course.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3686 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3688 game.quad[game.sector.i][game.sector.j] = IHDOT
3689 for m in range(course.moves):
3692 if course.origin.quadrant() != course.location.quadrant():
3693 newquadrant(noattack)
3695 elif check_collision(w):
3696 print "Collision detected"
3700 # We're in destination quadrant -- compute new average enemy distances
3701 game.quad[game.sector.i][game.sector.j] = game.ship
3703 for enemy in game.enemies:
3704 finald = (w-enemy.kloc).distance()
3705 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3706 enemy.kdist = finald
3707 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
3708 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3709 attack(torps_ok=False)
3710 for enemy in game.enemies:
3711 enemy.kavgd = enemy.kdist
3714 setwnd(message_window)
3718 "Dock our ship at a starbase."
3720 if game.condition == "docked" and verbose:
3721 prout(_("Already docked."))
3724 prout(_("You must first leave standard orbit."))
3726 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3727 prout(crmshp() + _(" not adjacent to base."))
3729 game.condition = "docked"
3733 if game.energy < game.inenrg:
3734 game.energy = game.inenrg
3735 game.shield = game.inshld
3736 game.torps = game.intorps
3737 game.lsupres = game.inlsr
3738 game.state.crew = FULLCREW
3739 if not damaged(DRADIO) and \
3740 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3741 # get attack report from base
3742 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3746 # This program originally required input in terms of a (clock)
3747 # direction and distance. Somewhere in history, it was changed to
3748 # cartesian coordinates. So we need to convert. Probably
3749 # "manual" input should still be done this way -- it's a real
3750 # pain if the computer isn't working! Manual mode is still confusing
3751 # because it involves giving x and y motions, yet the coordinates
3752 # are always displayed y - x, where +y is downward!
3754 def cartesian(loc1=None, loc2=None):
3756 return game.quadrant * QUADSIZE + game.sector
3758 return game.quadrant * QUADSIZE + loc1
3760 return loc1 * QUADSIZE + loc2
3762 def getcourse(isprobe):
3763 "Get a course and distance from the user."
3765 dquad = copy.copy(game.quadrant)
3766 navmode = "unspecified"
3770 if game.landed and not isprobe:
3771 prout(_("Dummy! You can't leave standard orbit until you"))
3772 proutn(_("are back aboard the ship."))
3775 while navmode == "unspecified":
3776 if damaged(DNAVSYS):
3778 prout(_("Computer damaged; manual navigation only"))
3780 prout(_("Computer damaged; manual movement only"))
3785 key = scanner.next()
3787 proutn(_("Manual or automatic- "))
3790 elif key == "IHALPHA":
3791 if scanner.sees("manual"):
3793 key = scanner.next()
3795 elif scanner.sees("automatic"):
3796 navmode = "automatic"
3797 key = scanner.next()
3805 prout(_("(Manual navigation assumed.)"))
3807 prout(_("(Manual movement assumed.)"))
3811 if navmode == "automatic":
3812 while key == "IHEOL":
3814 proutn(_("Target quadrant or quadrant§or- "))
3816 proutn(_("Destination sector or quadrant§or- "))
3819 key = scanner.next()
3823 xi = int(round(scanner.real))-1
3824 key = scanner.next()
3828 xj = int(round(scanner.real))-1
3829 key = scanner.next()
3831 # both quadrant and sector specified
3832 xk = int(round(scanner.real))-1
3833 key = scanner.next()
3837 xl = int(round(scanner.real))-1
3843 # only one pair of numbers was specified
3845 # only quadrant specified -- go to center of dest quad
3848 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3850 # only sector specified
3854 if not dquad.valid_quadrant() or not dsect.valid_sector():
3861 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3863 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3864 # the actual deltas get computed here
3865 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3866 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3868 while key == "IHEOL":
3869 proutn(_("X and Y displacements- "))
3872 key = scanner.next()
3877 delta.j = scanner.real
3878 key = scanner.next()
3882 delta.i = scanner.real
3883 # Check for zero movement
3884 if delta.i == 0 and delta.j == 0:
3887 if itemp == "verbose" and not isprobe:
3889 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3891 return course(bearing=delta.bearing(), distance=delta.distance())
3894 def __init__(self, bearing, distance, origin=None):
3895 self.distance = distance
3896 self.bearing = bearing
3898 self.origin = cartesian(game.quadrant, game.sector)
3900 self.origin = origin
3901 # The bearing() code we inherited from FORTRAN is actually computing
3902 # clockface directions!
3903 if self.bearing < 0.0:
3904 self.bearing += 12.0
3905 self.angle = ((15.0 - self.bearing) * 0.5235988)
3907 self.origin = cartesian(game.quadrant, game.sector)
3909 self.origin = cartesian(game.quadrant, origin)
3910 self.increment = coord(-math.sin(self.angle), math.cos(self.angle))
3911 bigger = max(abs(self.increment.i), abs(self.increment.j))
3912 self.increment /= bigger
3913 self.moves = int(round(10*self.distance*bigger))
3915 self.final = (self.location + self.moves*self.increment).roundtogrid()
3917 self.location = self.origin
3920 return self.location.roundtogrid() == self.final
3922 "Next step on course."
3924 self.nextlocation = self.location + self.increment
3925 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3926 self.location = self.nextlocation
3929 return self.location.quadrant()
3931 return self.location.sector()
3932 def power(self, warp):
3933 return self.distance*(warp**3)*(game.shldup+1)
3934 def time(self, warp):
3935 return 10.0*self.distance/warp**2
3938 "Move under impulse power."
3940 if damaged(DIMPULS):
3943 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3945 if game.energy > 30.0:
3947 course = getcourse(isprobe=False)
3950 power = 20.0 + 100.0*course.distance
3953 if power >= game.energy:
3954 # Insufficient power for trip
3956 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3957 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3958 if game.energy > 30:
3959 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3960 int(0.01 * (game.energy-20.0)-0.05))
3961 prout(_(" quadrants.\""))
3963 prout(_("quadrant. They are, therefore, useless.\""))
3966 # Make sure enough time is left for the trip
3967 game.optime = course.dist/0.095
3968 if game.optime >= game.state.remtime:
3969 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3970 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3971 proutn(_("we dare spend the time?\" "))
3974 # Activate impulse engines and pay the cost
3975 imove(course, noattack=False)
3979 power = 20.0 + 100.0*course.dist
3980 game.energy -= power
3981 game.optime = course.dist/0.095
3982 if game.energy <= 0:
3986 def warp(course, involuntary):
3987 "ove under warp drive."
3988 blooey = False; twarp = False
3989 if not involuntary: # Not WARPX entry
3991 if game.damage[DWARPEN] > 10.0:
3994 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3996 if damaged(DWARPEN) and game.warpfac > 4.0:
3999 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4000 prout(_(" is repaired, I can only give you warp 4.\""))
4002 # Read in course and distance
4005 course = getcourse(isprobe=False)
4008 # Make sure starship has enough energy for the trip
4009 # Note: this formula is slightly different from the C version,
4010 # and lets you skate a bit closer to the edge.
4011 if course.power(game.warpfac) >= game.energy:
4012 # Insufficient power for trip
4015 prout(_("Engineering to bridge--"))
4016 if not game.shldup or 0.5*power > game.energy:
4017 iwarp = (game.energy/(course.dist+0.05)) ** 0.333333333
4019 prout(_("We can't do it, Captain. We don't have enough energy."))
4021 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4024 prout(_("if you'll lower the shields."))
4028 prout(_("We haven't the energy to go that far with the shields up."))
4030 # Make sure enough time is left for the trip
4031 game.optime = course.time(game.warpfac)
4032 if game.optime >= 0.8*game.state.remtime:
4034 prout(_("First Officer Spock- \"Captain, I compute that such"))
4035 proutn(_(" a trip would require approximately %2.0f") %
4036 (100.0*game.optime/game.state.remtime))
4037 prout(_(" percent of our"))
4038 proutn(_(" remaining time. Are you sure this is wise?\" "))
4044 if game.warpfac > 6.0:
4045 # Decide if engine damage will occur
4046 # ESR: Seems wrong. Probability of damage goes *down* with distance?
4047 prob = course.distance*(6.0-game.warpfac)**2/66.666666666
4048 if prob > randreal():
4050 course.distance = randreal(course.distance)
4051 # Decide if time warp will occur
4052 if 0.5*course.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
4054 if idebug and game.warpfac==10 and not twarp:
4056 proutn("=== Force time warp? ")
4060 # If time warp or engine damage, check path
4061 # If it is obstructed, don't do warp or damage
4062 for m in range(course.moves):
4065 if not w.valid_sector():
4067 if game.quad[w.i][w.j] != IHDOT:
4071 # Activate Warp Engines and pay the cost
4072 imove(course, noattack=False)
4075 game.energy -= course.power(game.warpfac)
4076 if game.energy <= 0:
4078 game.optime = course.time(game.warpfac)
4082 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4084 prout(_("Engineering to bridge--"))
4085 prout(_(" Scott here. The warp engines are damaged."))
4086 prout(_(" We'll have to reduce speed to warp 4."))
4091 "Change the warp factor."
4097 proutn(_("Warp factor- "))
4102 if game.damage[DWARPEN] > 10.0:
4103 prout(_("Warp engines inoperative."))
4105 if damaged(DWARPEN) and scanner.real > 4.0:
4106 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4107 prout(_(" but right now we can only go warp 4.\""))
4109 if scanner.real > 10.0:
4110 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4112 if scanner.real < 1.0:
4113 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4115 oldfac = game.warpfac
4116 game.warpfac = scanner.real
4117 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4118 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4121 if game.warpfac < 8.00:
4122 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4124 if game.warpfac == 10.0:
4125 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4127 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4131 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4133 # is captain on planet?
4135 if damaged(DTRANSP):
4138 prout(_("Scotty rushes to the transporter controls."))
4140 prout(_("But with the shields up it's hopeless."))
4142 prouts(_("His desperate attempt to rescue you . . ."))
4147 prout(_("SUCCEEDS!"))
4150 proutn(_("The crystals mined were "))
4158 # Check to see if captain in shuttle craft
4163 # Inform captain of attempt to reach safety
4167 prouts(_("***RED ALERT! RED ALERT!"))
4169 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4170 prouts(_(" a supernova."))
4172 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4173 prout(_("safely out of quadrant."))
4174 if not damaged(DRADIO):
4175 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4176 # Try to use warp engines
4177 if damaged(DWARPEN):
4179 prout(_("Warp engines damaged."))
4182 game.warpfac = randreal(6.0, 8.0)
4183 prout(_("Warp factor set to %d") % int(game.warpfac))
4184 power = 0.75*game.energy
4185 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4186 dist = max(dist, randreal(math.sqrt(2)))
4187 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4188 game.optime = bugout.time(game.warpfac)
4190 game.inorbit = False
4191 warp(bugout, involuntary=True)
4193 # This is bad news, we didn't leave quadrant.
4197 prout(_("Insufficient energy to leave quadrant."))
4200 # Repeat if another snova
4201 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4203 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4204 finish(FWON) # Snova killed remaining enemy.
4207 "Let's do the time warp again."
4208 prout(_("***TIME WARP ENTERED."))
4209 if game.state.snap and withprob(0.5):
4211 prout(_("You are traveling backwards in time %d stardates.") %
4212 int(game.state.date-game.snapsht.date))
4213 game.state = game.snapsht
4214 game.state.snap = False
4215 if len(game.state.kcmdr):
4216 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4217 schedule(FBATTAK, expran(0.3*game.intime))
4218 schedule(FSNOVA, expran(0.5*game.intime))
4219 # next snapshot will be sooner
4220 schedule(FSNAP, expran(0.25*game.state.remtime))
4222 if game.state.nscrem:
4223 schedule(FSCMOVE, 0.2777)
4227 game.battle.invalidate()
4228 # Make sure Galileo is consistant -- Snapshot may have been taken
4229 # when on planet, which would give us two Galileos!
4231 for l in range(game.inplan):
4232 if game.state.planets[l].known == "shuttle_down":
4234 if game.iscraft == "onship" and game.ship==IHE:
4235 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4236 game.iscraft = "offship"
4237 # Likewise, if in the original time the Galileo was abandoned, but
4238 # was on ship earlier, it would have vanished -- let's restore it.
4239 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4240 prout(_("Checkov- \"Security reports the Galileo has reappeared in the dock!\""))
4241 game.iscraft = "onship"
4242 # There used to be code to do the actual reconstrction here,
4243 # but the starchart is now part of the snapshotted galaxy state.
4244 prout(_("Spock has reconstructed a correct star chart from memory"))
4246 # Go forward in time
4247 game.optime = -0.5*game.intime*math.log(randreal())
4248 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4249 # cheat to make sure no tractor beams occur during time warp
4250 postpone(FTBEAM, game.optime)
4251 game.damage[DRADIO] += game.optime
4253 events() # Stas Sergeev added this -- do pending events
4256 "Launch deep-space probe."
4257 # New code to launch a deep space probe
4258 if game.nprobes == 0:
4261 if game.ship == IHE:
4262 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4264 prout(_("Ye Faerie Queene has no deep space probes."))
4269 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4271 if is_scheduled(FDSPROB):
4274 if damaged(DRADIO) and game.condition != "docked":
4275 prout(_("Spock- \"Records show the previous probe has not yet"))
4276 prout(_(" reached its destination.\""))
4278 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4280 key = scanner.next()
4282 if game.nprobes == 1:
4283 prout(_("1 probe left."))
4285 prout(_("%d probes left") % game.nprobes)
4286 proutn(_("Are you sure you want to fire a probe? "))
4289 game.isarmed = False
4290 if key == "IHALPHA" and scanner.token == "armed":
4292 key = scanner.next()
4293 elif key == "IHEOL":
4294 proutn(_("Arm NOVAMAX warhead? "))
4296 elif key == "IHREAL": # first element of course
4297 scanner.push(scanner.token)
4299 game.probe = getcourse(isprobe=True)
4303 schedule(FDSPROB, 0.01) # Time to move one sector
4304 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4309 "Yell for help from nearest starbase."
4310 # There's more than one way to move in this game!
4312 # Test for conditions which prevent calling for help
4313 if game.condition == "docked":
4314 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4317 prout(_("Subspace radio damaged."))
4319 if not game.state.baseq:
4320 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4323 prout(_("You must be aboard the %s.") % crmshp())
4325 # OK -- call for help from nearest starbase
4328 # There's one in this quadrant
4329 ddist = (game.base - game.sector).distance()
4332 for ibq in game.state.baseq:
4333 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4336 # Since starbase not in quadrant, set up new quadrant
4339 # dematerialize starship
4340 game.quad[game.sector.i][game.sector.j]=IHDOT
4341 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4342 % (game.quadrant, crmshp()))
4343 game.sector.invalidate()
4344 for m in range(1, 5+1):
4345 w = game.base.scatter()
4346 if w.valid_sector() and game.quad[w.i][w.j]==IHDOT:
4347 # found one -- finish up
4350 if not game.sector.is_valid():
4351 prout(_("You have been lost in space..."))
4352 finish(FMATERIALIZE)
4354 # Give starbase three chances to rematerialize starship
4355 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4356 for m in range(1, 3+1):
4357 if m == 1: proutn(_("1st"))
4358 elif m == 2: proutn(_("2nd"))
4359 elif m == 3: proutn(_("3rd"))
4360 proutn(_(" attempt to re-materialize ") + crmshp())
4361 game.quad[ix][iy]=(IHMATER0,IHMATER1,IHMATER2)[m-1]
4364 if randreal() > probf:
4367 curses.delay_output(500)
4370 game.quad[ix][iy]=IHQUEST
4373 setwnd(message_window)
4374 finish(FMATERIALIZE)
4376 game.quad[ix][iy]=game.ship
4378 prout(_("succeeds."))
4382 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4387 if game.condition=="docked":
4389 prout(_("You cannot abandon Ye Faerie Queene."))
4392 # Must take shuttle craft to exit
4393 if game.damage[DSHUTTL]==-1:
4394 prout(_("Ye Faerie Queene has no shuttle craft."))
4396 if game.damage[DSHUTTL]<0:
4397 prout(_("Shuttle craft now serving Big Macs."))
4399 if game.damage[DSHUTTL]>0:
4400 prout(_("Shuttle craft damaged."))
4403 prout(_("You must be aboard the ship."))
4405 if game.iscraft != "onship":
4406 prout(_("Shuttle craft not currently available."))
4408 # Emit abandon ship messages
4410 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4412 prouts(_("***ALL HANDS ABANDON SHIP!"))
4414 prout(_("Captain and crew escape in shuttle craft."))
4415 if not game.state.baseq:
4416 # Oops! no place to go...
4419 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4421 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4422 prout(_("Remainder of ship's complement beam down"))
4423 prout(_("to nearest habitable planet."))
4424 elif q.planet != None and not damaged(DTRANSP):
4425 prout(_("Remainder of ship's complement beam down to %s.") %
4428 prout(_("Entire crew of %d left to die in outer space.") %
4430 game.casual += game.state.crew
4431 game.abandoned += game.state.crew
4432 # If at least one base left, give 'em the Faerie Queene
4434 game.icrystl = False # crystals are lost
4435 game.nprobes = 0 # No probes
4436 prout(_("You are captured by Klingons and released to"))
4437 prout(_("the Federation in a prisoner-of-war exchange."))
4438 nb = randrange(len(game.state.baseq))
4439 # Set up quadrant and position FQ adjacient to base
4440 if not game.quadrant == game.state.baseq[nb]:
4441 game.quadrant = game.state.baseq[nb]
4442 game.sector.i = game.sector.j = 5
4445 # position next to base by trial and error
4446 game.quad[game.sector.i][game.sector.j] = IHDOT
4447 for l in range(QUADSIZE):
4448 game.sector = game.base.scatter()
4449 if game.sector.valid_sector() and \
4450 game.quad[game.sector.i][game.sector.j] == IHDOT:
4453 break # found a spot
4454 game.sector.i=QUADSIZE/2
4455 game.sector.j=QUADSIZE/2
4457 # Get new commission
4458 game.quad[game.sector.i][game.sector.j] = game.ship = IHF
4459 game.state.crew = FULLCREW
4460 prout(_("Starfleet puts you in command of another ship,"))
4461 prout(_("the Faerie Queene, which is antiquated but,"))
4462 prout(_("still useable."))
4464 prout(_("The dilithium crystals have been moved."))
4466 game.iscraft = "offship" # Galileo disappears
4468 game.condition="docked"
4469 for l in range(NDEVICES):
4470 game.damage[l] = 0.0
4471 game.damage[DSHUTTL] = -1
4472 game.energy = game.inenrg = 3000.0
4473 game.shield = game.inshld = 1250.0
4474 game.torps = game.intorps = 6
4475 game.lsupres=game.inlsr=3.0
4480 # Code from planets.c begins here.
4483 "Abort a lengthy operation if an event interrupts it."
4486 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4491 "Report on (uninhabited) planets in the galaxy."
4495 prout(_("Spock- \"Planet report follows, Captain.\""))
4497 for i in range(game.inplan):
4498 if game.state.planets[i].pclass == "destroyed":
4500 if (game.state.planets[i].known != "unknown" \
4501 and not game.state.planets[i].inhabited) \
4504 if idebug and game.state.planets[i].known=="unknown":
4505 proutn("(Unknown) ")
4506 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4507 proutn(_(" class "))
4508 proutn(game.state.planets[i].pclass)
4510 if game.state.planets[i].crystals != present:
4512 prout(_("dilithium crystals present."))
4513 if game.state.planets[i].known=="shuttle_down":
4514 prout(_(" Shuttle Craft Galileo on surface."))
4516 prout(_("No information available."))
4519 "Enter standard orbit."
4523 prout(_("Already in standard orbit."))
4525 if damaged(DWARPEN) and damaged(DIMPULS):
4526 prout(_("Both warp and impulse engines damaged."))
4528 if not game.plnet.is_valid():
4529 prout("There is no planet in this sector.")
4531 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4532 prout(crmshp() + _(" not adjacent to planet."))
4535 game.optime = randreal(0.02, 0.05)
4536 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4540 game.height = randreal(1400, 8600)
4541 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4546 "Examine planets in this quadrant."
4547 if damaged(DSRSENS):
4548 if game.options & OPTION_TTY:
4549 prout(_("Short range sensors damaged."))
4551 if game.iplnet == None:
4552 if game.options & OPTION_TTY:
4553 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4555 if game.iplnet.known == "unknown":
4556 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4558 prout(_(" Planet at Sector %s is of class %s.") %
4559 (game.plnet, game.iplnet.pclass))
4560 if game.iplnet.known=="shuttle_down":
4561 prout(_(" Sensors show Galileo still on surface."))
4562 proutn(_(" Readings indicate"))
4563 if game.iplnet.crystals != "present":
4565 prout(_(" dilithium crystals present.\""))
4566 if game.iplnet.known == "unknown":
4567 game.iplnet.known = "known"
4568 elif game.iplnet.inhabited:
4569 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4570 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4573 "Use the transporter."
4577 if damaged(DTRANSP):
4578 prout(_("Transporter damaged."))
4579 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4581 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4585 if not game.inorbit:
4586 prout(crmshp() + _(" not in standard orbit."))
4589 prout(_("Impossible to transport through shields."))
4591 if game.iplnet.known=="unknown":
4592 prout(_("Spock- \"Captain, we have no information on this planet"))
4593 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4594 prout(_(" you may not go down.\""))
4596 if not game.landed and game.iplnet.crystals=="absent":
4597 prout(_("Spock- \"Captain, I fail to see the logic in"))
4598 prout(_(" exploring a planet with no dilithium crystals."))
4599 proutn(_(" Are you sure this is wise?\" "))
4603 if not (game.options & OPTION_PLAIN):
4604 nrgneed = 50 * game.skill + game.height / 100.0
4605 if nrgneed > game.energy:
4606 prout(_("Engineering to bridge--"))
4607 prout(_(" Captain, we don't have enough energy for transportation."))
4609 if not game.landed and nrgneed * 2 > game.energy:
4610 prout(_("Engineering to bridge--"))
4611 prout(_(" Captain, we have enough energy only to transport you down to"))
4612 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4613 if game.iplnet.known == "shuttle_down":
4614 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4615 proutn(_(" Are you sure this is wise?\" "))
4620 # Coming from planet
4621 if game.iplnet.known=="shuttle_down":
4622 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4626 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4627 prout(_("Landing party assembled, ready to beam up."))
4629 prout(_("Kirk whips out communicator..."))
4630 prouts(_("BEEP BEEP BEEP"))
4632 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4635 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4637 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4639 prout(_("Kirk- \"Energize.\""))
4642 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4645 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4647 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4650 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4651 game.landed = not game.landed
4652 game.energy -= nrgneed
4654 prout(_("Transport complete."))
4655 if game.landed and game.iplnet.known=="shuttle_down":
4656 prout(_("The shuttle craft Galileo is here!"))
4657 if not game.landed and game.imine:
4664 "Strip-mine a world for dilithium."
4668 prout(_("Mining party not on planet."))
4670 if game.iplnet.crystals == "mined":
4671 prout(_("This planet has already been strip-mined for dilithium."))
4673 elif game.iplnet.crystals == "absent":
4674 prout(_("No dilithium crystals on this planet."))
4677 prout(_("You've already mined enough crystals for this trip."))
4679 if game.icrystl and game.cryprob == 0.05:
4680 prout(_("With all those fresh crystals aboard the ") + crmshp())
4681 prout(_("there's no reason to mine more at this time."))
4683 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4686 prout(_("Mining operation complete."))
4687 game.iplnet.crystals = "mined"
4688 game.imine = game.ididit = True
4691 "Use dilithium crystals."
4695 if not game.icrystl:
4696 prout(_("No dilithium crystals available."))
4698 if game.energy >= 1000:
4699 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4700 prout(_(" except when Condition Yellow exists."))
4702 prout(_("Spock- \"Captain, I must warn you that loading"))
4703 prout(_(" raw dilithium crystals into the ship's power"))
4704 prout(_(" system may risk a severe explosion."))
4705 proutn(_(" Are you sure this is wise?\" "))
4710 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4711 prout(_(" Mr. Spock and I will try it.\""))
4713 prout(_("Spock- \"Crystals in place, Sir."))
4714 prout(_(" Ready to activate circuit.\""))
4716 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4718 if with(game.cryprob):
4719 prouts(_(" \"Activating now! - - No good! It's***"))
4721 prouts(_("***RED ALERT! RED A*L********************************"))
4724 prouts(_("****************** KA-BOOM!!!! *******************"))
4728 game.energy += randreal(5000.0, 5500.0)
4729 prouts(_(" \"Activating now! - - "))
4730 prout(_("The instruments"))
4731 prout(_(" are going crazy, but I think it's"))
4732 prout(_(" going to work!! Congratulations, Sir!\""))
4737 "Use shuttlecraft for planetary jaunt."
4740 if damaged(DSHUTTL):
4741 if game.damage[DSHUTTL] == -1.0:
4742 if game.inorbit and game.iplnet.known == "shuttle_down":
4743 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4745 prout(_("Ye Faerie Queene had no shuttle craft."))
4746 elif game.damage[DSHUTTL] > 0:
4747 prout(_("The Galileo is damaged."))
4748 else: # game.damage[DSHUTTL] < 0
4749 prout(_("Shuttle craft is now serving Big Macs."))
4751 if not game.inorbit:
4752 prout(crmshp() + _(" not in standard orbit."))
4754 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4755 prout(_("Shuttle craft not currently available."))
4757 if not game.landed and game.iplnet.known=="shuttle_down":
4758 prout(_("You will have to beam down to retrieve the shuttle craft."))
4760 if game.shldup or game.condition == "docked":
4761 prout(_("Shuttle craft cannot pass through shields."))
4763 if game.iplnet.known=="unknown":
4764 prout(_("Spock- \"Captain, we have no information on this planet"))
4765 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4766 prout(_(" you may not fly down.\""))
4768 game.optime = 3.0e-5*game.height
4769 if game.optime >= 0.8*game.state.remtime:
4770 prout(_("First Officer Spock- \"Captain, I compute that such"))
4771 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4772 int(100*game.optime/game.state.remtime))
4773 prout(_("remaining time."))
4774 proutn(_("Are you sure this is wise?\" "))
4780 if game.iscraft == "onship":
4782 if not damaged(DTRANSP):
4783 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4787 proutn(_("Shuttle crew"))
4789 proutn(_("Rescue party"))
4790 prout(_(" boards Galileo and swoops toward planet surface."))
4791 game.iscraft = "offship"
4795 game.iplnet.known="shuttle_down"
4796 prout(_("Trip complete."))
4799 # Ready to go back to ship
4800 prout(_("You and your mining party board the"))
4801 prout(_("shuttle craft for the trip back to the Enterprise."))
4803 prouts(_("The short hop begins . . ."))
4805 game.iplnet.known="known"
4811 game.iscraft = "onship"
4817 prout(_("Trip complete."))
4820 # Kirk on ship and so is Galileo
4821 prout(_("Mining party assembles in the hangar deck,"))
4822 prout(_("ready to board the shuttle craft \"Galileo\"."))
4824 prouts(_("The hangar doors open; the trip begins."))
4827 game.iscraft = "offship"
4830 game.iplnet.known = "shuttle_down"
4833 prout(_("Trip complete."))
4837 "Use the big zapper."
4841 if game.ship != IHE:
4842 prout(_("Ye Faerie Queene has no death ray."))
4844 if len(game.enemies)==0:
4845 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4848 prout(_("Death Ray is damaged."))
4850 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4851 prout(_(" is highly unpredictible. Considering the alternatives,"))
4852 proutn(_(" are you sure this is wise?\" "))
4855 prout(_("Spock- \"Acknowledged.\""))
4858 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4860 prout(_("Crew scrambles in emergency preparation."))
4861 prout(_("Spock and Scotty ready the death ray and"))
4862 prout(_("prepare to channel all ship's power to the device."))
4864 prout(_("Spock- \"Preparations complete, sir.\""))
4865 prout(_("Kirk- \"Engage!\""))
4867 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4870 if game.options & OPTION_PLAIN:
4874 prouts(_("Sulu- \"Captain! It's working!\""))
4876 while len(game.enemies) > 0:
4877 deadkl(game.enemies[1].kloc, game.quad[game.enemies[1].kloc.i][game.enemies[1].kloc.j],game.enemies[1].kloc)
4878 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4879 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4881 if (game.options & OPTION_PLAIN) == 0:
4882 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4884 prout(_(" is still operational.\""))
4886 prout(_(" has been rendered nonfunctional.\""))
4887 game.damage[DDRAY] = 39.95
4889 r = randreal() # Pick failure method
4891 prouts(_("Sulu- \"Captain! It's working!\""))
4893 prouts(_("***RED ALERT! RED ALERT!"))
4895 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4897 prouts(_("***RED ALERT! RED A*L********************************"))
4900 prouts(_("****************** KA-BOOM!!!! *******************"))
4905 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4907 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4909 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4910 prout(_(" have apparently been transformed into strange mutations."))
4911 prout(_(" Vulcans do not seem to be affected."))
4913 prout(_("Kirk- \"Raauch! Raauch!\""))
4918 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4920 proutn(_("Spock- \"I believe the word is"))
4921 prouts(_(" *ASTONISHING*"))
4922 prout(_(" Mr. Sulu."))
4923 for i in range(QUADSIZE):
4924 for j in range(QUADSIZE):
4925 if game.quad[i][j] == IHDOT:
4926 game.quad[i][j] = IHQUEST
4927 prout(_(" Captain, our quadrant is now infested with"))
4928 prouts(_(" - - - - - - *THINGS*."))
4930 prout(_(" I have no logical explanation.\""))
4932 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4934 prout(_("Scotty- \"There are so many tribbles down here"))
4935 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4939 # Code from reports.c begins here
4941 def attackreport(curt):
4942 "eport status of bases under attack."
4944 if is_scheduled(FCDBAS):
4945 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4946 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4947 elif game.isatb == 1:
4948 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4949 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4951 prout(_("No Starbase is currently under attack."))
4953 if is_scheduled(FCDBAS):
4954 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4956 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4960 # report on general game status
4962 s1 = "" and game.thawed and _("thawed ")
4963 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4964 s3 = (None, _("novice"). _("fair"),
4965 _("good"), _("expert"), _("emeritus"))[game.skill]
4966 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4967 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4968 prout(_("No plaque is allowed."))
4970 prout(_("This is tournament game %d.") % game.tourn)
4971 prout(_("Your secret password is \"%s\"") % game.passwd)
4972 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4973 (game.inkling + game.incom + game.inscom)))
4974 if game.incom - len(game.state.kcmdr):
4975 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4976 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4977 prout(_(", but no Commanders."))
4980 if game.skill > SKILL_FAIR:
4981 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4982 if len(game.state.baseq) != game.inbase:
4984 if game.inbase-len(game.state.baseq)==1:
4985 proutn(_("has been 1 base"))
4987 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4988 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4990 prout(_("There are %d bases.") % game.inbase)
4991 if communicating() or game.iseenit:
4992 # Don't report this if not seen and
4993 # either the radio is dead or not at base!
4997 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4999 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
5000 if game.ship == IHE:
5001 proutn(_("You have "))
5003 proutn("%d" % (game.nprobes))
5006 proutn(_(" deep space probe"))
5010 if communicating() and is_scheduled(FDSPROB):
5012 proutn(_("An armed deep space probe is in "))
5014 proutn(_("A deep space probe is in "))
5015 prout("Quadrant %s." % game.probec)
5017 if game.cryprob <= .05:
5018 prout(_("Dilithium crystals aboard ship... not yet used."))
5022 while game.cryprob > ai:
5025 prout(_("Dilithium crystals have been used %d time%s.") % \
5026 (i, (_("s"), "")[i==1]))
5030 "Long-range sensor scan."
5031 if damaged(DLRSENS):
5032 # Now allow base's sensors if docked
5033 if game.condition != "docked":
5035 prout(_("LONG-RANGE SENSORS DAMAGED."))
5038 prout(_("Starbase's long-range scan"))
5040 prout(_("Long-range scan"))
5041 for x in range(game.quadrant.i-1, game.quadrant.i+2):
5044 for y in range(game.quadrant.j-1, game.quadrant.j+2):
5045 if not coord(x, y).valid_quadrant():
5049 if not damaged(DRADIO):
5050 game.state.galaxy[x][y].charted = True
5051 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5052 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5053 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5054 if not silent and game.state.galaxy[x][y].supernova:
5057 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
5064 for i in range(NDEVICES):
5067 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5068 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5070 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5071 game.damage[i]+0.05,
5072 game.docfac*game.damage[i]+0.005))
5074 prout(_("All devices functional."))
5077 "Update the chart in the Enterprise's computer from galaxy data."
5078 game.lastchart = game.state.date
5079 for i in range(GALSIZE):
5080 for j in range(GALSIZE):
5081 if game.state.galaxy[i][j].charted:
5082 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5083 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5084 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5087 "Display the star chart."
5089 if (game.options & OPTION_AUTOSCAN):
5091 if not damaged(DRADIO):
5093 if game.lastchart < game.state.date and game.condition == "docked":
5094 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5096 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5097 if game.state.date > game.lastchart:
5098 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5099 prout(" 1 2 3 4 5 6 7 8")
5100 for i in range(GALSIZE):
5101 proutn("%d |" % (i+1))
5102 for j in range(GALSIZE):
5103 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5107 if game.state.galaxy[i][j].supernova:
5109 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5111 elif game.state.galaxy[i][j].charted:
5112 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5116 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5124 def sectscan(goodScan, i, j):
5125 "Light up an individual dot in a sector."
5126 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5127 if (game.quad[i][j]==IHMATER0) or (game.quad[i][j]==IHMATER1) or (game.quad[i][j]==IHMATER2) or (game.quad[i][j]==IHE) or (game.quad[i][j]==IHF):
5128 #if game.condition == "red": textcolor("red")
5129 #elif game.condition == "green": textcolor("green")
5130 #elif game.condition == "yellow": textcolor("yellow")
5131 #elif game.condition == "docked": textcolor("cyan")
5132 #elif game.condition == "dead": textcolor("brown")
5133 if game.quad[i][j] != game.ship:
5135 proutn("%c " % game.quad[i][j])
5141 "Emit status report lines"
5142 if not req or req == 1:
5143 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5144 % (game.state.date, game.state.remtime))
5145 if not req or req == 2:
5146 if game.condition != "docked":
5148 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5149 (game.condition.upper(), sum(map(lambda x: x > 0, game.damage))))
5150 if not req or req == 3:
5151 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5152 if not req or req == 4:
5153 if damaged(DLIFSUP):
5154 if game.condition == "docked":
5155 s = _("DAMAGED, Base provides")
5157 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5160 prstat(_("Life Support"), s)
5161 if not req or req == 5:
5162 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5163 if not req or req == 6:
5165 if game.icrystl and (game.options & OPTION_SHOWME):
5166 extra = _(" (have crystals)")
5167 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5168 if not req or req == 7:
5169 prstat(_("Torpedoes"), "%d" % (game.torps))
5170 if not req or req == 8:
5171 if damaged(DSHIELD):
5177 data = _(" %d%% %.1f units") \
5178 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5179 prstat(_("Shields"), s+data)
5180 if not req or req == 9:
5181 prstat(_("Klingons Left"), "%d" \
5182 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5183 if not req or req == 10:
5184 if game.options & OPTION_WORLDS:
5185 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5186 if plnet and plnet.inhabited:
5187 prstat(_("Major system"), plnet.name)
5189 prout(_("Sector is uninhabited"))
5190 elif not req or req == 11:
5191 attackreport(not req)
5194 "Request specified status data, a historical relic from slow TTYs."
5195 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5196 while scanner.next() == "IHEOL":
5197 proutn(_("Information desired? "))
5199 if scanner.token in requests:
5200 status(requests.index(scanner.token))
5202 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5203 prout((" date, condition, position, lsupport, warpfactor,"))
5204 prout((" energy, torpedoes, shields, klingons, system, time."))
5209 if damaged(DSRSENS):
5210 # Allow base's sensors if docked
5211 if game.condition != "docked":
5212 prout(_(" S.R. SENSORS DAMAGED!"))
5215 prout(_(" [Using Base's sensors]"))
5217 prout(_(" Short-range scan"))
5218 if goodScan and not damaged(DRADIO):
5219 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5220 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5221 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5222 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5223 prout(" 1 2 3 4 5 6 7 8 9 10")
5224 if game.condition != "docked":
5226 for i in range(QUADSIZE):
5227 proutn("%2d " % (i+1))
5228 for j in range(QUADSIZE):
5229 sectscan(goodScan, i, j)
5233 "Use computer to get estimated time of arrival for a warp jump."
5234 w1 = coord(); w2 = coord()
5236 if damaged(DCOMPTR):
5237 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5240 if scanner.next() != "IHREAL":
5243 proutn(_("Destination quadrant and/or sector? "))
5244 if scanner.next()!="IHREAL":
5247 w1.j = int(scanner.real-0.5)
5248 if scanner.next() != "IHREAL":
5251 w1.i = int(scanner.real-0.5)
5252 if scanner.next() == "IHREAL":
5253 w2.j = int(scanner.real-0.5)
5254 if scanner.next() != "IHREAL":
5257 w2.i = int(scanner.real-0.5)
5259 if game.quadrant.j>w1.i:
5263 if game.quadrant.i>w1.j:
5267 if not w1.valid_quadrant() or not w2.valid_sector():
5270 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5271 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5274 prout(_("Answer \"no\" if you don't know the value:"))
5277 proutn(_("Time or arrival date? "))
5278 if scanner.next()=="IHREAL":
5279 ttime = scanner.real
5280 if ttime > game.state.date:
5281 ttime -= game.state.date # Actually a star date
5282 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5283 if ttime <= 1e-10 or twarp > 10:
5284 prout(_("We'll never make it, sir."))
5291 proutn(_("Warp factor? "))
5292 if scanner.next()== "IHREAL":
5294 twarp = scanner.real
5295 if twarp<1.0 or twarp > 10.0:
5299 prout(_("Captain, certainly you can give me one of these."))
5302 ttime = (10.0*dist)/twarp**2
5303 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5304 if tpower >= game.energy:
5305 prout(_("Insufficient energy, sir."))
5306 if not game.shldup or tpower > game.energy*2.0:
5309 proutn(_("New warp factor to try? "))
5310 if scanner.next() == "IHREAL":
5312 twarp = scanner.real
5313 if twarp<1.0 or twarp > 10.0:
5321 prout(_("But if you lower your shields,"))
5322 proutn(_("remaining"))
5325 proutn(_("Remaining"))
5326 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5328 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5330 prout(_("Any warp speed is adequate."))
5332 prout(_("Minimum warp needed is %.2f,") % (twarp))
5333 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5334 if game.state.remtime < ttime:
5335 prout(_("Unfortunately, the Federation will be destroyed by then."))
5337 prout(_("You'll be taking risks at that speed, Captain"))
5338 if (game.isatb==1 and game.state.kscmdr == w1 and \
5339 scheduled(FSCDBAS)< ttime+game.state.date) or \
5340 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5341 prout(_("The starbase there will be destroyed by then."))
5342 proutn(_("New warp factor to try? "))
5343 if scanner.next() == "IHREAL":
5345 twarp = scanner.real
5346 if twarp<1.0 or twarp > 10.0:
5354 # Code from setup.c begins here
5357 "Issue a historically correct banner."
5359 prout(_("-SUPER- STAR TREK"))
5361 # From the FORTRAN original
5362 # prout(_("Latest update-21 Sept 78"))
5368 scanner.push("emsave.trk")
5369 key = scanner.next()
5371 proutn(_("File name: "))
5372 key = scanner.next()
5373 if key != "IHALPHA":
5377 if '.' not in scanner.token:
5378 scanner.token += ".trk"
5380 fp = open(scanner.token, "wb")
5382 prout(_("Can't freeze game as file %s") % scanner.token)
5384 cPickle.dump(game, fp)
5388 "Retrieve saved game."
5389 game.passwd[0] = '\0'
5390 key = scanner.next()
5392 proutn(_("File name: "))
5393 key = scanner.next()
5394 if key != "IHALPHA":
5398 if '.' not in scanner.token:
5399 scanner.token += ".trk"
5401 fp = open(scanner.token, "rb")
5403 prout(_("Can't thaw game in %s") % scanner.token)
5405 game = cPickle.load(fp)
5409 # I used <http://www.memory-alpha.org> to find planets
5410 # with references in ST:TOS. Eath and the Alpha Centauri
5411 # Colony have been omitted.
5413 # Some planets marked Class G and P here will be displayed as class M
5414 # because of the way planets are generated. This is a known bug.
5417 _("Andoria (Fesoan)"), # several episodes
5418 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5419 _("Vulcan (T'Khasi)"), # many episodes
5420 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5421 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5422 _("Ardana"), # TOS: "The Cloud Minders"
5423 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5424 _("Gideon"), # TOS: "The Mark of Gideon"
5425 _("Aldebaran III"), # TOS: "The Deadly Years"
5426 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5427 _("Altair IV"), # TOS: "Amok Time
5428 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5429 _("Benecia"), # TOS: "The Conscience of the King"
5430 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5431 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5432 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5433 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5434 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5435 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5436 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5437 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5438 _("Ingraham B"), # TOS: "Operation: Annihilate"
5439 _("Janus IV"), # TOS: "The Devil in the Dark"
5440 _("Makus III"), # TOS: "The Galileo Seven"
5441 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5442 _("Omega IV"), # TOS: "The Omega Glory"
5443 _("Regulus V"), # TOS: "Amok Time
5444 _("Deneva"), # TOS: "Operation -- Annihilate!"
5445 # Worlds from BSD Trek
5446 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5447 _("Beta III"), # TOS: "The Return of the Archons"
5448 _("Triacus"), # TOS: "And the Children Shall Lead",
5449 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5451 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5452 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5453 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5454 # _("Izar"), # TOS: "Whom Gods Destroy"
5455 # _("Tiburon"), # TOS: "The Way to Eden"
5456 # _("Merak II"), # TOS: "The Cloud Minders"
5457 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5458 # _("Iotia"), # TOS: "A Piece of the Action"
5462 _("S. R. Sensors"), \
5463 _("L. R. Sensors"), \
5465 _("Photon Tubes"), \
5466 _("Life Support"), \
5467 _("Warp Engines"), \
5468 _("Impulse Engines"), \
5470 _("Subspace Radio"), \
5471 _("Shuttle Craft"), \
5473 _("Navigation System"), \
5475 _("Shield Control"), \
5481 "Prepare to play, set up cosmos."
5483 # Decide how many of everything
5485 return # frozen game
5486 # Prepare the Enterprise
5487 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5489 game.state.crew = FULLCREW
5490 game.energy = game.inenrg = 5000.0
5491 game.shield = game.inshld = 2500.0
5494 game.quadrant = randplace(GALSIZE)
5495 game.sector = randplace(QUADSIZE)
5496 game.torps = game.intorps = 10
5497 game.nprobes = randrange(2, 5)
5499 for i in range(NDEVICES):
5500 game.damage[i] = 0.0
5501 # Set up assorted game parameters
5502 game.battle = coord()
5503 game.state.date = game.indate = 100.0 * randreal(20, 51)
5504 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5505 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5506 game.isatb = game.state.nplankl = 0
5507 game.state.starkl = game.state.basekl = 0
5508 game.iscraft = "onship"
5512 # Starchart is functional but we've never seen it
5513 game.lastchart = FOREVER
5514 # Put stars in the galaxy
5516 for i in range(GALSIZE):
5517 for j in range(GALSIZE):
5518 k = randrange(1, QUADSIZE**2/10+1)
5520 game.state.galaxy[i][j].stars = k
5521 # Locate star bases in galaxy
5522 for i in range(game.inbase):
5525 w = randplace(GALSIZE)
5526 if not game.state.galaxy[w.i][w.j].starbase:
5529 # C version: for (j = i-1; j > 0; j--)
5530 # so it did them in the opposite order.
5531 for j in range(1, i):
5532 # Improved placement algorithm to spread out bases
5533 distq = (w - game.state.baseq[j]).distance()
5534 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5537 prout("=== Abandoning base #%d at %s" % (i, w))
5539 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5541 prout("=== Saving base #%d, close to #%d" % (i, j))
5544 game.state.baseq.append(w)
5545 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5546 # Position ordinary Klingon Battle Cruisers
5548 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5549 if klumper > MAXKLQUAD:
5553 klump = (1.0 - r*r)*klumper
5558 w = randplace(GALSIZE)
5559 if not game.state.galaxy[w.i][w.j].supernova and \
5560 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5562 game.state.galaxy[w.i][w.j].klingons += int(klump)
5565 # Position Klingon Commander Ships
5566 for i in range(game.incom):
5568 w = randplace(GALSIZE)
5569 if not welcoming(w) or w in game.state.kcmdr:
5571 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5573 game.state.galaxy[w.i][w.j].klingons += 1
5574 game.state.kcmdr.append(w)
5575 # Locate planets in galaxy
5576 for i in range(game.inplan):
5578 w = randplace(GALSIZE)
5579 if game.state.galaxy[w.i][w.j].planet == None:
5583 new.crystals = "absent"
5584 if (game.options & OPTION_WORLDS) and i < NINHAB:
5585 new.pclass = "M" # All inhabited planets are class M
5586 new.crystals = "absent"
5588 new.name = systnames[i]
5589 new.inhabited = True
5591 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5593 new.crystals = "present"
5594 new.known = "unknown"
5595 new.inhabited = False
5596 game.state.galaxy[w.i][w.j].planet = new
5597 game.state.planets.append(new)
5599 for i in range(game.state.nromrem):
5600 w = randplace(GALSIZE)
5601 game.state.galaxy[w.i][w.j].romulans += 1
5602 # Place the Super-Commander if needed
5603 if game.state.nscrem > 0:
5605 w = randplace(GALSIZE)
5608 game.state.kscmdr = w
5609 game.state.galaxy[w.i][w.j].klingons += 1
5610 # Initialize times for extraneous events
5611 schedule(FSNOVA, expran(0.5 * game.intime))
5612 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5613 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5614 schedule(FBATTAK, expran(0.3*game.intime))
5616 if game.state.nscrem:
5617 schedule(FSCMOVE, 0.2777)
5622 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5623 schedule(FDISTR, expran(1.0 + game.intime))
5628 # Place thing (in tournament game, we don't want one!)
5629 # New in SST2K: never place the Thing near a starbase.
5630 # This makes sense and avoids a special case in the old code.
5632 if game.tourn is None:
5634 thing = randplace(GALSIZE)
5635 if thing not in game.state.baseq:
5638 game.state.snap = False
5639 if game.skill == SKILL_NOVICE:
5640 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5641 prout(_("a deadly Klingon invasion force. As captain of the United"))
5642 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5643 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5644 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5645 prout(_("your mission. As you proceed you may be given more time."))
5647 prout(_("You will have %d supporting starbases.") % (game.inbase))
5648 proutn(_("Starbase locations- "))
5650 prout(_("Stardate %d.") % int(game.state.date))
5652 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5653 prout(_("An unknown number of Romulans."))
5654 if game.state.nscrem:
5655 prout(_("And one (GULP) Super-Commander."))
5656 prout(_("%d stardates.") % int(game.intime))
5657 proutn(_("%d starbases in ") % game.inbase)
5658 for i in range(game.inbase):
5659 proutn(`game.state.baseq[i]`)
5662 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5663 proutn(_(" Sector %s") % game.sector)
5665 prout(_("Good Luck!"))
5666 if game.state.nscrem:
5667 prout(_(" YOU'LL NEED IT."))
5670 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5672 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5673 attack(torps_ok=False)
5676 "Choose your game type."
5681 game.skill = SKILL_NONE
5683 if not scanner.inqueue: # Can start with command line options
5684 proutn(_("Would you like a regular, tournament, or saved game? "))
5686 if scanner.sees("tournament"):
5687 while scanner.next() == "IHEOL":
5688 proutn(_("Type in tournament number-"))
5689 if scanner.real == 0:
5691 continue # We don't want a blank entry
5692 game.tourn = int(round(scanner.real))
5693 random.seed(scanner.real)
5695 logfp.write("# random.seed(%d)\n" % scanner.real)
5697 if scanner.sees("saved") or scanner.sees("frozen"):
5701 if game.passwd == None:
5703 if not game.alldone:
5704 game.thawed = True # No plaque if not finished
5708 if scanner.sees("regular"):
5710 proutn(_("What is \"%s\"?") % scanner.token)
5712 while game.length==0 or game.skill==SKILL_NONE:
5713 if scanner.next() == "IHALPHA":
5714 if scanner.sees("short"):
5716 elif scanner.sees("medium"):
5718 elif scanner.sees("long"):
5720 elif scanner.sees("novice"):
5721 game.skill = SKILL_NOVICE
5722 elif scanner.sees("fair"):
5723 game.skill = SKILL_FAIR
5724 elif scanner.sees("good"):
5725 game.skill = SKILL_GOOD
5726 elif scanner.sees("expert"):
5727 game.skill = SKILL_EXPERT
5728 elif scanner.sees("emeritus"):
5729 game.skill = SKILL_EMERITUS
5731 proutn(_("What is \""))
5732 proutn(scanner.token)
5737 proutn(_("Would you like a Short, Medium, or Long game? "))
5738 elif game.skill == SKILL_NONE:
5739 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5740 # Choose game options -- added by ESR for SST2K
5741 if scanner.next() != "IHALPHA":
5743 proutn(_("Choose your game style (or just press enter): "))
5745 if scanner.sees("plain"):
5746 # Approximates the UT FORTRAN version.
5747 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5748 game.options |= OPTION_PLAIN
5749 elif scanner.sees("almy"):
5750 # Approximates Tom Almy's version.
5751 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5752 game.options |= OPTION_ALMY
5753 elif scanner.sees("fancy") or scanner.sees("\n"):
5755 elif len(scanner.token):
5756 proutn(_("What is \"%s\"?") % scanner.token)
5758 if game.passwd == "debug":
5760 prout("=== Debug mode enabled.")
5761 # Use parameters to generate initial values of things
5762 game.damfac = 0.5 * game.skill
5763 game.inbase = randrange(BASEMIN, BASEMAX+1)
5765 if game.options & OPTION_PLANETS:
5766 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5767 if game.options & OPTION_WORLDS:
5768 game.inplan += int(NINHAB)
5769 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5770 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5771 game.state.remtime = 7.0 * game.length
5772 game.intime = game.state.remtime
5773 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5774 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5775 game.state.remres = (game.inkling+4*game.incom)*game.intime
5776 game.inresor = game.state.remres
5777 if game.inkling > 50:
5778 game.state.inbase += 1
5781 def dropin(iquad=None):
5782 "Drop a feature on a random dot in the current quadrant."
5784 w = randplace(QUADSIZE)
5785 if game.quad[w.i][w.j] == IHDOT:
5787 if iquad is not None:
5788 game.quad[w.i][w.j] = iquad
5792 "Update our alert status."
5793 game.condition = "green"
5794 if game.energy < 1000.0:
5795 game.condition = "yellow"
5796 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5797 game.condition = "red"
5799 game.condition="dead"
5802 "Drop new Klingon into current quadrant."
5803 return enemy(IHK, loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5806 "Set up a new state of quadrant, for when we enter or re-enter it."
5809 game.neutz = game.inorbit = game.landed = False
5810 game.ientesc = game.iseenit = False
5811 # Create a blank quadrant
5812 game.quad = fill2d(QUADSIZE, lambda i, j: IHDOT)
5814 # Attempt to escape Super-commander, so tbeam back!
5817 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5818 # cope with supernova
5821 game.klhere = q.klingons
5822 game.irhere = q.romulans
5824 game.quad[game.sector.i][game.sector.j] = game.ship
5827 # Position ordinary Klingons
5828 for i in range(game.klhere):
5830 # If we need a commander, promote a Klingon
5831 for cmdr in game.state.kcmdr:
5832 if cmdr == game.quadrant:
5833 e = game.enemies[game.klhere-1]
5834 game.quad[e.kloc.i][e.kloc.j] = IHC
5835 e.kpower = randreal(950,1350) + 50.0*game.skill
5837 # If we need a super-commander, promote a Klingon
5838 if game.quadrant == game.state.kscmdr:
5840 game.quad[e.kloc.i][e.kloc.j] = IHS
5841 e.kpower = randreal(1175.0, 1575.0) + 125.0*game.skill
5842 game.iscate = (game.state.remkl > 1)
5843 # Put in Romulans if needed
5844 for i in range(q.romulans):
5845 enemy(IHR, loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5846 # If quadrant needs a starbase, put it in
5848 game.base = dropin(IHB)
5849 # If quadrant needs a planet, put it in
5851 game.iplnet = q.planet
5852 if not q.planet.inhabited:
5853 game.plnet = dropin(IHP)
5855 game.plnet = dropin(IHW)
5856 # Check for condition
5859 if game.irhere > 0 and game.klhere == 0:
5861 if not damaged(DRADIO):
5863 prout(_("LT. Uhura- \"Captain, an urgent message."))
5864 prout(_(" I'll put it on audio.\" CLICK"))
5866 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5867 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5868 # Put in THING if needed
5869 if thing == game.quadrant:
5870 enemy(type=IHQUEST, loc=dropin(),
5871 power=randreal(6000,6500.0)+250.0*game.skill)
5872 if not damaged(DSRSENS):
5874 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5875 prout(_(" Please examine your short-range scan.\""))
5876 # Decide if quadrant needs a Tholian; lighten up if skill is low
5877 if game.options & OPTION_THOLIAN:
5878 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5879 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5880 (game.skill > SKILL_GOOD and withprob(0.08)):
5883 w.i = withprob(0.5) * (QUADSIZE-1)
5884 w.j = withprob(0.5) * (QUADSIZE-1)
5885 if game.quad[w.i][w.j] == IHDOT:
5887 game.tholian = enemy(type=IHT, loc=w,
5888 power=randrange(100, 500) + 25.0*game.skill)
5889 # Reserve unoccupied corners
5890 if game.quad[0][0]==IHDOT:
5891 game.quad[0][0] = 'X'
5892 if game.quad[0][QUADSIZE-1]==IHDOT:
5893 game.quad[0][QUADSIZE-1] = 'X'
5894 if game.quad[QUADSIZE-1][0]==IHDOT:
5895 game.quad[QUADSIZE-1][0] = 'X'
5896 if game.quad[QUADSIZE-1][QUADSIZE-1]==IHDOT:
5897 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5898 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
5899 # And finally the stars
5900 for i in range(q.stars):
5902 # Put in a few black holes
5903 for i in range(1, 3+1):
5906 # Take out X's in corners if Tholian present
5908 if game.quad[0][0]=='X':
5909 game.quad[0][0] = IHDOT
5910 if game.quad[0][QUADSIZE-1]=='X':
5911 game.quad[0][QUADSIZE-1] = IHDOT
5912 if game.quad[QUADSIZE-1][0]=='X':
5913 game.quad[QUADSIZE-1][0] = IHDOT
5914 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5915 game.quad[QUADSIZE-1][QUADSIZE-1] = IHDOT
5918 "Set the self-destruct password."
5919 if game.options & OPTION_PLAIN:
5922 proutn(_("Please type in a secret password- "))
5924 game.passwd = scanner.token
5925 if game.passwd != None:
5930 game.passwd += chr(ord('a')+randrange(26))
5932 # Code from sst.c begins here
5935 "SRSCAN": OPTION_TTY,
5936 "STATUS": OPTION_TTY,
5937 "REQUEST": OPTION_TTY,
5938 "LRSCAN": OPTION_TTY,
5951 "SENSORS": OPTION_PLANETS,
5952 "ORBIT": OPTION_PLANETS,
5953 "TRANSPORT": OPTION_PLANETS,
5954 "MINE": OPTION_PLANETS,
5955 "CRYSTALS": OPTION_PLANETS,
5956 "SHUTTLE": OPTION_PLANETS,
5957 "PLANETS": OPTION_PLANETS,
5962 "PROBE": OPTION_PROBE,
5964 "FREEZE": 0, # Synonym for SAVE
5970 "SOS": 0, # Synonym for MAYDAY
5971 "CALL": 0, # Synonym for MAYDAY
5977 "Generate a list of legal commands."
5978 prout(_("LEGAL COMMANDS ARE:"))
5980 for key in commands:
5981 if not commands[key] or (commands[key] & game.options):
5982 proutn("%-12s " % key)
5984 if emitted % 5 == 4:
5989 "Browse on-line help."
5990 key = scanner.next()
5993 setwnd(prompt_window)
5994 proutn(_("Help on what command? "))
5995 key = scanner.next()
5996 setwnd(message_window)
5999 if scanner.token in commands or scanner.token == "ABBREV":
6006 cmd = scanner.token.upper()
6008 fp = open(SSTDOC, "r")
6011 fp = open(DOC_NAME, "r")
6013 prout(_("Spock- \"Captain, that information is missing from the"))
6014 proutn(_(" computer. You need to find "))
6016 prout(_(" and put it in the"))
6017 proutn(_(" current directory or to "))
6020 # This used to continue: "You need to find SST.DOC and put
6021 # it in the current directory."
6024 linebuf = fp.readline()
6026 prout(_("Spock- \"Captain, there is no information on that command.\""))
6029 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
6030 linebuf = linebuf[3:].strip()
6034 prout(_("Spock- \"Captain, I've found the following information:\""))
6036 while linebuf in fp:
6037 if "******" in linebuf:
6043 "Command-interpretation loop."
6045 setwnd(message_window)
6046 while True: # command loop
6048 while True: # get a command
6053 setwnd(prompt_window)
6056 if scanner.next() == "IHEOL":
6057 if game.options & OPTION_CURSES:
6060 elif scanner.token == "":
6064 setwnd(message_window)
6066 candidates = filter(lambda x: x.startswith(scanner.token.upper()),
6068 if len(candidates) == 1:
6071 elif candidates and not (game.options & OPTION_PLAIN):
6072 prout("Commands with prefix '%s': %s" % (scanner.token, " ".join(candidates)))
6076 if cmd == "SRSCAN": # srscan
6078 elif cmd == "STATUS": # status
6080 elif cmd == "REQUEST": # status request
6082 elif cmd == "LRSCAN": # long range scan
6083 lrscan(silent=False)
6084 elif cmd == "PHASERS": # phasers
6088 elif cmd == "TORPEDO": # photon torpedos
6092 elif cmd == "MOVE": # move under warp
6093 warp(course=None, involuntary=False)
6094 elif cmd == "SHIELDS": # shields
6095 doshield(shraise=False)
6098 game.shldchg = False
6099 elif cmd == "DOCK": # dock at starbase
6102 attack(torps_ok=False)
6103 elif cmd == "DAMAGES": # damage reports
6105 elif cmd == "CHART": # chart
6107 elif cmd == "IMPULSE": # impulse
6109 elif cmd == "REST": # rest
6113 elif cmd == "WARP": # warp
6115 elif cmd == "SCORE": # score
6117 elif cmd == "SENSORS": # sensors
6119 elif cmd == "ORBIT": # orbit
6123 elif cmd == "TRANSPORT": # transport "beam"
6125 elif cmd == "MINE": # mine
6129 elif cmd == "CRYSTALS": # crystals
6133 elif cmd == "SHUTTLE": # shuttle
6137 elif cmd == "PLANETS": # Planet list
6139 elif cmd == "REPORT": # Game Report
6141 elif cmd == "COMPUTER": # use COMPUTER!
6143 elif cmd == "COMMANDS":
6145 elif cmd == "EMEXIT": # Emergency exit
6146 clrscr() # Hide screen
6147 freeze(True) # forced save
6148 raise SysExit,1 # And quick exit
6149 elif cmd == "PROBE":
6150 probe() # Launch probe
6153 elif cmd == "ABANDON": # Abandon Ship
6155 elif cmd == "DESTRUCT": # Self Destruct
6157 elif cmd == "SAVE": # Save Game
6160 if game.skill > SKILL_GOOD:
6161 prout(_("WARNING--Saved games produce no plaques!"))
6162 elif cmd == "DEATHRAY": # Try a desparation measure
6166 elif cmd == "DEBUGCMD": # What do we want for debug???
6168 elif cmd == "MAYDAY": # Call for help
6173 game.alldone = True # quit the game
6178 break # Game has ended
6179 if game.optime != 0.0:
6182 break # Events did us in
6183 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6186 if hitme and not game.justin:
6187 attack(torps_ok=True)
6190 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6201 "Emit the name of an enemy or feature."
6202 if type == IHR: s = _("Romulan")
6203 elif type == IHK: s = _("Klingon")
6204 elif type == IHC: s = _("Commander")
6205 elif type == IHS: s = _("Super-commander")
6206 elif type == IHSTAR: s = _("Star")
6207 elif type == IHP: s = _("Planet")
6208 elif type == IHB: s = _("Starbase")
6209 elif type == IHBLANK: s = _("Black hole")
6210 elif type == IHT: s = _("Tholian")
6211 elif type == IHWEB: s = _("Tholian web")
6212 elif type == IHQUEST: s = _("Stranger")
6213 elif type == IHW: s = _("Inhabited World")
6214 else: s = "Unknown??"
6217 def crmena(stars, enemy, loctype, w):
6218 "Emit the name of an enemy and his location."
6222 buf += cramen(enemy) + _(" at ")
6223 if loctype == "quadrant":
6224 buf += _("Quadrant ")
6225 elif loctype == "sector":
6230 "Emit our ship name."
6231 return{IHE:_("Enterprise"),IHF:_("Faerie Queene")}.get(game.ship,"Ship???")
6234 "Emit a line of stars"
6235 prouts("******************************************************")
6239 return -avrage*math.log(1e-7 + randreal())
6241 def randplace(size):
6242 "Choose a random location."
6244 w.i = randrange(size)
6245 w.j = randrange(size)
6255 # Get a token from the user
6258 # Fill the token quue if nothing here
6259 while not self.inqueue:
6261 if curwnd==prompt_window:
6263 setwnd(message_window)
6270 self.inqueue = line.lstrip().split() + ["\n"]
6271 # From here on in it's all looking at the queue
6272 self.token = self.inqueue.pop(0)
6273 if self.token == "\n":
6277 self.real = float(self.token)
6278 self.type = "IHREAL"
6283 self.token = self.token.lower()
6284 self.type = "IHALPHA"
6287 def append(self, tok):
6288 self.inqueue.append(tok)
6289 def push(self, tok):
6290 self.inqueue.insert(0, tok)
6294 # Demand input for next scan
6296 self.real = self.token = None
6298 # compares s to item and returns true if it matches to the length of s
6299 return s.startswith(self.token)
6301 # Round token value to nearest integer
6302 return int(round(scanner.real))
6306 if scanner.type != "IHREAL":
6309 s.i = scanner.int()-1
6311 if scanner.type != "IHREAL":
6314 s.j = scanner.int()-1
6317 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6320 "Yes-or-no confirmation."
6324 if scanner.token == 'y':
6326 if scanner.token == 'n':
6329 proutn(_("Please answer with \"y\" or \"n\": "))
6332 "Complain about unparseable input."
6335 prout(_("Beg your pardon, Captain?"))
6338 "Access to the internals for debugging."
6339 proutn("Reset levels? ")
6341 if game.energy < game.inenrg:
6342 game.energy = game.inenrg
6343 game.shield = game.inshld
6344 game.torps = game.intorps
6345 game.lsupres = game.inlsr
6346 proutn("Reset damage? ")
6348 for i in range(NDEVICES):
6349 if game.damage[i] > 0.0:
6350 game.damage[i] = 0.0
6351 proutn("Toggle debug flag? ")
6355 prout("Debug output ON")
6357 prout("Debug output OFF")
6358 proutn("Cause selective damage? ")
6360 for i in range(NDEVICES):
6361 proutn("Kill %s?" % device[i])
6363 key = scanner.next()
6364 if key == "IHALPHA" and scanner.sees("y"):
6365 game.damage[i] = 10.0
6366 proutn("Examine/change events? ")
6371 FSNOVA: "Supernova ",
6374 FBATTAK: "Base Attack ",
6375 FCDBAS: "Base Destroy ",
6376 FSCMOVE: "SC Move ",
6377 FSCDBAS: "SC Base Destroy ",
6378 FDSPROB: "Probe Move ",
6379 FDISTR: "Distress Call ",
6380 FENSLV: "Enslavement ",
6381 FREPRO: "Klingon Build ",
6383 for i in range(1, NEVENTS):
6386 proutn("%.2f" % (scheduled(i)-game.state.date))
6387 if i == FENSLV or i == FREPRO:
6389 proutn(" in %s" % ev.quadrant)
6394 key = scanner.next()
6398 elif key == "IHREAL":
6399 ev = schedule(i, scanner.real)
6400 if i == FENSLV or i == FREPRO:
6402 proutn("In quadrant- ")
6403 key = scanner.next()
6404 # "IHEOL" says to leave coordinates as they are
6407 prout("Event %d canceled, no x coordinate." % (i))
6410 w.i = int(round(scanner.real))
6411 key = scanner.next()
6413 prout("Event %d canceled, no y coordinate." % (i))
6416 w.j = int(round(scanner.real))
6419 proutn("Induce supernova here? ")
6421 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6424 if __name__ == '__main__':
6425 import getopt, socket
6427 global line, thing, game, idebug
6433 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6434 if os.getenv("TERM"):
6435 game.options |= OPTION_CURSES
6437 game.options |= OPTION_TTY
6438 seed = int(time.time())
6439 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:tx")
6440 for (switch, val) in options:
6443 replayfp = open(val, "r")
6445 sys.stderr.write("sst: can't open replay file %s\n" % val)
6448 line = replayfp.readline().strip()
6449 (leader, key, seed) = line.split()
6451 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6452 line = replayfp.readline().strip()
6453 arguments += line.split()[2:]
6455 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6457 game.options |= OPTION_TTY
6458 game.options &=~ OPTION_CURSES
6459 elif switch == '-s':
6461 elif switch == '-t':
6462 game.options |= OPTION_TTY
6463 game.options &=~ OPTION_CURSES
6464 elif switch == '-x':
6467 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6469 # where to save the input in case of bugs
6471 logfp = open("/usr/tmp/sst-input.log", "w")
6473 sys.stderr.write("sst: warning, can't open logfile\n")
6475 logfp.write("# seed %s\n" % seed)
6476 logfp.write("# options %s\n" % " ".join(arguments))
6477 logfp.write("# recorded by %s@%s on %s\n" % \
6478 (os.getenv("LOGNAME"),socket.gethostname(),time.ctime()))
6480 scanner = sstscanner()
6481 map(scanner.append, arguments)
6484 while True: # Play a game
6485 setwnd(fullscreen_window)
6491 game.alldone = False
6497 if game.tourn and game.alldone:
6498 proutn(_("Do you want your score recorded?"))
6504 proutn(_("Do you want to play again? "))
6508 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6512 except KeyboardInterrupt: