3 sst.py -- Super Star Trek 2K
5 SST2K is a Python translation of a C translation of a FORTRAN
6 original dating back to 1973. Beautiful Python it is not, but it
7 works. Translation by Eric S. Raymond; original game by David Matuszek
8 and Paul Reynolds, with modifications by Don Smith, Tom Almy,
9 Stas Sergeev, and Eric S. Raymond.
11 See the doc/HACKING file in the distribution for designers notes and advice
12 on how to modify (and how not to modify!) this code.
14 import os, sys, math, curses, time, readline, cPickle, random, copy, gettext, getpass
18 docpath = (".", "../doc", "/usr/share/doc/sst")
21 return gettext.gettext(st)
23 GALSIZE = 8 # Galaxy size in quadrants
24 NINHAB = (GALSIZE * GALSIZE / 2) # Number of inhabited worlds
25 MAXUNINHAB = 10 # Maximum uninhabited worlds
26 QUADSIZE = 10 # Quadrant size in sectors
27 BASEMIN = 2 # Minimum starbases
28 BASEMAX = (GALSIZE * GALSIZE / 12) # Maximum starbases
29 MAXKLGAME = 127 # Maximum Klingons per game
30 MAXKLQUAD = 9 # Maximum Klingons per quadrant
31 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
32 FOREVER = 1e30 # Time for the indefinite future
33 MAXBURST = 3 # Max # of torps you can launch in one turn
34 MINCMDR = 10 # Minimum number of Klingon commanders
35 DOCKFAC = 0.25 # Repair faster when docked
36 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
56 class TrekError(Exception):
59 class JumpOut(Exception):
63 def __init__(self, x=None, y=None):
66 def valid_quadrant(self):
67 return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
68 def valid_sector(self):
69 return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
71 self.i = self.j = None
73 return self.i != None and self.j != None
74 def __eq__(self, other):
75 return other != None and self.i == other.i and self.j == other.j
76 def __ne__(self, other):
77 return other == None or self.i != other.i or self.j != other.j
78 def __add__(self, other):
79 return Coord(self.i+other.i, self.j+other.j)
80 def __sub__(self, other):
81 return Coord(self.i-other.i, self.j-other.j)
82 def __mul__(self, other):
83 return Coord(self.i*other, self.j*other)
84 def __rmul__(self, other):
85 return Coord(self.i*other, self.j*other)
86 def __div__(self, other):
87 return Coord(self.i/other, self.j/other)
88 def __mod__(self, other):
89 return Coord(self.i % other, self.j % other)
90 def __rdiv__(self, other):
91 return Coord(self.i/other, self.j/other)
92 def roundtogrid(self):
93 return Coord(int(round(self.i)), int(round(self.j)))
94 def distance(self, other=None):
97 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
99 return 1.90985*math.atan2(self.j, self.i)
105 s.i = self.i / abs(self.i)
109 s.j = self.j / abs(self.j)
112 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
113 return self.roundtogrid() / QUADSIZE
115 return self.roundtogrid() % QUADSIZE
118 s.i = self.i + randrange(-1, 2)
119 s.j = self.j + randrange(-1, 2)
122 if self.i == None or self.j == None:
124 return "%s - %s" % (self.i+1, self.j+1)
128 "Do not anger the Space Thingy!"
135 return (q.i, q.j) == (self.i, self.j)
139 self.name = None # string-valued if inhabited
140 self.quadrant = Coord() # quadrant located
141 self.pclass = None # could be ""M", "N", "O", or "destroyed"
142 self.crystals = "absent"# could be "mined", "present", "absent"
143 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
144 self.inhabited = False # is it inhabites?
152 self.starbase = False
155 self.supernova = False
157 self.status = "secure" # Could be "secure", "distressed", "enslaved"
165 def fill2d(size, fillfun):
166 "Fill an empty list in 2D."
168 for i in range(size):
170 for j in range(size):
171 lst[i].append(fillfun(i, j))
176 self.snap = False # snapshot taken
177 self.crew = 0 # crew complement
178 self.remkl = 0 # remaining klingons
179 self.nscrem = 0 # remaining super commanders
180 self.starkl = 0 # destroyed stars
181 self.basekl = 0 # destroyed bases
182 self.nromrem = 0 # Romulans remaining
183 self.nplankl = 0 # destroyed uninhabited planets
184 self.nworldkl = 0 # destroyed inhabited planets
185 self.planets = [] # Planet information
186 self.date = 0.0 # stardate
187 self.remres = 0 # remaining resources
188 self.remtime = 0 # remaining time
189 self.baseq = [] # Base quadrant coordinates
190 self.kcmdr = [] # Commander quadrant coordinates
191 self.kscmdr = Coord() # Supercommander quadrant coordinates
193 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
195 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
199 self.date = None # A real number
200 self.quadrant = None # A coord structure
203 OPTION_ALL = 0xffffffff
204 OPTION_TTY = 0x00000001 # old interface
205 OPTION_CURSES = 0x00000002 # new interface
206 OPTION_IOMODES = 0x00000003 # cover both interfaces
207 OPTION_PLANETS = 0x00000004 # planets and mining
208 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
209 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
210 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
211 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
212 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
213 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
214 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
215 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
216 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
217 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
218 OPTION_PLAIN = 0x01000000 # user chose plain game
219 OPTION_ALMY = 0x02000000 # user chose Almy variant
220 OPTION_COLOR = 0x04000000 # enable color display (experimental, ESR, 2010)
239 NDEVICES = 16 # Number of devices
249 return (game.damage[dev] != 0.0)
251 return not damaged(DRADIO) or game.condition=="docked"
253 # Define future events
254 FSPY = 0 # Spy event happens always (no future[] entry)
255 # can cause SC to tractor beam Enterprise
256 FSNOVA = 1 # Supernova
257 FTBEAM = 2 # Commander tractor beams Enterprise
258 FSNAP = 3 # Snapshot for time warp
259 FBATTAK = 4 # Commander attacks base
260 FCDBAS = 5 # Commander destroys base
261 FSCMOVE = 6 # Supercommander moves (might attack base)
262 FSCDBAS = 7 # Supercommander destroys base
263 FDSPROB = 8 # Move deep space probe
264 FDISTR = 9 # Emit distress call from an inhabited world
265 FENSLV = 10 # Inhabited word is enslaved */
266 FREPRO = 11 # Klingons build a ship in an enslaved system
269 # Abstract out the event handling -- underlying data structures will change
270 # when we implement stateful events
271 def findevent(evtype):
272 return game.future[evtype]
275 def __init__(self, etype=None, loc=None, power=None):
277 self.location = Coord()
282 self.power = power # enemy energy level
283 game.enemies.append(self)
285 motion = (loc != self.location)
286 if self.location.i is not None and self.location.j is not None:
289 game.quad[self.location.i][self.location.j] = '#'
291 game.quad[self.location.i][self.location.j] = '.'
293 self.location = copy.copy(loc)
294 game.quad[self.location.i][self.location.j] = self.type
295 self.kdist = self.kavgd = (game.sector - loc).distance()
297 self.location = Coord()
298 self.kdist = self.kavgd = None
299 game.enemies.remove(self)
302 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
306 self.options = None # Game options
307 self.state = Snapshot() # A snapshot structure
308 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
309 self.quad = None # contents of our quadrant
310 self.damage = [0.0] * NDEVICES # damage encountered
311 self.future = [] # future events
315 self.future.append(Event())
316 self.passwd = None # Self Destruct password
318 self.quadrant = None # where we are in the large
319 self.sector = None # where we are in the small
320 self.tholian = None # Tholian enemy object
321 self.base = None # position of base in current quadrant
322 self.battle = None # base coordinates being attacked
323 self.plnet = None # location of planet in quadrant
324 self.gamewon = False # Finished!
325 self.ididit = False # action taken -- allows enemy to attack
326 self.alive = False # we are alive (not killed)
327 self.justin = False # just entered quadrant
328 self.shldup = False # shields are up
329 self.shldchg = False # shield is changing (affects efficiency)
330 self.iscate = False # super commander is here
331 self.ientesc = False # attempted escape from supercommander
332 self.resting = False # rest time
333 self.icraft = False # Kirk in Galileo
334 self.landed = False # party on planet (true), on ship (false)
335 self.alldone = False # game is now finished
336 self.neutz = False # Romulan Neutral Zone
337 self.isarmed = False # probe is armed
338 self.inorbit = False # orbiting a planet
339 self.imine = False # mining
340 self.icrystl = False # dilithium crystals aboard
341 self.iseenit = False # seen base attack report
342 self.thawed = False # thawed game
343 self.condition = None # "green", "yellow", "red", "docked", "dead"
344 self.iscraft = None # "onship", "offship", "removed"
345 self.skill = None # Player skill level
346 self.inkling = 0 # initial number of klingons
347 self.inbase = 0 # initial number of bases
348 self.incom = 0 # initial number of commanders
349 self.inscom = 0 # initial number of commanders
350 self.inrom = 0 # initial number of commanders
351 self.instar = 0 # initial stars
352 self.intorps = 0 # initial/max torpedoes
353 self.torps = 0 # number of torpedoes
354 self.ship = 0 # ship type -- 'E' is Enterprise
355 self.abandoned = 0 # count of crew abandoned in space
356 self.length = 0 # length of game
357 self.klhere = 0 # klingons here
358 self.casual = 0 # causalties
359 self.nhelp = 0 # calls for help
360 self.nkinks = 0 # count of energy-barrier crossings
361 self.iplnet = None # planet # in quadrant
362 self.inplan = 0 # initial planets
363 self.irhere = 0 # Romulans in quadrant
364 self.isatb = 0 # =2 if super commander is attacking base
365 self.tourn = None # tournament number
366 self.nprobes = 0 # number of probes available
367 self.inresor = 0.0 # initial resources
368 self.intime = 0.0 # initial time
369 self.inenrg = 0.0 # initial/max energy
370 self.inshld = 0.0 # initial/max shield
371 self.inlsr = 0.0 # initial life support resources
372 self.indate = 0.0 # initial date
373 self.energy = 0.0 # energy level
374 self.shield = 0.0 # shield level
375 self.warpfac = 0.0 # warp speed
376 self.lsupres = 0.0 # life support reserves
377 self.optime = 0.0 # time taken by current operation
378 self.damfac = 0.0 # damage factor
379 self.lastchart = 0.0 # time star chart was last updated
380 self.cryprob = 0.0 # probability that crystal will work
381 self.probe = None # object holding probe course info
382 self.height = 0.0 # height of orbit around planet
383 self.score = 0.0 # overall score
384 self.perdate = 0.0 # rate of kills
385 self.idebug = False # Debugging instrumentation enabled?
386 self.statekscmdr = None # No SuperCommander coordinates yet.
388 # Stas thinks this should be (C expression):
389 # game.state.remkl + len(game.state.kcmdr) > 0 ?
390 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
391 # He says the existing expression is prone to divide-by-zero errors
392 # after killing the last klingon when score is shown -- perhaps also
393 # if the only remaining klingon is SCOM.
394 self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.state.kcmdr))
420 return random.random() < p
422 def randrange(*args):
423 return random.randrange(*args)
428 v *= args[0] # from [0, args[0])
430 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
433 # Code from ai.c begins here
436 "Would this quadrant welcome another Klingon?"
437 return iq.valid_quadrant() and \
438 not game.state.galaxy[iq.i][iq.j].supernova and \
439 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
441 def tryexit(enemy, look, irun):
442 "A bad guy attempts to bug out."
444 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
445 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
446 if not welcoming(iq):
448 if enemy.type == 'R':
449 return False # Romulans cannot escape!
451 # avoid intruding on another commander's territory
452 if enemy.type == 'C':
453 if iq in game.state.kcmdr:
455 # refuse to leave if currently attacking starbase
456 if game.battle == game.quadrant:
458 # don't leave if over 1000 units of energy
459 if enemy.power > 1000.0:
461 oldloc = copy.copy(enemy.location)
462 # handle local matters related to escape
465 if game.condition != "docked":
467 # Handle global matters related to escape
468 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
469 game.state.galaxy[iq.i][iq.j].klingons += 1
470 if enemy.type == 'S':
474 schedule(FSCMOVE, 0.2777)
476 game.state.kscmdr = iq
478 for cmdr in game.state.kcmdr:
479 if cmdr == game.quadrant:
480 game.state.kcmdr.append(iq)
482 # report move out of quadrant.
483 return [(True, enemy, oldloc, ibq)]
485 # The bad-guy movement algorithm:
487 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
488 # If both are operating full strength, force is 1000. If both are damaged,
489 # force is -1000. Having shields down subtracts an additional 1000.
491 # 2. Enemy has forces equal to the energy of the attacker plus
492 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
493 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
495 # Attacker Initial energy levels (nominal):
496 # Klingon Romulan Commander Super-Commander
497 # Novice 400 700 1200
499 # Good 450 800 1300 1750
500 # Expert 475 850 1350 1875
501 # Emeritus 500 900 1400 2000
502 # VARIANCE 75 200 200 200
504 # Enemy vessels only move prior to their attack. In Novice - Good games
505 # only commanders move. In Expert games, all enemy vessels move if there
506 # is a commander present. In Emeritus games all enemy vessels move.
508 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
509 # forces are 1000 greater than Enterprise.
511 # Agressive action on average cuts the distance between the ship and
512 # the enemy to 1/4 the original.
514 # 4. At lower energy advantage, movement units are proportional to the
515 # advantage with a 650 advantage being to hold ground, 800 to move forward
516 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
518 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
519 # retreat, especially at high skill levels.
521 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
523 def movebaddy(enemy):
524 "Tactical movement for the bad guys."
528 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
529 if game.skill >= SKILL_EXPERT:
530 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
532 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
533 old_dist = enemy.kdist
534 mdist = int(old_dist + 0.5) # Nearest integer distance
535 # If SC, check with spy to see if should hi-tail it
536 if enemy.type == 'S' and \
537 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
541 # decide whether to advance, retreat, or hold position
542 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
544 forces += 1000 # Good for enemy if shield is down!
545 if not damaged(DPHASER) or not damaged(DPHOTON):
546 if damaged(DPHASER): # phasers damaged
549 forces -= 0.2*(game.energy - 2500.0)
550 if damaged(DPHOTON): # photon torpedoes damaged
553 forces -= 50.0*game.torps
555 # phasers and photon tubes both out!
558 if forces <= 1000.0 and game.condition != "docked": # Typical situation
559 motion = ((forces + randreal(200))/150.0) - 5.0
561 if forces > 1000.0: # Very strong -- move in for kill
562 motion = (1.0 - randreal())**2 * old_dist + 1.0
563 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
564 motion -= game.skill*(2.0-randreal()**2)
566 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
567 # don't move if no motion
570 # Limit motion according to skill
571 if abs(motion) > game.skill:
576 # calculate preferred number of steps
577 nsteps = abs(int(motion))
578 if motion > 0 and nsteps > mdist:
579 nsteps = mdist # don't overshoot
580 if nsteps > QUADSIZE:
581 nsteps = QUADSIZE # This shouldn't be necessary
583 nsteps = 1 # This shouldn't be necessary
585 proutn("NSTEPS = %d:" % nsteps)
586 # Compute preferred values of delta X and Y
587 m = game.sector - enemy.location
588 if 2.0 * abs(m.i) < abs(m.j):
590 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
592 m = (motion * m).sgn()
593 goto = enemy.location
595 for ll in range(nsteps):
597 proutn(" %d" % (ll+1))
598 # Check if preferred position available
609 attempts = 0 # Settle mysterious hang problem
610 while attempts < 20 and not success:
612 if look.i < 0 or look.i >= QUADSIZE:
614 return tryexit(enemy, look, irun)
615 if krawli == m.i or m.j == 0:
617 look.i = goto.i + krawli
619 elif look.j < 0 or look.j >= QUADSIZE:
621 return tryexit(enemy, look, irun)
622 if krawlj == m.j or m.i == 0:
624 look.j = goto.j + krawlj
626 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
627 # See if enemy should ram ship
628 if game.quad[look.i][look.j] == game.ship and \
629 (enemy.type == 'C' or enemy.type == 'S'):
630 collision(rammed=True, enemy=enemy)
632 if krawli != m.i and m.j != 0:
633 look.i = goto.i + krawli
635 elif krawlj != m.j and m.i != 0:
636 look.j = goto.j + krawlj
639 break # we have failed
650 # Enemy moved, but is still in sector
651 return [(False, enemy, old_dist, goto)]
654 "Sequence Klingon tactical movement."
657 # Figure out which Klingon is the commander (or Supercommander)
660 if game.quadrant in game.state.kcmdr:
661 for enemy in game.enemies:
662 if enemy.type == 'C':
663 tacmoves += movebaddy(enemy)
664 if game.state.kscmdr == game.quadrant:
665 for enemy in game.enemies:
666 if enemy.type == 'S':
667 tacmoves += movebaddy(enemy)
669 # If skill level is high, move other Klingons and Romulans too!
670 # Move these last so they can base their actions on what the
672 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
673 for enemy in game.enemies:
674 if enemy.type in ('K', 'R'):
675 tacmoves += movebaddy(enemy)
678 def movescom(iq, avoid):
679 "Commander movement helper."
680 # Avoid quadrants with bases if we want to avoid Enterprise
681 if not welcoming(iq) or (avoid and iq in game.state.baseq):
683 if game.justin and not game.iscate:
686 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
687 game.state.kscmdr = iq
688 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
689 if game.state.kscmdr == game.quadrant:
690 # SC has scooted, remove him from current quadrant
695 for enemy in game.enemies:
696 if enemy.type == 'S':
699 if game.condition != "docked":
702 # check for a helpful planet
703 for i in range(game.inplan):
704 if game.state.planets[i].quadrant == game.state.kscmdr and \
705 game.state.planets[i].crystals == "present":
707 game.state.planets[i].pclass = "destroyed"
708 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
711 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
712 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
713 prout(_(" by the Super-commander.\""))
715 return True # looks good!
717 def supercommander():
718 "Move the Super Commander."
725 prout("== SUPERCOMMANDER")
726 # Decide on being active or passive
727 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 \
728 (game.state.date-game.indate) < 3.0)
729 if not game.iscate and avoid:
730 # compute move away from Enterprise
731 idelta = game.state.kscmdr-game.quadrant
732 if idelta.distance() > 2.0:
734 idelta.i = game.state.kscmdr.j-game.quadrant.j
735 idelta.j = game.quadrant.i-game.state.kscmdr.i
737 # compute distances to starbases
738 if not game.state.baseq:
742 sc = game.state.kscmdr
743 for (i, base) in enumerate(game.state.baseq):
744 basetbl.append((i, (base - sc).distance()))
745 if game.state.baseq > 1:
746 basetbl.sort(lambda x, y: cmp(x[1], y[1]))
747 # look for nearest base without a commander, no Enterprise, and
748 # without too many Klingons, and not already under attack.
749 ifindit = iwhichb = 0
750 for (i2, base) in enumerate(game.state.baseq):
751 i = basetbl[i2][0] # bug in original had it not finding nearest
752 if base == game.quadrant or base == game.battle or not welcoming(base):
754 # if there is a commander, and no other base is appropriate,
755 # we will take the one with the commander
756 for cmdr in game.state.kcmdr:
757 if base == cmdr and ifindit != 2:
761 else: # no commander -- use this one
766 return # Nothing suitable -- wait until next time
767 ibq = game.state.baseq[iwhichb]
768 # decide how to move toward base
769 idelta = ibq - game.state.kscmdr
770 # Maximum movement is 1 quadrant in either or both axes
771 idelta = idelta.sgn()
772 # try moving in both x and y directions
773 # there was what looked like a bug in the Almy C code here,
774 # but it might be this translation is just wrong.
775 iq = game.state.kscmdr + idelta
776 if not movescom(iq, avoid):
777 # failed -- try some other maneuvers
778 if idelta.i == 0 or idelta.j == 0:
781 iq.j = game.state.kscmdr.j + 1
782 if not movescom(iq, avoid):
783 iq.j = game.state.kscmdr.j - 1
786 iq.i = game.state.kscmdr.i + 1
787 if not movescom(iq, avoid):
788 iq.i = game.state.kscmdr.i - 1
791 # try moving just in x or y
792 iq.j = game.state.kscmdr.j
793 if not movescom(iq, avoid):
794 iq.j = game.state.kscmdr.j + idelta.j
795 iq.i = game.state.kscmdr.i
798 if len(game.state.baseq) == 0:
801 for ibq in game.state.baseq:
802 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
805 return # no, don't attack base!
808 schedule(FSCDBAS, randreal(1.0, 3.0))
809 if is_scheduled(FCDBAS):
810 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
811 if not communicating():
815 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
817 prout(_(" reports that it is under attack from the Klingon Super-commander."))
818 proutn(_(" It can survive until stardate %d.\"") \
819 % int(scheduled(FSCDBAS)))
822 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
826 game.optime = 0.0 # actually finished
828 # Check for intelligence report
829 if not game.idebug and \
831 (not communicating()) or \
832 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
835 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
836 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
841 if not game.tholian or game.justin:
844 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
847 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
850 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
853 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
857 # something is wrong!
858 game.tholian.move(None)
859 prout("***Internal error: Tholian in a bad spot.")
861 # do nothing if we are blocked
862 if game.quad[tid.i][tid.j] not in ('.', '#'):
864 here = copy.copy(game.tholian.location)
865 delta = (tid - game.tholian.location).sgn()
867 while here.i != tid.i:
869 if game.quad[here.i][here.j] == '.':
870 game.tholian.move(here)
872 while here.j != tid.j:
874 if game.quad[here.i][here.j] == '.':
875 game.tholian.move(here)
876 # check to see if all holes plugged
877 for i in range(QUADSIZE):
878 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
880 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
882 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
884 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
886 # All plugged up -- Tholian splits
887 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
889 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
890 game.tholian.move(None)
893 # Code from battle.c begins here
895 def doshield(shraise):
896 "Change shield status."
904 if scanner.sees("transfer"):
908 prout(_("Shields damaged and down."))
910 if scanner.sees("up"):
912 elif scanner.sees("down"):
915 proutn(_("Do you wish to change shield energy? "))
918 elif damaged(DSHIELD):
919 prout(_("Shields damaged and down."))
922 proutn(_("Shields are up. Do you want them down? "))
929 proutn(_("Shields are down. Do you want them up? "))
935 if action == "SHUP": # raise shields
937 prout(_("Shields already up."))
941 if game.condition != "docked":
943 prout(_("Shields raised."))
946 prout(_("Shields raising uses up last of energy."))
951 elif action == "SHDN":
953 prout(_("Shields already down."))
957 prout(_("Shields lowered."))
960 elif action == "NRG":
961 while scanner.next() != "IHREAL":
963 proutn(_("Energy to transfer to shields- "))
968 if nrg > game.energy:
969 prout(_("Insufficient ship energy."))
972 if game.shield+nrg >= game.inshld:
973 prout(_("Shield energy maximized."))
974 if game.shield+nrg > game.inshld:
975 prout(_("Excess energy requested returned to ship energy"))
976 game.energy -= game.inshld-game.shield
977 game.shield = game.inshld
979 if nrg < 0.0 and game.energy-nrg > game.inenrg:
980 # Prevent shield drain loophole
982 prout(_("Engineering to bridge--"))
983 prout(_(" Scott here. Power circuit problem, Captain."))
984 prout(_(" I can't drain the shields."))
987 if game.shield+nrg < 0:
988 prout(_("All shield energy transferred to ship."))
989 game.energy += game.shield
992 proutn(_("Scotty- \""))
994 prout(_("Transferring energy to shields.\""))
996 prout(_("Draining energy from shields.\""))
1002 "Choose a device to damage, at random."
1004 105, # DSRSENS: short range scanners 10.5%
1005 105, # DLRSENS: long range scanners 10.5%
1006 120, # DPHASER: phasers 12.0%
1007 120, # DPHOTON: photon torpedoes 12.0%
1008 25, # DLIFSUP: life support 2.5%
1009 65, # DWARPEN: warp drive 6.5%
1010 70, # DIMPULS: impulse engines 6.5%
1011 145, # DSHIELD: deflector shields 14.5%
1012 30, # DRADIO: subspace radio 3.0%
1013 45, # DSHUTTL: shuttle 4.5%
1014 15, # DCOMPTR: computer 1.5%
1015 20, # NAVCOMP: navigation system 2.0%
1016 75, # DTRANSP: transporter 7.5%
1017 20, # DSHCTRL: high-speed shield controller 2.0%
1018 10, # DDRAY: death ray 1.0%
1019 30, # DDSP: deep-space probes 3.0%
1021 assert(sum(weights) == 1000)
1022 idx = randrange(1000)
1024 for (i, w) in enumerate(weights):
1028 return None # we should never get here
1030 def collision(rammed, enemy):
1031 "Collision handling fot rammong events."
1032 prouts(_("***RED ALERT! RED ALERT!"))
1034 prout(_("***COLLISION IMMINENT."))
1038 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1040 proutn(_(" rammed by "))
1043 proutn(crmena(False, enemy.type, "sector", enemy.location))
1045 proutn(_(" (original position)"))
1047 deadkl(enemy.location, enemy.type, game.sector)
1048 proutn("***" + crmshp() + " heavily damaged.")
1049 icas = randrange(10, 30)
1050 prout(_("***Sickbay reports %d casualties") % icas)
1052 game.state.crew -= icas
1053 # In the pre-SST2K version, all devices got equiprobably damaged,
1054 # which was silly. Instead, pick up to half the devices at
1055 # random according to our weighting table,
1056 ncrits = randrange(NDEVICES/2)
1060 if game.damage[dev] < 0:
1062 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1063 # Damage for at least time of travel!
1064 game.damage[dev] += game.optime + extradm
1066 prout(_("***Shields are down."))
1067 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1074 def torpedo(origin, bearing, dispersion, number, nburst):
1075 "Let a photon torpedo fly"
1076 if not damaged(DSRSENS) or game.condition == "docked":
1077 setwnd(srscan_window)
1079 setwnd(message_window)
1080 ac = bearing + 0.25*dispersion # dispersion is a random variable
1081 bullseye = (15.0 - bearing)*0.5235988
1082 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1083 bumpto = Coord(0, 0)
1084 # Loop to move a single torpedo
1085 setwnd(message_window)
1086 for step in range(1, QUADSIZE*2):
1087 if not track.next():
1090 if not w.valid_sector():
1092 iquad = game.quad[w.i][w.j]
1093 tracktorpedo(w, step, number, nburst, iquad)
1097 setwnd(message_window)
1098 if not damaged(DSRSENS) or game.condition == "docked":
1099 skip(1) # start new line after text track
1100 if iquad in ('E', 'F'): # Hit our ship
1102 prout(_("Torpedo hits %s.") % crmshp())
1103 hit = 700.0 + randreal(100) - \
1104 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1105 newcnd() # we're blown out of dock
1106 if game.landed or game.condition == "docked":
1107 return hit # Cheat if on a planet
1108 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1109 # is 143 degrees, which is almost exactly 4.8 clockface units
1110 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1112 bumpto = displacement.sector()
1113 if not bumpto.valid_sector():
1115 if game.quad[bumpto.i][bumpto.j] == ' ':
1118 if game.quad[bumpto.i][bumpto.j] != '.':
1119 # can't move into object
1121 game.sector = bumpto
1123 game.quad[w.i][w.j] = '.'
1124 game.quad[bumpto.i][bumpto.j] = iquad
1125 prout(_(" displaced by blast to Sector %s ") % bumpto)
1126 for enemy in game.enemies:
1127 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1130 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1132 if iquad in ('C', 'S') and withprob(0.05):
1133 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1134 prout(_(" torpedo neutralized."))
1136 for enemy in game.enemies:
1137 if w == enemy.location:
1138 kp = math.fabs(enemy.power)
1139 h1 = 700.0 + randrange(100) - \
1140 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1148 if enemy.power == 0:
1151 proutn(crmena(True, iquad, "sector", w))
1152 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1154 bumpto = displacement.sector()
1155 if not bumpto.valid_sector():
1156 prout(_(" damaged but not destroyed."))
1158 if game.quad[bumpto.i][bumpto.j] == ' ':
1159 prout(_(" buffeted into black hole."))
1160 deadkl(w, iquad, bumpto)
1161 if game.quad[bumpto.i][bumpto.j] != '.':
1162 prout(_(" damaged but not destroyed."))
1164 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1165 enemy.location = bumpto
1166 game.quad[w.i][w.j] = '.'
1167 game.quad[bumpto.i][bumpto.j] = iquad
1168 for enemy in game.enemies:
1169 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1173 prout("Internal error, no enemy where expected!")
1176 elif iquad == 'B': # Hit a base
1178 prout(_("***STARBASE DESTROYED.."))
1179 game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
1180 game.quad[w.i][w.j] = '.'
1181 game.base.invalidate()
1182 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1
1183 game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1
1184 game.state.basekl += 1
1187 elif iquad == 'P': # Hit a planet
1188 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1189 game.state.nplankl += 1
1190 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1191 game.iplnet.pclass = "destroyed"
1193 game.plnet.invalidate()
1194 game.quad[w.i][w.j] = '.'
1196 # captain perishes on planet
1199 elif iquad == '@': # Hit an inhabited world -- very bad!
1200 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1201 game.state.nworldkl += 1
1202 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1203 game.iplnet.pclass = "destroyed"
1205 game.plnet.invalidate()
1206 game.quad[w.i][w.j] = '.'
1208 # captain perishes on planet
1210 prout(_("The torpedo destroyed an inhabited planet."))
1212 elif iquad == '*': # Hit a star
1216 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1218 elif iquad == '?': # Hit a thingy
1219 if not (game.options & OPTION_THINGY) or withprob(0.3):
1221 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1223 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1225 proutn(_("Mr. Spock-"))
1226 prouts(_(" \"Fascinating!\""))
1230 # Stas Sergeev added the possibility that
1231 # you can shove the Thingy and piss it off.
1232 # It then becomes an enemy and may fire at you.
1235 elif iquad == ' ': # Black hole
1237 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1239 elif iquad == '#': # hit the web
1241 prout(_("***Torpedo absorbed by Tholian web."))
1243 elif iquad == 'T': # Hit a Tholian
1244 h1 = 700.0 + randrange(100) - \
1245 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1248 game.quad[w.i][w.j] = '.'
1253 proutn(crmena(True, 'T', "sector", w))
1255 prout(_(" survives photon blast."))
1257 prout(_(" disappears."))
1258 game.tholian.move(None)
1259 game.quad[w.i][w.j] = '#'
1264 proutn("Don't know how to handle torpedo collision with ")
1265 proutn(crmena(True, iquad, "sector", w))
1270 setwnd(message_window)
1271 prout(_("Torpedo missed."))
1275 "Critical-hit resolution."
1276 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1278 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1279 proutn(_("***CRITICAL HIT--"))
1280 # Select devices and cause damage
1285 # Cheat to prevent shuttle damage unless on ship
1286 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship")):
1289 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1290 game.damage[j] += extradm
1293 for (i, j) in enumerate(cdam):
1295 if skipcount % 3 == 2 and i < len(cdam)-1:
1300 prout(_(" damaged."))
1301 if damaged(DSHIELD) and game.shldup:
1302 prout(_("***Shields knocked down."))
1305 def attack(torps_ok):
1306 # bad guy attacks us
1307 # torps_ok == False forces use of phasers in an attack
1308 # game could be over at this point, check
1318 prout("=== ATTACK!")
1319 # Tholian gets to move before attacking
1322 # if you have just entered the RNZ, you'll get a warning
1323 if game.neutz: # The one chance not to be attacked
1326 # commanders get a chance to tac-move towards you
1327 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:
1328 for (bugout, enemy, old, goto) in moveklings():
1330 # we know about this if either short or long range
1331 # sensors are working
1332 if damaged(DSRSENS) and damaged(DLRSENS) \
1333 and game.condition != "docked":
1334 prout(crmena(True, enemy.type, "sector", old) + \
1335 (_(" escapes to Quadrant %s (and regains strength).") % goto))
1336 else: # Enemy still in-sector
1337 if enemy.move(goto):
1338 if not damaged(DSRSENS) or game.condition == "docked":
1339 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
1340 if enemy.kdist < old:
1341 proutn(_(" advances to "))
1343 proutn(_(" retreats to "))
1344 prout("Sector %s." % goto)
1346 # if no enemies remain after movement, we're done
1347 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered):
1349 # set up partial hits if attack happens during shield status change
1350 pfac = 1.0/game.inshld
1352 chgfac = 0.25 + randreal(0.5)
1354 # message verbosity control
1355 if game.skill <= SKILL_FAIR:
1357 for enemy in game.enemies:
1359 continue # too weak to attack
1360 # compute hit strength and diminish shield power
1362 # Increase chance of photon torpedos if docked or enemy energy is low
1363 if game.condition == "docked":
1365 if enemy.power < 500:
1367 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1369 # different enemies have different probabilities of throwing a torp
1370 usephasers = not torps_ok or \
1371 (enemy.type == 'K' and r > 0.0005) or \
1372 (enemy.type == 'C' and r > 0.015) or \
1373 (enemy.type == 'R' and r > 0.3) or \
1374 (enemy.type == 'S' and r > 0.07) or \
1375 (enemy.type == '?' and r > 0.05)
1376 if usephasers: # Enemy uses phasers
1377 if game.condition == "docked":
1378 continue # Don't waste the effort!
1379 attempt = True # Attempt to attack
1380 dustfac = randreal(0.8, 0.85)
1381 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1383 else: # Enemy uses photon torpedo
1384 # We should be able to make the bearing() method work here
1385 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1387 proutn(_("***TORPEDO INCOMING"))
1388 if not damaged(DSRSENS):
1389 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1392 dispersion = (randreal()+randreal())*0.5 - 0.5
1393 dispersion += 0.002*enemy.power*dispersion
1394 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1395 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1396 finish(FWON) # Klingons did themselves in!
1397 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1398 return # Supernova or finished
1401 # incoming phaser or torpedo, shields may dissipate it
1402 if game.shldup or game.shldchg or game.condition == "docked":
1403 # shields will take hits
1404 propor = pfac * game.shield
1405 if game.condition == "docked":
1409 hitsh = propor*chgfac*hit+1.0
1411 if absorb > game.shield:
1412 absorb = game.shield
1413 game.shield -= absorb
1415 # taking a hit blasts us out of a starbase dock
1416 if game.condition == "docked":
1418 # but the shields may take care of it
1419 if propor > 0.1 and hit < 0.005*game.energy:
1421 # hit from this opponent got through shields, so take damage
1423 proutn(_("%d unit hit") % int(hit))
1424 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1425 proutn(_(" on the ") + crmshp())
1426 if not damaged(DSRSENS) and usephasers:
1427 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1429 # Decide if hit is critical
1435 if game.energy <= 0:
1436 # Returning home upon your shield, not with it...
1439 if not attempt and game.condition == "docked":
1440 prout(_("***Enemies decide against attacking your ship."))
1441 percent = 100.0*pfac*game.shield+0.5
1443 # Shields fully protect ship
1444 proutn(_("Enemy attack reduces shield strength to "))
1446 # Emit message if starship suffered hit(s)
1448 proutn(_("Energy left %2d shields ") % int(game.energy))
1451 elif not damaged(DSHIELD):
1454 proutn(_("damaged, "))
1455 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1456 # Check if anyone was hurt
1457 if hitmax >= 200 or hittot >= 500:
1458 icas = randrange(int(hittot * 0.015))
1461 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1462 prout(_(" in that last attack.\""))
1464 game.state.crew -= icas
1465 # After attack, reset average distance to enemies
1466 for enemy in game.enemies:
1467 enemy.kavgd = enemy.kdist
1471 def deadkl(w, etype, mv):
1472 "Kill a Klingon, Tholian, Romulan, or Thingy."
1473 # Added mv to allow enemy to "move" before dying
1474 proutn(crmena(True, etype, "sector", mv))
1475 # Decide what kind of enemy it is and update appropriately
1477 # Chalk up a Romulan
1478 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1480 game.state.nromrem -= 1
1489 # Killed some type of Klingon
1490 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1493 game.state.kcmdr.remove(game.quadrant)
1495 if game.state.kcmdr:
1496 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1497 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1500 game.state.remkl -= 1
1502 game.state.nscrem -= 1
1503 game.state.kscmdr.invalidate()
1508 # For each kind of enemy, finish message to player
1509 prout(_(" destroyed."))
1510 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1513 # Remove enemy ship from arrays describing local conditions
1514 for e in game.enemies:
1521 "Return None if target is invalid, otherwise return a course angle."
1522 if not w.valid_sector():
1526 # C code this was translated from is wacky -- why the sign reversal?
1527 delta.j = (w.j - game.sector.j)
1528 delta.i = (game.sector.i - w.i)
1529 if delta == Coord(0, 0):
1531 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1532 prout(_(" I recommend an immediate review of"))
1533 prout(_(" the Captain's psychological profile.\""))
1536 return delta.bearing()
1539 "Launch photon torpedo salvo."
1542 if damaged(DPHOTON):
1543 prout(_("Photon tubes damaged."))
1547 prout(_("No torpedoes left."))
1550 # First, get torpedo count
1553 if scanner.token == "IHALPHA":
1556 elif scanner.token == "IHEOL" or not scanner.waiting():
1557 prout(_("%d torpedoes left.") % game.torps)
1559 proutn(_("Number of torpedoes to fire- "))
1560 continue # Go back around to get a number
1561 else: # key == "IHREAL"
1563 if n <= 0: # abort command
1568 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1571 scanner.chew() # User requested more torps than available
1572 continue # Go back around
1573 break # All is good, go to next stage
1577 key = scanner.next()
1578 if i == 0 and key == "IHEOL":
1579 break # no coordinate waiting, we will try prompting
1580 if i == 1 and key == "IHEOL":
1581 # direct all torpedoes at one target
1583 target.append(target[0])
1584 tcourse.append(tcourse[0])
1587 scanner.push(scanner.token)
1588 target.append(scanner.getcoord())
1589 if target[-1] == None:
1591 tcourse.append(targetcheck(target[-1]))
1592 if tcourse[-1] == None:
1595 if len(target) == 0:
1596 # prompt for each one
1598 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1600 target.append(scanner.getcoord())
1601 if target[-1] == None:
1603 tcourse.append(targetcheck(target[-1]))
1604 if tcourse[-1] == None:
1607 # Loop for moving <n> torpedoes
1609 if game.condition != "docked":
1611 dispersion = (randreal()+randreal())*0.5 -0.5
1612 if math.fabs(dispersion) >= 0.47:
1614 dispersion *= randreal(1.2, 2.2)
1616 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1618 prouts(_("***TORPEDO MISFIRES."))
1621 prout(_(" Remainder of burst aborted."))
1623 prout(_("***Photon tubes damaged by misfire."))
1624 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1626 if game.shldup or game.condition == "docked":
1627 dispersion *= 1.0 + 0.0001*game.shield
1628 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1629 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1631 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1635 "Check for phasers overheating."
1637 checkburn = (rpow-1500.0)*0.00038
1638 if withprob(checkburn):
1639 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1640 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1642 def checkshctrl(rpow):
1643 "Check shield control."
1646 prout(_("Shields lowered."))
1648 # Something bad has happened
1649 prouts(_("***RED ALERT! RED ALERT!"))
1651 hit = rpow*game.shield/game.inshld
1652 game.energy -= rpow+hit*0.8
1653 game.shield -= hit*0.2
1654 if game.energy <= 0.0:
1655 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1660 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1662 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1663 icas = randrange(int(hit*0.012))
1668 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1669 prout(_(" %d casualties so far.\"") % icas)
1671 game.state.crew -= icas
1673 prout(_("Phaser energy dispersed by shields."))
1674 prout(_("Enemy unaffected."))
1679 "Register a phaser hit on Klingons and Romulans."
1686 dustfac = randreal(0.9, 1.0)
1687 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1688 kpini = game.enemies[kk].power
1689 kp = math.fabs(kpini)
1690 if PHASEFAC*hit < kp:
1692 if game.enemies[kk].power < 0:
1693 game.enemies[kk].power -= -kp
1695 game.enemies[kk].power -= kp
1696 kpow = game.enemies[kk].power
1697 w = game.enemies[kk].location
1699 if not damaged(DSRSENS):
1701 proutn(_("%d unit hit on ") % int(hit))
1703 proutn(_("Very small hit on "))
1704 ienm = game.quad[w.i][w.j]
1707 proutn(crmena(False, ienm, "sector", w))
1711 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1715 kk -= 1 # don't do the increment
1717 else: # decide whether or not to emasculate klingon
1718 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1719 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1720 prout(_(" has just lost its firepower.\""))
1721 game.enemies[kk].power = -kpow
1726 "Fire phasers at bad guys."
1730 irec = 0 # Cheating inhibitor
1739 # SR sensors and Computer are needed for automode
1740 if damaged(DSRSENS) or damaged(DCOMPTR):
1742 if game.condition == "docked":
1743 prout(_("Phasers can't be fired through base shields."))
1746 if damaged(DPHASER):
1747 prout(_("Phaser control damaged."))
1751 if damaged(DSHCTRL):
1752 prout(_("High speed shield control damaged."))
1755 if game.energy <= 200.0:
1756 prout(_("Insufficient energy to activate high-speed shield control."))
1759 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1761 # Original code so convoluted, I re-did it all
1762 # (That was Tom Almy talking about the C code, I think -- ESR)
1763 while automode == "NOTSET":
1764 key = scanner.next()
1765 if key == "IHALPHA":
1766 if scanner.sees("manual"):
1767 if len(game.enemies)==0:
1768 prout(_("There is no enemy present to select."))
1771 automode = "AUTOMATIC"
1774 key = scanner.next()
1775 elif scanner.sees("automatic"):
1776 if (not itarg) and len(game.enemies) != 0:
1777 automode = "FORCEMAN"
1779 if len(game.enemies)==0:
1780 prout(_("Energy will be expended into space."))
1781 automode = "AUTOMATIC"
1782 key = scanner.next()
1783 elif scanner.sees("no"):
1788 elif key == "IHREAL":
1789 if len(game.enemies)==0:
1790 prout(_("Energy will be expended into space."))
1791 automode = "AUTOMATIC"
1793 automode = "FORCEMAN"
1795 automode = "AUTOMATIC"
1798 if len(game.enemies)==0:
1799 prout(_("Energy will be expended into space."))
1800 automode = "AUTOMATIC"
1802 automode = "FORCEMAN"
1804 proutn(_("Manual or automatic? "))
1809 if automode == "AUTOMATIC":
1810 if key == "IHALPHA" and scanner.sees("no"):
1812 key = scanner.next()
1813 if key != "IHREAL" and len(game.enemies) != 0:
1814 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1819 for i in range(len(game.enemies)):
1820 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1822 proutn(_("%d units required. ") % irec)
1824 proutn(_("Units to fire= "))
1825 key = scanner.next()
1830 proutn(_("Energy available= %.2f") % avail)
1833 if not rpow > avail:
1839 key = scanner.next()
1840 if key == "IHALPHA" and scanner.sees("no"):
1843 game.energy -= 200 # Go and do it!
1844 if checkshctrl(rpow):
1849 if len(game.enemies):
1852 for i in range(len(game.enemies)):
1856 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1857 over = randreal(1.01, 1.06) * hits[i]
1859 powrem -= hits[i] + over
1860 if powrem <= 0 and temp < hits[i]:
1869 if extra > 0 and not game.alldone:
1871 proutn(_("*** Tholian web absorbs "))
1872 if len(game.enemies)>0:
1873 proutn(_("excess "))
1874 prout(_("phaser energy."))
1876 prout(_("%d expended on empty space.") % int(extra))
1877 elif automode == "FORCEMAN":
1880 if damaged(DCOMPTR):
1881 prout(_("Battle computer damaged, manual fire only."))
1884 prouts(_("---WORKING---"))
1886 prout(_("Short-range-sensors-damaged"))
1887 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1888 prout(_("Manual-fire-must-be-used"))
1890 elif automode == "MANUAL":
1892 for k in range(len(game.enemies)):
1893 aim = game.enemies[k].location
1894 ienm = game.quad[aim.i][aim.j]
1896 proutn(_("Energy available= %.2f") % (avail-0.006))
1900 if damaged(DSRSENS) and \
1901 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1902 prout(cramen(ienm) + _(" can't be located without short range scan."))
1905 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
1910 if itarg and k > kz:
1911 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1914 if not damaged(DCOMPTR):
1919 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1920 key = scanner.next()
1921 if key == "IHALPHA" and scanner.sees("no"):
1923 key = scanner.next()
1925 if key == "IHALPHA":
1929 if k == 1: # Let me say I'm baffled by this
1932 if scanner.real < 0:
1936 hits[k] = scanner.real
1937 rpow += scanner.real
1938 # If total requested is too much, inform and start over
1940 prout(_("Available energy exceeded -- try again."))
1943 key = scanner.next() # scan for next value
1946 # zero energy -- abort
1949 if key == "IHALPHA" and scanner.sees("no"):
1954 game.energy -= 200.0
1955 if checkshctrl(rpow):
1959 # Say shield raised or malfunction, if necessary
1966 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1967 prouts(_(" CLICK CLICK POP . . ."))
1968 prout(_(" No response, sir!"))
1971 prout(_("Shields raised."))
1976 # Code from events,c begins here.
1978 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1979 # event of each type active at any given time. Mostly these means we can
1980 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1981 # BSD Trek, from which we swiped the idea, can have up to 5.
1983 def unschedule(evtype):
1984 "Remove an event from the schedule."
1985 game.future[evtype].date = FOREVER
1986 return game.future[evtype]
1988 def is_scheduled(evtype):
1989 "Is an event of specified type scheduled."
1990 return game.future[evtype].date != FOREVER
1992 def scheduled(evtype):
1993 "When will this event happen?"
1994 return game.future[evtype].date
1996 def schedule(evtype, offset):
1997 "Schedule an event of specified type."
1998 game.future[evtype].date = game.state.date + offset
1999 return game.future[evtype]
2001 def postpone(evtype, offset):
2002 "Postpone a scheduled event."
2003 game.future[evtype].date += offset
2006 "Rest period is interrupted by event."
2009 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2011 game.resting = False
2017 "Run through the event queue looking for things to do."
2019 fintim = game.state.date + game.optime
2028 def tractorbeam(yank):
2029 "Tractor-beaming cases merge here."
2031 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2033 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2034 # If Kirk & Co. screwing around on planet, handle
2035 atover(True) # atover(true) is Grab
2038 if game.icraft: # Caught in Galileo?
2041 # Check to see if shuttle is aboard
2042 if game.iscraft == "offship":
2045 prout(_("Galileo, left on the planet surface, is captured"))
2046 prout(_("by aliens and made into a flying McDonald's."))
2047 game.damage[DSHUTTL] = -10
2048 game.iscraft = "removed"
2050 prout(_("Galileo, left on the planet surface, is well hidden."))
2052 game.quadrant = game.state.kscmdr
2054 game.quadrant = game.state.kcmdr[i]
2055 game.sector = randplace(QUADSIZE)
2056 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2057 % (game.quadrant, game.sector))
2059 prout(_("(Remainder of rest/repair period cancelled.)"))
2060 game.resting = False
2062 if not damaged(DSHIELD) and game.shield > 0:
2063 doshield(shraise=True) # raise shields
2064 game.shldchg = False
2066 prout(_("(Shields not currently useable.)"))
2068 # Adjust finish time to time of tractor beaming?
2069 # fintim = game.state.date+game.optime
2070 attack(torps_ok=False)
2071 if not game.state.kcmdr:
2074 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2077 "Code merges here for any commander destroying a starbase."
2078 # Not perfect, but will have to do
2079 # Handle case where base is in same quadrant as starship
2080 if game.battle == game.quadrant:
2081 game.state.chart[game.battle.i][game.battle.j].starbase = False
2082 game.quad[game.base.i][game.base.j] = '.'
2083 game.base.invalidate()
2086 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2087 elif game.state.baseq and communicating():
2088 # Get word via subspace radio
2091 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2092 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2094 prout(_("the Klingon Super-Commander"))
2096 prout(_("a Klingon Commander"))
2097 game.state.chart[game.battle.i][game.battle.j].starbase = False
2098 # Remove Starbase from galaxy
2099 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2100 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2102 # reinstate a commander's base attack
2106 game.battle.invalidate()
2108 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2109 for i in range(1, NEVENTS):
2110 if i == FSNOVA: proutn("=== Supernova ")
2111 elif i == FTBEAM: proutn("=== T Beam ")
2112 elif i == FSNAP: proutn("=== Snapshot ")
2113 elif i == FBATTAK: proutn("=== Base Attack ")
2114 elif i == FCDBAS: proutn("=== Base Destroy ")
2115 elif i == FSCMOVE: proutn("=== SC Move ")
2116 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2117 elif i == FDSPROB: proutn("=== Probe Move ")
2118 elif i == FDISTR: proutn("=== Distress Call ")
2119 elif i == FENSLV: proutn("=== Enslavement ")
2120 elif i == FREPRO: proutn("=== Klingon Build ")
2122 prout("%.2f" % (scheduled(i)))
2125 radio_was_broken = damaged(DRADIO)
2128 # Select earliest extraneous event, evcode==0 if no events
2133 for l in range(1, NEVENTS):
2134 if game.future[l].date < datemin:
2137 prout("== Event %d fires" % evcode)
2138 datemin = game.future[l].date
2139 xtime = datemin-game.state.date
2140 game.state.date = datemin
2141 # Decrement Federation resources and recompute remaining time
2142 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2144 if game.state.remtime <= 0:
2147 # Any crew left alive?
2148 if game.state.crew <= 0:
2151 # Is life support adequate?
2152 if damaged(DLIFSUP) and game.condition != "docked":
2153 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2156 game.lsupres -= xtime
2157 if game.damage[DLIFSUP] <= xtime:
2158 game.lsupres = game.inlsr
2161 if game.condition == "docked":
2163 # Don't fix Deathray here
2164 for l in range(NDEVICES):
2165 if game.damage[l] > 0.0 and l != DDRAY:
2166 if game.damage[l]-repair > 0.0:
2167 game.damage[l] -= repair
2169 game.damage[l] = 0.0
2170 # If radio repaired, update star chart and attack reports
2171 if radio_was_broken and not damaged(DRADIO):
2172 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2173 prout(_(" surveillance reports are coming in."))
2175 if not game.iseenit:
2179 prout(_(" The star chart is now up to date.\""))
2181 # Cause extraneous event EVCODE to occur
2182 game.optime -= xtime
2183 if evcode == FSNOVA: # Supernova
2186 schedule(FSNOVA, expran(0.5*game.intime))
2187 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2189 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2190 if game.state.nscrem == 0 or \
2191 ictbeam or istract or \
2192 game.condition == "docked" or game.isatb == 1 or game.iscate:
2194 if game.ientesc or \
2195 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2196 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2197 (damaged(DSHIELD) and \
2198 (game.energy < 2500 or damaged(DPHASER)) and \
2199 (game.torps < 5 or damaged(DPHOTON))):
2201 istract = ictbeam = True
2202 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2205 elif evcode == FTBEAM: # Tractor beam
2206 if not game.state.kcmdr:
2209 i = randrange(len(game.state.kcmdr))
2210 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2211 if istract or game.condition == "docked" or yank == 0:
2212 # Drats! Have to reschedule
2214 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2218 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2219 game.snapsht = copy.deepcopy(game.state)
2220 game.state.snap = True
2221 schedule(FSNAP, expran(0.5 * game.intime))
2222 elif evcode == FBATTAK: # Commander attacks starbase
2223 if not game.state.kcmdr or not game.state.baseq:
2229 for ibq in game.state.baseq:
2230 for cmdr in game.state.kcmdr:
2231 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2234 # no match found -- try later
2235 schedule(FBATTAK, expran(0.3*game.intime))
2240 # commander + starbase combination found -- launch attack
2242 schedule(FCDBAS, randreal(1.0, 4.0))
2243 if game.isatb: # extra time if SC already attacking
2244 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2245 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2246 game.iseenit = False
2247 if not communicating():
2248 continue # No warning :-(
2252 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2253 prout(_(" reports that it is under attack and that it can"))
2254 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2257 elif evcode == FSCDBAS: # Supercommander destroys base
2260 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2261 continue # WAS RETURN!
2263 game.battle = game.state.kscmdr
2265 elif evcode == FCDBAS: # Commander succeeds in destroying base
2266 if evcode == FCDBAS:
2268 if not game.state.baseq() \
2269 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2270 game.battle.invalidate()
2272 # find the lucky pair
2273 for cmdr in game.state.kcmdr:
2274 if cmdr == game.battle:
2277 # No action to take after all
2280 elif evcode == FSCMOVE: # Supercommander moves
2281 schedule(FSCMOVE, 0.2777)
2282 if not game.ientesc and not istract and game.isatb != 1 and \
2283 (not game.iscate or not game.justin):
2285 elif evcode == FDSPROB: # Move deep space probe
2286 schedule(FDSPROB, 0.01)
2287 if not game.probe.next():
2288 if not game.probe.quadrant().valid_quadrant() or \
2289 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2290 # Left galaxy or ran into supernova
2294 proutn(_("Lt. Uhura- \"The deep space probe "))
2295 if not game.probe.quadrant().valid_quadrant():
2296 prout(_("has left the galaxy.\""))
2298 prout(_("is no longer transmitting.\""))
2304 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2305 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2307 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2308 chp.klingons = pdest.klingons
2309 chp.starbase = pdest.starbase
2310 chp.stars = pdest.stars
2311 pdest.charted = True
2312 game.probe.moves -= 1 # One less to travel
2313 if game.probe.arrived() and game.isarmed and pdest.stars:
2314 supernova(game.probe) # fire in the hole!
2316 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2318 elif evcode == FDISTR: # inhabited system issues distress call
2320 # try a whole bunch of times to find something suitable
2321 for i in range(100):
2322 # need a quadrant which is not the current one,
2323 # which has some stars which are inhabited and
2324 # not already under attack, which is not
2325 # supernova'ed, and which has some Klingons in it
2326 w = randplace(GALSIZE)
2327 q = game.state.galaxy[w.i][w.j]
2328 if not (game.quadrant == w or q.planet == None or \
2329 not q.planet.inhabited or \
2330 q.supernova or q.status!="secure" or q.klingons<=0):
2333 # can't seem to find one; ignore this call
2335 prout("=== Couldn't find location for distress event.")
2337 # got one!! Schedule its enslavement
2338 ev = schedule(FENSLV, expran(game.intime))
2340 q.status = "distressed"
2341 # tell the captain about it if we can
2343 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2344 % (q.planet, repr(w)))
2345 prout(_("by a Klingon invasion fleet."))
2348 elif evcode == FENSLV: # starsystem is enslaved
2349 ev = unschedule(FENSLV)
2350 # see if current distress call still active
2351 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2355 q.status = "enslaved"
2357 # play stork and schedule the first baby
2358 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2359 ev2.quadrant = ev.quadrant
2361 # report the disaster if we can
2363 prout(_("Uhura- We've lost contact with starsystem %s") % \
2365 prout(_("in Quadrant %s.\n") % ev.quadrant)
2366 elif evcode == FREPRO: # Klingon reproduces
2367 # If we ever switch to a real event queue, we'll need to
2368 # explicitly retrieve and restore the x and y.
2369 ev = schedule(FREPRO, expran(1.0 * game.intime))
2370 # see if current distress call still active
2371 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2375 if game.state.remkl >= MAXKLGAME:
2376 continue # full right now
2377 # reproduce one Klingon
2380 if game.klhere >= MAXKLQUAD:
2382 # this quadrant not ok, pick an adjacent one
2383 for m.i in range(w.i - 1, w.i + 2):
2384 for m.j in range(w.j - 1, w.j + 2):
2385 if not m.valid_quadrant():
2387 q = game.state.galaxy[m.i][m.j]
2388 # check for this quad ok (not full & no snova)
2389 if q.klingons >= MAXKLQUAD or q.supernova:
2393 continue # search for eligible quadrant failed
2397 game.state.remkl += 1
2399 if game.quadrant == w:
2401 game.enemies.append(newkling())
2402 # recompute time left
2405 if game.quadrant == w:
2406 prout(_("Spock- sensors indicate the Klingons have"))
2407 prout(_("launched a warship from %s.") % q.planet)
2409 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2410 if q.planet != None:
2411 proutn(_("near %s ") % q.planet)
2412 prout(_("in Quadrant %s.") % w)
2418 key = scanner.next()
2421 proutn(_("How long? "))
2426 origTime = delay = scanner.real
2429 if delay >= game.state.remtime or len(game.enemies) != 0:
2430 proutn(_("Are you sure? "))
2433 # Alternate resting periods (events) with attacks
2437 game.resting = False
2438 if not game.resting:
2439 prout(_("%d stardates left.") % int(game.state.remtime))
2441 temp = game.optime = delay
2442 if len(game.enemies):
2443 rtime = randreal(1.0, 2.0)
2447 if game.optime < delay:
2448 attack(torps_ok=False)
2456 # Repair Deathray if long rest at starbase
2457 if origTime-delay >= 9.99 and game.condition == "docked":
2458 game.damage[DDRAY] = 0.0
2459 # leave if quadrant supernovas
2460 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2462 game.resting = False
2467 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2468 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2470 # Wow! We've supernova'ed
2471 supernova(game.quadrant)
2473 # handle initial nova
2474 game.quad[nov.i][nov.j] = '.'
2475 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2476 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2477 game.state.starkl += 1
2478 # Set up queue to recursively trigger adjacent stars
2484 for offset.i in range(-1, 1+1):
2485 for offset.j in range(-1, 1+1):
2486 if offset.j == 0 and offset.i == 0:
2488 neighbor = start + offset
2489 if not neighbor.valid_sector():
2491 iquad = game.quad[neighbor.i][neighbor.j]
2492 # Empty space ends reaction
2493 if iquad in ('.', '?', ' ', 'T', '#'):
2495 elif iquad == '*': # Affect another star
2497 # This star supernovas
2498 supernova(game.quadrant)
2501 hits.append(neighbor)
2502 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2503 game.state.starkl += 1
2504 proutn(crmena(True, '*', "sector", neighbor))
2506 game.quad[neighbor.i][neighbor.j] = '.'
2508 elif iquad in ('P', '@'): # Destroy planet
2509 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2511 game.state.nplankl += 1
2513 game.state.nworldkl += 1
2514 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2515 game.iplnet.pclass = "destroyed"
2517 game.plnet.invalidate()
2521 game.quad[neighbor.i][neighbor.j] = '.'
2522 elif iquad == 'B': # Destroy base
2523 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2524 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2525 game.base.invalidate()
2526 game.state.basekl += 1
2528 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2529 game.quad[neighbor.i][neighbor.j] = '.'
2530 elif iquad in ('E', 'F'): # Buffet ship
2531 prout(_("***Starship buffeted by nova."))
2533 if game.shield >= 2000.0:
2534 game.shield -= 2000.0
2536 diff = 2000.0 - game.shield
2540 prout(_("***Shields knocked out."))
2541 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2543 game.energy -= 2000.0
2544 if game.energy <= 0:
2547 # add in course nova contributes to kicking starship
2548 bump += (game.sector-hits[-1]).sgn()
2549 elif iquad == 'K': # kill klingon
2550 deadkl(neighbor, iquad, neighbor)
2551 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2552 for ll in range(len(game.enemies)):
2553 if game.enemies[ll].location == neighbor:
2555 game.enemies[ll].power -= 800.0 # If firepower is lost, die
2556 if game.enemies[ll].power <= 0.0:
2557 deadkl(neighbor, iquad, neighbor)
2559 newc = neighbor + neighbor - hits[-1]
2560 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2561 if not newc.valid_sector():
2562 # can't leave quadrant
2565 iquad1 = game.quad[newc.i][newc.j]
2567 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2569 deadkl(neighbor, iquad, newc)
2572 # can't move into something else
2575 proutn(_(", buffeted to Sector %s") % newc)
2576 game.quad[neighbor.i][neighbor.j] = '.'
2577 game.quad[newc.i][newc.j] = iquad
2578 game.enemies[ll].move(newc)
2579 # Starship affected by nova -- kick it away.
2581 direc = ncourse[3*(bump.i+1)+bump.j+2]
2586 scourse = course(bearing=direc, distance=dist)
2587 game.optime = scourse.time(warp=4)
2589 prout(_("Force of nova displaces starship."))
2590 imove(scourse, noattack=True)
2591 game.optime = scourse.time(warp=4)
2595 "Star goes supernova."
2600 # Scheduled supernova -- select star at random.
2603 for nq.i in range(GALSIZE):
2604 for nq.j in range(GALSIZE):
2605 stars += game.state.galaxy[nq.i][nq.j].stars
2607 return # nothing to supernova exists
2608 num = randrange(stars) + 1
2609 for nq.i in range(GALSIZE):
2610 for nq.j in range(GALSIZE):
2611 num -= game.state.galaxy[nq.i][nq.j].stars
2617 proutn("=== Super nova here?")
2620 if not nq == game.quadrant or game.justin:
2621 # it isn't here, or we just entered (treat as enroute)
2624 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2625 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2628 # we are in the quadrant!
2629 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2630 for ns.i in range(QUADSIZE):
2631 for ns.j in range(QUADSIZE):
2632 if game.quad[ns.i][ns.j]=='*':
2639 prouts(_("***RED ALERT! RED ALERT!"))
2641 prout(_("***Incipient supernova detected at Sector %s") % ns)
2642 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2643 proutn(_("Emergency override attempts t"))
2644 prouts("***************")
2648 # destroy any Klingons in supernovaed quadrant
2649 kldead = game.state.galaxy[nq.i][nq.j].klingons
2650 game.state.galaxy[nq.i][nq.j].klingons = 0
2651 if nq == game.state.kscmdr:
2652 # did in the Supercommander!
2653 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2657 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2658 comkills = len(game.state.kcmdr) - len(survivors)
2659 game.state.kcmdr = survivors
2661 if not game.state.kcmdr:
2663 game.state.remkl -= kldead
2664 # destroy Romulans and planets in supernovaed quadrant
2665 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2666 game.state.galaxy[nq.i][nq.j].romulans = 0
2667 game.state.nromrem -= nrmdead
2669 for loop in range(game.inplan):
2670 if game.state.planets[loop].quadrant == nq:
2671 game.state.planets[loop].pclass = "destroyed"
2673 # Destroy any base in supernovaed quadrant
2674 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2675 # If starship caused supernova, tally up destruction
2677 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2678 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2679 game.state.nplankl += npdead
2680 # mark supernova in galaxy and in star chart
2681 if game.quadrant == nq or communicating():
2682 game.state.galaxy[nq.i][nq.j].supernova = True
2683 # If supernova destroys last Klingons give special message
2684 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2687 prout(_("Lucky you!"))
2688 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2691 # if some Klingons remain, continue or die in supernova
2696 # Code from finish.c ends here.
2699 "Self-destruct maneuver. Finish with a BANG!"
2701 if damaged(DCOMPTR):
2702 prout(_("Computer damaged; cannot execute destruct sequence."))
2704 prouts(_("---WORKING---")); skip(1)
2705 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2706 prouts(" 10"); skip(1)
2707 prouts(" 9"); skip(1)
2708 prouts(" 8"); skip(1)
2709 prouts(" 7"); skip(1)
2710 prouts(" 6"); skip(1)
2712 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2714 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2716 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2719 if game.passwd != scanner.token:
2720 prouts(_("PASSWORD-REJECTED;"))
2722 prouts(_("CONTINUITY-EFFECTED"))
2725 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2726 prouts(" 5"); skip(1)
2727 prouts(" 4"); skip(1)
2728 prouts(" 3"); skip(1)
2729 prouts(" 2"); skip(1)
2730 prouts(" 1"); skip(1)
2732 prouts(_("GOODBYE-CRUEL-WORLD"))
2740 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2744 if len(game.enemies) != 0:
2745 whammo = 25.0 * game.energy
2746 for l in range(len(game.enemies)):
2747 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2748 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2752 "Compute our rate of kils over time."
2753 elapsed = game.state.date - game.indate
2754 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2757 starting = (game.inkling + game.incom + game.inscom)
2758 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2759 return (starting - remaining)/elapsed
2763 badpt = 5.0*game.state.starkl + \
2765 10.0*game.state.nplankl + \
2766 300*game.state.nworldkl + \
2768 100.0*game.state.basekl +\
2770 if game.ship == 'F':
2772 elif game.ship == None:
2777 # end the game, with appropriate notfications
2781 prout(_("It is stardate %.1f.") % game.state.date)
2783 if ifin == FWON: # Game has been won
2784 if game.state.nromrem != 0:
2785 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2788 prout(_("You have smashed the Klingon invasion fleet and saved"))
2789 prout(_("the Federation."))
2794 badpt = 0.0 # Close enough!
2795 # killsPerDate >= RateMax
2796 if game.state.date-game.indate < 5.0 or \
2797 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2799 prout(_("In fact, you have done so well that Starfleet Command"))
2800 if game.skill == SKILL_NOVICE:
2801 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2802 elif game.skill == SKILL_FAIR:
2803 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2804 elif game.skill == SKILL_GOOD:
2805 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2806 elif game.skill == SKILL_EXPERT:
2807 prout(_("promotes you to Commodore Emeritus."))
2809 prout(_("Now that you think you're really good, try playing"))
2810 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2811 elif game.skill == SKILL_EMERITUS:
2813 proutn(_("Computer- "))
2814 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2816 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2818 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2820 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2822 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2824 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2826 prout(_("Now you can retire and write your own Star Trek game!"))
2828 elif game.skill >= SKILL_EXPERT:
2829 if game.thawed and not game.idebug:
2830 prout(_("You cannot get a citation, so..."))
2832 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2836 # Only grant long life if alive (original didn't!)
2838 prout(_("LIVE LONG AND PROSPER."))
2843 elif ifin == FDEPLETE: # Federation Resources Depleted
2844 prout(_("Your time has run out and the Federation has been"))
2845 prout(_("conquered. Your starship is now Klingon property,"))
2846 prout(_("and you are put on trial as a war criminal. On the"))
2847 proutn(_("basis of your record, you are "))
2848 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2849 prout(_("acquitted."))
2851 prout(_("LIVE LONG AND PROSPER."))
2853 prout(_("found guilty and"))
2854 prout(_("sentenced to death by slow torture."))
2858 elif ifin == FLIFESUP:
2859 prout(_("Your life support reserves have run out, and"))
2860 prout(_("you die of thirst, starvation, and asphyxiation."))
2861 prout(_("Your starship is a derelict in space."))
2863 prout(_("Your energy supply is exhausted."))
2865 prout(_("Your starship is a derelict in space."))
2866 elif ifin == FBATTLE:
2867 prout(_("The %s has been destroyed in battle.") % crmshp())
2869 prout(_("Dulce et decorum est pro patria mori."))
2871 prout(_("You have made three attempts to cross the negative energy"))
2872 prout(_("barrier which surrounds the galaxy."))
2874 prout(_("Your navigation is abominable."))
2877 prout(_("Your starship has been destroyed by a nova."))
2878 prout(_("That was a great shot."))
2880 elif ifin == FSNOVAED:
2881 prout(_("The %s has been fried by a supernova.") % crmshp())
2882 prout(_("...Not even cinders remain..."))
2883 elif ifin == FABANDN:
2884 prout(_("You have been captured by the Klingons. If you still"))
2885 prout(_("had a starbase to be returned to, you would have been"))
2886 prout(_("repatriated and given another chance. Since you have"))
2887 prout(_("no starbases, you will be mercilessly tortured to death."))
2888 elif ifin == FDILITHIUM:
2889 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2890 elif ifin == FMATERIALIZE:
2891 prout(_("Starbase was unable to re-materialize your starship."))
2892 prout(_("Sic transit gloria mundi"))
2893 elif ifin == FPHASER:
2894 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2896 prout(_("You and your landing party have been"))
2897 prout(_("converted to energy, disipating through space."))
2898 elif ifin == FMINING:
2899 prout(_("You are left with your landing party on"))
2900 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2902 prout(_("They are very fond of \"Captain Kirk\" soup."))
2904 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2905 elif ifin == FDPLANET:
2906 prout(_("You and your mining party perish."))
2908 prout(_("That was a great shot."))
2911 prout(_("The Galileo is instantly annihilated by the supernova."))
2912 prout(_("You and your mining party are atomized."))
2914 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2915 prout(_("joins the Romulans, wreaking terror on the Federation."))
2916 elif ifin == FPNOVA:
2917 prout(_("You and your mining party are atomized."))
2919 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2920 prout(_("joins the Romulans, wreaking terror on the Federation."))
2921 elif ifin == FSTRACTOR:
2922 prout(_("The shuttle craft Galileo is also caught,"))
2923 prout(_("and breaks up under the strain."))
2925 prout(_("Your debris is scattered for millions of miles."))
2926 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2928 prout(_("The mutants attack and kill Spock."))
2929 prout(_("Your ship is captured by Klingons, and"))
2930 prout(_("your crew is put on display in a Klingon zoo."))
2931 elif ifin == FTRIBBLE:
2932 prout(_("Tribbles consume all remaining water,"))
2933 prout(_("food, and oxygen on your ship."))
2935 prout(_("You die of thirst, starvation, and asphyxiation."))
2936 prout(_("Your starship is a derelict in space."))
2938 prout(_("Your ship is drawn to the center of the black hole."))
2939 prout(_("You are crushed into extremely dense matter."))
2941 prout(_("Your last crew member has died."))
2942 if game.ship == 'F':
2944 elif game.ship == 'E':
2947 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2948 goodies = game.state.remres/game.inresor
2949 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2950 if goodies/baddies >= randreal(1.0, 1.5):
2951 prout(_("As a result of your actions, a treaty with the Klingon"))
2952 prout(_("Empire has been signed. The terms of the treaty are"))
2953 if goodies/baddies >= randreal(3.0):
2954 prout(_("favorable to the Federation."))
2956 prout(_("Congratulations!"))
2958 prout(_("highly unfavorable to the Federation."))
2960 prout(_("The Federation will be destroyed."))
2962 prout(_("Since you took the last Klingon with you, you are a"))
2963 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2964 prout(_("statue in your memory. Rest in peace, and try not"))
2965 prout(_("to think about pigeons."))
2970 "Compute player's score."
2971 timused = game.state.date - game.indate
2972 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2974 game.perdate = killrate()
2975 ithperd = 500*game.perdate + 0.5
2978 iwon = 100*game.skill
2979 if game.ship == 'E':
2981 elif game.ship == 'F':
2985 game.score = 10*(game.inkling - game.state.remkl) \
2986 + 50*(game.incom - len(game.state.kcmdr)) \
2988 + 20*(game.inrom - game.state.nromrem) \
2989 + 200*(game.inscom - game.state.nscrem) \
2990 - game.state.nromrem \
2995 prout(_("Your score --"))
2996 if game.inrom - game.state.nromrem:
2997 prout(_("%6d Romulans destroyed %5d") %
2998 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
2999 if game.state.nromrem and game.gamewon:
3000 prout(_("%6d Romulans captured %5d") %
3001 (game.state.nromrem, game.state.nromrem))
3002 if game.inkling - game.state.remkl:
3003 prout(_("%6d ordinary Klingons destroyed %5d") %
3004 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
3005 if game.incom - len(game.state.kcmdr):
3006 prout(_("%6d Klingon commanders destroyed %5d") %
3007 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3008 if game.inscom - game.state.nscrem:
3009 prout(_("%6d Super-Commander destroyed %5d") %
3010 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3012 prout(_("%6.2f Klingons per stardate %5d") %
3013 (game.perdate, ithperd))
3014 if game.state.starkl:
3015 prout(_("%6d stars destroyed by your action %5d") %
3016 (game.state.starkl, -5*game.state.starkl))
3017 if game.state.nplankl:
3018 prout(_("%6d planets destroyed by your action %5d") %
3019 (game.state.nplankl, -10*game.state.nplankl))
3020 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3021 prout(_("%6d inhabited planets destroyed by your action %5d") %
3022 (game.state.nworldkl, -300*game.state.nworldkl))
3023 if game.state.basekl:
3024 prout(_("%6d bases destroyed by your action %5d") %
3025 (game.state.basekl, -100*game.state.basekl))
3027 prout(_("%6d calls for help from starbase %5d") %
3028 (game.nhelp, -45*game.nhelp))
3030 prout(_("%6d casualties incurred %5d") %
3031 (game.casual, -game.casual))
3033 prout(_("%6d crew abandoned in space %5d") %
3034 (game.abandoned, -3*game.abandoned))
3036 prout(_("%6d ship(s) lost or destroyed %5d") %
3037 (klship, -100*klship))
3039 prout(_("Penalty for getting yourself killed -200"))
3041 proutn(_("Bonus for winning "))
3042 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3043 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3044 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3045 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3046 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3047 prout(" %5d" % iwon)
3049 prout(_("TOTAL SCORE %5d") % game.score)
3052 "Emit winner's commemmorative plaque."
3055 proutn(_("File or device name for your plaque: "))
3058 fp = open(winner, "w")
3061 prout(_("Invalid name."))
3063 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3065 # The 38 below must be 64 for 132-column paper
3066 nskip = 38 - len(winner)/2
3067 fp.write("\n\n\n\n")
3068 # --------DRAW ENTERPRISE PICTURE.
3069 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3070 fp.write(" EEE E : : : E\n" )
3071 fp.write(" EE EEE E : : NCC-1701 : E\n")
3072 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3073 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3074 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3075 fp.write(" EEEEEEE EEEEE E E E E\n")
3076 fp.write(" EEE E E E E\n")
3077 fp.write(" E E E E\n")
3078 fp.write(" EEEEEEEEEEEEE E E\n")
3079 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3080 fp.write(" :E : EEEE E\n")
3081 fp.write(" .-E -:----- E\n")
3082 fp.write(" :E : E\n")
3083 fp.write(" EE : EEEEEEEE\n")
3084 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3086 fp.write(_(" U. S. S. ENTERPRISE\n"))
3087 fp.write("\n\n\n\n")
3088 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3090 fp.write(_(" Starfleet Command bestows to you\n"))
3092 fp.write("%*s%s\n\n" % (nskip, "", winner))
3093 fp.write(_(" the rank of\n\n"))
3094 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3096 if game.skill == SKILL_EXPERT:
3097 fp.write(_(" Expert level\n\n"))
3098 elif game.skill == SKILL_EMERITUS:
3099 fp.write(_("Emeritus level\n\n"))
3101 fp.write(_(" Cheat level\n\n"))
3102 timestring = time.ctime()
3103 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3104 (timestring+4, timestring+20, timestring+11))
3105 fp.write(_(" Your score: %d\n\n") % game.score)
3106 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3109 # Code from io.c begins here
3111 rows = linecount = 0 # for paging
3114 fullscreen_window = None
3115 srscan_window = None
3116 report_window = None
3117 status_window = None
3118 lrscan_window = None
3119 message_window = None
3120 prompt_window = None
3125 "for some recent versions of python2, the following enables UTF8"
3126 "for the older ones we probably need to set C locale, and the python3"
3127 "has no problems at all"
3128 if sys.version_info[0] < 3:
3130 locale.setlocale(locale.LC_ALL, "")
3131 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3132 gettext.textdomain("sst")
3133 if not (game.options & OPTION_CURSES):
3134 ln_env = os.getenv("LINES")
3140 stdscr = curses.initscr()
3144 if game.options & OPTION_COLOR:
3145 curses.start_color()
3146 curses.use_default_colors()
3147 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3148 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3149 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3150 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3151 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3152 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3153 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3154 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3155 global fullscreen_window, srscan_window, report_window, status_window
3156 global lrscan_window, message_window, prompt_window
3157 (rows, columns) = stdscr.getmaxyx()
3158 fullscreen_window = stdscr
3159 srscan_window = curses.newwin(12, 25, 0, 0)
3160 report_window = curses.newwin(11, 0, 1, 25)
3161 status_window = curses.newwin(10, 0, 1, 39)
3162 lrscan_window = curses.newwin(5, 0, 0, 64)
3163 message_window = curses.newwin(0, 0, 12, 0)
3164 prompt_window = curses.newwin(1, 0, rows-2, 0)
3165 message_window.scrollok(True)
3166 setwnd(fullscreen_window)
3170 if game.options & OPTION_CURSES:
3171 stdscr.keypad(False)
3177 "Wait for user action -- OK to do nothing if on a TTY"
3178 if game.options & OPTION_CURSES:
3183 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3187 if game.skill > SKILL_FAIR:
3188 prompt = _("[CONTINUE?]")
3190 prompt = _("[PRESS ENTER TO CONTINUE]")
3192 if game.options & OPTION_CURSES:
3194 setwnd(prompt_window)
3195 prompt_window.clear()
3196 prompt_window.addstr(prompt)
3197 prompt_window.getstr()
3198 prompt_window.clear()
3199 prompt_window.refresh()
3200 setwnd(message_window)
3203 sys.stdout.write('\n')
3207 sys.stdout.write('\n' * rows)
3211 "Skip i lines. Pause game if this would cause a scrolling event."
3212 for dummy in range(i):
3213 if game.options & OPTION_CURSES:
3214 (y, x) = curwnd.getyx()
3217 except curses.error:
3222 if rows and linecount >= rows:
3225 sys.stdout.write('\n')
3228 "Utter a line with no following line feed."
3229 if game.options & OPTION_CURSES:
3230 (y, x) = curwnd.getyx()
3231 (my, mx) = curwnd.getmaxyx()
3232 if curwnd == message_window and y >= my - 2:
3235 # Uncomment this to debug curses problems
3237 logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(line)))
3241 sys.stdout.write(line)
3251 if not replayfp or replayfp.closed: # Don't slow down replays
3254 if game.options & OPTION_CURSES:
3258 if not replayfp or replayfp.closed:
3262 "Get a line of input."
3263 if game.options & OPTION_CURSES:
3264 line = curwnd.getstr() + "\n"
3267 if replayfp and not replayfp.closed:
3269 line = replayfp.readline()
3272 prout("*** Replay finished")
3275 elif line[0] != "#":
3278 line = raw_input() + "\n"
3284 "Change windows -- OK for this to be a no-op in tty mode."
3286 if game.options & OPTION_CURSES:
3287 # Uncomment this to debug curses problems
3289 if wnd == fullscreen_window:
3290 legend = "fullscreen"
3291 elif wnd == srscan_window:
3293 elif wnd == report_window:
3295 elif wnd == status_window:
3297 elif wnd == lrscan_window:
3299 elif wnd == message_window:
3301 elif wnd == prompt_window:
3305 logfp.write("#curses: setwnd(%s)\n" % legend)
3307 # Some curses implementations get confused when you try this.
3309 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3310 except curses.error:
3314 "Clear to end of line -- can be a no-op in tty mode"
3315 if game.options & OPTION_CURSES:
3320 "Clear screen -- can be a no-op in tty mode."
3322 if game.options & OPTION_CURSES:
3328 def textcolor(color=DEFAULT):
3329 if game.options & OPTION_COLOR:
3330 if color == DEFAULT:
3332 elif color == BLACK:
3333 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3335 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3336 elif color == GREEN:
3337 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3339 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3341 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3342 elif color == MAGENTA:
3343 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3344 elif color == BROWN:
3345 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3346 elif color == LIGHTGRAY:
3347 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3348 elif color == DARKGRAY:
3349 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3350 elif color == LIGHTBLUE:
3351 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3352 elif color == LIGHTGREEN:
3353 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3354 elif color == LIGHTCYAN:
3355 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3356 elif color == LIGHTRED:
3357 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3358 elif color == LIGHTMAGENTA:
3359 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3360 elif color == YELLOW:
3361 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3362 elif color == WHITE:
3363 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3366 if game.options & OPTION_COLOR:
3367 curwnd.attron(curses.A_REVERSE)
3370 # Things past this point have policy implications.
3374 "Hook to be called after moving to redraw maps."
3375 if game.options & OPTION_CURSES:
3378 setwnd(srscan_window)
3382 setwnd(status_window)
3383 status_window.clear()
3384 status_window.move(0, 0)
3385 setwnd(report_window)
3386 report_window.clear()
3387 report_window.move(0, 0)
3389 setwnd(lrscan_window)
3390 lrscan_window.clear()
3391 lrscan_window.move(0, 0)
3392 lrscan(silent=False)
3394 def put_srscan_sym(w, sym):
3395 "Emit symbol for short-range scan."
3396 srscan_window.move(w.i+1, w.j*2+2)
3397 srscan_window.addch(sym)
3398 srscan_window.refresh()
3401 "Enemy fall down, go boom."
3402 if game.options & OPTION_CURSES:
3404 setwnd(srscan_window)
3405 srscan_window.attron(curses.A_REVERSE)
3406 put_srscan_sym(w, game.quad[w.i][w.j])
3410 srscan_window.attroff(curses.A_REVERSE)
3411 put_srscan_sym(w, game.quad[w.i][w.j])
3412 curses.delay_output(500)
3413 setwnd(message_window)
3416 "Sound and visual effects for teleportation."
3417 if game.options & OPTION_CURSES:
3419 setwnd(message_window)
3421 prouts(" . . . . . ")
3422 if game.options & OPTION_CURSES:
3423 #curses.delay_output(1000)
3427 def tracktorpedo(w, step, i, n, iquad):
3428 "Torpedo-track animation."
3429 if not game.options & OPTION_CURSES:
3433 proutn(_("Track for torpedo number %d- ") % (i+1))
3436 proutn(_("Torpedo track- "))
3437 elif step==4 or step==9:
3441 if not damaged(DSRSENS) or game.condition=="docked":
3442 if i != 0 and step == 1:
3445 if (iquad=='.') or (iquad==' '):
3446 put_srscan_sym(w, '+')
3450 put_srscan_sym(w, iquad)
3452 curwnd.attron(curses.A_REVERSE)
3453 put_srscan_sym(w, iquad)
3457 curwnd.attroff(curses.A_REVERSE)
3458 put_srscan_sym(w, iquad)
3463 "Display the current galaxy chart."
3464 if game.options & OPTION_CURSES:
3465 setwnd(message_window)
3466 message_window.clear()
3468 if game.options & OPTION_TTY:
3473 def prstat(txt, data):
3475 if game.options & OPTION_CURSES:
3477 setwnd(status_window)
3479 proutn(" " * (NSYM - len(txt)))
3482 if game.options & OPTION_CURSES:
3483 setwnd(report_window)
3485 # Code from moving.c begins here
3487 def imove(icourse=None, noattack=False):
3488 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3491 def newquadrant(noattack):
3492 # Leaving quadrant -- allow final enemy attack
3493 # Don't do it if being pushed by Nova
3494 if len(game.enemies) != 0 and not noattack:
3496 for enemy in game.enemies:
3497 finald = (w - enemy.location).distance()
3498 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3499 # Stas Sergeev added the condition
3500 # that attacks only happen if Klingons
3501 # are present and your skill is good.
3502 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3503 attack(torps_ok=False)
3506 # check for edge of galaxy
3510 if icourse.final.i < 0:
3511 icourse.final.i = -icourse.final.i
3513 if icourse.final.j < 0:
3514 icourse.final.j = -icourse.final.j
3516 if icourse.final.i >= GALSIZE*QUADSIZE:
3517 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3519 if icourse.final.j >= GALSIZE*QUADSIZE:
3520 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3528 if game.nkinks == 3:
3529 # Three strikes -- you're out!
3533 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3534 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3535 prout(_("YOU WILL BE DESTROYED."))
3536 # Compute final position in new quadrant
3537 if trbeam: # Don't bother if we are to be beamed
3539 game.quadrant = icourse.final.quadrant()
3540 game.sector = icourse.final.sector()
3542 prout(_("Entering Quadrant %s.") % game.quadrant)
3543 game.quad[game.sector.i][game.sector.j] = game.ship
3545 if game.skill>SKILL_NOVICE:
3546 attack(torps_ok=False)
3548 def check_collision(h):
3549 iquad = game.quad[h.i][h.j]
3551 # object encountered in flight path
3552 stopegy = 50.0*icourse.distance/game.optime
3553 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3554 for enemy in game.enemies:
3555 if enemy.location == game.sector:
3557 collision(rammed=False, enemy=enemy)
3561 prouts(_("***RED ALERT! RED ALERT!"))
3563 proutn("***" + crmshp())
3564 proutn(_(" pulled into black hole at Sector %s") % h)
3565 # Getting pulled into a black hole was certain
3566 # death in Almy's original. Stas Sergeev added a
3567 # possibility that you'll get timewarped instead.
3569 for m in range(NDEVICES):
3570 if game.damage[m]>0:
3572 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3573 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3583 prout(_(" encounters Tholian web at %s;") % h)
3585 prout(_(" blocked by object at %s;") % h)
3586 proutn(_("Emergency stop required "))
3587 prout(_("%2d units of energy.") % int(stopegy))
3588 game.energy -= stopegy
3589 if game.energy <= 0:
3596 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3597 game.inorbit = False
3598 # If tractor beam is to occur, don't move full distance
3599 if game.state.date+game.optime >= scheduled(FTBEAM):
3601 game.condition = "red"
3602 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3603 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3605 game.quad[game.sector.i][game.sector.j] = '.'
3606 for m in range(icourse.moves):
3608 w = icourse.sector()
3609 if icourse.origin.quadrant() != icourse.location.quadrant():
3610 newquadrant(noattack)
3612 elif check_collision(w):
3613 print "Collision detected"
3617 # We're in destination quadrant -- compute new average enemy distances
3618 game.quad[game.sector.i][game.sector.j] = game.ship
3620 for enemy in game.enemies:
3621 finald = (w-enemy.location).distance()
3622 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3623 enemy.kdist = finald
3625 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3626 attack(torps_ok=False)
3627 for enemy in game.enemies:
3628 enemy.kavgd = enemy.kdist
3631 setwnd(message_window)
3635 "Dock our ship at a starbase."
3637 if game.condition == "docked" and verbose:
3638 prout(_("Already docked."))
3641 prout(_("You must first leave standard orbit."))
3643 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3644 prout(crmshp() + _(" not adjacent to base."))
3646 game.condition = "docked"
3650 if game.energy < game.inenrg:
3651 game.energy = game.inenrg
3652 game.shield = game.inshld
3653 game.torps = game.intorps
3654 game.lsupres = game.inlsr
3655 game.state.crew = FULLCREW
3656 if not damaged(DRADIO) and \
3657 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3658 # get attack report from base
3659 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3663 def cartesian(loc1=None, loc2=None):
3665 return game.quadrant * QUADSIZE + game.sector
3667 return game.quadrant * QUADSIZE + loc1
3669 return loc1 * QUADSIZE + loc2
3671 def getcourse(isprobe):
3672 "Get a course and distance from the user."
3674 dquad = copy.copy(game.quadrant)
3675 navmode = "unspecified"
3679 if game.landed and not isprobe:
3680 prout(_("Dummy! You can't leave standard orbit until you"))
3681 proutn(_("are back aboard the ship."))
3684 while navmode == "unspecified":
3685 if damaged(DNAVSYS):
3687 prout(_("Computer damaged; manual navigation only"))
3689 prout(_("Computer damaged; manual movement only"))
3694 key = scanner.next()
3696 proutn(_("Manual or automatic- "))
3699 elif key == "IHALPHA":
3700 if scanner.sees("manual"):
3702 key = scanner.next()
3704 elif scanner.sees("automatic"):
3705 navmode = "automatic"
3706 key = scanner.next()
3714 prout(_("(Manual navigation assumed.)"))
3716 prout(_("(Manual movement assumed.)"))
3720 if navmode == "automatic":
3721 while key == "IHEOL":
3723 proutn(_("Target quadrant or quadrant§or- "))
3725 proutn(_("Destination sector or quadrant§or- "))
3728 key = scanner.next()
3732 xi = int(round(scanner.real))-1
3733 key = scanner.next()
3737 xj = int(round(scanner.real))-1
3738 key = scanner.next()
3740 # both quadrant and sector specified
3741 xk = int(round(scanner.real))-1
3742 key = scanner.next()
3746 xl = int(round(scanner.real))-1
3752 # only one pair of numbers was specified
3754 # only quadrant specified -- go to center of dest quad
3757 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3759 # only sector specified
3763 if not dquad.valid_quadrant() or not dsect.valid_sector():
3770 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3772 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3773 # the actual deltas get computed here
3774 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3775 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3777 while key == "IHEOL":
3778 proutn(_("X and Y displacements- "))
3781 key = scanner.next()
3786 delta.j = scanner.real
3787 key = scanner.next()
3791 delta.i = scanner.real
3792 # Check for zero movement
3793 if delta.i == 0 and delta.j == 0:
3796 if itemp == "verbose" and not isprobe:
3798 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3800 return course(bearing=delta.bearing(), distance=delta.distance())
3803 def __init__(self, bearing, distance, origin=None):
3804 self.distance = distance
3805 self.bearing = bearing
3807 self.origin = cartesian(game.quadrant, game.sector)
3809 self.origin = origin
3810 # The bearing() code we inherited from FORTRAN is actually computing
3811 # clockface directions!
3812 if self.bearing < 0.0:
3813 self.bearing += 12.0
3814 self.angle = ((15.0 - self.bearing) * 0.5235988)
3816 self.origin = cartesian(game.quadrant, game.sector)
3818 self.origin = cartesian(game.quadrant, origin)
3819 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
3820 bigger = max(abs(self.increment.i), abs(self.increment.j))
3821 self.increment /= bigger
3822 self.moves = int(round(10*self.distance*bigger))
3824 self.final = (self.location + self.moves*self.increment).roundtogrid()
3826 self.location = self.origin
3829 return self.location.roundtogrid() == self.final
3831 "Next step on course."
3833 self.nextlocation = self.location + self.increment
3834 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3835 self.location = self.nextlocation
3838 return self.location.quadrant()
3840 return self.location.sector()
3841 def power(self, warp):
3842 return self.distance*(warp**3)*(game.shldup+1)
3843 def time(self, warp):
3844 return 10.0*self.distance/warp**2
3847 "Move under impulse power."
3849 if damaged(DIMPULS):
3852 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3854 if game.energy > 30.0:
3856 course = getcourse(isprobe=False)
3859 power = 20.0 + 100.0*course.distance
3862 if power >= game.energy:
3863 # Insufficient power for trip
3865 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3866 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3867 if game.energy > 30:
3868 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3869 int(0.01 * (game.energy-20.0)-0.05))
3870 prout(_(" quadrants.\""))
3872 prout(_("quadrant. They are, therefore, useless.\""))
3875 # Make sure enough time is left for the trip
3876 game.optime = course.distance/0.095
3877 if game.optime >= game.state.remtime:
3878 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3879 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3880 proutn(_("we dare spend the time?\" "))
3883 # Activate impulse engines and pay the cost
3884 imove(course, noattack=False)
3888 power = 20.0 + 100.0*course.distance
3889 game.energy -= power
3890 game.optime = course.distance/0.095
3891 if game.energy <= 0:
3895 def warp(wcourse, involuntary):
3896 "ove under warp drive."
3897 blooey = False; twarp = False
3898 if not involuntary: # Not WARPX entry
3900 if game.damage[DWARPEN] > 10.0:
3903 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3905 if damaged(DWARPEN) and game.warpfac > 4.0:
3908 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3909 prout(_(" is repaired, I can only give you warp 4.\""))
3911 # Read in course and distance
3914 wcourse = getcourse(isprobe=False)
3917 # Make sure starship has enough energy for the trip
3918 # Note: this formula is slightly different from the C version,
3919 # and lets you skate a bit closer to the edge.
3920 if wcourse.power(game.warpfac) >= game.energy:
3921 # Insufficient power for trip
3924 prout(_("Engineering to bridge--"))
3925 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
3926 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
3928 prout(_("We can't do it, Captain. We don't have enough energy."))
3930 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3933 prout(_("if you'll lower the shields."))
3937 prout(_("We haven't the energy to go that far with the shields up."))
3939 # Make sure enough time is left for the trip
3940 game.optime = wcourse.time(game.warpfac)
3941 if game.optime >= 0.8*game.state.remtime:
3943 prout(_("First Officer Spock- \"Captain, I compute that such"))
3944 proutn(_(" a trip would require approximately %2.0f") %
3945 (100.0*game.optime/game.state.remtime))
3946 prout(_(" percent of our"))
3947 proutn(_(" remaining time. Are you sure this is wise?\" "))
3953 if game.warpfac > 6.0:
3954 # Decide if engine damage will occur
3955 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3956 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
3957 if prob > randreal():
3959 wcourse.distance = randreal(wcourse.distance)
3960 # Decide if time warp will occur
3961 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3963 if game.idebug and game.warpfac==10 and not twarp:
3965 proutn("=== Force time warp? ")
3969 # If time warp or engine damage, check path
3970 # If it is obstructed, don't do warp or damage
3971 look = wcourse.moves
3975 w = wcourse.sector()
3976 if not w.valid_sector():
3978 if game.quad[w.i][w.j] != '.':
3982 # Activate Warp Engines and pay the cost
3983 imove(wcourse, noattack=False)
3986 game.energy -= wcourse.power(game.warpfac)
3987 if game.energy <= 0:
3989 game.optime = wcourse.time(game.warpfac)
3993 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
3995 prout(_("Engineering to bridge--"))
3996 prout(_(" Scott here. The warp engines are damaged."))
3997 prout(_(" We'll have to reduce speed to warp 4."))
4002 "Change the warp factor."
4008 proutn(_("Warp factor- "))
4012 if game.damage[DWARPEN] > 10.0:
4013 prout(_("Warp engines inoperative."))
4015 if damaged(DWARPEN) and scanner.real > 4.0:
4016 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4017 prout(_(" but right now we can only go warp 4.\""))
4019 if scanner.real > 10.0:
4020 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4022 if scanner.real < 1.0:
4023 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4025 oldfac = game.warpfac
4026 game.warpfac = scanner.real
4027 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4028 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4031 if game.warpfac < 8.00:
4032 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4034 if game.warpfac == 10.0:
4035 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4037 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4041 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4043 # is captain on planet?
4045 if damaged(DTRANSP):
4048 prout(_("Scotty rushes to the transporter controls."))
4050 prout(_("But with the shields up it's hopeless."))
4052 prouts(_("His desperate attempt to rescue you . . ."))
4057 prout(_("SUCCEEDS!"))
4060 proutn(_("The crystals mined were "))
4068 # Check to see if captain in shuttle craft
4073 # Inform captain of attempt to reach safety
4077 prouts(_("***RED ALERT! RED ALERT!"))
4079 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4080 prouts(_(" a supernova."))
4082 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4083 prout(_("safely out of quadrant."))
4084 if not damaged(DRADIO):
4085 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4086 # Try to use warp engines
4087 if damaged(DWARPEN):
4089 prout(_("Warp engines damaged."))
4092 game.warpfac = randreal(6.0, 8.0)
4093 prout(_("Warp factor set to %d") % int(game.warpfac))
4094 power = 0.75*game.energy
4095 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4096 dist = max(dist, randreal(math.sqrt(2)))
4097 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4098 game.optime = bugout.time(game.warpfac)
4100 game.inorbit = False
4101 warp(bugout, involuntary=True)
4103 # This is bad news, we didn't leave quadrant.
4107 prout(_("Insufficient energy to leave quadrant."))
4110 # Repeat if another snova
4111 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4113 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4114 finish(FWON) # Snova killed remaining enemy.
4117 "Let's do the time warp again."
4118 prout(_("***TIME WARP ENTERED."))
4119 if game.state.snap and withprob(0.5):
4121 prout(_("You are traveling backwards in time %d stardates.") %
4122 int(game.state.date-game.snapsht.date))
4123 game.state = game.snapsht
4124 game.state.snap = False
4125 if len(game.state.kcmdr):
4126 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4127 schedule(FBATTAK, expran(0.3*game.intime))
4128 schedule(FSNOVA, expran(0.5*game.intime))
4129 # next snapshot will be sooner
4130 schedule(FSNAP, expran(0.25*game.state.remtime))
4132 if game.state.nscrem:
4133 schedule(FSCMOVE, 0.2777)
4137 game.battle.invalidate()
4138 # Make sure Galileo is consistant -- Snapshot may have been taken
4139 # when on planet, which would give us two Galileos!
4141 for l in range(game.inplan):
4142 if game.state.planets[l].known == "shuttle_down":
4144 if game.iscraft == "onship" and game.ship=='E':
4145 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4146 game.iscraft = "offship"
4147 # Likewise, if in the original time the Galileo was abandoned, but
4148 # was on ship earlier, it would have vanished -- let's restore it.
4149 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4150 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4151 game.iscraft = "onship"
4152 # There used to be code to do the actual reconstrction here,
4153 # but the starchart is now part of the snapshotted galaxy state.
4154 prout(_("Spock has reconstructed a correct star chart from memory"))
4156 # Go forward in time
4157 game.optime = expran(0.5*game.intime)
4158 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4159 # cheat to make sure no tractor beams occur during time warp
4160 postpone(FTBEAM, game.optime)
4161 game.damage[DRADIO] += game.optime
4163 events() # Stas Sergeev added this -- do pending events
4166 "Launch deep-space probe."
4167 # New code to launch a deep space probe
4168 if game.nprobes == 0:
4171 if game.ship == 'E':
4172 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4174 prout(_("Ye Faerie Queene has no deep space probes."))
4179 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4181 if is_scheduled(FDSPROB):
4184 if damaged(DRADIO) and game.condition != "docked":
4185 prout(_("Spock- \"Records show the previous probe has not yet"))
4186 prout(_(" reached its destination.\""))
4188 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4190 key = scanner.next()
4192 if game.nprobes == 1:
4193 prout(_("1 probe left."))
4195 prout(_("%d probes left") % game.nprobes)
4196 proutn(_("Are you sure you want to fire a probe? "))
4199 game.isarmed = False
4200 if key == "IHALPHA" and scanner.token == "armed":
4202 key = scanner.next()
4203 elif key == "IHEOL":
4204 proutn(_("Arm NOVAMAX warhead? "))
4206 elif key == "IHREAL": # first element of course
4207 scanner.push(scanner.token)
4209 game.probe = getcourse(isprobe=True)
4213 schedule(FDSPROB, 0.01) # Time to move one sector
4214 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4219 "Yell for help from nearest starbase."
4220 # There's more than one way to move in this game!
4222 # Test for conditions which prevent calling for help
4223 if game.condition == "docked":
4224 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4227 prout(_("Subspace radio damaged."))
4229 if not game.state.baseq:
4230 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4233 prout(_("You must be aboard the %s.") % crmshp())
4235 # OK -- call for help from nearest starbase
4238 # There's one in this quadrant
4239 ddist = (game.base - game.sector).distance()
4242 for ibq in game.state.baseq:
4243 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4246 # Since starbase not in quadrant, set up new quadrant
4249 # dematerialize starship
4250 game.quad[game.sector.i][game.sector.j]='.'
4251 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4252 % (game.quadrant, crmshp()))
4253 game.sector.invalidate()
4254 for m in range(1, 5+1):
4255 w = game.base.scatter()
4256 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4257 # found one -- finish up
4260 if not game.sector.is_valid():
4261 prout(_("You have been lost in space..."))
4262 finish(FMATERIALIZE)
4264 # Give starbase three chances to rematerialize starship
4265 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4266 for m in range(1, 3+1):
4267 if m == 1: proutn(_("1st"))
4268 elif m == 2: proutn(_("2nd"))
4269 elif m == 3: proutn(_("3rd"))
4270 proutn(_(" attempt to re-materialize ") + crmshp())
4271 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4274 if randreal() > probf:
4278 curses.delay_output(500)
4280 game.quad[game.sector.i][game.sector.j]='?'
4283 setwnd(message_window)
4284 finish(FMATERIALIZE)
4286 game.quad[game.sector.i][game.sector.j]=game.ship
4288 prout(_("succeeds."))
4292 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4297 if game.condition=="docked":
4299 prout(_("You cannot abandon Ye Faerie Queene."))
4302 # Must take shuttle craft to exit
4303 if game.damage[DSHUTTL]==-1:
4304 prout(_("Ye Faerie Queene has no shuttle craft."))
4306 if game.damage[DSHUTTL]<0:
4307 prout(_("Shuttle craft now serving Big Macs."))
4309 if game.damage[DSHUTTL]>0:
4310 prout(_("Shuttle craft damaged."))
4313 prout(_("You must be aboard the ship."))
4315 if game.iscraft != "onship":
4316 prout(_("Shuttle craft not currently available."))
4318 # Emit abandon ship messages
4320 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4322 prouts(_("***ALL HANDS ABANDON SHIP!"))
4324 prout(_("Captain and crew escape in shuttle craft."))
4325 if not game.state.baseq:
4326 # Oops! no place to go...
4329 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4331 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4332 prout(_("Remainder of ship's complement beam down"))
4333 prout(_("to nearest habitable planet."))
4334 elif q.planet != None and not damaged(DTRANSP):
4335 prout(_("Remainder of ship's complement beam down to %s.") %
4338 prout(_("Entire crew of %d left to die in outer space.") %
4340 game.casual += game.state.crew
4341 game.abandoned += game.state.crew
4342 # If at least one base left, give 'em the Faerie Queene
4344 game.icrystl = False # crystals are lost
4345 game.nprobes = 0 # No probes
4346 prout(_("You are captured by Klingons and released to"))
4347 prout(_("the Federation in a prisoner-of-war exchange."))
4348 nb = randrange(len(game.state.baseq))
4349 # Set up quadrant and position FQ adjacient to base
4350 if not game.quadrant == game.state.baseq[nb]:
4351 game.quadrant = game.state.baseq[nb]
4352 game.sector.i = game.sector.j = 5
4355 # position next to base by trial and error
4356 game.quad[game.sector.i][game.sector.j] = '.'
4357 for l in range(QUADSIZE):
4358 game.sector = game.base.scatter()
4359 if game.sector.valid_sector() and \
4360 game.quad[game.sector.i][game.sector.j] == '.':
4363 break # found a spot
4364 game.sector.i=QUADSIZE/2
4365 game.sector.j=QUADSIZE/2
4367 # Get new commission
4368 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4369 game.state.crew = FULLCREW
4370 prout(_("Starfleet puts you in command of another ship,"))
4371 prout(_("the Faerie Queene, which is antiquated but,"))
4372 prout(_("still useable."))
4374 prout(_("The dilithium crystals have been moved."))
4376 game.iscraft = "offship" # Galileo disappears
4378 game.condition="docked"
4379 for l in range(NDEVICES):
4380 game.damage[l] = 0.0
4381 game.damage[DSHUTTL] = -1
4382 game.energy = game.inenrg = 3000.0
4383 game.shield = game.inshld = 1250.0
4384 game.torps = game.intorps = 6
4385 game.lsupres=game.inlsr=3.0
4390 # Code from planets.c begins here.
4393 "Abort a lengthy operation if an event interrupts it."
4396 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4401 "Report on (uninhabited) planets in the galaxy."
4405 prout(_("Spock- \"Planet report follows, Captain.\""))
4407 for i in range(game.inplan):
4408 if game.state.planets[i].pclass == "destroyed":
4410 if (game.state.planets[i].known != "unknown" \
4411 and not game.state.planets[i].inhabited) \
4414 if game.idebug and game.state.planets[i].known=="unknown":
4415 proutn("(Unknown) ")
4416 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4417 proutn(_(" class "))
4418 proutn(game.state.planets[i].pclass)
4420 if game.state.planets[i].crystals != "present":
4422 prout(_("dilithium crystals present."))
4423 if game.state.planets[i].known=="shuttle_down":
4424 prout(_(" Shuttle Craft Galileo on surface."))
4426 prout(_("No information available."))
4429 "Enter standard orbit."
4433 prout(_("Already in standard orbit."))
4435 if damaged(DWARPEN) and damaged(DIMPULS):
4436 prout(_("Both warp and impulse engines damaged."))
4438 if not game.plnet.is_valid():
4439 prout("There is no planet in this sector.")
4441 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4442 prout(crmshp() + _(" not adjacent to planet."))
4445 game.optime = randreal(0.02, 0.05)
4446 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4450 game.height = randreal(1400, 8600)
4451 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4456 "Examine planets in this quadrant."
4457 if damaged(DSRSENS):
4458 if game.options & OPTION_TTY:
4459 prout(_("Short range sensors damaged."))
4461 if game.iplnet == None:
4462 if game.options & OPTION_TTY:
4463 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4465 if game.iplnet.known == "unknown":
4466 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4468 prout(_(" Planet at Sector %s is of class %s.") %
4469 (game.plnet, game.iplnet.pclass))
4470 if game.iplnet.known=="shuttle_down":
4471 prout(_(" Sensors show Galileo still on surface."))
4472 proutn(_(" Readings indicate"))
4473 if game.iplnet.crystals != "present":
4475 prout(_(" dilithium crystals present.\""))
4476 if game.iplnet.known == "unknown":
4477 game.iplnet.known = "known"
4478 elif game.iplnet.inhabited:
4479 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4480 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4483 "Use the transporter."
4487 if damaged(DTRANSP):
4488 prout(_("Transporter damaged."))
4489 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4491 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4495 if not game.inorbit:
4496 prout(crmshp() + _(" not in standard orbit."))
4499 prout(_("Impossible to transport through shields."))
4501 if game.iplnet.known=="unknown":
4502 prout(_("Spock- \"Captain, we have no information on this planet"))
4503 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4504 prout(_(" you may not go down.\""))
4506 if not game.landed and game.iplnet.crystals=="absent":
4507 prout(_("Spock- \"Captain, I fail to see the logic in"))
4508 prout(_(" exploring a planet with no dilithium crystals."))
4509 proutn(_(" Are you sure this is wise?\" "))
4513 if not (game.options & OPTION_PLAIN):
4514 nrgneed = 50 * game.skill + game.height / 100.0
4515 if nrgneed > game.energy:
4516 prout(_("Engineering to bridge--"))
4517 prout(_(" Captain, we don't have enough energy for transportation."))
4519 if not game.landed and nrgneed * 2 > game.energy:
4520 prout(_("Engineering to bridge--"))
4521 prout(_(" Captain, we have enough energy only to transport you down to"))
4522 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4523 if game.iplnet.known == "shuttle_down":
4524 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4525 proutn(_(" Are you sure this is wise?\" "))
4530 # Coming from planet
4531 if game.iplnet.known=="shuttle_down":
4532 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4536 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4537 prout(_("Landing party assembled, ready to beam up."))
4539 prout(_("Kirk whips out communicator..."))
4540 prouts(_("BEEP BEEP BEEP"))
4542 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4545 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4547 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4549 prout(_("Kirk- \"Energize.\""))
4552 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4555 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4557 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4560 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4561 game.landed = not game.landed
4562 game.energy -= nrgneed
4564 prout(_("Transport complete."))
4565 if game.landed and game.iplnet.known=="shuttle_down":
4566 prout(_("The shuttle craft Galileo is here!"))
4567 if not game.landed and game.imine:
4574 "Strip-mine a world for dilithium."
4578 prout(_("Mining party not on planet."))
4580 if game.iplnet.crystals == "mined":
4581 prout(_("This planet has already been strip-mined for dilithium."))
4583 elif game.iplnet.crystals == "absent":
4584 prout(_("No dilithium crystals on this planet."))
4587 prout(_("You've already mined enough crystals for this trip."))
4589 if game.icrystl and game.cryprob == 0.05:
4590 prout(_("With all those fresh crystals aboard the ") + crmshp())
4591 prout(_("there's no reason to mine more at this time."))
4593 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4596 prout(_("Mining operation complete."))
4597 game.iplnet.crystals = "mined"
4598 game.imine = game.ididit = True
4601 "Use dilithium crystals."
4605 if not game.icrystl:
4606 prout(_("No dilithium crystals available."))
4608 if game.energy >= 1000:
4609 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4610 prout(_(" except when Condition Yellow exists."))
4612 prout(_("Spock- \"Captain, I must warn you that loading"))
4613 prout(_(" raw dilithium crystals into the ship's power"))
4614 prout(_(" system may risk a severe explosion."))
4615 proutn(_(" Are you sure this is wise?\" "))
4620 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4621 prout(_(" Mr. Spock and I will try it.\""))
4623 prout(_("Spock- \"Crystals in place, Sir."))
4624 prout(_(" Ready to activate circuit.\""))
4626 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4628 if withprob(game.cryprob):
4629 prouts(_(" \"Activating now! - - No good! It's***"))
4631 prouts(_("***RED ALERT! RED A*L********************************"))
4634 prouts(_("****************** KA-BOOM!!!! *******************"))
4638 game.energy += randreal(5000.0, 5500.0)
4639 prouts(_(" \"Activating now! - - "))
4640 prout(_("The instruments"))
4641 prout(_(" are going crazy, but I think it's"))
4642 prout(_(" going to work!! Congratulations, Sir!\""))
4647 "Use shuttlecraft for planetary jaunt."
4650 if damaged(DSHUTTL):
4651 if game.damage[DSHUTTL] == -1.0:
4652 if game.inorbit and game.iplnet.known == "shuttle_down":
4653 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4655 prout(_("Ye Faerie Queene had no shuttle craft."))
4656 elif game.damage[DSHUTTL] > 0:
4657 prout(_("The Galileo is damaged."))
4658 else: # game.damage[DSHUTTL] < 0
4659 prout(_("Shuttle craft is now serving Big Macs."))
4661 if not game.inorbit:
4662 prout(crmshp() + _(" not in standard orbit."))
4664 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4665 prout(_("Shuttle craft not currently available."))
4667 if not game.landed and game.iplnet.known=="shuttle_down":
4668 prout(_("You will have to beam down to retrieve the shuttle craft."))
4670 if game.shldup or game.condition == "docked":
4671 prout(_("Shuttle craft cannot pass through shields."))
4673 if game.iplnet.known=="unknown":
4674 prout(_("Spock- \"Captain, we have no information on this planet"))
4675 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4676 prout(_(" you may not fly down.\""))
4678 game.optime = 3.0e-5*game.height
4679 if game.optime >= 0.8*game.state.remtime:
4680 prout(_("First Officer Spock- \"Captain, I compute that such"))
4681 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4682 int(100*game.optime/game.state.remtime))
4683 prout(_("remaining time."))
4684 proutn(_("Are you sure this is wise?\" "))
4690 if game.iscraft == "onship":
4692 if not damaged(DTRANSP):
4693 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4697 proutn(_("Shuttle crew"))
4699 proutn(_("Rescue party"))
4700 prout(_(" boards Galileo and swoops toward planet surface."))
4701 game.iscraft = "offship"
4705 game.iplnet.known="shuttle_down"
4706 prout(_("Trip complete."))
4709 # Ready to go back to ship
4710 prout(_("You and your mining party board the"))
4711 prout(_("shuttle craft for the trip back to the Enterprise."))
4713 prouts(_("The short hop begins . . ."))
4715 game.iplnet.known="known"
4721 game.iscraft = "onship"
4727 prout(_("Trip complete."))
4730 # Kirk on ship and so is Galileo
4731 prout(_("Mining party assembles in the hangar deck,"))
4732 prout(_("ready to board the shuttle craft \"Galileo\"."))
4734 prouts(_("The hangar doors open; the trip begins."))
4737 game.iscraft = "offship"
4740 game.iplnet.known = "shuttle_down"
4743 prout(_("Trip complete."))
4747 "Use the big zapper."
4751 if game.ship != 'E':
4752 prout(_("Ye Faerie Queene has no death ray."))
4754 if len(game.enemies)==0:
4755 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4758 prout(_("Death Ray is damaged."))
4760 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4761 prout(_(" is highly unpredictible. Considering the alternatives,"))
4762 proutn(_(" are you sure this is wise?\" "))
4765 prout(_("Spock- \"Acknowledged.\""))
4768 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4770 prout(_("Crew scrambles in emergency preparation."))
4771 prout(_("Spock and Scotty ready the death ray and"))
4772 prout(_("prepare to channel all ship's power to the device."))
4774 prout(_("Spock- \"Preparations complete, sir.\""))
4775 prout(_("Kirk- \"Engage!\""))
4777 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4780 if game.options & OPTION_PLAIN:
4784 prouts(_("Sulu- \"Captain! It's working!\""))
4786 while len(game.enemies) > 0:
4787 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4788 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4789 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4791 if (game.options & OPTION_PLAIN) == 0:
4792 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4794 prout(_(" is still operational.\""))
4796 prout(_(" has been rendered nonfunctional.\""))
4797 game.damage[DDRAY] = 39.95
4799 r = randreal() # Pick failure method
4801 prouts(_("Sulu- \"Captain! It's working!\""))
4803 prouts(_("***RED ALERT! RED ALERT!"))
4805 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4807 prouts(_("***RED ALERT! RED A*L********************************"))
4810 prouts(_("****************** KA-BOOM!!!! *******************"))
4815 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4817 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4819 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4820 prout(_(" have apparently been transformed into strange mutations."))
4821 prout(_(" Vulcans do not seem to be affected."))
4823 prout(_("Kirk- \"Raauch! Raauch!\""))
4827 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4829 proutn(_("Spock- \"I believe the word is"))
4830 prouts(_(" *ASTONISHING*"))
4831 prout(_(" Mr. Sulu."))
4832 for i in range(QUADSIZE):
4833 for j in range(QUADSIZE):
4834 if game.quad[i][j] == '.':
4835 game.quad[i][j] = '?'
4836 prout(_(" Captain, our quadrant is now infested with"))
4837 prouts(_(" - - - - - - *THINGS*."))
4839 prout(_(" I have no logical explanation.\""))
4841 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4843 prout(_("Scotty- \"There are so many tribbles down here"))
4844 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4848 # Code from reports.c begins here
4850 def attackreport(curt):
4851 "eport status of bases under attack."
4853 if is_scheduled(FCDBAS):
4854 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4855 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4856 elif game.isatb == 1:
4857 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4858 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4860 prout(_("No Starbase is currently under attack."))
4862 if is_scheduled(FCDBAS):
4863 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4865 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4869 # report on general game status
4871 s1 = (game.thawed and _("thawed ")) or ""
4872 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4873 s3 = (None, _("novice"), _("fair"),
4874 _("good"), _("expert"), _("emeritus"))[game.skill]
4875 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4876 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4877 prout(_("No plaque is allowed."))
4879 prout(_("This is tournament game %d.") % game.tourn)
4880 prout(_("Your secret password is \"%s\"") % game.passwd)
4881 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4882 (game.inkling + game.incom + game.inscom)))
4883 if game.incom - len(game.state.kcmdr):
4884 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4885 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4886 prout(_(", but no Commanders."))
4889 if game.skill > SKILL_FAIR:
4890 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4891 if len(game.state.baseq) != game.inbase:
4893 if game.inbase-len(game.state.baseq)==1:
4894 proutn(_("has been 1 base"))
4896 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4897 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4899 prout(_("There are %d bases.") % game.inbase)
4900 if communicating() or game.iseenit:
4901 # Don't report this if not seen and
4902 # either the radio is dead or not at base!
4906 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4908 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4909 if game.ship == 'E':
4910 proutn(_("You have "))
4912 proutn("%d" % (game.nprobes))
4915 proutn(_(" deep space probe"))
4919 if communicating() and is_scheduled(FDSPROB):
4921 proutn(_("An armed deep space probe is in "))
4923 proutn(_("A deep space probe is in "))
4924 prout("Quadrant %s." % game.probec)
4926 if game.cryprob <= .05:
4927 prout(_("Dilithium crystals aboard ship... not yet used."))
4931 while game.cryprob > ai:
4934 prout(_("Dilithium crystals have been used %d time%s.") % \
4935 (i, (_("s"), "")[i==1]))
4939 "Long-range sensor scan."
4940 if damaged(DLRSENS):
4941 # Now allow base's sensors if docked
4942 if game.condition != "docked":
4944 prout(_("LONG-RANGE SENSORS DAMAGED."))
4947 prout(_("Starbase's long-range scan"))
4949 prout(_("Long-range scan"))
4950 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4953 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4954 if not Coord(x, y).valid_quadrant():
4958 if not damaged(DRADIO):
4959 game.state.galaxy[x][y].charted = True
4960 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4961 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4962 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4963 if not silent and game.state.galaxy[x][y].supernova:
4966 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4974 for i in range(NDEVICES):
4977 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4978 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4980 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4981 game.damage[i]+0.05,
4982 DOCKFAC*game.damage[i]+0.005))
4984 prout(_("All devices functional."))
4987 "Update the chart in the Enterprise's computer from galaxy data."
4988 game.lastchart = game.state.date
4989 for i in range(GALSIZE):
4990 for j in range(GALSIZE):
4991 if game.state.galaxy[i][j].charted:
4992 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
4993 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
4994 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
4997 "Display the star chart."
4999 if (game.options & OPTION_AUTOSCAN):
5001 if not damaged(DRADIO):
5003 if game.lastchart < game.state.date and game.condition == "docked":
5004 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5006 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5007 if game.state.date > game.lastchart:
5008 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5009 prout(" 1 2 3 4 5 6 7 8")
5010 for i in range(GALSIZE):
5011 proutn("%d |" % (i+1))
5012 for j in range(GALSIZE):
5013 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5017 if game.state.galaxy[i][j].supernova:
5019 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5021 elif game.state.galaxy[i][j].charted:
5022 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5026 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5034 def sectscan(goodScan, i, j):
5035 "Light up an individual dot in a sector."
5036 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5037 textcolor({"green":GREEN,
5041 "dead":BROWN}[game.condition])
5042 if game.quad[i][j] != game.ship:
5044 proutn("%c " % game.quad[i][j])
5050 "Emit status report lines"
5051 if not req or req == 1:
5052 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5053 % (game.state.date, game.state.remtime))
5054 if not req or req == 2:
5055 if game.condition != "docked":
5057 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5058 (game.condition.upper(), sum(map(lambda x: x > 0, game.damage))))
5059 if not req or req == 3:
5060 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5061 if not req or req == 4:
5062 if damaged(DLIFSUP):
5063 if game.condition == "docked":
5064 s = _("DAMAGED, Base provides")
5066 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5069 prstat(_("Life Support"), s)
5070 if not req or req == 5:
5071 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5072 if not req or req == 6:
5074 if game.icrystl and (game.options & OPTION_SHOWME):
5075 extra = _(" (have crystals)")
5076 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5077 if not req or req == 7:
5078 prstat(_("Torpedoes"), "%d" % (game.torps))
5079 if not req or req == 8:
5080 if damaged(DSHIELD):
5086 data = _(" %d%% %.1f units") \
5087 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5088 prstat(_("Shields"), s+data)
5089 if not req or req == 9:
5090 prstat(_("Klingons Left"), "%d" \
5091 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5092 if not req or req == 10:
5093 if game.options & OPTION_WORLDS:
5094 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5095 if plnet and plnet.inhabited:
5096 prstat(_("Major system"), plnet.name)
5098 prout(_("Sector is uninhabited"))
5099 elif not req or req == 11:
5100 attackreport(not req)
5103 "Request specified status data, a historical relic from slow TTYs."
5104 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5105 while scanner.next() == "IHEOL":
5106 proutn(_("Information desired? "))
5108 if scanner.token in requests:
5109 status(requests.index(scanner.token))
5111 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5112 prout((" date, condition, position, lsupport, warpfactor,"))
5113 prout((" energy, torpedoes, shields, klingons, system, time."))
5118 if damaged(DSRSENS):
5119 # Allow base's sensors if docked
5120 if game.condition != "docked":
5121 prout(_(" S.R. SENSORS DAMAGED!"))
5124 prout(_(" [Using Base's sensors]"))
5126 prout(_(" Short-range scan"))
5127 if goodScan and not damaged(DRADIO):
5128 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5129 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5130 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5131 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5132 prout(" 1 2 3 4 5 6 7 8 9 10")
5133 if game.condition != "docked":
5135 for i in range(QUADSIZE):
5136 proutn("%2d " % (i+1))
5137 for j in range(QUADSIZE):
5138 sectscan(goodScan, i, j)
5142 "Use computer to get estimated time of arrival for a warp jump."
5143 w1 = Coord(); w2 = Coord()
5145 if damaged(DCOMPTR):
5146 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5149 if scanner.next() != "IHREAL":
5152 proutn(_("Destination quadrant and/or sector? "))
5153 if scanner.next()!="IHREAL":
5156 w1.j = int(scanner.real-0.5)
5157 if scanner.next() != "IHREAL":
5160 w1.i = int(scanner.real-0.5)
5161 if scanner.next() == "IHREAL":
5162 w2.j = int(scanner.real-0.5)
5163 if scanner.next() != "IHREAL":
5166 w2.i = int(scanner.real-0.5)
5168 if game.quadrant.j>w1.i:
5172 if game.quadrant.i>w1.j:
5176 if not w1.valid_quadrant() or not w2.valid_sector():
5179 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5180 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5183 prout(_("Answer \"no\" if you don't know the value:"))
5186 proutn(_("Time or arrival date? "))
5187 if scanner.next()=="IHREAL":
5188 ttime = scanner.real
5189 if ttime > game.state.date:
5190 ttime -= game.state.date # Actually a star date
5191 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5192 if ttime <= 1e-10 or twarp > 10:
5193 prout(_("We'll never make it, sir."))
5200 proutn(_("Warp factor? "))
5201 if scanner.next()== "IHREAL":
5203 twarp = scanner.real
5204 if twarp<1.0 or twarp > 10.0:
5208 prout(_("Captain, certainly you can give me one of these."))
5211 ttime = (10.0*dist)/twarp**2
5212 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5213 if tpower >= game.energy:
5214 prout(_("Insufficient energy, sir."))
5215 if not game.shldup or tpower > game.energy*2.0:
5218 proutn(_("New warp factor to try? "))
5219 if scanner.next() == "IHREAL":
5221 twarp = scanner.real
5222 if twarp<1.0 or twarp > 10.0:
5230 prout(_("But if you lower your shields,"))
5231 proutn(_("remaining"))
5234 proutn(_("Remaining"))
5235 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5237 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5239 prout(_("Any warp speed is adequate."))
5241 prout(_("Minimum warp needed is %.2f,") % (twarp))
5242 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5243 if game.state.remtime < ttime:
5244 prout(_("Unfortunately, the Federation will be destroyed by then."))
5246 prout(_("You'll be taking risks at that speed, Captain"))
5247 if (game.isatb==1 and game.state.kscmdr == w1 and \
5248 scheduled(FSCDBAS)< ttime+game.state.date) or \
5249 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5250 prout(_("The starbase there will be destroyed by then."))
5251 proutn(_("New warp factor to try? "))
5252 if scanner.next() == "IHREAL":
5254 twarp = scanner.real
5255 if twarp<1.0 or twarp > 10.0:
5263 # Code from setup.c begins here
5266 "Issue a historically correct banner."
5268 prout(_("-SUPER- STAR TREK"))
5270 # From the FORTRAN original
5271 # prout(_("Latest update-21 Sept 78"))
5277 scanner.push("emsave.trk")
5278 key = scanner.next()
5280 proutn(_("File name: "))
5281 key = scanner.next()
5282 if key != "IHALPHA":
5285 if '.' not in scanner.token:
5286 scanner.token += ".trk"
5288 fp = open(scanner.token, "wb")
5290 prout(_("Can't freeze game as file %s") % scanner.token)
5292 cPickle.dump(game, fp)
5297 "Retrieve saved game."
5300 key = scanner.next()
5302 proutn(_("File name: "))
5303 key = scanner.next()
5304 if key != "IHALPHA":
5307 if '.' not in scanner.token:
5308 scanner.token += ".trk"
5310 fp = open(scanner.token, "rb")
5312 prout(_("Can't thaw game in %s") % scanner.token)
5314 game = cPickle.load(fp)
5319 # I used <http://www.memory-alpha.org> to find planets
5320 # with references in ST:TOS. Earth and the Alpha Centauri
5321 # Colony have been omitted.
5323 # Some planets marked Class G and P here will be displayed as class M
5324 # because of the way planets are generated. This is a known bug.
5327 _("Andoria (Fesoan)"), # several episodes
5328 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5329 _("Vulcan (T'Khasi)"), # many episodes
5330 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5331 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5332 _("Ardana"), # TOS: "The Cloud Minders"
5333 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5334 _("Gideon"), # TOS: "The Mark of Gideon"
5335 _("Aldebaran III"), # TOS: "The Deadly Years"
5336 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5337 _("Altair IV"), # TOS: "Amok Time
5338 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5339 _("Benecia"), # TOS: "The Conscience of the King"
5340 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5341 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5342 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5343 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5344 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5345 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5346 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5347 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5348 _("Ingraham B"), # TOS: "Operation: Annihilate"
5349 _("Janus IV"), # TOS: "The Devil in the Dark"
5350 _("Makus III"), # TOS: "The Galileo Seven"
5351 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5352 _("Omega IV"), # TOS: "The Omega Glory"
5353 _("Regulus V"), # TOS: "Amok Time
5354 _("Deneva"), # TOS: "Operation -- Annihilate!"
5355 # Worlds from BSD Trek
5356 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5357 _("Beta III"), # TOS: "The Return of the Archons"
5358 _("Triacus"), # TOS: "And the Children Shall Lead",
5359 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5361 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5362 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5363 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5364 # _("Izar"), # TOS: "Whom Gods Destroy"
5365 # _("Tiburon"), # TOS: "The Way to Eden"
5366 # _("Merak II"), # TOS: "The Cloud Minders"
5367 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5368 # _("Iotia"), # TOS: "A Piece of the Action"
5372 _("S. R. Sensors"), \
5373 _("L. R. Sensors"), \
5375 _("Photon Tubes"), \
5376 _("Life Support"), \
5377 _("Warp Engines"), \
5378 _("Impulse Engines"), \
5380 _("Subspace Radio"), \
5381 _("Shuttle Craft"), \
5383 _("Navigation System"), \
5385 _("Shield Control"), \
5391 "Prepare to play, set up cosmos."
5393 # Decide how many of everything
5395 return # frozen game
5396 # Prepare the Enterprise
5397 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5399 game.state.crew = FULLCREW
5400 game.energy = game.inenrg = 5000.0
5401 game.shield = game.inshld = 2500.0
5404 game.quadrant = randplace(GALSIZE)
5405 game.sector = randplace(QUADSIZE)
5406 game.torps = game.intorps = 10
5407 game.nprobes = randrange(2, 5)
5409 for i in range(NDEVICES):
5410 game.damage[i] = 0.0
5411 # Set up assorted game parameters
5412 game.battle = Coord()
5413 game.state.date = game.indate = 100.0 * randreal(20, 51)
5414 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5415 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5416 game.isatb = game.state.nplankl = 0
5417 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5418 game.iscraft = "onship"
5423 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5425 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5427 game.state.planets = [] # Planet information
5428 game.state.baseq = [] # Base quadrant coordinates
5429 game.state.kcmdr = [] # Commander quadrant coordinates
5430 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5432 # Starchart is functional but we've never seen it
5433 game.lastchart = FOREVER
5434 # Put stars in the galaxy
5436 for i in range(GALSIZE):
5437 for j in range(GALSIZE):
5438 k = randrange(1, QUADSIZE**2/10+1)
5440 game.state.galaxy[i][j].stars = k
5441 # Locate star bases in galaxy
5442 for i in range(game.inbase):
5445 w = randplace(GALSIZE)
5446 if not game.state.galaxy[w.i][w.j].starbase:
5449 # C version: for (j = i-1; j > 0; j--)
5450 # so it did them in the opposite order.
5451 for j in range(1, i):
5452 # Improved placement algorithm to spread out bases
5453 distq = (w - game.state.baseq[j]).distance()
5454 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5457 prout("=== Abandoning base #%d at %s" % (i, w))
5459 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5461 prout("=== Saving base #%d, close to #%d" % (i, j))
5464 game.state.baseq.append(w)
5465 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5466 # Position ordinary Klingon Battle Cruisers
5468 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5469 if klumper > MAXKLQUAD:
5473 klump = (1.0 - r*r)*klumper
5478 w = randplace(GALSIZE)
5479 if not game.state.galaxy[w.i][w.j].supernova and \
5480 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5482 game.state.galaxy[w.i][w.j].klingons += int(klump)
5485 # Position Klingon Commander Ships
5486 for i in range(game.incom):
5488 w = randplace(GALSIZE)
5489 if not welcoming(w) or w in game.state.kcmdr:
5491 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5493 game.state.galaxy[w.i][w.j].klingons += 1
5494 game.state.kcmdr.append(w)
5495 # Locate planets in galaxy
5496 for i in range(game.inplan):
5498 w = randplace(GALSIZE)
5499 if game.state.galaxy[w.i][w.j].planet == None:
5503 new.crystals = "absent"
5504 if (game.options & OPTION_WORLDS) and i < NINHAB:
5505 new.pclass = "M" # All inhabited planets are class M
5506 new.crystals = "absent"
5508 new.name = systnames[i]
5509 new.inhabited = True
5511 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5513 new.crystals = "present"
5514 new.known = "unknown"
5515 new.inhabited = False
5516 game.state.galaxy[w.i][w.j].planet = new
5517 game.state.planets.append(new)
5519 for i in range(game.state.nromrem):
5520 w = randplace(GALSIZE)
5521 game.state.galaxy[w.i][w.j].romulans += 1
5522 # Place the Super-Commander if needed
5523 if game.state.nscrem > 0:
5525 w = randplace(GALSIZE)
5528 game.state.kscmdr = w
5529 game.state.galaxy[w.i][w.j].klingons += 1
5530 # Initialize times for extraneous events
5531 schedule(FSNOVA, expran(0.5 * game.intime))
5532 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5533 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5534 schedule(FBATTAK, expran(0.3*game.intime))
5536 if game.state.nscrem:
5537 schedule(FSCMOVE, 0.2777)
5542 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5543 schedule(FDISTR, expran(1.0 + game.intime))
5548 # Place thing (in tournament game, we don't want one!)
5549 # New in SST2K: never place the Thing near a starbase.
5550 # This makes sense and avoids a special case in the old code.
5552 if game.tourn is None:
5554 thing = randplace(GALSIZE)
5555 if thing not in game.state.baseq:
5558 game.state.snap = False
5559 if game.skill == SKILL_NOVICE:
5560 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5561 prout(_("a deadly Klingon invasion force. As captain of the United"))
5562 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5563 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5564 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5565 prout(_("your mission. As you proceed you may be given more time."))
5567 prout(_("You will have %d supporting starbases.") % (game.inbase))
5568 proutn(_("Starbase locations- "))
5570 prout(_("Stardate %d.") % int(game.state.date))
5572 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5573 prout(_("An unknown number of Romulans."))
5574 if game.state.nscrem:
5575 prout(_("And one (GULP) Super-Commander."))
5576 prout(_("%d stardates.") % int(game.intime))
5577 proutn(_("%d starbases in ") % game.inbase)
5578 for i in range(game.inbase):
5579 proutn(`game.state.baseq[i]`)
5582 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5583 proutn(_(" Sector %s") % game.sector)
5585 prout(_("Good Luck!"))
5586 if game.state.nscrem:
5587 prout(_(" YOU'LL NEED IT."))
5590 setwnd(message_window)
5592 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5594 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5595 attack(torps_ok=False)
5598 "Choose your game type."
5600 game.tourn = game.length = 0
5602 game.skill = SKILL_NONE
5604 # if not scanner.inqueue: # Can start with command line options
5605 proutn(_("Would you like a regular, tournament, or saved game? "))
5607 if scanner.sees("tournament"):
5608 while scanner.next() == "IHEOL":
5609 proutn(_("Type in tournament number-"))
5610 if scanner.real == 0:
5612 continue # We don't want a blank entry
5613 game.tourn = int(round(scanner.real))
5614 random.seed(scanner.real)
5616 logfp.write("# random.seed(%d)\n" % scanner.real)
5618 if scanner.sees("saved") or scanner.sees("frozen"):
5622 if game.passwd == None:
5624 if not game.alldone:
5625 game.thawed = True # No plaque if not finished
5629 if scanner.sees("regular"):
5631 proutn(_("What is \"%s\"? ") % scanner.token)
5633 while game.length==0 or game.skill==SKILL_NONE:
5634 if scanner.next() == "IHALPHA":
5635 if scanner.sees("short"):
5637 elif scanner.sees("medium"):
5639 elif scanner.sees("long"):
5641 elif scanner.sees("novice"):
5642 game.skill = SKILL_NOVICE
5643 elif scanner.sees("fair"):
5644 game.skill = SKILL_FAIR
5645 elif scanner.sees("good"):
5646 game.skill = SKILL_GOOD
5647 elif scanner.sees("expert"):
5648 game.skill = SKILL_EXPERT
5649 elif scanner.sees("emeritus"):
5650 game.skill = SKILL_EMERITUS
5652 proutn(_("What is \""))
5653 proutn(scanner.token)
5658 proutn(_("Would you like a Short, Medium, or Long game? "))
5659 elif game.skill == SKILL_NONE:
5660 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5661 # Choose game options -- added by ESR for SST2K
5662 if scanner.next() != "IHALPHA":
5664 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5666 if scanner.sees("plain"):
5667 # Approximates the UT FORTRAN version.
5668 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5669 game.options |= OPTION_PLAIN
5670 elif scanner.sees("almy"):
5671 # Approximates Tom Almy's version.
5672 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5673 game.options |= OPTION_ALMY
5674 elif scanner.sees("fancy") or scanner.sees("\n"):
5676 elif len(scanner.token):
5677 proutn(_("What is \"%s\"?") % scanner.token)
5678 game.options &=~ OPTION_COLOR
5680 if game.passwd == "debug":
5682 prout("=== Debug mode enabled.")
5683 # Use parameters to generate initial values of things
5684 game.damfac = 0.5 * game.skill
5685 game.inbase = randrange(BASEMIN, BASEMAX+1)
5687 if game.options & OPTION_PLANETS:
5688 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5689 if game.options & OPTION_WORLDS:
5690 game.inplan += int(NINHAB)
5691 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5692 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5693 game.state.remtime = 7.0 * game.length
5694 game.intime = game.state.remtime
5695 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5696 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5697 game.state.remres = (game.inkling+4*game.incom)*game.intime
5698 game.inresor = game.state.remres
5699 if game.inkling > 50:
5700 game.state.inbase += 1
5703 def dropin(iquad=None):
5704 "Drop a feature on a random dot in the current quadrant."
5706 w = randplace(QUADSIZE)
5707 if game.quad[w.i][w.j] == '.':
5709 if iquad is not None:
5710 game.quad[w.i][w.j] = iquad
5714 "Update our alert status."
5715 game.condition = "green"
5716 if game.energy < 1000.0:
5717 game.condition = "yellow"
5718 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5719 game.condition = "red"
5721 game.condition="dead"
5724 "Drop new Klingon into current quadrant."
5725 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5728 "Sort enemies by distance so 'nearest' is meaningful."
5729 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
5732 "Set up a new state of quadrant, for when we enter or re-enter it."
5735 game.neutz = game.inorbit = game.landed = False
5736 game.ientesc = game.iseenit = False
5737 # Create a blank quadrant
5738 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5740 # Attempt to escape Super-commander, so tbeam back!
5743 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5744 # cope with supernova
5747 game.klhere = q.klingons
5748 game.irhere = q.romulans
5750 game.quad[game.sector.i][game.sector.j] = game.ship
5753 # Position ordinary Klingons
5754 for i in range(game.klhere):
5756 # If we need a commander, promote a Klingon
5757 for cmdr in game.state.kcmdr:
5758 if cmdr == game.quadrant:
5759 e = game.enemies[game.klhere-1]
5760 game.quad[e.location.i][e.location.j] = 'C'
5761 e.power = randreal(950,1350) + 50.0*game.skill
5763 # If we need a super-commander, promote a Klingon
5764 if game.quadrant == game.state.kscmdr:
5766 game.quad[e.location.i][e.location.j] = 'S'
5767 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5768 game.iscate = (game.state.remkl > 1)
5769 # Put in Romulans if needed
5770 for i in range(q.romulans):
5771 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5772 # If quadrant needs a starbase, put it in
5774 game.base = dropin('B')
5775 # If quadrant needs a planet, put it in
5777 game.iplnet = q.planet
5778 if not q.planet.inhabited:
5779 game.plnet = dropin('P')
5781 game.plnet = dropin('@')
5782 # Check for condition
5785 if game.irhere > 0 and game.klhere == 0:
5787 if not damaged(DRADIO):
5789 prout(_("LT. Uhura- \"Captain, an urgent message."))
5790 prout(_(" I'll put it on audio.\" CLICK"))
5792 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5793 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5794 # Put in THING if needed
5795 if thing == game.quadrant:
5796 Enemy(etype='?', loc=dropin(),
5797 power=randreal(6000,6500.0)+250.0*game.skill)
5798 if not damaged(DSRSENS):
5800 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5801 prout(_(" Please examine your short-range scan.\""))
5802 # Decide if quadrant needs a Tholian; lighten up if skill is low
5803 if game.options & OPTION_THOLIAN:
5804 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5805 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5806 (game.skill > SKILL_GOOD and withprob(0.08)):
5809 w.i = withprob(0.5) * (QUADSIZE-1)
5810 w.j = withprob(0.5) * (QUADSIZE-1)
5811 if game.quad[w.i][w.j] == '.':
5813 game.tholian = Enemy(etype='T', loc=w,
5814 power=randrange(100, 500) + 25.0*game.skill)
5815 # Reserve unoccupied corners
5816 if game.quad[0][0]=='.':
5817 game.quad[0][0] = 'X'
5818 if game.quad[0][QUADSIZE-1]=='.':
5819 game.quad[0][QUADSIZE-1] = 'X'
5820 if game.quad[QUADSIZE-1][0]=='.':
5821 game.quad[QUADSIZE-1][0] = 'X'
5822 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5823 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5825 # And finally the stars
5826 for i in range(q.stars):
5828 # Put in a few black holes
5829 for i in range(1, 3+1):
5832 # Take out X's in corners if Tholian present
5834 if game.quad[0][0]=='X':
5835 game.quad[0][0] = '.'
5836 if game.quad[0][QUADSIZE-1]=='X':
5837 game.quad[0][QUADSIZE-1] = '.'
5838 if game.quad[QUADSIZE-1][0]=='X':
5839 game.quad[QUADSIZE-1][0] = '.'
5840 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5841 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5844 "Set the self-destruct password."
5845 if game.options & OPTION_PLAIN:
5848 proutn(_("Please type in a secret password- "))
5850 game.passwd = scanner.token
5851 if game.passwd != None:
5855 game.passwd += chr(ord('a')+randrange(26))
5856 game.passwd += chr(ord('a')+randrange(26))
5857 game.passwd += chr(ord('a')+randrange(26))
5859 # Code from sst.c begins here
5862 ("SRSCAN", OPTION_TTY),
5863 ("STATUS", OPTION_TTY),
5864 ("REQUEST", OPTION_TTY),
5865 ("LRSCAN", OPTION_TTY),
5878 ("SENSORS", OPTION_PLANETS),
5879 ("ORBIT", OPTION_PLANETS),
5880 ("TRANSPORT", OPTION_PLANETS),
5881 ("MINE", OPTION_PLANETS),
5882 ("CRYSTALS", OPTION_PLANETS),
5883 ("SHUTTLE", OPTION_PLANETS),
5884 ("PLANETS", OPTION_PLANETS),
5889 ("PROBE", OPTION_PROBE),
5891 ("FREEZE", 0), # Synonym for SAVE
5897 ("SOS", 0), # Synonym for MAYDAY
5898 ("CALL", 0), # Synonym for MAYDAY
5905 "Generate a list of legal commands."
5906 prout(_("LEGAL COMMANDS ARE:"))
5908 for (key, opt) in commands:
5909 if not opt or (opt & game.options):
5910 proutn("%-12s " % key)
5912 if emitted % 5 == 4:
5917 "Browse on-line help."
5918 key = scanner.next()
5921 setwnd(prompt_window)
5922 proutn(_("Help on what command? "))
5923 key = scanner.next()
5924 setwnd(message_window)
5927 cmds = map(lambda x: x[0], commands)
5928 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
5935 cmd = scanner.token.upper()
5936 for directory in docpath:
5938 fp = open(os.path.join(directory, "sst.doc"), "r")
5943 prout(_("Spock- \"Captain, that information is missing from the"))
5944 prout(_(" computer. You need to find sst.doc and put it somewhere"))
5945 proutn(_(" in these directories: %s") % ":".join(docpath))
5947 # This used to continue: "You need to find SST.DOC and put
5948 # it in the current directory."
5951 linebuf = fp.readline()
5953 prout(_("Spock- \"Captain, there is no information on that command.\""))
5956 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5957 linebuf = linebuf[3:].strip()
5958 if cmd.upper() == linebuf:
5961 prout(_("Spock- \"Captain, I've found the following information:\""))
5964 linebuf = fp.readline()
5965 if "******" in linebuf:
5971 "Command-interpretation loop."
5972 while True: # command loop
5974 while True: # get a command
5976 game.optime = game.justin = False
5978 setwnd(prompt_window)
5981 if scanner.next() == "IHEOL":
5982 if game.options & OPTION_CURSES:
5985 elif scanner.token == "":
5989 setwnd(message_window)
5991 abandon_passed = False
5992 for (cmd, opt) in commands:
5993 # commands after ABANDON cannot be abbreviated
5994 if cmd == "ABANDON":
5995 abandon_passed = True
5996 if cmd == scanner.token.upper() or (not abandon_passed \
5997 and cmd.startswith(scanner.token.upper())):
6004 if cmd == "SRSCAN": # srscan
6006 elif cmd == "STATUS": # status
6008 elif cmd == "REQUEST": # status request
6010 elif cmd == "LRSCAN": # long range scan
6011 lrscan(silent=False)
6012 elif cmd == "PHASERS": # phasers
6016 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6020 elif cmd == "MOVE": # move under warp
6021 warp(wcourse=None, involuntary=False)
6022 elif cmd == "SHIELDS": # shields
6023 doshield(shraise=False)
6026 game.shldchg = False
6027 elif cmd == "DOCK": # dock at starbase
6030 attack(torps_ok=False)
6031 elif cmd == "DAMAGES": # damage reports
6033 elif cmd == "CHART": # chart
6035 elif cmd == "IMPULSE": # impulse
6037 elif cmd == "REST": # rest
6041 elif cmd == "WARP": # warp
6043 elif cmd == "SCORE": # score
6045 elif cmd == "SENSORS": # sensors
6047 elif cmd == "ORBIT": # orbit
6051 elif cmd == "TRANSPORT": # transport "beam"
6053 elif cmd == "MINE": # mine
6057 elif cmd == "CRYSTALS": # crystals
6061 elif cmd == "SHUTTLE": # shuttle
6065 elif cmd == "PLANETS": # Planet list
6067 elif cmd == "REPORT": # Game Report
6069 elif cmd == "COMPUTER": # use COMPUTER!
6071 elif cmd == "COMMANDS":
6073 elif cmd == "EMEXIT": # Emergency exit
6074 clrscr() # Hide screen
6075 freeze(True) # forced save
6076 raise SystemExit,1 # And quick exit
6077 elif cmd == "PROBE":
6078 probe() # Launch probe
6081 elif cmd == "ABANDON": # Abandon Ship
6083 elif cmd == "DESTRUCT": # Self Destruct
6085 elif cmd == "SAVE": # Save Game
6088 if game.skill > SKILL_GOOD:
6089 prout(_("WARNING--Saved games produce no plaques!"))
6090 elif cmd == "DEATHRAY": # Try a desparation measure
6094 elif cmd == "DEBUGCMD": # What do we want for debug???
6096 elif cmd == "MAYDAY": # Call for help
6101 game.alldone = True # quit the game
6106 break # Game has ended
6107 if game.optime != 0.0:
6110 break # Events did us in
6111 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6114 if hitme and not game.justin:
6115 attack(torps_ok=True)
6118 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6129 "Emit the name of an enemy or feature."
6130 if type == 'R': s = _("Romulan")
6131 elif type == 'K': s = _("Klingon")
6132 elif type == 'C': s = _("Commander")
6133 elif type == 'S': s = _("Super-commander")
6134 elif type == '*': s = _("Star")
6135 elif type == 'P': s = _("Planet")
6136 elif type == 'B': s = _("Starbase")
6137 elif type == ' ': s = _("Black hole")
6138 elif type == 'T': s = _("Tholian")
6139 elif type == '#': s = _("Tholian web")
6140 elif type == '?': s = _("Stranger")
6141 elif type == '@': s = _("Inhabited World")
6142 else: s = "Unknown??"
6145 def crmena(stars, enemy, loctype, w):
6146 "Emit the name of an enemy and his location."
6150 buf += cramen(enemy) + _(" at ")
6151 if loctype == "quadrant":
6152 buf += _("Quadrant ")
6153 elif loctype == "sector":
6158 "Emit our ship name."
6159 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6162 "Emit a line of stars"
6163 prouts("******************************************************")
6167 return -avrage*math.log(1e-7 + randreal())
6169 def randplace(size):
6170 "Choose a random location."
6172 w.i = randrange(size)
6173 w.j = randrange(size)
6183 # Get a token from the user
6186 # Fill the token quue if nothing here
6187 while not self.inqueue:
6189 if curwnd==prompt_window:
6191 setwnd(message_window)
6198 self.inqueue = line.lstrip().split() + ["\n"]
6199 # From here on in it's all looking at the queue
6200 self.token = self.inqueue.pop(0)
6201 if self.token == "\n":
6205 self.real = float(self.token)
6206 self.type = "IHREAL"
6211 self.token = self.token.lower()
6212 self.type = "IHALPHA"
6215 def append(self, tok):
6216 self.inqueue.append(tok)
6217 def push(self, tok):
6218 self.inqueue.insert(0, tok)
6222 # Demand input for next scan
6224 self.real = self.token = None
6226 # compares s to item and returns true if it matches to the length of s
6227 return s.startswith(self.token)
6229 # Round token value to nearest integer
6230 return int(round(scanner.real))
6234 if scanner.type != "IHREAL":
6237 s.i = scanner.int()-1
6239 if scanner.type != "IHREAL":
6242 s.j = scanner.int()-1
6245 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6248 "Yes-or-no confirmation."
6252 if scanner.token == 'y':
6254 if scanner.token == 'n':
6257 proutn(_("Please answer with \"y\" or \"n\": "))
6260 "Complain about unparseable input."
6263 prout(_("Beg your pardon, Captain?"))
6266 "Access to the internals for debugging."
6267 proutn("Reset levels? ")
6269 if game.energy < game.inenrg:
6270 game.energy = game.inenrg
6271 game.shield = game.inshld
6272 game.torps = game.intorps
6273 game.lsupres = game.inlsr
6274 proutn("Reset damage? ")
6276 for i in range(NDEVICES):
6277 if game.damage[i] > 0.0:
6278 game.damage[i] = 0.0
6279 proutn("Toggle debug flag? ")
6281 game.idebug = not game.idebug
6283 prout("Debug output ON")
6285 prout("Debug output OFF")
6286 proutn("Cause selective damage? ")
6288 for i in range(NDEVICES):
6289 proutn("Kill %s?" % device[i])
6291 key = scanner.next()
6292 if key == "IHALPHA" and scanner.sees("y"):
6293 game.damage[i] = 10.0
6294 proutn("Examine/change events? ")
6299 FSNOVA: "Supernova ",
6302 FBATTAK: "Base Attack ",
6303 FCDBAS: "Base Destroy ",
6304 FSCMOVE: "SC Move ",
6305 FSCDBAS: "SC Base Destroy ",
6306 FDSPROB: "Probe Move ",
6307 FDISTR: "Distress Call ",
6308 FENSLV: "Enslavement ",
6309 FREPRO: "Klingon Build ",
6311 for i in range(1, NEVENTS):
6314 proutn("%.2f" % (scheduled(i)-game.state.date))
6315 if i == FENSLV or i == FREPRO:
6317 proutn(" in %s" % ev.quadrant)
6322 key = scanner.next()
6326 elif key == "IHREAL":
6327 ev = schedule(i, scanner.real)
6328 if i == FENSLV or i == FREPRO:
6330 proutn("In quadrant- ")
6331 key = scanner.next()
6332 # "IHEOL" says to leave coordinates as they are
6335 prout("Event %d canceled, no x coordinate." % (i))
6338 w.i = int(round(scanner.real))
6339 key = scanner.next()
6341 prout("Event %d canceled, no y coordinate." % (i))
6344 w.j = int(round(scanner.real))
6347 proutn("Induce supernova here? ")
6349 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6352 if __name__ == '__main__':
6353 import getopt, socket
6355 global line, thing, game
6359 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6360 if os.getenv("TERM"):
6361 game.options |= OPTION_CURSES
6363 game.options |= OPTION_TTY
6364 seed = int(time.time())
6365 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6367 for (switch, val) in options:
6370 replayfp = open(val, "r")
6372 sys.stderr.write("sst: can't open replay file %s\n" % val)
6375 line = replayfp.readline().strip()
6376 (leader, __, seed) = line.split()
6378 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6379 line = replayfp.readline().strip()
6380 arguments += line.split()[2:]
6383 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6385 game.options |= OPTION_TTY
6386 game.options &=~ OPTION_CURSES
6387 elif switch == '-s':
6389 elif switch == '-t':
6390 game.options |= OPTION_TTY
6391 game.options &=~ OPTION_CURSES
6392 elif switch == '-x':
6394 elif switch == '-V':
6395 print "SST2K", version
6398 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6400 # where to save the input in case of bugs
6401 if "TMPDIR" in os.environ:
6402 tmpdir = os.environ['TMPDIR']
6406 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6408 sys.stderr.write("sst: warning, can't open logfile\n")
6411 logfp.write("# seed %s\n" % seed)
6412 logfp.write("# options %s\n" % " ".join(arguments))
6413 logfp.write("# SST2K version %s\n" % version)
6414 logfp.write("# recorded by %s@%s on %s\n" % \
6415 (getpass.getuser(),socket.gethostname(),time.ctime()))
6417 scanner = sstscanner()
6418 map(scanner.append, arguments)
6421 while True: # Play a game
6422 setwnd(fullscreen_window)
6428 game.alldone = False
6436 if game.tourn and game.alldone:
6437 proutn(_("Do you want your score recorded?"))
6443 proutn(_("Do you want to play again? "))
6447 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6451 except KeyboardInterrupt: