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!"
137 self.name = None # string-valued if inhabited
138 self.quadrant = Coord() # quadrant located
139 self.pclass = None # could be ""M", "N", "O", or "destroyed"
140 self.crystals = "absent"# could be "mined", "present", "absent"
141 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
142 self.inhabited = False # is it inhabites?
150 self.starbase = False
153 self.supernova = False
155 self.status = "secure" # Could be "secure", "distressed", "enslaved"
163 def fill2d(size, fillfun):
164 "Fill an empty list in 2D."
166 for i in range(size):
168 for j in range(size):
169 lst[i].append(fillfun(i, j))
174 self.snap = False # snapshot taken
175 self.crew = 0 # crew complement
176 self.remkl = 0 # remaining klingons
177 self.nscrem = 0 # remaining super commanders
178 self.starkl = 0 # destroyed stars
179 self.basekl = 0 # destroyed bases
180 self.nromrem = 0 # Romulans remaining
181 self.nplankl = 0 # destroyed uninhabited planets
182 self.nworldkl = 0 # destroyed inhabited planets
183 self.planets = [] # Planet information
184 self.date = 0.0 # stardate
185 self.remres = 0 # remaining resources
186 self.remtime = 0 # remaining time
187 self.baseq = [] # Base quadrant coordinates
188 self.kcmdr = [] # Commander quadrant coordinates
189 self.kscmdr = Coord() # Supercommander quadrant coordinates
191 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
193 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
197 self.date = None # A real number
198 self.quadrant = None # A coord structure
201 OPTION_ALL = 0xffffffff
202 OPTION_TTY = 0x00000001 # old interface
203 OPTION_CURSES = 0x00000002 # new interface
204 OPTION_IOMODES = 0x00000003 # cover both interfaces
205 OPTION_PLANETS = 0x00000004 # planets and mining
206 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
207 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
208 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
209 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
210 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
211 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
212 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
213 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
214 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
215 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
216 OPTION_PLAIN = 0x01000000 # user chose plain game
217 OPTION_ALMY = 0x02000000 # user chose Almy variant
218 OPTION_COLOR = 0x04000000 # enable color display (experimental, ESR, 2010)
237 NDEVICES = 16 # Number of devices
247 return (game.damage[dev] != 0.0)
249 return not damaged(DRADIO) or game.condition=="docked"
251 # Define future events
252 FSPY = 0 # Spy event happens always (no future[] entry)
253 # can cause SC to tractor beam Enterprise
254 FSNOVA = 1 # Supernova
255 FTBEAM = 2 # Commander tractor beams Enterprise
256 FSNAP = 3 # Snapshot for time warp
257 FBATTAK = 4 # Commander attacks base
258 FCDBAS = 5 # Commander destroys base
259 FSCMOVE = 6 # Supercommander moves (might attack base)
260 FSCDBAS = 7 # Supercommander destroys base
261 FDSPROB = 8 # Move deep space probe
262 FDISTR = 9 # Emit distress call from an inhabited world
263 FENSLV = 10 # Inhabited word is enslaved */
264 FREPRO = 11 # Klingons build a ship in an enslaved system
267 # Abstract out the event handling -- underlying data structures will change
268 # when we implement stateful events
269 def findevent(evtype):
270 return game.future[evtype]
273 def __init__(self, etype=None, loc=None, power=None):
275 self.location = Coord()
278 self.power = power # enemy energy level
279 game.enemies.append(self)
281 motion = (loc != self.location)
282 if self.location.i is not None and self.location.j is not None:
285 game.quad[self.location.i][self.location.j] = '#'
287 game.quad[self.location.i][self.location.j] = '.'
289 self.location = copy.copy(loc)
290 game.quad[self.location.i][self.location.j] = self.type
291 self.kdist = self.kavgd = (game.sector - loc).distance()
293 self.location = Coord()
294 self.kdist = self.kavgd = None
295 game.enemies.remove(self)
298 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
302 self.options = None # Game options
303 self.state = Snapshot() # A snapshot structure
304 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
305 self.quad = None # contents of our quadrant
306 self.damage = [0.0] * NDEVICES # damage encountered
307 self.future = [] # future events
311 self.future.append(Event())
312 self.passwd = None # Self Destruct password
314 self.quadrant = None # where we are in the large
315 self.sector = None # where we are in the small
316 self.tholian = None # Tholian enemy object
317 self.base = None # position of base in current quadrant
318 self.battle = None # base coordinates being attacked
319 self.plnet = None # location of planet in quadrant
320 self.gamewon = False # Finished!
321 self.ididit = False # action taken -- allows enemy to attack
322 self.alive = False # we are alive (not killed)
323 self.justin = False # just entered quadrant
324 self.shldup = False # shields are up
325 self.shldchg = False # shield is changing (affects efficiency)
326 self.iscate = False # super commander is here
327 self.ientesc = False # attempted escape from supercommander
328 self.resting = False # rest time
329 self.icraft = False # Kirk in Galileo
330 self.landed = False # party on planet (true), on ship (false)
331 self.alldone = False # game is now finished
332 self.neutz = False # Romulan Neutral Zone
333 self.isarmed = False # probe is armed
334 self.inorbit = False # orbiting a planet
335 self.imine = False # mining
336 self.icrystl = False # dilithium crystals aboard
337 self.iseenit = False # seen base attack report
338 self.thawed = False # thawed game
339 self.condition = None # "green", "yellow", "red", "docked", "dead"
340 self.iscraft = None # "onship", "offship", "removed"
341 self.skill = None # Player skill level
342 self.inkling = 0 # initial number of klingons
343 self.inbase = 0 # initial number of bases
344 self.incom = 0 # initial number of commanders
345 self.inscom = 0 # initial number of commanders
346 self.inrom = 0 # initial number of commanders
347 self.instar = 0 # initial stars
348 self.intorps = 0 # initial/max torpedoes
349 self.torps = 0 # number of torpedoes
350 self.ship = 0 # ship type -- 'E' is Enterprise
351 self.abandoned = 0 # count of crew abandoned in space
352 self.length = 0 # length of game
353 self.klhere = 0 # klingons here
354 self.casual = 0 # causalties
355 self.nhelp = 0 # calls for help
356 self.nkinks = 0 # count of energy-barrier crossings
357 self.iplnet = None # planet # in quadrant
358 self.inplan = 0 # initial planets
359 self.irhere = 0 # Romulans in quadrant
360 self.isatb = 0 # =2 if super commander is attacking base
361 self.tourn = None # tournament number
362 self.nprobes = 0 # number of probes available
363 self.inresor = 0.0 # initial resources
364 self.intime = 0.0 # initial time
365 self.inenrg = 0.0 # initial/max energy
366 self.inshld = 0.0 # initial/max shield
367 self.inlsr = 0.0 # initial life support resources
368 self.indate = 0.0 # initial date
369 self.energy = 0.0 # energy level
370 self.shield = 0.0 # shield level
371 self.warpfac = 0.0 # warp speed
372 self.lsupres = 0.0 # life support reserves
373 self.optime = 0.0 # time taken by current operation
374 self.damfac = 0.0 # damage factor
375 self.lastchart = 0.0 # time star chart was last updated
376 self.cryprob = 0.0 # probability that crystal will work
377 self.probe = None # object holding probe course info
378 self.height = 0.0 # height of orbit around planet
379 self.score = 0.0 # overall score
380 self.perdate = 0.0 # rate of kills
381 self.idebug = False # Debugging instrumentation enabled?
383 # Stas thinks this should be (C expression):
384 # game.state.remkl + len(game.state.kcmdr) > 0 ?
385 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
386 # He says the existing expression is prone to divide-by-zero errors
387 # after killing the last klingon when score is shown -- perhaps also
388 # if the only remaining klingon is SCOM.
389 self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.state.kcmdr))
415 return random.random() < p
417 def randrange(*args):
418 return random.randrange(*args)
423 v *= args[0] # from [0, args[0])
425 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
428 # Code from ai.c begins here
431 "Would this quadrant welcome another Klingon?"
432 return iq.valid_quadrant() and \
433 not game.state.galaxy[iq.i][iq.j].supernova and \
434 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
436 def tryexit(enemy, look, irun):
437 "A bad guy attempts to bug out."
439 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
440 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
441 if not welcoming(iq):
443 if enemy.type == 'R':
444 return False # Romulans cannot escape!
446 # avoid intruding on another commander's territory
447 if enemy.type == 'C':
448 if iq in game.state.kcmdr:
450 # refuse to leave if currently attacking starbase
451 if game.battle == game.quadrant:
453 # don't leave if over 1000 units of energy
454 if enemy.power > 1000.0:
456 # emit escape message and move out of quadrant.
457 # we know this if either short or long range sensors are working
458 if not damaged(DSRSENS) or not damaged(DLRSENS) or \
459 game.condition == "docked":
460 prout(crmena(True, enemy.type, "sector", enemy.location) + \
461 (_(" escapes to Quadrant %s (and regains strength).") % iq))
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 return True # success
484 # The bad-guy movement algorithm:
486 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
487 # If both are operating full strength, force is 1000. If both are damaged,
488 # force is -1000. Having shields down subtracts an additional 1000.
490 # 2. Enemy has forces equal to the energy of the attacker plus
491 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
492 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
494 # Attacker Initial energy levels (nominal):
495 # Klingon Romulan Commander Super-Commander
496 # Novice 400 700 1200
498 # Good 450 800 1300 1750
499 # Expert 475 850 1350 1875
500 # Emeritus 500 900 1400 2000
501 # VARIANCE 75 200 200 200
503 # Enemy vessels only move prior to their attack. In Novice - Good games
504 # only commanders move. In Expert games, all enemy vessels move if there
505 # is a commander present. In Emeritus games all enemy vessels move.
507 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
508 # forces are 1000 greater than Enterprise.
510 # Agressive action on average cuts the distance between the ship and
511 # the enemy to 1/4 the original.
513 # 4. At lower energy advantage, movement units are proportional to the
514 # advantage with a 650 advantage being to hold ground, 800 to move forward
515 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
517 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
518 # retreat, especially at high skill levels.
520 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
522 def movebaddy(enemy):
523 "Tactical movement for the bad guys."
527 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
528 if game.skill >= SKILL_EXPERT:
529 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
531 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
533 mdist = int(dist1 + 0.5) # Nearest integer distance
534 # If SC, check with spy to see if should hi-tail it
535 if enemy.type == 'S' and \
536 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
540 # decide whether to advance, retreat, or hold position
541 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
543 forces += 1000 # Good for enemy if shield is down!
544 if not damaged(DPHASER) or not damaged(DPHOTON):
545 if damaged(DPHASER): # phasers damaged
548 forces -= 0.2*(game.energy - 2500.0)
549 if damaged(DPHOTON): # photon torpedoes damaged
552 forces -= 50.0*game.torps
554 # phasers and photon tubes both out!
557 if forces <= 1000.0 and game.condition != "docked": # Typical situation
558 motion = ((forces + randreal(200))/150.0) - 5.0
560 if forces > 1000.0: # Very strong -- move in for kill
561 motion = (1.0 - randreal())**2 * dist1 + 1.0
562 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
563 motion -= game.skill*(2.0-randreal()**2)
565 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
566 # don't move if no motion
569 # Limit motion according to skill
570 if abs(motion) > game.skill:
575 # calculate preferred number of steps
576 nsteps = abs(int(motion))
577 if motion > 0 and nsteps > mdist:
578 nsteps = mdist # don't overshoot
579 if nsteps > QUADSIZE:
580 nsteps = QUADSIZE # This shouldn't be necessary
582 nsteps = 1 # This shouldn't be necessary
584 proutn("NSTEPS = %d:" % nsteps)
585 # Compute preferred values of delta X and Y
586 m = game.sector - enemy.location
587 if 2.0 * abs(m.i) < abs(m.j):
589 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
591 m = (motion * m).sgn()
592 goto = enemy.location
594 for ll in range(nsteps):
596 proutn(" %d" % (ll+1))
597 # Check if preferred position available
608 attempts = 0 # Settle mysterious hang problem
609 while attempts < 20 and not success:
611 if look.i < 0 or look.i >= QUADSIZE:
612 if motion < 0 and tryexit(enemy, look, irun):
614 if krawli == m.i or m.j == 0:
616 look.i = goto.i + krawli
618 elif look.j < 0 or look.j >= QUADSIZE:
619 if motion < 0 and tryexit(enemy, look, irun):
621 if krawlj == m.j or m.i == 0:
623 look.j = goto.j + krawlj
625 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
626 # See if enemy should ram ship
627 if game.quad[look.i][look.j] == game.ship and \
628 (enemy.type == 'C' or enemy.type == 'S'):
629 collision(rammed=True, enemy=enemy)
631 if krawli != m.i and m.j != 0:
632 look.i = goto.i + krawli
634 elif krawlj != m.j and m.i != 0:
635 look.j = goto.j + krawlj
638 break # we have failed
650 if not damaged(DSRSENS) or game.condition == "docked":
651 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
652 if enemy.kdist < dist1:
653 proutn(_(" advances to "))
655 proutn(_(" retreats to "))
656 prout("Sector %s." % goto)
659 "Sequence Klingon tactical movement."
662 # Figure out which Klingon is the commander (or Supercommander)
664 if game.quadrant in game.state.kcmdr:
665 for enemy in game.enemies:
666 if enemy.type == 'C':
668 if game.state.kscmdr == game.quadrant:
669 for enemy in game.enemies:
670 if enemy.type == 'S':
673 # If skill level is high, move other Klingons and Romulans too!
674 # Move these last so they can base their actions on what the
676 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
677 for enemy in game.enemies:
678 if enemy.type in ('K', 'R'):
682 def movescom(iq, avoid):
683 "Commander movement helper."
684 # Avoid quadrants with bases if we want to avoid Enterprise
685 if not welcoming(iq) or (avoid and iq in game.state.baseq):
687 if game.justin and not game.iscate:
690 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
691 game.state.kscmdr = iq
692 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
693 if game.state.kscmdr == game.quadrant:
694 # SC has scooted, remove him from current quadrant
699 for enemy in game.enemies:
700 if enemy.type == 'S':
704 if game.condition != "docked":
707 # check for a helpful planet
708 for i in range(game.inplan):
709 if game.state.planets[i].quadrant == game.state.kscmdr and \
710 game.state.planets[i].crystals == "present":
712 game.state.planets[i].pclass = "destroyed"
713 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
716 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
717 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
718 prout(_(" by the Super-commander.\""))
720 return True # looks good!
722 def supercommander():
723 "Move the Super Commander."
730 prout("== SUPERCOMMANDER")
731 # Decide on being active or passive
732 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 \
733 (game.state.date-game.indate) < 3.0)
734 if not game.iscate and avoid:
735 # compute move away from Enterprise
736 idelta = game.state.kscmdr-game.quadrant
737 if idelta.distance() > 2.0:
739 idelta.i = game.state.kscmdr.j-game.quadrant.j
740 idelta.j = game.quadrant.i-game.state.kscmdr.i
742 # compute distances to starbases
743 if not game.state.baseq:
747 sc = game.state.kscmdr
748 for (i, base) in enumerate(game.state.baseq):
749 basetbl.append((i, (base - sc).distance()))
750 if game.state.baseq > 1:
751 basetbl.sort(lambda x, y: cmp(x[1], y[1]))
752 # look for nearest base without a commander, no Enterprise, and
753 # without too many Klingons, and not already under attack.
754 ifindit = iwhichb = 0
755 for (i2, base) in enumerate(game.state.baseq):
756 i = basetbl[i2][0] # bug in original had it not finding nearest
757 if base == game.quadrant or base == game.battle or not welcoming(base):
759 # if there is a commander, and no other base is appropriate,
760 # we will take the one with the commander
761 for cmdr in game.state.kcmdr:
762 if base == cmdr and ifindit != 2:
766 else: # no commander -- use this one
771 return # Nothing suitable -- wait until next time
772 ibq = game.state.baseq[iwhichb]
773 # decide how to move toward base
774 idelta = ibq - game.state.kscmdr
775 # Maximum movement is 1 quadrant in either or both axes
776 idelta = idelta.sgn()
777 # try moving in both x and y directions
778 # there was what looked like a bug in the Almy C code here,
779 # but it might be this translation is just wrong.
780 iq = game.state.kscmdr + idelta
781 if not movescom(iq, avoid):
782 # failed -- try some other maneuvers
783 if idelta.i == 0 or idelta.j == 0:
786 iq.j = game.state.kscmdr.j + 1
787 if not movescom(iq, avoid):
788 iq.j = game.state.kscmdr.j - 1
791 iq.i = game.state.kscmdr.i + 1
792 if not movescom(iq, avoid):
793 iq.i = game.state.kscmdr.i - 1
796 # try moving just in x or y
797 iq.j = game.state.kscmdr.j
798 if not movescom(iq, avoid):
799 iq.j = game.state.kscmdr.j + idelta.j
800 iq.i = game.state.kscmdr.i
803 if len(game.state.baseq) == 0:
806 for ibq in game.state.baseq:
807 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
810 return # no, don't attack base!
813 schedule(FSCDBAS, randreal(1.0, 3.0))
814 if is_scheduled(FCDBAS):
815 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
816 if not communicating():
820 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
822 prout(_(" reports that it is under attack from the Klingon Super-commander."))
823 proutn(_(" It can survive until stardate %d.\"") \
824 % int(scheduled(FSCDBAS)))
827 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
831 game.optime = 0.0 # actually finished
833 # Check for intelligence report
834 if not game.idebug and \
836 (not communicating()) or \
837 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
840 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
841 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
846 if not game.tholian or game.justin:
849 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
852 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
855 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
858 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
862 # something is wrong!
863 game.tholian.move(None)
864 prout("***Internal error: Tholian in a bad spot.")
866 # do nothing if we are blocked
867 if game.quad[tid.i][tid.j] not in ('.', '#'):
869 here = copy.copy(game.tholian.location)
870 delta = (tid - game.tholian.location).sgn()
872 while here.i != tid.i:
874 if game.quad[here.i][here.j] == '.':
875 game.tholian.move(here)
877 while here.j != tid.j:
879 if game.quad[here.i][here.j] == '.':
880 game.tholian.move(here)
881 # check to see if all holes plugged
882 for i in range(QUADSIZE):
883 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
885 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
887 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
889 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
891 # All plugged up -- Tholian splits
892 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
894 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
895 game.tholian.move(None)
898 # Code from battle.c begins here
900 def doshield(shraise):
901 "Change shield status."
909 if scanner.sees("transfer"):
913 prout(_("Shields damaged and down."))
915 if scanner.sees("up"):
917 elif scanner.sees("down"):
920 proutn(_("Do you wish to change shield energy? "))
923 elif damaged(DSHIELD):
924 prout(_("Shields damaged and down."))
927 proutn(_("Shields are up. Do you want them down? "))
934 proutn(_("Shields are down. Do you want them up? "))
940 if action == "SHUP": # raise shields
942 prout(_("Shields already up."))
946 if game.condition != "docked":
948 prout(_("Shields raised."))
951 prout(_("Shields raising uses up last of energy."))
956 elif action == "SHDN":
958 prout(_("Shields already down."))
962 prout(_("Shields lowered."))
965 elif action == "NRG":
966 while scanner.next() != "IHREAL":
968 proutn(_("Energy to transfer to shields- "))
973 if nrg > game.energy:
974 prout(_("Insufficient ship energy."))
977 if game.shield+nrg >= game.inshld:
978 prout(_("Shield energy maximized."))
979 if game.shield+nrg > game.inshld:
980 prout(_("Excess energy requested returned to ship energy"))
981 game.energy -= game.inshld-game.shield
982 game.shield = game.inshld
984 if nrg < 0.0 and game.energy-nrg > game.inenrg:
985 # Prevent shield drain loophole
987 prout(_("Engineering to bridge--"))
988 prout(_(" Scott here. Power circuit problem, Captain."))
989 prout(_(" I can't drain the shields."))
992 if game.shield+nrg < 0:
993 prout(_("All shield energy transferred to ship."))
994 game.energy += game.shield
997 proutn(_("Scotty- \""))
999 prout(_("Transferring energy to shields.\""))
1001 prout(_("Draining energy from shields.\""))
1007 "Choose a device to damage, at random."
1009 105, # DSRSENS: short range scanners 10.5%
1010 105, # DLRSENS: long range scanners 10.5%
1011 120, # DPHASER: phasers 12.0%
1012 120, # DPHOTON: photon torpedoes 12.0%
1013 25, # DLIFSUP: life support 2.5%
1014 65, # DWARPEN: warp drive 6.5%
1015 70, # DIMPULS: impulse engines 6.5%
1016 145, # DSHIELD: deflector shields 14.5%
1017 30, # DRADIO: subspace radio 3.0%
1018 45, # DSHUTTL: shuttle 4.5%
1019 15, # DCOMPTR: computer 1.5%
1020 20, # NAVCOMP: navigation system 2.0%
1021 75, # DTRANSP: transporter 7.5%
1022 20, # DSHCTRL: high-speed shield controller 2.0%
1023 10, # DDRAY: death ray 1.0%
1024 30, # DDSP: deep-space probes 3.0%
1026 assert(sum(weights) == 1000)
1027 idx = randrange(1000)
1029 for (i, w) in enumerate(weights):
1033 return None # we should never get here
1035 def collision(rammed, enemy):
1036 "Collision handling fot rammong events."
1037 prouts(_("***RED ALERT! RED ALERT!"))
1039 prout(_("***COLLISION IMMINENT."))
1043 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1045 proutn(_(" rammed by "))
1048 proutn(crmena(False, enemy.type, "sector", enemy.location))
1050 proutn(_(" (original position)"))
1052 deadkl(enemy.location, enemy.type, game.sector)
1053 proutn("***" + crmshp() + " heavily damaged.")
1054 icas = randrange(10, 30)
1055 prout(_("***Sickbay reports %d casualties") % icas)
1057 game.state.crew -= icas
1058 # In the pre-SST2K version, all devices got equiprobably damaged,
1059 # which was silly. Instead, pick up to half the devices at
1060 # random according to our weighting table,
1061 ncrits = randrange(NDEVICES/2)
1065 if game.damage[dev] < 0:
1067 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1068 # Damage for at least time of travel!
1069 game.damage[dev] += game.optime + extradm
1071 prout(_("***Shields are down."))
1072 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1079 def torpedo(origin, bearing, dispersion, number, nburst):
1080 "Let a photon torpedo fly"
1081 if not damaged(DSRSENS) or game.condition == "docked":
1082 setwnd(srscan_window)
1084 setwnd(message_window)
1085 ac = bearing + 0.25*dispersion # dispersion is a random variable
1086 bullseye = (15.0 - bearing)*0.5235988
1087 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1088 bumpto = Coord(0, 0)
1089 # Loop to move a single torpedo
1090 setwnd(message_window)
1091 for step in range(1, QUADSIZE*2):
1092 if not track.next():
1095 if not w.valid_sector():
1097 iquad = game.quad[w.i][w.j]
1098 tracktorpedo(w, step, number, nburst, iquad)
1102 setwnd(message_window)
1103 if not damaged(DSRSENS) or game.condition == "docked":
1104 skip(1) # start new line after text track
1105 if iquad in ('E', 'F'): # Hit our ship
1107 prout(_("Torpedo hits %s.") % crmshp())
1108 hit = 700.0 + randreal(100) - \
1109 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1110 newcnd() # we're blown out of dock
1111 if game.landed or game.condition == "docked":
1112 return hit # Cheat if on a planet
1113 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1114 # is 143 degrees, which is almost exactly 4.8 clockface units
1115 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1117 bumpto = displacement.sector()
1118 if not bumpto.valid_sector():
1120 if game.quad[bumpto.i][bumpto.j] == ' ':
1123 if game.quad[bumpto.i][bumpto.j] != '.':
1124 # can't move into object
1126 game.sector = bumpto
1128 game.quad[w.i][w.j] = '.'
1129 game.quad[bumpto.i][bumpto.j] = iquad
1130 prout(_(" displaced by blast to Sector %s ") % bumpto)
1131 for enemy in game.enemies:
1132 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1135 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1137 if iquad in ('C', 'S') and withprob(0.05):
1138 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1139 prout(_(" torpedo neutralized."))
1141 for enemy in game.enemies:
1142 if w == enemy.location:
1144 kp = math.fabs(enemy.power)
1145 h1 = 700.0 + randrange(100) - \
1146 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1154 if enemy.power == 0:
1157 proutn(crmena(True, iquad, "sector", w))
1158 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1160 bumpto = displacement.sector()
1161 if not bumpto.valid_sector():
1162 prout(_(" damaged but not destroyed."))
1164 if game.quad[bumpto.i][bumpto.j] == ' ':
1165 prout(_(" buffeted into black hole."))
1166 deadkl(w, iquad, bumpto)
1167 if game.quad[bumpto.i][bumpto.j] != '.':
1168 prout(_(" damaged but not destroyed."))
1170 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1171 enemy.location = bumpto
1172 game.quad[w.i][w.j] = '.'
1173 game.quad[bumpto.i][bumpto.j] = iquad
1174 for enemy in game.enemies:
1175 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1178 elif iquad == 'B': # Hit a base
1180 prout(_("***STARBASE DESTROYED.."))
1181 game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
1182 game.quad[w.i][w.j] = '.'
1183 game.base.invalidate()
1184 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1
1185 game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1
1186 game.state.basekl += 1
1189 elif iquad == 'P': # Hit a planet
1190 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1191 game.state.nplankl += 1
1192 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1193 game.iplnet.pclass = "destroyed"
1195 game.plnet.invalidate()
1196 game.quad[w.i][w.j] = '.'
1198 # captain perishes on planet
1201 elif iquad == '@': # Hit an inhabited world -- very bad!
1202 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1203 game.state.nworldkl += 1
1204 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1205 game.iplnet.pclass = "destroyed"
1207 game.plnet.invalidate()
1208 game.quad[w.i][w.j] = '.'
1210 # captain perishes on planet
1212 prout(_("The torpedo destroyed an inhabited planet."))
1214 elif iquad == '*': # Hit a star
1218 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1220 elif iquad == '?': # Hit a thingy
1221 if not (game.options & OPTION_THINGY) or withprob(0.3):
1223 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1225 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1227 proutn(_("Mr. Spock-"))
1228 prouts(_(" \"Fascinating!\""))
1232 # Stas Sergeev added the possibility that
1233 # you can shove the Thingy and piss it off.
1234 # It then becomes an enemy and may fire at you.
1237 elif iquad == ' ': # Black hole
1239 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1241 elif iquad == '#': # hit the web
1243 prout(_("***Torpedo absorbed by Tholian web."))
1245 elif iquad == 'T': # Hit a Tholian
1246 h1 = 700.0 + randrange(100) - \
1247 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1250 game.quad[w.i][w.j] = '.'
1255 proutn(crmena(True, 'T', "sector", w))
1257 prout(_(" survives photon blast."))
1259 prout(_(" disappears."))
1260 game.tholian.move(None)
1261 game.quad[w.i][w.j] = '#'
1266 proutn("Don't know how to handle torpedo collision with ")
1267 proutn(crmena(True, iquad, "sector", w))
1272 prout(_("Torpedo missed."))
1276 "Critical-hit resolution."
1277 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1279 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1280 proutn(_("***CRITICAL HIT--"))
1281 # Select devices and cause damage
1287 # Cheat to prevent shuttle damage unless on ship
1288 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship")):
1291 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1292 game.damage[j] += extradm
1294 for (i, j) in enumerate(cdam):
1296 if skipcount % 3 == 2 and i < len(cdam)-1:
1301 prout(_(" damaged."))
1302 if damaged(DSHIELD) and game.shldup:
1303 prout(_("***Shields knocked down."))
1306 def attack(torps_ok):
1307 # bad guy attacks us
1308 # torps_ok == False forces use of phasers in an attack
1309 # game could be over at this point, check
1319 prout("=== ATTACK!")
1320 # Tholian gets to move before attacking
1323 # if you have just entered the RNZ, you'll get a warning
1324 if game.neutz: # The one chance not to be attacked
1327 # commanders get a chance to tac-move towards you
1328 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:
1330 # if no enemies remain after movement, we're done
1331 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing == game.quadrant and not thing.angered):
1333 # set up partial hits if attack happens during shield status change
1334 pfac = 1.0/game.inshld
1336 chgfac = 0.25 + randreal(0.5)
1338 # message verbosity control
1339 if game.skill <= SKILL_FAIR:
1341 for enemy in game.enemies:
1343 continue # too weak to attack
1344 # compute hit strength and diminish shield power
1346 # Increase chance of photon torpedos if docked or enemy energy is low
1347 if game.condition == "docked":
1349 if enemy.power < 500:
1351 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1353 # different enemies have different probabilities of throwing a torp
1354 usephasers = not torps_ok or \
1355 (enemy.type == 'K' and r > 0.0005) or \
1356 (enemy.type == 'C' and r > 0.015) or \
1357 (enemy.type == 'R' and r > 0.3) or \
1358 (enemy.type == 'S' and r > 0.07) or \
1359 (enemy.type == '?' and r > 0.05)
1360 if usephasers: # Enemy uses phasers
1361 if game.condition == "docked":
1362 continue # Don't waste the effort!
1363 attempt = True # Attempt to attack
1364 dustfac = randreal(0.8, 0.85)
1365 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1367 else: # Enemy uses photon torpedo
1368 # We should be able to make the bearing() method work here
1369 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1371 proutn(_("***TORPEDO INCOMING"))
1372 if not damaged(DSRSENS):
1373 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1376 dispersion = (randreal()+randreal())*0.5 - 0.5
1377 dispersion += 0.002*enemy.power*dispersion
1378 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1379 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1380 finish(FWON) # Klingons did themselves in!
1381 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1382 return # Supernova or finished
1385 # incoming phaser or torpedo, shields may dissipate it
1386 if game.shldup or game.shldchg or game.condition == "docked":
1387 # shields will take hits
1388 propor = pfac * game.shield
1389 if game.condition == "docked":
1393 hitsh = propor*chgfac*hit+1.0
1395 if absorb > game.shield:
1396 absorb = game.shield
1397 game.shield -= absorb
1399 # taking a hit blasts us out of a starbase dock
1400 if game.condition == "docked":
1402 # but the shields may take care of it
1403 if propor > 0.1 and hit < 0.005*game.energy:
1405 # hit from this opponent got through shields, so take damage
1407 proutn(_("%d unit hit") % int(hit))
1408 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1409 proutn(_(" on the ") + crmshp())
1410 if not damaged(DSRSENS) and usephasers:
1411 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1413 # Decide if hit is critical
1419 if game.energy <= 0:
1420 # Returning home upon your shield, not with it...
1423 if not attempt and game.condition == "docked":
1424 prout(_("***Enemies decide against attacking your ship."))
1425 percent = 100.0*pfac*game.shield+0.5
1427 # Shields fully protect ship
1428 proutn(_("Enemy attack reduces shield strength to "))
1430 # Emit message if starship suffered hit(s)
1432 proutn(_("Energy left %2d shields ") % int(game.energy))
1435 elif not damaged(DSHIELD):
1438 proutn(_("damaged, "))
1439 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1440 # Check if anyone was hurt
1441 if hitmax >= 200 or hittot >= 500:
1442 icas = randrange(int(hittot * 0.015))
1445 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1446 prout(_(" in that last attack.\""))
1448 game.state.crew -= icas
1449 # After attack, reset average distance to enemies
1450 for enemy in game.enemies:
1451 enemy.kavgd = enemy.kdist
1455 def deadkl(w, etype, mv):
1456 "Kill a Klingon, Tholian, Romulan, or Thingy."
1457 # Added mv to allow enemy to "move" before dying
1458 proutn(crmena(True, etype, "sector", mv))
1459 # Decide what kind of enemy it is and update appropriately
1461 # Chalk up a Romulan
1462 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1464 game.state.nromrem -= 1
1473 # Killed some type of Klingon
1474 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1477 game.state.kcmdr.remove(game.quadrant)
1479 if game.state.kcmdr:
1480 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1481 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1484 game.state.remkl -= 1
1486 game.state.nscrem -= 1
1487 game.state.kscmdr.invalidate()
1492 # For each kind of enemy, finish message to player
1493 prout(_(" destroyed."))
1494 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1497 # Remove enemy ship from arrays describing local conditions
1498 for e in game.enemies:
1505 "Return None if target is invalid, otherwise return a course angle."
1506 if not w.valid_sector():
1510 # C code this was translated from is wacky -- why the sign reversal?
1511 delta.j = (w.j - game.sector.j)
1512 delta.i = (game.sector.i - w.i)
1513 if delta == Coord(0, 0):
1515 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1516 prout(_(" I recommend an immediate review of"))
1517 prout(_(" the Captain's psychological profile.\""))
1520 return delta.bearing()
1523 "Launch photon torpedo salvo."
1526 if damaged(DPHOTON):
1527 prout(_("Photon tubes damaged."))
1531 prout(_("No torpedoes left."))
1534 # First, get torpedo count
1537 if scanner.token == "IHALPHA":
1540 elif scanner.token == "IHEOL" or not scanner.waiting():
1541 prout(_("%d torpedoes left.") % game.torps)
1543 proutn(_("Number of torpedoes to fire- "))
1544 continue # Go back around to get a number
1545 else: # key == "IHREAL"
1547 if n <= 0: # abort command
1552 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1555 scanner.chew() # User requested more torps than available
1556 continue # Go back around
1557 break # All is good, go to next stage
1561 key = scanner.next()
1562 if i == 0 and key == "IHEOL":
1563 break # no coordinate waiting, we will try prompting
1564 if i == 1 and key == "IHEOL":
1565 # direct all torpedoes at one target
1567 target.append(target[0])
1568 tcourse.append(tcourse[0])
1571 scanner.push(scanner.token)
1572 target.append(scanner.getcoord())
1573 if target[-1] == None:
1575 tcourse.append(targetcheck(target[-1]))
1576 if tcourse[-1] == None:
1579 if len(target) == 0:
1580 # prompt for each one
1582 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1584 target.append(scanner.getcoord())
1585 if target[-1] == None:
1587 tcourse.append(targetcheck(target[-1]))
1588 if tcourse[-1] == None:
1591 # Loop for moving <n> torpedoes
1593 if game.condition != "docked":
1595 dispersion = (randreal()+randreal())*0.5 -0.5
1596 if math.fabs(dispersion) >= 0.47:
1598 dispersion *= randreal(1.2, 2.2)
1600 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1602 prouts(_("***TORPEDO MISFIRES."))
1605 prout(_(" Remainder of burst aborted."))
1607 prout(_("***Photon tubes damaged by misfire."))
1608 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1610 if game.shldup or game.condition == "docked":
1611 dispersion *= 1.0 + 0.0001*game.shield
1612 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1613 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1615 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1619 "Check for phasers overheating."
1621 checkburn = (rpow-1500.0)*0.00038
1622 if withprob(checkburn):
1623 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1624 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1626 def checkshctrl(rpow):
1627 "Check shield control."
1630 prout(_("Shields lowered."))
1632 # Something bad has happened
1633 prouts(_("***RED ALERT! RED ALERT!"))
1635 hit = rpow*game.shield/game.inshld
1636 game.energy -= rpow+hit*0.8
1637 game.shield -= hit*0.2
1638 if game.energy <= 0.0:
1639 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1644 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1646 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1647 icas = randrange(int(hit*0.012))
1652 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1653 prout(_(" %d casualties so far.\"") % icas)
1655 game.state.crew -= icas
1657 prout(_("Phaser energy dispersed by shields."))
1658 prout(_("Enemy unaffected."))
1663 "Register a phaser hit on Klingons and Romulans."
1666 for (kk, wham) in enumerate(hits):
1669 dustfac = randreal(0.9, 1.0)
1670 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1671 kpini = game.enemies[kk].power
1672 kp = math.fabs(kpini)
1673 if PHASEFAC*hit < kp:
1675 if game.enemies[kk].power < 0:
1676 game.enemies[kk].power -= -kp
1678 game.enemies[kk].power -= kp
1679 kpow = game.enemies[kk].power
1680 w = game.enemies[kk].location
1682 if not damaged(DSRSENS):
1684 proutn(_("%d unit hit on ") % int(hit))
1686 proutn(_("Very small hit on "))
1687 ienm = game.quad[w.i][w.j]
1690 proutn(crmena(False, ienm, "sector", w))
1694 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1698 kk -= 1 # don't do the increment
1700 else: # decide whether or not to emasculate klingon
1701 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1702 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1703 prout(_(" has just lost its firepower.\""))
1704 game.enemies[kk].power = -kpow
1709 "Fire phasers at bad guys."
1713 irec = 0 # Cheating inhibitor
1722 # SR sensors and Computer are needed for automode
1723 if damaged(DSRSENS) or damaged(DCOMPTR):
1725 if game.condition == "docked":
1726 prout(_("Phasers can't be fired through base shields."))
1729 if damaged(DPHASER):
1730 prout(_("Phaser control damaged."))
1734 if damaged(DSHCTRL):
1735 prout(_("High speed shield control damaged."))
1738 if game.energy <= 200.0:
1739 prout(_("Insufficient energy to activate high-speed shield control."))
1742 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1744 # Original code so convoluted, I re-did it all
1745 # (That was Tom Almy talking about the C code, I think -- ESR)
1746 while automode == "NOTSET":
1747 key = scanner.next()
1748 if key == "IHALPHA":
1749 if scanner.sees("manual"):
1750 if len(game.enemies)==0:
1751 prout(_("There is no enemy present to select."))
1754 automode = "AUTOMATIC"
1757 key = scanner.next()
1758 elif scanner.sees("automatic"):
1759 if (not itarg) and len(game.enemies) != 0:
1760 automode = "FORCEMAN"
1762 if len(game.enemies)==0:
1763 prout(_("Energy will be expended into space."))
1764 automode = "AUTOMATIC"
1765 key = scanner.next()
1766 elif scanner.sees("no"):
1771 elif key == "IHREAL":
1772 if len(game.enemies)==0:
1773 prout(_("Energy will be expended into space."))
1774 automode = "AUTOMATIC"
1776 automode = "FORCEMAN"
1778 automode = "AUTOMATIC"
1781 if len(game.enemies)==0:
1782 prout(_("Energy will be expended into space."))
1783 automode = "AUTOMATIC"
1785 automode = "FORCEMAN"
1787 proutn(_("Manual or automatic? "))
1792 if automode == "AUTOMATIC":
1793 if key == "IHALPHA" and scanner.sees("no"):
1795 key = scanner.next()
1796 if key != "IHREAL" and len(game.enemies) != 0:
1797 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1802 for i in range(len(game.enemies)):
1803 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1805 proutn(_("%d units required. ") % irec)
1807 proutn(_("Units to fire= "))
1808 key = scanner.next()
1813 proutn(_("Energy available= %.2f") % avail)
1816 if not rpow > avail:
1822 key = scanner.next()
1823 if key == "IHALPHA" and scanner.sees("no"):
1826 game.energy -= 200 # Go and do it!
1827 if checkshctrl(rpow):
1832 if len(game.enemies):
1835 for i in range(len(game.enemies)):
1839 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1840 over = randreal(1.01, 1.06) * hits[i]
1842 powrem -= hits[i] + over
1843 if powrem <= 0 and temp < hits[i]:
1852 if extra > 0 and not game.alldone:
1854 proutn(_("*** Tholian web absorbs "))
1855 if len(game.enemies)>0:
1856 proutn(_("excess "))
1857 prout(_("phaser energy."))
1859 prout(_("%d expended on empty space.") % int(extra))
1860 elif automode == "FORCEMAN":
1863 if damaged(DCOMPTR):
1864 prout(_("Battle computer damaged, manual fire only."))
1867 prouts(_("---WORKING---"))
1869 prout(_("Short-range-sensors-damaged"))
1870 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1871 prout(_("Manual-fire-must-be-used"))
1873 elif automode == "MANUAL":
1875 for k in range(len(game.enemies)):
1876 aim = game.enemies[k].location
1877 ienm = game.quad[aim.i][aim.j]
1879 proutn(_("Energy available= %.2f") % (avail-0.006))
1883 if damaged(DSRSENS) and \
1884 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1885 prout(cramen(ienm) + _(" can't be located without short range scan."))
1888 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
1893 if itarg and k > kz:
1894 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1897 if not damaged(DCOMPTR):
1902 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1903 key = scanner.next()
1904 if key == "IHALPHA" and scanner.sees("no"):
1906 key = scanner.next()
1908 if key == "IHALPHA":
1912 if k == 1: # Let me say I'm baffled by this
1915 if scanner.real < 0:
1919 hits[k] = scanner.real
1920 rpow += scanner.real
1921 # If total requested is too much, inform and start over
1923 prout(_("Available energy exceeded -- try again."))
1926 key = scanner.next() # scan for next value
1929 # zero energy -- abort
1932 if key == "IHALPHA" and scanner.sees("no"):
1937 game.energy -= 200.0
1938 if checkshctrl(rpow):
1942 # Say shield raised or malfunction, if necessary
1949 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1950 prouts(_(" CLICK CLICK POP . . ."))
1951 prout(_(" No response, sir!"))
1954 prout(_("Shields raised."))
1959 # Code from events,c begins here.
1961 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1962 # event of each type active at any given time. Mostly these means we can
1963 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1964 # BSD Trek, from which we swiped the idea, can have up to 5.
1966 def unschedule(evtype):
1967 "Remove an event from the schedule."
1968 game.future[evtype].date = FOREVER
1969 return game.future[evtype]
1971 def is_scheduled(evtype):
1972 "Is an event of specified type scheduled."
1973 return game.future[evtype].date != FOREVER
1975 def scheduled(evtype):
1976 "When will this event happen?"
1977 return game.future[evtype].date
1979 def schedule(evtype, offset):
1980 "Schedule an event of specified type."
1981 game.future[evtype].date = game.state.date + offset
1982 return game.future[evtype]
1984 def postpone(evtype, offset):
1985 "Postpone a scheduled event."
1986 game.future[evtype].date += offset
1989 "Rest period is interrupted by event."
1992 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
1994 game.resting = False
2000 "Run through the event queue looking for things to do."
2002 fintim = game.state.date + game.optime
2011 def tractorbeam(yank):
2012 "Tractor-beaming cases merge here."
2014 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2016 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2017 # If Kirk & Co. screwing around on planet, handle
2018 atover(True) # atover(true) is Grab
2021 if game.icraft: # Caught in Galileo?
2024 # Check to see if shuttle is aboard
2025 if game.iscraft == "offship":
2028 prout(_("Galileo, left on the planet surface, is captured"))
2029 prout(_("by aliens and made into a flying McDonald's."))
2030 game.damage[DSHUTTL] = -10
2031 game.iscraft = "removed"
2033 prout(_("Galileo, left on the planet surface, is well hidden."))
2035 game.quadrant = game.state.kscmdr
2037 game.quadrant = game.state.kcmdr[i]
2038 game.sector = randplace(QUADSIZE)
2039 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2040 % (game.quadrant, game.sector))
2042 prout(_("(Remainder of rest/repair period cancelled.)"))
2043 game.resting = False
2045 if not damaged(DSHIELD) and game.shield > 0:
2046 doshield(shraise=True) # raise shields
2047 game.shldchg = False
2049 prout(_("(Shields not currently useable.)"))
2051 # Adjust finish time to time of tractor beaming
2052 fintim = game.state.date+game.optime
2053 attack(torps_ok=False)
2054 if not game.state.kcmdr:
2057 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2060 "Code merges here for any commander destroying a starbase."
2061 # Not perfect, but will have to do
2062 # Handle case where base is in same quadrant as starship
2063 if game.battle == game.quadrant:
2064 game.state.chart[game.battle.i][game.battle.j].starbase = False
2065 game.quad[game.base.i][game.base.j] = '.'
2066 game.base.invalidate()
2069 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2070 elif game.state.baseq and communicating():
2071 # Get word via subspace radio
2074 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2075 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2077 prout(_("the Klingon Super-Commander"))
2079 prout(_("a Klingon Commander"))
2080 game.state.chart[game.battle.i][game.battle.j].starbase = False
2081 # Remove Starbase from galaxy
2082 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2083 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2085 # reinstate a commander's base attack
2089 game.battle.invalidate()
2091 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2092 for i in range(1, NEVENTS):
2093 if i == FSNOVA: proutn("=== Supernova ")
2094 elif i == FTBEAM: proutn("=== T Beam ")
2095 elif i == FSNAP: proutn("=== Snapshot ")
2096 elif i == FBATTAK: proutn("=== Base Attack ")
2097 elif i == FCDBAS: proutn("=== Base Destroy ")
2098 elif i == FSCMOVE: proutn("=== SC Move ")
2099 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2100 elif i == FDSPROB: proutn("=== Probe Move ")
2101 elif i == FDISTR: proutn("=== Distress Call ")
2102 elif i == FENSLV: proutn("=== Enslavement ")
2103 elif i == FREPRO: proutn("=== Klingon Build ")
2105 prout("%.2f" % (scheduled(i)))
2108 radio_was_broken = damaged(DRADIO)
2111 # Select earliest extraneous event, evcode==0 if no events
2116 for l in range(1, NEVENTS):
2117 if game.future[l].date < datemin:
2120 prout("== Event %d fires" % evcode)
2121 datemin = game.future[l].date
2122 xtime = datemin-game.state.date
2123 game.state.date = datemin
2124 # Decrement Federation resources and recompute remaining time
2125 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2127 if game.state.remtime <= 0:
2130 # Any crew left alive?
2131 if game.state.crew <= 0:
2134 # Is life support adequate?
2135 if damaged(DLIFSUP) and game.condition != "docked":
2136 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2139 game.lsupres -= xtime
2140 if game.damage[DLIFSUP] <= xtime:
2141 game.lsupres = game.inlsr
2144 if game.condition == "docked":
2146 # Don't fix Deathray here
2147 for l in range(NDEVICES):
2148 if game.damage[l] > 0.0 and l != DDRAY:
2149 if game.damage[l]-repair > 0.0:
2150 game.damage[l] -= repair
2152 game.damage[l] = 0.0
2153 # If radio repaired, update star chart and attack reports
2154 if radio_was_broken and not damaged(DRADIO):
2155 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2156 prout(_(" surveillance reports are coming in."))
2158 if not game.iseenit:
2162 prout(_(" The star chart is now up to date.\""))
2164 # Cause extraneous event EVCODE to occur
2165 game.optime -= xtime
2166 if evcode == FSNOVA: # Supernova
2169 schedule(FSNOVA, expran(0.5*game.intime))
2170 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2172 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2173 if game.state.nscrem == 0 or \
2174 ictbeam or istract or \
2175 game.condition == "docked" or game.isatb == 1 or game.iscate:
2177 if game.ientesc or \
2178 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2179 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2180 (damaged(DSHIELD) and \
2181 (game.energy < 2500 or damaged(DPHASER)) and \
2182 (game.torps < 5 or damaged(DPHOTON))):
2184 istract = ictbeam = True
2185 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2188 elif evcode == FTBEAM: # Tractor beam
2189 if not game.state.kcmdr:
2192 i = randrange(len(game.state.kcmdr))
2193 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2194 if istract or game.condition == "docked" or yank == 0:
2195 # Drats! Have to reschedule
2197 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2201 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2202 game.snapsht = copy.deepcopy(game.state)
2203 game.state.snap = True
2204 schedule(FSNAP, expran(0.5 * game.intime))
2205 elif evcode == FBATTAK: # Commander attacks starbase
2206 if not game.state.kcmdr or not game.state.baseq:
2212 for ibq in game.state.baseq:
2213 for cmdr in game.state.kcmdr:
2214 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2217 # no match found -- try later
2218 schedule(FBATTAK, expran(0.3*game.intime))
2223 # commander + starbase combination found -- launch attack
2225 schedule(FCDBAS, randreal(1.0, 4.0))
2226 if game.isatb: # extra time if SC already attacking
2227 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2228 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2229 game.iseenit = False
2230 if not communicating():
2231 continue # No warning :-(
2235 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2236 prout(_(" reports that it is under attack and that it can"))
2237 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2240 elif evcode == FSCDBAS: # Supercommander destroys base
2243 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2244 continue # WAS RETURN!
2246 game.battle = game.state.kscmdr
2248 elif evcode == FCDBAS: # Commander succeeds in destroying base
2249 if evcode == FCDBAS:
2251 if not game.state.baseq() \
2252 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2253 game.battle.invalidate()
2255 # find the lucky pair
2256 for cmdr in game.state.kcmdr:
2257 if cmdr == game.battle:
2260 # No action to take after all
2263 elif evcode == FSCMOVE: # Supercommander moves
2264 schedule(FSCMOVE, 0.2777)
2265 if not game.ientesc and not istract and game.isatb != 1 and \
2266 (not game.iscate or not game.justin):
2268 elif evcode == FDSPROB: # Move deep space probe
2269 schedule(FDSPROB, 0.01)
2270 if not game.probe.next():
2271 if not game.probe.quadrant().valid_quadrant() or \
2272 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2273 # Left galaxy or ran into supernova
2277 proutn(_("Lt. Uhura- \"The deep space probe "))
2278 if not game.probe.quadrant().valid_quadrant():
2279 prout(_("has left the galaxy.\""))
2281 prout(_("is no longer transmitting.\""))
2287 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2288 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2290 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2291 chp.klingons = pdest.klingons
2292 chp.starbase = pdest.starbase
2293 chp.stars = pdest.stars
2294 pdest.charted = True
2295 game.probe.moves -= 1 # One less to travel
2296 if game.probe.arrived() and game.isarmed and pdest.stars:
2297 supernova(game.probe) # fire in the hole!
2299 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2301 elif evcode == FDISTR: # inhabited system issues distress call
2303 # try a whole bunch of times to find something suitable
2304 for i in range(100):
2305 # need a quadrant which is not the current one,
2306 # which has some stars which are inhabited and
2307 # not already under attack, which is not
2308 # supernova'ed, and which has some Klingons in it
2309 w = randplace(GALSIZE)
2310 q = game.state.galaxy[w.i][w.j]
2311 if not (game.quadrant == w or q.planet == None or \
2312 not q.planet.inhabited or \
2313 q.supernova or q.status!="secure" or q.klingons<=0):
2316 # can't seem to find one; ignore this call
2318 prout("=== Couldn't find location for distress event.")
2320 # got one!! Schedule its enslavement
2321 ev = schedule(FENSLV, expran(game.intime))
2323 q.status = "distressed"
2324 # tell the captain about it if we can
2326 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2327 % (q.planet, repr(w)))
2328 prout(_("by a Klingon invasion fleet."))
2331 elif evcode == FENSLV: # starsystem is enslaved
2332 ev = unschedule(FENSLV)
2333 # see if current distress call still active
2334 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2338 q.status = "enslaved"
2340 # play stork and schedule the first baby
2341 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2342 ev2.quadrant = ev.quadrant
2344 # report the disaster if we can
2346 prout(_("Uhura- We've lost contact with starsystem %s") % \
2348 prout(_("in Quadrant %s.\n") % ev.quadrant)
2349 elif evcode == FREPRO: # Klingon reproduces
2350 # If we ever switch to a real event queue, we'll need to
2351 # explicitly retrieve and restore the x and y.
2352 ev = schedule(FREPRO, expran(1.0 * game.intime))
2353 # see if current distress call still active
2354 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2358 if game.state.remkl >= MAXKLGAME:
2359 continue # full right now
2360 # reproduce one Klingon
2363 if game.klhere >= MAXKLQUAD:
2365 # this quadrant not ok, pick an adjacent one
2366 for m.i in range(w.i - 1, w.i + 2):
2367 for m.j in range(w.j - 1, w.j + 2):
2368 if not m.valid_quadrant():
2370 q = game.state.galaxy[m.i][m.j]
2371 # check for this quad ok (not full & no snova)
2372 if q.klingons >= MAXKLQUAD or q.supernova:
2376 continue # search for eligible quadrant failed
2380 game.state.remkl += 1
2382 if game.quadrant == w:
2384 game.enemies.append(newkling())
2385 # recompute time left
2388 if game.quadrant == w:
2389 prout(_("Spock- sensors indicate the Klingons have"))
2390 prout(_("launched a warship from %s.") % q.planet)
2392 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2393 if q.planet != None:
2394 proutn(_("near %s ") % q.planet)
2395 prout(_("in Quadrant %s.") % w)
2401 key = scanner.next()
2404 proutn(_("How long? "))
2409 origTime = delay = scanner.real
2412 if delay >= game.state.remtime or len(game.enemies) != 0:
2413 proutn(_("Are you sure? "))
2416 # Alternate resting periods (events) with attacks
2420 game.resting = False
2421 if not game.resting:
2422 prout(_("%d stardates left.") % int(game.state.remtime))
2424 temp = game.optime = delay
2425 if len(game.enemies):
2426 rtime = randreal(1.0, 2.0)
2430 if game.optime < delay:
2431 attack(torps_ok=False)
2439 # Repair Deathray if long rest at starbase
2440 if origTime-delay >= 9.99 and game.condition == "docked":
2441 game.damage[DDRAY] = 0.0
2442 # leave if quadrant supernovas
2443 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2445 game.resting = False
2450 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2451 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2453 # Wow! We've supernova'ed
2454 supernova(game.quadrant)
2456 # handle initial nova
2457 game.quad[nov.i][nov.j] = '.'
2458 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2459 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2460 game.state.starkl += 1
2461 # Set up queue to recursively trigger adjacent stars
2467 for offset.i in range(-1, 1+1):
2468 for offset.j in range(-1, 1+1):
2469 if offset.j == 0 and offset.i == 0:
2471 neighbor = start + offset
2472 if not neighbor.valid_sector():
2474 iquad = game.quad[neighbor.i][neighbor.j]
2475 # Empty space ends reaction
2476 if iquad in ('.', '?', ' ', 'T', '#'):
2478 elif iquad == '*': # Affect another star
2480 # This star supernovas
2481 supernova(game.quadrant)
2484 hits.append(neighbor)
2485 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2486 game.state.starkl += 1
2487 proutn(crmena(True, '*', "sector", neighbor))
2489 game.quad[neighbor.i][neighbor.j] = '.'
2491 elif iquad in ('P', '@'): # Destroy planet
2492 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2494 game.state.nplankl += 1
2496 game.state.nworldkl += 1
2497 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2498 game.iplnet.pclass = "destroyed"
2500 game.plnet.invalidate()
2504 game.quad[neighbor.i][neighbor.j] = '.'
2505 elif iquad == 'B': # Destroy base
2506 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2507 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2508 game.base.invalidate()
2509 game.state.basekl += 1
2511 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2512 game.quad[neighbor.i][neighbor.j] = '.'
2513 elif iquad in ('E', 'F'): # Buffet ship
2514 prout(_("***Starship buffeted by nova."))
2516 if game.shield >= 2000.0:
2517 game.shield -= 2000.0
2519 diff = 2000.0 - game.shield
2523 prout(_("***Shields knocked out."))
2524 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2526 game.energy -= 2000.0
2527 if game.energy <= 0:
2530 # add in course nova contributes to kicking starship
2531 bump += (game.sector-hits[-1]).sgn()
2532 elif iquad == 'K': # kill klingon
2533 deadkl(neighbor, iquad, neighbor)
2534 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2535 for ll in range(len(game.enemies)):
2536 if game.enemies[ll].location == neighbor:
2538 game.enemies[ll].power -= 800.0 # If firepower is lost, die
2539 if game.enemies[ll].power <= 0.0:
2540 deadkl(neighbor, iquad, neighbor)
2542 newc = neighbor + neighbor - hits[-1]
2543 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2544 if not newc.valid_sector():
2545 # can't leave quadrant
2548 iquad1 = game.quad[newc.i][newc.j]
2550 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2552 deadkl(neighbor, iquad, newc)
2555 # can't move into something else
2558 proutn(_(", buffeted to Sector %s") % newc)
2559 game.quad[neighbor.i][neighbor.j] = '.'
2560 game.quad[newc.i][newc.j] = iquad
2561 game.enemies[ll].move(newc)
2562 # Starship affected by nova -- kick it away.
2564 direc = ncourse[3*(bump.i+1)+bump.j+2]
2569 scourse = course(bearing=direc, distance=dist)
2570 game.optime = scourse.time(warp=4)
2572 prout(_("Force of nova displaces starship."))
2573 imove(scourse, noattack=True)
2574 game.optime = scourse.time(warp=4)
2578 "Star goes supernova."
2583 # Scheduled supernova -- select star at random.
2586 for nq.i in range(GALSIZE):
2587 for nq.j in range(GALSIZE):
2588 stars += game.state.galaxy[nq.i][nq.j].stars
2590 return # nothing to supernova exists
2591 num = randrange(stars) + 1
2592 for nq.i in range(GALSIZE):
2593 for nq.j in range(GALSIZE):
2594 num -= game.state.galaxy[nq.i][nq.j].stars
2600 proutn("=== Super nova here?")
2603 if not nq == game.quadrant or game.justin:
2604 # it isn't here, or we just entered (treat as enroute)
2607 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2608 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2611 # we are in the quadrant!
2612 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2613 for ns.i in range(QUADSIZE):
2614 for ns.j in range(QUADSIZE):
2615 if game.quad[ns.i][ns.j]=='*':
2622 prouts(_("***RED ALERT! RED ALERT!"))
2624 prout(_("***Incipient supernova detected at Sector %s") % ns)
2625 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2626 proutn(_("Emergency override attempts t"))
2627 prouts("***************")
2631 # destroy any Klingons in supernovaed quadrant
2632 kldead = game.state.galaxy[nq.i][nq.j].klingons
2633 game.state.galaxy[nq.i][nq.j].klingons = 0
2634 if nq == game.state.kscmdr:
2635 # did in the Supercommander!
2636 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2640 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2641 comkills = len(game.state.kcmdr) - len(survivors)
2642 game.state.kcmdr = survivors
2644 if not game.state.kcmdr:
2646 game.state.remkl -= kldead
2647 # destroy Romulans and planets in supernovaed quadrant
2648 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2649 game.state.galaxy[nq.i][nq.j].romulans = 0
2650 game.state.nromrem -= nrmdead
2652 for loop in range(game.inplan):
2653 if game.state.planets[loop].quadrant == nq:
2654 game.state.planets[loop].pclass = "destroyed"
2656 # Destroy any base in supernovaed quadrant
2657 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2658 # If starship caused supernova, tally up destruction
2660 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2661 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2662 game.state.nplankl += npdead
2663 # mark supernova in galaxy and in star chart
2664 if game.quadrant == nq or communicating():
2665 game.state.galaxy[nq.i][nq.j].supernova = True
2666 # If supernova destroys last Klingons give special message
2667 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2670 prout(_("Lucky you!"))
2671 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2674 # if some Klingons remain, continue or die in supernova
2679 # Code from finish.c ends here.
2682 "Self-destruct maneuver. Finish with a BANG!"
2684 if damaged(DCOMPTR):
2685 prout(_("Computer damaged; cannot execute destruct sequence."))
2687 prouts(_("---WORKING---")); skip(1)
2688 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2689 prouts(" 10"); skip(1)
2690 prouts(" 9"); skip(1)
2691 prouts(" 8"); skip(1)
2692 prouts(" 7"); skip(1)
2693 prouts(" 6"); skip(1)
2695 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2697 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2699 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2702 if game.passwd != scanner.token:
2703 prouts(_("PASSWORD-REJECTED;"))
2705 prouts(_("CONTINUITY-EFFECTED"))
2708 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2709 prouts(" 5"); skip(1)
2710 prouts(" 4"); skip(1)
2711 prouts(" 3"); skip(1)
2712 prouts(" 2"); skip(1)
2713 prouts(" 1"); skip(1)
2715 prouts(_("GOODBYE-CRUEL-WORLD"))
2723 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2727 if len(game.enemies) != 0:
2728 whammo = 25.0 * game.energy
2729 for l in range(len(game.enemies)):
2730 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2731 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2735 "Compute our rate of kils over time."
2736 elapsed = game.state.date - game.indate
2737 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2740 starting = (game.inkling + game.incom + game.inscom)
2741 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2742 return (starting - remaining)/elapsed
2746 badpt = 5.0*game.state.starkl + \
2748 10.0*game.state.nplankl + \
2749 300*game.state.nworldkl + \
2751 100.0*game.state.basekl +\
2753 if game.ship == 'F':
2755 elif game.ship == None:
2760 # end the game, with appropriate notfications
2764 prout(_("It is stardate %.1f.") % game.state.date)
2766 if ifin == FWON: # Game has been won
2767 if game.state.nromrem != 0:
2768 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2771 prout(_("You have smashed the Klingon invasion fleet and saved"))
2772 prout(_("the Federation."))
2777 badpt = 0.0 # Close enough!
2778 # killsPerDate >= RateMax
2779 if game.state.date-game.indate < 5.0 or \
2780 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2782 prout(_("In fact, you have done so well that Starfleet Command"))
2783 if game.skill == SKILL_NOVICE:
2784 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2785 elif game.skill == SKILL_FAIR:
2786 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2787 elif game.skill == SKILL_GOOD:
2788 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2789 elif game.skill == SKILL_EXPERT:
2790 prout(_("promotes you to Commodore Emeritus."))
2792 prout(_("Now that you think you're really good, try playing"))
2793 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2794 elif game.skill == SKILL_EMERITUS:
2796 proutn(_("Computer- "))
2797 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2799 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2801 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2803 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2805 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2807 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2809 prout(_("Now you can retire and write your own Star Trek game!"))
2811 elif game.skill >= SKILL_EXPERT:
2812 if game.thawed and not game.idebug:
2813 prout(_("You cannot get a citation, so..."))
2815 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2819 # Only grant long life if alive (original didn't!)
2821 prout(_("LIVE LONG AND PROSPER."))
2826 elif ifin == FDEPLETE: # Federation Resources Depleted
2827 prout(_("Your time has run out and the Federation has been"))
2828 prout(_("conquered. Your starship is now Klingon property,"))
2829 prout(_("and you are put on trial as a war criminal. On the"))
2830 proutn(_("basis of your record, you are "))
2831 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2832 prout(_("acquitted."))
2834 prout(_("LIVE LONG AND PROSPER."))
2836 prout(_("found guilty and"))
2837 prout(_("sentenced to death by slow torture."))
2841 elif ifin == FLIFESUP:
2842 prout(_("Your life support reserves have run out, and"))
2843 prout(_("you die of thirst, starvation, and asphyxiation."))
2844 prout(_("Your starship is a derelict in space."))
2846 prout(_("Your energy supply is exhausted."))
2848 prout(_("Your starship is a derelict in space."))
2849 elif ifin == FBATTLE:
2850 prout(_("The %s has been destroyed in battle.") % crmshp())
2852 prout(_("Dulce et decorum est pro patria mori."))
2854 prout(_("You have made three attempts to cross the negative energy"))
2855 prout(_("barrier which surrounds the galaxy."))
2857 prout(_("Your navigation is abominable."))
2860 prout(_("Your starship has been destroyed by a nova."))
2861 prout(_("That was a great shot."))
2863 elif ifin == FSNOVAED:
2864 prout(_("The %s has been fried by a supernova.") % crmshp())
2865 prout(_("...Not even cinders remain..."))
2866 elif ifin == FABANDN:
2867 prout(_("You have been captured by the Klingons. If you still"))
2868 prout(_("had a starbase to be returned to, you would have been"))
2869 prout(_("repatriated and given another chance. Since you have"))
2870 prout(_("no starbases, you will be mercilessly tortured to death."))
2871 elif ifin == FDILITHIUM:
2872 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2873 elif ifin == FMATERIALIZE:
2874 prout(_("Starbase was unable to re-materialize your starship."))
2875 prout(_("Sic transit gloria mundi"))
2876 elif ifin == FPHASER:
2877 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2879 prout(_("You and your landing party have been"))
2880 prout(_("converted to energy, disipating through space."))
2881 elif ifin == FMINING:
2882 prout(_("You are left with your landing party on"))
2883 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2885 prout(_("They are very fond of \"Captain Kirk\" soup."))
2887 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2888 elif ifin == FDPLANET:
2889 prout(_("You and your mining party perish."))
2891 prout(_("That was a great shot."))
2894 prout(_("The Galileo is instantly annihilated by the supernova."))
2895 prout(_("You and your mining party are atomized."))
2897 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2898 prout(_("joins the Romulans, wreaking terror on the Federation."))
2899 elif ifin == FPNOVA:
2900 prout(_("You and your mining party are atomized."))
2902 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2903 prout(_("joins the Romulans, wreaking terror on the Federation."))
2904 elif ifin == FSTRACTOR:
2905 prout(_("The shuttle craft Galileo is also caught,"))
2906 prout(_("and breaks up under the strain."))
2908 prout(_("Your debris is scattered for millions of miles."))
2909 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2911 prout(_("The mutants attack and kill Spock."))
2912 prout(_("Your ship is captured by Klingons, and"))
2913 prout(_("your crew is put on display in a Klingon zoo."))
2914 elif ifin == FTRIBBLE:
2915 prout(_("Tribbles consume all remaining water,"))
2916 prout(_("food, and oxygen on your ship."))
2918 prout(_("You die of thirst, starvation, and asphyxiation."))
2919 prout(_("Your starship is a derelict in space."))
2921 prout(_("Your ship is drawn to the center of the black hole."))
2922 prout(_("You are crushed into extremely dense matter."))
2924 prout(_("Your last crew member has died."))
2925 if game.ship == 'F':
2927 elif game.ship == 'E':
2930 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2931 goodies = game.state.remres/game.inresor
2932 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2933 if goodies/baddies >= randreal(1.0, 1.5):
2934 prout(_("As a result of your actions, a treaty with the Klingon"))
2935 prout(_("Empire has been signed. The terms of the treaty are"))
2936 if goodies/baddies >= randreal(3.0):
2937 prout(_("favorable to the Federation."))
2939 prout(_("Congratulations!"))
2941 prout(_("highly unfavorable to the Federation."))
2943 prout(_("The Federation will be destroyed."))
2945 prout(_("Since you took the last Klingon with you, you are a"))
2946 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2947 prout(_("statue in your memory. Rest in peace, and try not"))
2948 prout(_("to think about pigeons."))
2953 "Compute player's score."
2954 timused = game.state.date - game.indate
2955 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2957 game.perdate = killrate()
2958 ithperd = 500*game.perdate + 0.5
2961 iwon = 100*game.skill
2962 if game.ship == 'E':
2964 elif game.ship == 'F':
2968 game.score = 10*(game.inkling - game.state.remkl) \
2969 + 50*(game.incom - len(game.state.kcmdr)) \
2971 + 20*(game.inrom - game.state.nromrem) \
2972 + 200*(game.inscom - game.state.nscrem) \
2973 - game.state.nromrem \
2978 prout(_("Your score --"))
2979 if game.inrom - game.state.nromrem:
2980 prout(_("%6d Romulans destroyed %5d") %
2981 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
2982 if game.state.nromrem and game.gamewon:
2983 prout(_("%6d Romulans captured %5d") %
2984 (game.state.nromrem, game.state.nromrem))
2985 if game.inkling - game.state.remkl:
2986 prout(_("%6d ordinary Klingons destroyed %5d") %
2987 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
2988 if game.incom - len(game.state.kcmdr):
2989 prout(_("%6d Klingon commanders destroyed %5d") %
2990 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
2991 if game.inscom - game.state.nscrem:
2992 prout(_("%6d Super-Commander destroyed %5d") %
2993 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
2995 prout(_("%6.2f Klingons per stardate %5d") %
2996 (game.perdate, ithperd))
2997 if game.state.starkl:
2998 prout(_("%6d stars destroyed by your action %5d") %
2999 (game.state.starkl, -5*game.state.starkl))
3000 if game.state.nplankl:
3001 prout(_("%6d planets destroyed by your action %5d") %
3002 (game.state.nplankl, -10*game.state.nplankl))
3003 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3004 prout(_("%6d inhabited planets destroyed by your action %5d") %
3005 (game.state.nworldkl, -300*game.state.nworldkl))
3006 if game.state.basekl:
3007 prout(_("%6d bases destroyed by your action %5d") %
3008 (game.state.basekl, -100*game.state.basekl))
3010 prout(_("%6d calls for help from starbase %5d") %
3011 (game.nhelp, -45*game.nhelp))
3013 prout(_("%6d casualties incurred %5d") %
3014 (game.casual, -game.casual))
3016 prout(_("%6d crew abandoned in space %5d") %
3017 (game.abandoned, -3*game.abandoned))
3019 prout(_("%6d ship(s) lost or destroyed %5d") %
3020 (klship, -100*klship))
3022 prout(_("Penalty for getting yourself killed -200"))
3024 proutn(_("Bonus for winning "))
3025 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3026 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3027 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3028 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3029 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3030 prout(" %5d" % iwon)
3032 prout(_("TOTAL SCORE %5d") % game.score)
3035 "Emit winner's commemmorative plaque."
3038 proutn(_("File or device name for your plaque: "))
3041 fp = open(winner, "w")
3044 prout(_("Invalid name."))
3046 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3048 # The 38 below must be 64 for 132-column paper
3049 nskip = 38 - len(winner)/2
3050 fp.write("\n\n\n\n")
3051 # --------DRAW ENTERPRISE PICTURE.
3052 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3053 fp.write(" EEE E : : : E\n" )
3054 fp.write(" EE EEE E : : NCC-1701 : E\n")
3055 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3056 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3057 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3058 fp.write(" EEEEEEE EEEEE E E E E\n")
3059 fp.write(" EEE E E E E\n")
3060 fp.write(" E E E E\n")
3061 fp.write(" EEEEEEEEEEEEE E E\n")
3062 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3063 fp.write(" :E : EEEE E\n")
3064 fp.write(" .-E -:----- E\n")
3065 fp.write(" :E : E\n")
3066 fp.write(" EE : EEEEEEEE\n")
3067 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3069 fp.write(_(" U. S. S. ENTERPRISE\n"))
3070 fp.write("\n\n\n\n")
3071 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3073 fp.write(_(" Starfleet Command bestows to you\n"))
3075 fp.write("%*s%s\n\n" % (nskip, "", winner))
3076 fp.write(_(" the rank of\n\n"))
3077 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3079 if game.skill == SKILL_EXPERT:
3080 fp.write(_(" Expert level\n\n"))
3081 elif game.skill == SKILL_EMERITUS:
3082 fp.write(_("Emeritus level\n\n"))
3084 fp.write(_(" Cheat level\n\n"))
3085 timestring = time.ctime()
3086 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3087 (timestring+4, timestring+20, timestring+11))
3088 fp.write(_(" Your score: %d\n\n") % game.score)
3089 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3092 # Code from io.c begins here
3094 rows = linecount = 0 # for paging
3097 fullscreen_window = None
3098 srscan_window = None
3099 report_window = None
3100 status_window = None
3101 lrscan_window = None
3102 message_window = None
3103 prompt_window = None
3108 "for some recent versions of python2, the following enables UTF8"
3109 "for the older ones we probably need to set C locale, and the python3"
3110 "has no problems at all"
3111 if sys.version_info[0] < 3:
3113 locale.setlocale(locale.LC_ALL, "")
3114 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3115 gettext.textdomain("sst")
3116 if not (game.options & OPTION_CURSES):
3117 ln_env = os.getenv("LINES")
3123 stdscr = curses.initscr()
3127 if game.options & OPTION_COLOR:
3128 curses.start_color()
3129 curses.use_default_colors()
3130 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3131 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3132 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3133 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3134 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3135 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3136 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3137 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3138 global fullscreen_window, srscan_window, report_window, status_window
3139 global lrscan_window, message_window, prompt_window
3140 (rows, columns) = stdscr.getmaxyx()
3141 fullscreen_window = stdscr
3142 srscan_window = curses.newwin(12, 25, 0, 0)
3143 report_window = curses.newwin(11, 0, 1, 25)
3144 status_window = curses.newwin(10, 0, 1, 39)
3145 lrscan_window = curses.newwin(5, 0, 0, 64)
3146 message_window = curses.newwin(0, 0, 12, 0)
3147 prompt_window = curses.newwin(1, 0, rows-2, 0)
3148 message_window.scrollok(True)
3149 setwnd(fullscreen_window)
3153 if game.options & OPTION_CURSES:
3154 stdscr.keypad(False)
3160 "Wait for user action -- OK to do nothing if on a TTY"
3161 if game.options & OPTION_CURSES:
3166 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3170 if game.skill > SKILL_FAIR:
3171 prompt = _("[CONTINUE?]")
3173 prompt = _("[PRESS ENTER TO CONTINUE]")
3175 if game.options & OPTION_CURSES:
3177 setwnd(prompt_window)
3178 prompt_window.clear()
3179 prompt_window.addstr(prompt)
3180 prompt_window.getstr()
3181 prompt_window.clear()
3182 prompt_window.refresh()
3183 setwnd(message_window)
3186 sys.stdout.write('\n')
3189 sys.stdout.write('\n' * rows)
3193 "Skip i lines. Pause game if this would cause a scrolling event."
3194 for dummy in range(i):
3195 if game.options & OPTION_CURSES:
3196 (y, x) = curwnd.getyx()
3199 except curses.error:
3204 if rows and linecount >= rows:
3207 sys.stdout.write('\n')
3210 "Utter a line with no following line feed."
3211 if game.options & OPTION_CURSES:
3212 (y, x) = curwnd.getyx()
3213 (my, mx) = curwnd.getmaxyx()
3214 if curwnd == message_window and y >= my - 2:
3217 # Uncomment this to debug curses problems
3219 logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(line)))
3223 sys.stdout.write(line)
3233 if not replayfp or replayfp.closed: # Don't slow down replays
3236 if game.options & OPTION_CURSES:
3240 if not replayfp or replayfp.closed:
3244 "Get a line of input."
3245 if game.options & OPTION_CURSES:
3246 line = curwnd.getstr() + "\n"
3249 if replayfp and not replayfp.closed:
3251 line = replayfp.readline()
3254 prout("*** Replay finished")
3257 elif line[0] != "#":
3260 line = raw_input() + "\n"
3266 "Change windows -- OK for this to be a no-op in tty mode."
3268 if game.options & OPTION_CURSES:
3269 # Uncomment this to debug curses problems
3271 if wnd == fullscreen_window:
3272 legend = "fullscreen"
3273 elif wnd == srscan_window:
3275 elif wnd == report_window:
3277 elif wnd == status_window:
3279 elif wnd == lrscan_window:
3281 elif wnd == message_window:
3283 elif wnd == prompt_window:
3287 logfp.write("#curses: setwnd(%s)\n" % legend)
3289 curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window)
3292 "Clear to end of line -- can be a no-op in tty mode"
3293 if game.options & OPTION_CURSES:
3298 "Clear screen -- can be a no-op in tty mode."
3300 if game.options & OPTION_CURSES:
3306 def textcolor(color=DEFAULT):
3307 if game.options & OPTION_COLOR:
3308 if color == DEFAULT:
3310 elif color == BLACK:
3311 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3313 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3314 elif color == GREEN:
3315 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3317 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3319 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3320 elif color == MAGENTA:
3321 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3322 elif color == BROWN:
3323 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3324 elif color == LIGHTGRAY:
3325 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3326 elif color == DARKGRAY:
3327 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3328 elif color == LIGHTBLUE:
3329 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3330 elif color == LIGHTGREEN:
3331 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3332 elif color == LIGHTCYAN:
3333 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3334 elif color == LIGHTRED:
3335 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3336 elif color == LIGHTMAGENTA:
3337 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3338 elif color == YELLOW:
3339 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3340 elif color == WHITE:
3341 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3344 if game.options & OPTION_COLOR:
3345 curwnd.attron(curses.A_REVERSE)
3348 # Things past this point have policy implications.
3352 "Hook to be called after moving to redraw maps."
3353 if game.options & OPTION_CURSES:
3356 setwnd(srscan_window)
3360 setwnd(status_window)
3361 status_window.clear()
3362 status_window.move(0, 0)
3363 setwnd(report_window)
3364 report_window.clear()
3365 report_window.move(0, 0)
3367 setwnd(lrscan_window)
3368 lrscan_window.clear()
3369 lrscan_window.move(0, 0)
3370 lrscan(silent=False)
3372 def put_srscan_sym(w, sym):
3373 "Emit symbol for short-range scan."
3374 srscan_window.move(w.i+1, w.j*2+2)
3375 srscan_window.addch(sym)
3376 srscan_window.refresh()
3379 "Enemy fall down, go boom."
3380 if game.options & OPTION_CURSES:
3382 setwnd(srscan_window)
3383 srscan_window.attron(curses.A_REVERSE)
3384 put_srscan_sym(w, game.quad[w.i][w.j])
3388 srscan_window.attroff(curses.A_REVERSE)
3389 put_srscan_sym(w, game.quad[w.i][w.j])
3390 curses.delay_output(500)
3391 setwnd(message_window)
3394 "Sound and visual effects for teleportation."
3395 if game.options & OPTION_CURSES:
3397 setwnd(message_window)
3399 prouts(" . . . . . ")
3400 if game.options & OPTION_CURSES:
3401 #curses.delay_output(1000)
3405 def tracktorpedo(w, step, i, n, iquad):
3406 "Torpedo-track animation."
3407 if not game.options & OPTION_CURSES:
3411 proutn(_("Track for torpedo number %d- ") % (i+1))
3414 proutn(_("Torpedo track- "))
3415 elif step==4 or step==9:
3419 if not damaged(DSRSENS) or game.condition=="docked":
3420 if i != 0 and step == 1:
3423 if (iquad=='.') or (iquad==' '):
3424 put_srscan_sym(w, '+')
3428 put_srscan_sym(w, iquad)
3430 curwnd.attron(curses.A_REVERSE)
3431 put_srscan_sym(w, iquad)
3435 curwnd.attroff(curses.A_REVERSE)
3436 put_srscan_sym(w, iquad)
3441 "Display the current galaxy chart."
3442 if game.options & OPTION_CURSES:
3443 setwnd(message_window)
3444 message_window.clear()
3446 if game.options & OPTION_TTY:
3451 def prstat(txt, data):
3453 if game.options & OPTION_CURSES:
3455 setwnd(status_window)
3457 proutn(" " * (NSYM - len(txt)))
3460 if game.options & OPTION_CURSES:
3461 setwnd(report_window)
3463 # Code from moving.c begins here
3465 def imove(icourse=None, noattack=False):
3466 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3469 def newquadrant(noattack):
3470 # Leaving quadrant -- allow final enemy attack
3471 # Don't do it if being pushed by Nova
3472 if len(game.enemies) != 0 and not noattack:
3474 for enemy in game.enemies:
3475 finald = (w - enemy.location).distance()
3476 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3477 # Stas Sergeev added the condition
3478 # that attacks only happen if Klingons
3479 # are present and your skill is good.
3480 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3481 attack(torps_ok=False)
3484 # check for edge of galaxy
3488 if icourse.final.i < 0:
3489 icourse.final.i = -icourse.final.i
3491 if icourse.final.j < 0:
3492 icourse.final.j = -icourse.final.j
3494 if icourse.final.i >= GALSIZE*QUADSIZE:
3495 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3497 if icourse.final.j >= GALSIZE*QUADSIZE:
3498 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3506 if game.nkinks == 3:
3507 # Three strikes -- you're out!
3511 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3512 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3513 prout(_("YOU WILL BE DESTROYED."))
3514 # Compute final position in new quadrant
3515 if trbeam: # Don't bother if we are to be beamed
3517 game.quadrant = icourse.final.quadrant()
3518 game.sector = icourse.final.sector()
3520 prout(_("Entering Quadrant %s.") % game.quadrant)
3521 game.quad[game.sector.i][game.sector.j] = game.ship
3523 if game.skill>SKILL_NOVICE:
3524 attack(torps_ok=False)
3526 def check_collision(h):
3527 iquad = game.quad[h.i][h.j]
3529 # object encountered in flight path
3530 stopegy = 50.0*icourse.distance/game.optime
3531 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3532 for enemy in game.enemies:
3533 if enemy.location == game.sector:
3535 collision(rammed=False, enemy=enemy)
3539 prouts(_("***RED ALERT! RED ALERT!"))
3541 proutn("***" + crmshp())
3542 proutn(_(" pulled into black hole at Sector %s") % h)
3543 # Getting pulled into a black hole was certain
3544 # death in Almy's original. Stas Sergeev added a
3545 # possibility that you'll get timewarped instead.
3547 for m in range(NDEVICES):
3548 if game.damage[m]>0:
3550 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3551 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3561 prout(_(" encounters Tholian web at %s;") % h)
3563 prout(_(" blocked by object at %s;") % h)
3564 proutn(_("Emergency stop required "))
3565 prout(_("%2d units of energy.") % int(stopegy))
3566 game.energy -= stopegy
3567 if game.energy <= 0:
3574 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3575 game.inorbit = False
3576 # If tractor beam is to occur, don't move full distance
3577 if game.state.date+game.optime >= scheduled(FTBEAM):
3579 game.condition = "red"
3580 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3581 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3583 game.quad[game.sector.i][game.sector.j] = '.'
3584 for m in range(icourse.moves):
3586 w = icourse.sector()
3587 if icourse.origin.quadrant() != icourse.location.quadrant():
3588 newquadrant(noattack)
3590 elif check_collision(w):
3591 print "Collision detected"
3595 # We're in destination quadrant -- compute new average enemy distances
3596 game.quad[game.sector.i][game.sector.j] = game.ship
3598 for enemy in game.enemies:
3599 finald = (w-enemy.location).distance()
3600 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3601 enemy.kdist = finald
3603 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3604 attack(torps_ok=False)
3605 for enemy in game.enemies:
3606 enemy.kavgd = enemy.kdist
3609 setwnd(message_window)
3613 "Dock our ship at a starbase."
3615 if game.condition == "docked" and verbose:
3616 prout(_("Already docked."))
3619 prout(_("You must first leave standard orbit."))
3621 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3622 prout(crmshp() + _(" not adjacent to base."))
3624 game.condition = "docked"
3628 if game.energy < game.inenrg:
3629 game.energy = game.inenrg
3630 game.shield = game.inshld
3631 game.torps = game.intorps
3632 game.lsupres = game.inlsr
3633 game.state.crew = FULLCREW
3634 if not damaged(DRADIO) and \
3635 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3636 # get attack report from base
3637 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3641 def cartesian(loc1=None, loc2=None):
3643 return game.quadrant * QUADSIZE + game.sector
3645 return game.quadrant * QUADSIZE + loc1
3647 return loc1 * QUADSIZE + loc2
3649 def getcourse(isprobe):
3650 "Get a course and distance from the user."
3652 dquad = copy.copy(game.quadrant)
3653 navmode = "unspecified"
3657 if game.landed and not isprobe:
3658 prout(_("Dummy! You can't leave standard orbit until you"))
3659 proutn(_("are back aboard the ship."))
3662 while navmode == "unspecified":
3663 if damaged(DNAVSYS):
3665 prout(_("Computer damaged; manual navigation only"))
3667 prout(_("Computer damaged; manual movement only"))
3672 key = scanner.next()
3674 proutn(_("Manual or automatic- "))
3677 elif key == "IHALPHA":
3678 if scanner.sees("manual"):
3680 key = scanner.next()
3682 elif scanner.sees("automatic"):
3683 navmode = "automatic"
3684 key = scanner.next()
3692 prout(_("(Manual navigation assumed.)"))
3694 prout(_("(Manual movement assumed.)"))
3698 if navmode == "automatic":
3699 while key == "IHEOL":
3701 proutn(_("Target quadrant or quadrant§or- "))
3703 proutn(_("Destination sector or quadrant§or- "))
3706 key = scanner.next()
3710 xi = int(round(scanner.real))-1
3711 key = scanner.next()
3715 xj = int(round(scanner.real))-1
3716 key = scanner.next()
3718 # both quadrant and sector specified
3719 xk = int(round(scanner.real))-1
3720 key = scanner.next()
3724 xl = int(round(scanner.real))-1
3730 # only one pair of numbers was specified
3732 # only quadrant specified -- go to center of dest quad
3735 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3737 # only sector specified
3741 if not dquad.valid_quadrant() or not dsect.valid_sector():
3748 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3750 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3751 # the actual deltas get computed here
3752 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3753 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3755 while key == "IHEOL":
3756 proutn(_("X and Y displacements- "))
3759 key = scanner.next()
3764 delta.j = scanner.real
3765 key = scanner.next()
3769 delta.i = scanner.real
3770 # Check for zero movement
3771 if delta.i == 0 and delta.j == 0:
3774 if itemp == "verbose" and not isprobe:
3776 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3778 return course(bearing=delta.bearing(), distance=delta.distance())
3781 def __init__(self, bearing, distance, origin=None):
3782 self.distance = distance
3783 self.bearing = bearing
3785 self.origin = cartesian(game.quadrant, game.sector)
3787 self.origin = origin
3788 # The bearing() code we inherited from FORTRAN is actually computing
3789 # clockface directions!
3790 if self.bearing < 0.0:
3791 self.bearing += 12.0
3792 self.angle = ((15.0 - self.bearing) * 0.5235988)
3794 self.origin = cartesian(game.quadrant, game.sector)
3796 self.origin = cartesian(game.quadrant, origin)
3797 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
3798 bigger = max(abs(self.increment.i), abs(self.increment.j))
3799 self.increment /= bigger
3800 self.moves = int(round(10*self.distance*bigger))
3802 self.final = (self.location + self.moves*self.increment).roundtogrid()
3804 self.location = self.origin
3807 return self.location.roundtogrid() == self.final
3809 "Next step on course."
3811 self.nextlocation = self.location + self.increment
3812 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3813 self.location = self.nextlocation
3816 return self.location.quadrant()
3818 return self.location.sector()
3819 def power(self, warp):
3820 return self.distance*(warp**3)*(game.shldup+1)
3821 def time(self, warp):
3822 return 10.0*self.distance/warp**2
3825 "Move under impulse power."
3827 if damaged(DIMPULS):
3830 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3832 if game.energy > 30.0:
3834 course = getcourse(isprobe=False)
3837 power = 20.0 + 100.0*course.distance
3840 if power >= game.energy:
3841 # Insufficient power for trip
3843 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3844 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3845 if game.energy > 30:
3846 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3847 int(0.01 * (game.energy-20.0)-0.05))
3848 prout(_(" quadrants.\""))
3850 prout(_("quadrant. They are, therefore, useless.\""))
3853 # Make sure enough time is left for the trip
3854 game.optime = course.dist/0.095
3855 if game.optime >= game.state.remtime:
3856 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3857 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3858 proutn(_("we dare spend the time?\" "))
3861 # Activate impulse engines and pay the cost
3862 imove(course, noattack=False)
3866 power = 20.0 + 100.0*course.dist
3867 game.energy -= power
3868 game.optime = course.dist/0.095
3869 if game.energy <= 0:
3873 def warp(wcourse, involuntary):
3874 "ove under warp drive."
3875 blooey = False; twarp = False
3876 if not involuntary: # Not WARPX entry
3878 if game.damage[DWARPEN] > 10.0:
3881 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3883 if damaged(DWARPEN) and game.warpfac > 4.0:
3886 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3887 prout(_(" is repaired, I can only give you warp 4.\""))
3889 # Read in course and distance
3892 wcourse = getcourse(isprobe=False)
3895 # Make sure starship has enough energy for the trip
3896 # Note: this formula is slightly different from the C version,
3897 # and lets you skate a bit closer to the edge.
3898 if wcourse.power(game.warpfac) >= game.energy:
3899 # Insufficient power for trip
3902 prout(_("Engineering to bridge--"))
3903 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
3904 iwarp = (game.energy/(wcourse.dist+0.05)) ** 0.333333333
3906 prout(_("We can't do it, Captain. We don't have enough energy."))
3908 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3911 prout(_("if you'll lower the shields."))
3915 prout(_("We haven't the energy to go that far with the shields up."))
3917 # Make sure enough time is left for the trip
3918 game.optime = wcourse.time(game.warpfac)
3919 if game.optime >= 0.8*game.state.remtime:
3921 prout(_("First Officer Spock- \"Captain, I compute that such"))
3922 proutn(_(" a trip would require approximately %2.0f") %
3923 (100.0*game.optime/game.state.remtime))
3924 prout(_(" percent of our"))
3925 proutn(_(" remaining time. Are you sure this is wise?\" "))
3931 if game.warpfac > 6.0:
3932 # Decide if engine damage will occur
3933 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3934 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
3935 if prob > randreal():
3937 wcourse.distance = randreal(wcourse.distance)
3938 # Decide if time warp will occur
3939 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3941 if game.idebug and game.warpfac==10 and not twarp:
3943 proutn("=== Force time warp? ")
3947 # If time warp or engine damage, check path
3948 # If it is obstructed, don't do warp or damage
3949 look = wcourse.moves
3953 w = wcourse.sector()
3954 if not w.valid_sector():
3956 if game.quad[w.i][w.j] != '.':
3960 # Activate Warp Engines and pay the cost
3961 imove(wcourse, noattack=False)
3964 game.energy -= wcourse.power(game.warpfac)
3965 if game.energy <= 0:
3967 game.optime = wcourse.time(game.warpfac)
3971 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
3973 prout(_("Engineering to bridge--"))
3974 prout(_(" Scott here. The warp engines are damaged."))
3975 prout(_(" We'll have to reduce speed to warp 4."))
3980 "Change the warp factor."
3986 proutn(_("Warp factor- "))
3990 if game.damage[DWARPEN] > 10.0:
3991 prout(_("Warp engines inoperative."))
3993 if damaged(DWARPEN) and scanner.real > 4.0:
3994 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
3995 prout(_(" but right now we can only go warp 4.\""))
3997 if scanner.real > 10.0:
3998 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4000 if scanner.real < 1.0:
4001 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4003 oldfac = game.warpfac
4004 game.warpfac = scanner.real
4005 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4006 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4009 if game.warpfac < 8.00:
4010 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4012 if game.warpfac == 10.0:
4013 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4015 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4019 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4021 # is captain on planet?
4023 if damaged(DTRANSP):
4026 prout(_("Scotty rushes to the transporter controls."))
4028 prout(_("But with the shields up it's hopeless."))
4030 prouts(_("His desperate attempt to rescue you . . ."))
4035 prout(_("SUCCEEDS!"))
4038 proutn(_("The crystals mined were "))
4046 # Check to see if captain in shuttle craft
4051 # Inform captain of attempt to reach safety
4055 prouts(_("***RED ALERT! RED ALERT!"))
4057 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4058 prouts(_(" a supernova."))
4060 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4061 prout(_("safely out of quadrant."))
4062 if not damaged(DRADIO):
4063 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4064 # Try to use warp engines
4065 if damaged(DWARPEN):
4067 prout(_("Warp engines damaged."))
4070 game.warpfac = randreal(6.0, 8.0)
4071 prout(_("Warp factor set to %d") % int(game.warpfac))
4072 power = 0.75*game.energy
4073 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4074 dist = max(dist, randreal(math.sqrt(2)))
4075 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4076 game.optime = bugout.time(game.warpfac)
4078 game.inorbit = False
4079 warp(bugout, involuntary=True)
4081 # This is bad news, we didn't leave quadrant.
4085 prout(_("Insufficient energy to leave quadrant."))
4088 # Repeat if another snova
4089 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4091 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4092 finish(FWON) # Snova killed remaining enemy.
4095 "Let's do the time warp again."
4096 prout(_("***TIME WARP ENTERED."))
4097 if game.state.snap and withprob(0.5):
4099 prout(_("You are traveling backwards in time %d stardates.") %
4100 int(game.state.date-game.snapsht.date))
4101 game.state = game.snapsht
4102 game.state.snap = False
4103 if len(game.state.kcmdr):
4104 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4105 schedule(FBATTAK, expran(0.3*game.intime))
4106 schedule(FSNOVA, expran(0.5*game.intime))
4107 # next snapshot will be sooner
4108 schedule(FSNAP, expran(0.25*game.state.remtime))
4110 if game.state.nscrem:
4111 schedule(FSCMOVE, 0.2777)
4115 game.battle.invalidate()
4116 # Make sure Galileo is consistant -- Snapshot may have been taken
4117 # when on planet, which would give us two Galileos!
4119 for l in range(game.inplan):
4120 if game.state.planets[l].known == "shuttle_down":
4122 if game.iscraft == "onship" and game.ship=='E':
4123 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4124 game.iscraft = "offship"
4125 # Likewise, if in the original time the Galileo was abandoned, but
4126 # was on ship earlier, it would have vanished -- let's restore it.
4127 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4128 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4129 game.iscraft = "onship"
4130 # There used to be code to do the actual reconstrction here,
4131 # but the starchart is now part of the snapshotted galaxy state.
4132 prout(_("Spock has reconstructed a correct star chart from memory"))
4134 # Go forward in time
4135 game.optime = expran(0.5*game.intime)
4136 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4137 # cheat to make sure no tractor beams occur during time warp
4138 postpone(FTBEAM, game.optime)
4139 game.damage[DRADIO] += game.optime
4141 events() # Stas Sergeev added this -- do pending events
4144 "Launch deep-space probe."
4145 # New code to launch a deep space probe
4146 if game.nprobes == 0:
4149 if game.ship == 'E':
4150 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4152 prout(_("Ye Faerie Queene has no deep space probes."))
4157 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4159 if is_scheduled(FDSPROB):
4162 if damaged(DRADIO) and game.condition != "docked":
4163 prout(_("Spock- \"Records show the previous probe has not yet"))
4164 prout(_(" reached its destination.\""))
4166 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4168 key = scanner.next()
4170 if game.nprobes == 1:
4171 prout(_("1 probe left."))
4173 prout(_("%d probes left") % game.nprobes)
4174 proutn(_("Are you sure you want to fire a probe? "))
4177 game.isarmed = False
4178 if key == "IHALPHA" and scanner.token == "armed":
4180 key = scanner.next()
4181 elif key == "IHEOL":
4182 proutn(_("Arm NOVAMAX warhead? "))
4184 elif key == "IHREAL": # first element of course
4185 scanner.push(scanner.token)
4187 game.probe = getcourse(isprobe=True)
4191 schedule(FDSPROB, 0.01) # Time to move one sector
4192 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4197 "Yell for help from nearest starbase."
4198 # There's more than one way to move in this game!
4200 # Test for conditions which prevent calling for help
4201 if game.condition == "docked":
4202 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4205 prout(_("Subspace radio damaged."))
4207 if not game.state.baseq:
4208 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4211 prout(_("You must be aboard the %s.") % crmshp())
4213 # OK -- call for help from nearest starbase
4216 # There's one in this quadrant
4217 ddist = (game.base - game.sector).distance()
4220 for ibq in game.state.baseq:
4221 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4224 # Since starbase not in quadrant, set up new quadrant
4227 # dematerialize starship
4228 game.quad[game.sector.i][game.sector.j]='.'
4229 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4230 % (game.quadrant, crmshp()))
4231 game.sector.invalidate()
4232 for m in range(1, 5+1):
4233 w = game.base.scatter()
4234 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4235 # found one -- finish up
4238 if not game.sector.is_valid():
4239 prout(_("You have been lost in space..."))
4240 finish(FMATERIALIZE)
4242 # Give starbase three chances to rematerialize starship
4243 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4244 for m in range(1, 3+1):
4245 if m == 1: proutn(_("1st"))
4246 elif m == 2: proutn(_("2nd"))
4247 elif m == 3: proutn(_("3rd"))
4248 proutn(_(" attempt to re-materialize ") + crmshp())
4249 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4252 if randreal() > probf:
4256 curses.delay_output(500)
4258 game.quad[game.sector.i][game.sector.j]='?'
4261 setwnd(message_window)
4262 finish(FMATERIALIZE)
4264 game.quad[game.sector.i][game.sector.j]=game.ship
4266 prout(_("succeeds."))
4270 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4275 if game.condition=="docked":
4277 prout(_("You cannot abandon Ye Faerie Queene."))
4280 # Must take shuttle craft to exit
4281 if game.damage[DSHUTTL]==-1:
4282 prout(_("Ye Faerie Queene has no shuttle craft."))
4284 if game.damage[DSHUTTL]<0:
4285 prout(_("Shuttle craft now serving Big Macs."))
4287 if game.damage[DSHUTTL]>0:
4288 prout(_("Shuttle craft damaged."))
4291 prout(_("You must be aboard the ship."))
4293 if game.iscraft != "onship":
4294 prout(_("Shuttle craft not currently available."))
4296 # Emit abandon ship messages
4298 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4300 prouts(_("***ALL HANDS ABANDON SHIP!"))
4302 prout(_("Captain and crew escape in shuttle craft."))
4303 if not game.state.baseq:
4304 # Oops! no place to go...
4307 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4309 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4310 prout(_("Remainder of ship's complement beam down"))
4311 prout(_("to nearest habitable planet."))
4312 elif q.planet != None and not damaged(DTRANSP):
4313 prout(_("Remainder of ship's complement beam down to %s.") %
4316 prout(_("Entire crew of %d left to die in outer space.") %
4318 game.casual += game.state.crew
4319 game.abandoned += game.state.crew
4320 # If at least one base left, give 'em the Faerie Queene
4322 game.icrystl = False # crystals are lost
4323 game.nprobes = 0 # No probes
4324 prout(_("You are captured by Klingons and released to"))
4325 prout(_("the Federation in a prisoner-of-war exchange."))
4326 nb = randrange(len(game.state.baseq))
4327 # Set up quadrant and position FQ adjacient to base
4328 if not game.quadrant == game.state.baseq[nb]:
4329 game.quadrant = game.state.baseq[nb]
4330 game.sector.i = game.sector.j = 5
4333 # position next to base by trial and error
4334 game.quad[game.sector.i][game.sector.j] = '.'
4335 for l in range(QUADSIZE):
4336 game.sector = game.base.scatter()
4337 if game.sector.valid_sector() and \
4338 game.quad[game.sector.i][game.sector.j] == '.':
4341 break # found a spot
4342 game.sector.i=QUADSIZE/2
4343 game.sector.j=QUADSIZE/2
4345 # Get new commission
4346 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4347 game.state.crew = FULLCREW
4348 prout(_("Starfleet puts you in command of another ship,"))
4349 prout(_("the Faerie Queene, which is antiquated but,"))
4350 prout(_("still useable."))
4352 prout(_("The dilithium crystals have been moved."))
4354 game.iscraft = "offship" # Galileo disappears
4356 game.condition="docked"
4357 for l in range(NDEVICES):
4358 game.damage[l] = 0.0
4359 game.damage[DSHUTTL] = -1
4360 game.energy = game.inenrg = 3000.0
4361 game.shield = game.inshld = 1250.0
4362 game.torps = game.intorps = 6
4363 game.lsupres=game.inlsr=3.0
4368 # Code from planets.c begins here.
4371 "Abort a lengthy operation if an event interrupts it."
4374 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4379 "Report on (uninhabited) planets in the galaxy."
4383 prout(_("Spock- \"Planet report follows, Captain.\""))
4385 for i in range(game.inplan):
4386 if game.state.planets[i].pclass == "destroyed":
4388 if (game.state.planets[i].known != "unknown" \
4389 and not game.state.planets[i].inhabited) \
4392 if game.idebug and game.state.planets[i].known=="unknown":
4393 proutn("(Unknown) ")
4394 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4395 proutn(_(" class "))
4396 proutn(game.state.planets[i].pclass)
4398 if game.state.planets[i].crystals != "present":
4400 prout(_("dilithium crystals present."))
4401 if game.state.planets[i].known=="shuttle_down":
4402 prout(_(" Shuttle Craft Galileo on surface."))
4404 prout(_("No information available."))
4407 "Enter standard orbit."
4411 prout(_("Already in standard orbit."))
4413 if damaged(DWARPEN) and damaged(DIMPULS):
4414 prout(_("Both warp and impulse engines damaged."))
4416 if not game.plnet.is_valid():
4417 prout("There is no planet in this sector.")
4419 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4420 prout(crmshp() + _(" not adjacent to planet."))
4423 game.optime = randreal(0.02, 0.05)
4424 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4428 game.height = randreal(1400, 8600)
4429 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4434 "Examine planets in this quadrant."
4435 if damaged(DSRSENS):
4436 if game.options & OPTION_TTY:
4437 prout(_("Short range sensors damaged."))
4439 if game.iplnet == None:
4440 if game.options & OPTION_TTY:
4441 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4443 if game.iplnet.known == "unknown":
4444 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4446 prout(_(" Planet at Sector %s is of class %s.") %
4447 (game.plnet, game.iplnet.pclass))
4448 if game.iplnet.known=="shuttle_down":
4449 prout(_(" Sensors show Galileo still on surface."))
4450 proutn(_(" Readings indicate"))
4451 if game.iplnet.crystals != "present":
4453 prout(_(" dilithium crystals present.\""))
4454 if game.iplnet.known == "unknown":
4455 game.iplnet.known = "known"
4456 elif game.iplnet.inhabited:
4457 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4458 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4461 "Use the transporter."
4465 if damaged(DTRANSP):
4466 prout(_("Transporter damaged."))
4467 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4469 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4473 if not game.inorbit:
4474 prout(crmshp() + _(" not in standard orbit."))
4477 prout(_("Impossible to transport through shields."))
4479 if game.iplnet.known=="unknown":
4480 prout(_("Spock- \"Captain, we have no information on this planet"))
4481 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4482 prout(_(" you may not go down.\""))
4484 if not game.landed and game.iplnet.crystals=="absent":
4485 prout(_("Spock- \"Captain, I fail to see the logic in"))
4486 prout(_(" exploring a planet with no dilithium crystals."))
4487 proutn(_(" Are you sure this is wise?\" "))
4491 if not (game.options & OPTION_PLAIN):
4492 nrgneed = 50 * game.skill + game.height / 100.0
4493 if nrgneed > game.energy:
4494 prout(_("Engineering to bridge--"))
4495 prout(_(" Captain, we don't have enough energy for transportation."))
4497 if not game.landed and nrgneed * 2 > game.energy:
4498 prout(_("Engineering to bridge--"))
4499 prout(_(" Captain, we have enough energy only to transport you down to"))
4500 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4501 if game.iplnet.known == "shuttle_down":
4502 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4503 proutn(_(" Are you sure this is wise?\" "))
4508 # Coming from planet
4509 if game.iplnet.known=="shuttle_down":
4510 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4514 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4515 prout(_("Landing party assembled, ready to beam up."))
4517 prout(_("Kirk whips out communicator..."))
4518 prouts(_("BEEP BEEP BEEP"))
4520 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4523 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4525 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4527 prout(_("Kirk- \"Energize.\""))
4530 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4533 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4535 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4538 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4539 game.landed = not game.landed
4540 game.energy -= nrgneed
4542 prout(_("Transport complete."))
4543 if game.landed and game.iplnet.known=="shuttle_down":
4544 prout(_("The shuttle craft Galileo is here!"))
4545 if not game.landed and game.imine:
4552 "Strip-mine a world for dilithium."
4556 prout(_("Mining party not on planet."))
4558 if game.iplnet.crystals == "mined":
4559 prout(_("This planet has already been strip-mined for dilithium."))
4561 elif game.iplnet.crystals == "absent":
4562 prout(_("No dilithium crystals on this planet."))
4565 prout(_("You've already mined enough crystals for this trip."))
4567 if game.icrystl and game.cryprob == 0.05:
4568 prout(_("With all those fresh crystals aboard the ") + crmshp())
4569 prout(_("there's no reason to mine more at this time."))
4571 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4574 prout(_("Mining operation complete."))
4575 game.iplnet.crystals = "mined"
4576 game.imine = game.ididit = True
4579 "Use dilithium crystals."
4583 if not game.icrystl:
4584 prout(_("No dilithium crystals available."))
4586 if game.energy >= 1000:
4587 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4588 prout(_(" except when Condition Yellow exists."))
4590 prout(_("Spock- \"Captain, I must warn you that loading"))
4591 prout(_(" raw dilithium crystals into the ship's power"))
4592 prout(_(" system may risk a severe explosion."))
4593 proutn(_(" Are you sure this is wise?\" "))
4598 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4599 prout(_(" Mr. Spock and I will try it.\""))
4601 prout(_("Spock- \"Crystals in place, Sir."))
4602 prout(_(" Ready to activate circuit.\""))
4604 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4606 if withprob(game.cryprob):
4607 prouts(_(" \"Activating now! - - No good! It's***"))
4609 prouts(_("***RED ALERT! RED A*L********************************"))
4612 prouts(_("****************** KA-BOOM!!!! *******************"))
4616 game.energy += randreal(5000.0, 5500.0)
4617 prouts(_(" \"Activating now! - - "))
4618 prout(_("The instruments"))
4619 prout(_(" are going crazy, but I think it's"))
4620 prout(_(" going to work!! Congratulations, Sir!\""))
4625 "Use shuttlecraft for planetary jaunt."
4628 if damaged(DSHUTTL):
4629 if game.damage[DSHUTTL] == -1.0:
4630 if game.inorbit and game.iplnet.known == "shuttle_down":
4631 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4633 prout(_("Ye Faerie Queene had no shuttle craft."))
4634 elif game.damage[DSHUTTL] > 0:
4635 prout(_("The Galileo is damaged."))
4636 else: # game.damage[DSHUTTL] < 0
4637 prout(_("Shuttle craft is now serving Big Macs."))
4639 if not game.inorbit:
4640 prout(crmshp() + _(" not in standard orbit."))
4642 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4643 prout(_("Shuttle craft not currently available."))
4645 if not game.landed and game.iplnet.known=="shuttle_down":
4646 prout(_("You will have to beam down to retrieve the shuttle craft."))
4648 if game.shldup or game.condition == "docked":
4649 prout(_("Shuttle craft cannot pass through shields."))
4651 if game.iplnet.known=="unknown":
4652 prout(_("Spock- \"Captain, we have no information on this planet"))
4653 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4654 prout(_(" you may not fly down.\""))
4656 game.optime = 3.0e-5*game.height
4657 if game.optime >= 0.8*game.state.remtime:
4658 prout(_("First Officer Spock- \"Captain, I compute that such"))
4659 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4660 int(100*game.optime/game.state.remtime))
4661 prout(_("remaining time."))
4662 proutn(_("Are you sure this is wise?\" "))
4668 if game.iscraft == "onship":
4670 if not damaged(DTRANSP):
4671 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4675 proutn(_("Shuttle crew"))
4677 proutn(_("Rescue party"))
4678 prout(_(" boards Galileo and swoops toward planet surface."))
4679 game.iscraft = "offship"
4683 game.iplnet.known="shuttle_down"
4684 prout(_("Trip complete."))
4687 # Ready to go back to ship
4688 prout(_("You and your mining party board the"))
4689 prout(_("shuttle craft for the trip back to the Enterprise."))
4691 prouts(_("The short hop begins . . ."))
4693 game.iplnet.known="known"
4699 game.iscraft = "onship"
4705 prout(_("Trip complete."))
4708 # Kirk on ship and so is Galileo
4709 prout(_("Mining party assembles in the hangar deck,"))
4710 prout(_("ready to board the shuttle craft \"Galileo\"."))
4712 prouts(_("The hangar doors open; the trip begins."))
4715 game.iscraft = "offship"
4718 game.iplnet.known = "shuttle_down"
4721 prout(_("Trip complete."))
4725 "Use the big zapper."
4729 if game.ship != 'E':
4730 prout(_("Ye Faerie Queene has no death ray."))
4732 if len(game.enemies)==0:
4733 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4736 prout(_("Death Ray is damaged."))
4738 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4739 prout(_(" is highly unpredictible. Considering the alternatives,"))
4740 proutn(_(" are you sure this is wise?\" "))
4743 prout(_("Spock- \"Acknowledged.\""))
4746 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4748 prout(_("Crew scrambles in emergency preparation."))
4749 prout(_("Spock and Scotty ready the death ray and"))
4750 prout(_("prepare to channel all ship's power to the device."))
4752 prout(_("Spock- \"Preparations complete, sir.\""))
4753 prout(_("Kirk- \"Engage!\""))
4755 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4758 if game.options & OPTION_PLAIN:
4762 prouts(_("Sulu- \"Captain! It's working!\""))
4764 while len(game.enemies) > 0:
4765 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4766 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4767 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4769 if (game.options & OPTION_PLAIN) == 0:
4770 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4772 prout(_(" is still operational.\""))
4774 prout(_(" has been rendered nonfunctional.\""))
4775 game.damage[DDRAY] = 39.95
4777 r = randreal() # Pick failure method
4779 prouts(_("Sulu- \"Captain! It's working!\""))
4781 prouts(_("***RED ALERT! RED ALERT!"))
4783 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4785 prouts(_("***RED ALERT! RED A*L********************************"))
4788 prouts(_("****************** KA-BOOM!!!! *******************"))
4793 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4795 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4797 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4798 prout(_(" have apparently been transformed into strange mutations."))
4799 prout(_(" Vulcans do not seem to be affected."))
4801 prout(_("Kirk- \"Raauch! Raauch!\""))
4805 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4807 proutn(_("Spock- \"I believe the word is"))
4808 prouts(_(" *ASTONISHING*"))
4809 prout(_(" Mr. Sulu."))
4810 for i in range(QUADSIZE):
4811 for j in range(QUADSIZE):
4812 if game.quad[i][j] == '.':
4813 game.quad[i][j] = '?'
4814 prout(_(" Captain, our quadrant is now infested with"))
4815 prouts(_(" - - - - - - *THINGS*."))
4817 prout(_(" I have no logical explanation.\""))
4819 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4821 prout(_("Scotty- \"There are so many tribbles down here"))
4822 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4826 # Code from reports.c begins here
4828 def attackreport(curt):
4829 "eport status of bases under attack."
4831 if is_scheduled(FCDBAS):
4832 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4833 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4834 elif game.isatb == 1:
4835 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4836 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4838 prout(_("No Starbase is currently under attack."))
4840 if is_scheduled(FCDBAS):
4841 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4843 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4847 # report on general game status
4849 s1 = (game.thawed and _("thawed ")) or ""
4850 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4851 s3 = (None, _("novice"), _("fair"),
4852 _("good"), _("expert"), _("emeritus"))[game.skill]
4853 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4854 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4855 prout(_("No plaque is allowed."))
4857 prout(_("This is tournament game %d.") % game.tourn)
4858 prout(_("Your secret password is \"%s\"") % game.passwd)
4859 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4860 (game.inkling + game.incom + game.inscom)))
4861 if game.incom - len(game.state.kcmdr):
4862 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4863 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4864 prout(_(", but no Commanders."))
4867 if game.skill > SKILL_FAIR:
4868 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4869 if len(game.state.baseq) != game.inbase:
4871 if game.inbase-len(game.state.baseq)==1:
4872 proutn(_("has been 1 base"))
4874 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4875 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4877 prout(_("There are %d bases.") % game.inbase)
4878 if communicating() or game.iseenit:
4879 # Don't report this if not seen and
4880 # either the radio is dead or not at base!
4884 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4886 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4887 if game.ship == 'E':
4888 proutn(_("You have "))
4890 proutn("%d" % (game.nprobes))
4893 proutn(_(" deep space probe"))
4897 if communicating() and is_scheduled(FDSPROB):
4899 proutn(_("An armed deep space probe is in "))
4901 proutn(_("A deep space probe is in "))
4902 prout("Quadrant %s." % game.probec)
4904 if game.cryprob <= .05:
4905 prout(_("Dilithium crystals aboard ship... not yet used."))
4909 while game.cryprob > ai:
4912 prout(_("Dilithium crystals have been used %d time%s.") % \
4913 (i, (_("s"), "")[i==1]))
4917 "Long-range sensor scan."
4918 if damaged(DLRSENS):
4919 # Now allow base's sensors if docked
4920 if game.condition != "docked":
4922 prout(_("LONG-RANGE SENSORS DAMAGED."))
4925 prout(_("Starbase's long-range scan"))
4927 prout(_("Long-range scan"))
4928 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4931 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4932 if not Coord(x, y).valid_quadrant():
4936 if not damaged(DRADIO):
4937 game.state.galaxy[x][y].charted = True
4938 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4939 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4940 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4941 if not silent and game.state.galaxy[x][y].supernova:
4944 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4952 for i in range(NDEVICES):
4955 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4956 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4958 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4959 game.damage[i]+0.05,
4960 DOCKFAC*game.damage[i]+0.005))
4962 prout(_("All devices functional."))
4965 "Update the chart in the Enterprise's computer from galaxy data."
4966 game.lastchart = game.state.date
4967 for i in range(GALSIZE):
4968 for j in range(GALSIZE):
4969 if game.state.galaxy[i][j].charted:
4970 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
4971 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
4972 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
4975 "Display the star chart."
4977 if (game.options & OPTION_AUTOSCAN):
4979 if not damaged(DRADIO):
4981 if game.lastchart < game.state.date and game.condition == "docked":
4982 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
4984 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
4985 if game.state.date > game.lastchart:
4986 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
4987 prout(" 1 2 3 4 5 6 7 8")
4988 for i in range(GALSIZE):
4989 proutn("%d |" % (i+1))
4990 for j in range(GALSIZE):
4991 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4995 if game.state.galaxy[i][j].supernova:
4997 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
4999 elif game.state.galaxy[i][j].charted:
5000 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5004 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5012 def sectscan(goodScan, i, j):
5013 "Light up an individual dot in a sector."
5014 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5015 textcolor({"green":GREEN,
5019 "dead":BROWN}[game.condition])
5020 if game.quad[i][j] != game.ship:
5022 proutn("%c " % game.quad[i][j])
5028 "Emit status report lines"
5029 if not req or req == 1:
5030 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5031 % (game.state.date, game.state.remtime))
5032 if not req or req == 2:
5033 if game.condition != "docked":
5035 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5036 (game.condition.upper(), sum(map(lambda x: x > 0, game.damage))))
5037 if not req or req == 3:
5038 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5039 if not req or req == 4:
5040 if damaged(DLIFSUP):
5041 if game.condition == "docked":
5042 s = _("DAMAGED, Base provides")
5044 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5047 prstat(_("Life Support"), s)
5048 if not req or req == 5:
5049 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5050 if not req or req == 6:
5052 if game.icrystl and (game.options & OPTION_SHOWME):
5053 extra = _(" (have crystals)")
5054 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5055 if not req or req == 7:
5056 prstat(_("Torpedoes"), "%d" % (game.torps))
5057 if not req or req == 8:
5058 if damaged(DSHIELD):
5064 data = _(" %d%% %.1f units") \
5065 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5066 prstat(_("Shields"), s+data)
5067 if not req or req == 9:
5068 prstat(_("Klingons Left"), "%d" \
5069 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5070 if not req or req == 10:
5071 if game.options & OPTION_WORLDS:
5072 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5073 if plnet and plnet.inhabited:
5074 prstat(_("Major system"), plnet.name)
5076 prout(_("Sector is uninhabited"))
5077 elif not req or req == 11:
5078 attackreport(not req)
5081 "Request specified status data, a historical relic from slow TTYs."
5082 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5083 while scanner.next() == "IHEOL":
5084 proutn(_("Information desired? "))
5086 if scanner.token in requests:
5087 status(requests.index(scanner.token))
5089 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5090 prout((" date, condition, position, lsupport, warpfactor,"))
5091 prout((" energy, torpedoes, shields, klingons, system, time."))
5096 if damaged(DSRSENS):
5097 # Allow base's sensors if docked
5098 if game.condition != "docked":
5099 prout(_(" S.R. SENSORS DAMAGED!"))
5102 prout(_(" [Using Base's sensors]"))
5104 prout(_(" Short-range scan"))
5105 if goodScan and not damaged(DRADIO):
5106 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5107 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5108 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5109 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5110 prout(" 1 2 3 4 5 6 7 8 9 10")
5111 if game.condition != "docked":
5113 for i in range(QUADSIZE):
5114 proutn("%2d " % (i+1))
5115 for j in range(QUADSIZE):
5116 sectscan(goodScan, i, j)
5120 "Use computer to get estimated time of arrival for a warp jump."
5121 w1 = Coord(); w2 = Coord()
5123 if damaged(DCOMPTR):
5124 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5127 if scanner.next() != "IHREAL":
5130 proutn(_("Destination quadrant and/or sector? "))
5131 if scanner.next()!="IHREAL":
5134 w1.j = int(scanner.real-0.5)
5135 if scanner.next() != "IHREAL":
5138 w1.i = int(scanner.real-0.5)
5139 if scanner.next() == "IHREAL":
5140 w2.j = int(scanner.real-0.5)
5141 if scanner.next() != "IHREAL":
5144 w2.i = int(scanner.real-0.5)
5146 if game.quadrant.j>w1.i:
5150 if game.quadrant.i>w1.j:
5154 if not w1.valid_quadrant() or not w2.valid_sector():
5157 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5158 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5161 prout(_("Answer \"no\" if you don't know the value:"))
5164 proutn(_("Time or arrival date? "))
5165 if scanner.next()=="IHREAL":
5166 ttime = scanner.real
5167 if ttime > game.state.date:
5168 ttime -= game.state.date # Actually a star date
5169 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5170 if ttime <= 1e-10 or twarp > 10:
5171 prout(_("We'll never make it, sir."))
5178 proutn(_("Warp factor? "))
5179 if scanner.next()== "IHREAL":
5181 twarp = scanner.real
5182 if twarp<1.0 or twarp > 10.0:
5186 prout(_("Captain, certainly you can give me one of these."))
5189 ttime = (10.0*dist)/twarp**2
5190 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5191 if tpower >= game.energy:
5192 prout(_("Insufficient energy, sir."))
5193 if not game.shldup or tpower > game.energy*2.0:
5196 proutn(_("New warp factor to try? "))
5197 if scanner.next() == "IHREAL":
5199 twarp = scanner.real
5200 if twarp<1.0 or twarp > 10.0:
5208 prout(_("But if you lower your shields,"))
5209 proutn(_("remaining"))
5212 proutn(_("Remaining"))
5213 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5215 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5217 prout(_("Any warp speed is adequate."))
5219 prout(_("Minimum warp needed is %.2f,") % (twarp))
5220 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5221 if game.state.remtime < ttime:
5222 prout(_("Unfortunately, the Federation will be destroyed by then."))
5224 prout(_("You'll be taking risks at that speed, Captain"))
5225 if (game.isatb==1 and game.state.kscmdr == w1 and \
5226 scheduled(FSCDBAS)< ttime+game.state.date) or \
5227 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5228 prout(_("The starbase there will be destroyed by then."))
5229 proutn(_("New warp factor to try? "))
5230 if scanner.next() == "IHREAL":
5232 twarp = scanner.real
5233 if twarp<1.0 or twarp > 10.0:
5241 # Code from setup.c begins here
5244 "Issue a historically correct banner."
5246 prout(_("-SUPER- STAR TREK"))
5248 # From the FORTRAN original
5249 # prout(_("Latest update-21 Sept 78"))
5255 scanner.push("emsave.trk")
5256 key = scanner.next()
5258 proutn(_("File name: "))
5259 key = scanner.next()
5260 if key != "IHALPHA":
5263 if '.' not in scanner.token:
5264 scanner.token += ".trk"
5266 fp = open(scanner.token, "wb")
5268 prout(_("Can't freeze game as file %s") % scanner.token)
5270 cPickle.dump(game, fp)
5275 "Retrieve saved game."
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, "rb")
5290 prout(_("Can't thaw game in %s") % scanner.token)
5292 game = cPickle.load(fp)
5297 # I used <http://www.memory-alpha.org> to find planets
5298 # with references in ST:TOS. Earth and the Alpha Centauri
5299 # Colony have been omitted.
5301 # Some planets marked Class G and P here will be displayed as class M
5302 # because of the way planets are generated. This is a known bug.
5305 _("Andoria (Fesoan)"), # several episodes
5306 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5307 _("Vulcan (T'Khasi)"), # many episodes
5308 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5309 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5310 _("Ardana"), # TOS: "The Cloud Minders"
5311 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5312 _("Gideon"), # TOS: "The Mark of Gideon"
5313 _("Aldebaran III"), # TOS: "The Deadly Years"
5314 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5315 _("Altair IV"), # TOS: "Amok Time
5316 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5317 _("Benecia"), # TOS: "The Conscience of the King"
5318 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5319 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5320 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5321 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5322 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5323 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5324 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5325 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5326 _("Ingraham B"), # TOS: "Operation: Annihilate"
5327 _("Janus IV"), # TOS: "The Devil in the Dark"
5328 _("Makus III"), # TOS: "The Galileo Seven"
5329 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5330 _("Omega IV"), # TOS: "The Omega Glory"
5331 _("Regulus V"), # TOS: "Amok Time
5332 _("Deneva"), # TOS: "Operation -- Annihilate!"
5333 # Worlds from BSD Trek
5334 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5335 _("Beta III"), # TOS: "The Return of the Archons"
5336 _("Triacus"), # TOS: "And the Children Shall Lead",
5337 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5339 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5340 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5341 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5342 # _("Izar"), # TOS: "Whom Gods Destroy"
5343 # _("Tiburon"), # TOS: "The Way to Eden"
5344 # _("Merak II"), # TOS: "The Cloud Minders"
5345 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5346 # _("Iotia"), # TOS: "A Piece of the Action"
5350 _("S. R. Sensors"), \
5351 _("L. R. Sensors"), \
5353 _("Photon Tubes"), \
5354 _("Life Support"), \
5355 _("Warp Engines"), \
5356 _("Impulse Engines"), \
5358 _("Subspace Radio"), \
5359 _("Shuttle Craft"), \
5361 _("Navigation System"), \
5363 _("Shield Control"), \
5369 "Prepare to play, set up cosmos."
5371 # Decide how many of everything
5373 return # frozen game
5374 # Prepare the Enterprise
5375 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5377 game.state.crew = FULLCREW
5378 game.energy = game.inenrg = 5000.0
5379 game.shield = game.inshld = 2500.0
5382 game.quadrant = randplace(GALSIZE)
5383 game.sector = randplace(QUADSIZE)
5384 game.torps = game.intorps = 10
5385 game.nprobes = randrange(2, 5)
5387 for i in range(NDEVICES):
5388 game.damage[i] = 0.0
5389 # Set up assorted game parameters
5390 game.battle = Coord()
5391 game.state.date = game.indate = 100.0 * randreal(20, 51)
5392 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5393 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5394 game.isatb = game.state.nplankl = 0
5395 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5396 game.iscraft = "onship"
5401 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5403 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5405 game.state.planets = [] # Planet information
5406 game.state.baseq = [] # Base quadrant coordinates
5407 game.state.kcmdr = [] # Commander quadrant coordinates
5408 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5410 # Starchart is functional but we've never seen it
5411 game.lastchart = FOREVER
5412 # Put stars in the galaxy
5414 for i in range(GALSIZE):
5415 for j in range(GALSIZE):
5416 k = randrange(1, QUADSIZE**2/10+1)
5418 game.state.galaxy[i][j].stars = k
5419 # Locate star bases in galaxy
5420 for i in range(game.inbase):
5423 w = randplace(GALSIZE)
5424 if not game.state.galaxy[w.i][w.j].starbase:
5427 # C version: for (j = i-1; j > 0; j--)
5428 # so it did them in the opposite order.
5429 for j in range(1, i):
5430 # Improved placement algorithm to spread out bases
5431 distq = (w - game.state.baseq[j]).distance()
5432 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5435 prout("=== Abandoning base #%d at %s" % (i, w))
5437 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5439 prout("=== Saving base #%d, close to #%d" % (i, j))
5442 game.state.baseq.append(w)
5443 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5444 # Position ordinary Klingon Battle Cruisers
5446 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5447 if klumper > MAXKLQUAD:
5451 klump = (1.0 - r*r)*klumper
5456 w = randplace(GALSIZE)
5457 if not game.state.galaxy[w.i][w.j].supernova and \
5458 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5460 game.state.galaxy[w.i][w.j].klingons += int(klump)
5463 # Position Klingon Commander Ships
5464 for i in range(game.incom):
5466 w = randplace(GALSIZE)
5467 if not welcoming(w) or w in game.state.kcmdr:
5469 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5471 game.state.galaxy[w.i][w.j].klingons += 1
5472 game.state.kcmdr.append(w)
5473 # Locate planets in galaxy
5474 for i in range(game.inplan):
5476 w = randplace(GALSIZE)
5477 if game.state.galaxy[w.i][w.j].planet == None:
5481 new.crystals = "absent"
5482 if (game.options & OPTION_WORLDS) and i < NINHAB:
5483 new.pclass = "M" # All inhabited planets are class M
5484 new.crystals = "absent"
5486 new.name = systnames[i]
5487 new.inhabited = True
5489 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5491 new.crystals = "present"
5492 new.known = "unknown"
5493 new.inhabited = False
5494 game.state.galaxy[w.i][w.j].planet = new
5495 game.state.planets.append(new)
5497 for i in range(game.state.nromrem):
5498 w = randplace(GALSIZE)
5499 game.state.galaxy[w.i][w.j].romulans += 1
5500 # Place the Super-Commander if needed
5501 if game.state.nscrem > 0:
5503 w = randplace(GALSIZE)
5506 game.state.kscmdr = w
5507 game.state.galaxy[w.i][w.j].klingons += 1
5508 # Initialize times for extraneous events
5509 schedule(FSNOVA, expran(0.5 * game.intime))
5510 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5511 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5512 schedule(FBATTAK, expran(0.3*game.intime))
5514 if game.state.nscrem:
5515 schedule(FSCMOVE, 0.2777)
5520 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5521 schedule(FDISTR, expran(1.0 + game.intime))
5526 # Place thing (in tournament game, we don't want one!)
5527 # New in SST2K: never place the Thing near a starbase.
5528 # This makes sense and avoids a special case in the old code.
5530 if game.tourn is None:
5532 thing = randplace(GALSIZE)
5533 if thing not in game.state.baseq:
5536 game.state.snap = False
5537 if game.skill == SKILL_NOVICE:
5538 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5539 prout(_("a deadly Klingon invasion force. As captain of the United"))
5540 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5541 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5542 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5543 prout(_("your mission. As you proceed you may be given more time."))
5545 prout(_("You will have %d supporting starbases.") % (game.inbase))
5546 proutn(_("Starbase locations- "))
5548 prout(_("Stardate %d.") % int(game.state.date))
5550 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5551 prout(_("An unknown number of Romulans."))
5552 if game.state.nscrem:
5553 prout(_("And one (GULP) Super-Commander."))
5554 prout(_("%d stardates.") % int(game.intime))
5555 proutn(_("%d starbases in ") % game.inbase)
5556 for i in range(game.inbase):
5557 proutn(`game.state.baseq[i]`)
5560 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5561 proutn(_(" Sector %s") % game.sector)
5563 prout(_("Good Luck!"))
5564 if game.state.nscrem:
5565 prout(_(" YOU'LL NEED IT."))
5568 setwnd(message_window)
5570 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5572 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5573 attack(torps_ok=False)
5576 "Choose your game type."
5578 game.tourn = game.length = 0
5580 game.skill = SKILL_NONE
5582 # if not scanner.inqueue: # Can start with command line options
5583 proutn(_("Would you like a regular, tournament, or saved game? "))
5585 if scanner.sees("tournament"):
5586 while scanner.next() == "IHEOL":
5587 proutn(_("Type in tournament number-"))
5588 if scanner.real == 0:
5590 continue # We don't want a blank entry
5591 game.tourn = int(round(scanner.real))
5592 random.seed(scanner.real)
5594 logfp.write("# random.seed(%d)\n" % scanner.real)
5596 if scanner.sees("saved") or scanner.sees("frozen"):
5600 if game.passwd == None:
5602 if not game.alldone:
5603 game.thawed = True # No plaque if not finished
5607 if scanner.sees("regular"):
5609 proutn(_("What is \"%s\"? ") % scanner.token)
5611 while game.length==0 or game.skill==SKILL_NONE:
5612 if scanner.next() == "IHALPHA":
5613 if scanner.sees("short"):
5615 elif scanner.sees("medium"):
5617 elif scanner.sees("long"):
5619 elif scanner.sees("novice"):
5620 game.skill = SKILL_NOVICE
5621 elif scanner.sees("fair"):
5622 game.skill = SKILL_FAIR
5623 elif scanner.sees("good"):
5624 game.skill = SKILL_GOOD
5625 elif scanner.sees("expert"):
5626 game.skill = SKILL_EXPERT
5627 elif scanner.sees("emeritus"):
5628 game.skill = SKILL_EMERITUS
5630 proutn(_("What is \""))
5631 proutn(scanner.token)
5636 proutn(_("Would you like a Short, Medium, or Long game? "))
5637 elif game.skill == SKILL_NONE:
5638 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5639 # Choose game options -- added by ESR for SST2K
5640 if scanner.next() != "IHALPHA":
5642 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5644 if scanner.sees("plain"):
5645 # Approximates the UT FORTRAN version.
5646 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5647 game.options |= OPTION_PLAIN
5648 elif scanner.sees("almy"):
5649 # Approximates Tom Almy's version.
5650 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5651 game.options |= OPTION_ALMY
5652 elif scanner.sees("fancy") or scanner.sees("\n"):
5654 elif len(scanner.token):
5655 proutn(_("What is \"%s\"?") % scanner.token)
5656 game.options &=~ OPTION_COLOR
5658 if game.passwd == "debug":
5660 prout("=== Debug mode enabled.")
5661 # Use parameters to generate initial values of things
5662 game.damfac = 0.5 * game.skill
5663 game.inbase = randrange(BASEMIN, BASEMAX+1)
5665 if game.options & OPTION_PLANETS:
5666 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5667 if game.options & OPTION_WORLDS:
5668 game.inplan += int(NINHAB)
5669 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5670 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5671 game.state.remtime = 7.0 * game.length
5672 game.intime = game.state.remtime
5673 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5674 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5675 game.state.remres = (game.inkling+4*game.incom)*game.intime
5676 game.inresor = game.state.remres
5677 if game.inkling > 50:
5678 game.state.inbase += 1
5681 def dropin(iquad=None):
5682 "Drop a feature on a random dot in the current quadrant."
5684 w = randplace(QUADSIZE)
5685 if game.quad[w.i][w.j] == '.':
5687 if iquad is not None:
5688 game.quad[w.i][w.j] = iquad
5692 "Update our alert status."
5693 game.condition = "green"
5694 if game.energy < 1000.0:
5695 game.condition = "yellow"
5696 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5697 game.condition = "red"
5699 game.condition="dead"
5702 "Drop new Klingon into current quadrant."
5703 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5706 "Sort enemies by distance so 'nearest' is meaningful."
5707 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
5710 "Set up a new state of quadrant, for when we enter or re-enter it."
5713 game.neutz = game.inorbit = game.landed = False
5714 game.ientesc = game.iseenit = False
5715 # Create a blank quadrant
5716 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5718 # Attempt to escape Super-commander, so tbeam back!
5721 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5722 # cope with supernova
5725 game.klhere = q.klingons
5726 game.irhere = q.romulans
5728 game.quad[game.sector.i][game.sector.j] = game.ship
5731 # Position ordinary Klingons
5732 for i in range(game.klhere):
5734 # If we need a commander, promote a Klingon
5735 for cmdr in game.state.kcmdr:
5736 if cmdr == game.quadrant:
5737 e = game.enemies[game.klhere-1]
5738 game.quad[e.location.i][e.location.j] = 'C'
5739 e.power = randreal(950,1350) + 50.0*game.skill
5741 # If we need a super-commander, promote a Klingon
5742 if game.quadrant == game.state.kscmdr:
5744 game.quad[e.location.i][e.location.j] = 'S'
5745 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5746 game.iscate = (game.state.remkl > 1)
5747 # Put in Romulans if needed
5748 for i in range(q.romulans):
5749 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5750 # If quadrant needs a starbase, put it in
5752 game.base = dropin('B')
5753 # If quadrant needs a planet, put it in
5755 game.iplnet = q.planet
5756 if not q.planet.inhabited:
5757 game.plnet = dropin('P')
5759 game.plnet = dropin('@')
5760 # Check for condition
5763 if game.irhere > 0 and game.klhere == 0:
5765 if not damaged(DRADIO):
5767 prout(_("LT. Uhura- \"Captain, an urgent message."))
5768 prout(_(" I'll put it on audio.\" CLICK"))
5770 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5771 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5772 # Put in THING if needed
5773 if thing == game.quadrant:
5774 Enemy(type='?', loc=dropin(),
5775 power=randreal(6000,6500.0)+250.0*game.skill)
5776 if not damaged(DSRSENS):
5778 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5779 prout(_(" Please examine your short-range scan.\""))
5780 # Decide if quadrant needs a Tholian; lighten up if skill is low
5781 if game.options & OPTION_THOLIAN:
5782 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5783 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5784 (game.skill > SKILL_GOOD and withprob(0.08)):
5787 w.i = withprob(0.5) * (QUADSIZE-1)
5788 w.j = withprob(0.5) * (QUADSIZE-1)
5789 if game.quad[w.i][w.j] == '.':
5791 game.tholian = Enemy(type='T', loc=w,
5792 power=randrange(100, 500) + 25.0*game.skill)
5793 # Reserve unoccupied corners
5794 if game.quad[0][0]=='.':
5795 game.quad[0][0] = 'X'
5796 if game.quad[0][QUADSIZE-1]=='.':
5797 game.quad[0][QUADSIZE-1] = 'X'
5798 if game.quad[QUADSIZE-1][0]=='.':
5799 game.quad[QUADSIZE-1][0] = 'X'
5800 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5801 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5803 # And finally the stars
5804 for i in range(q.stars):
5806 # Put in a few black holes
5807 for i in range(1, 3+1):
5810 # Take out X's in corners if Tholian present
5812 if game.quad[0][0]=='X':
5813 game.quad[0][0] = '.'
5814 if game.quad[0][QUADSIZE-1]=='X':
5815 game.quad[0][QUADSIZE-1] = '.'
5816 if game.quad[QUADSIZE-1][0]=='X':
5817 game.quad[QUADSIZE-1][0] = '.'
5818 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5819 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5822 "Set the self-destruct password."
5823 if game.options & OPTION_PLAIN:
5826 proutn(_("Please type in a secret password- "))
5828 game.passwd = scanner.token
5829 if game.passwd != None:
5833 game.passwd += chr(ord('a')+randrange(26))
5834 game.passwd += chr(ord('a')+randrange(26))
5835 game.passwd += chr(ord('a')+randrange(26))
5837 # Code from sst.c begins here
5840 ("SRSCAN", OPTION_TTY),
5841 ("STATUS", OPTION_TTY),
5842 ("REQUEST", OPTION_TTY),
5843 ("LRSCAN", OPTION_TTY),
5856 ("SENSORS", OPTION_PLANETS),
5857 ("ORBIT", OPTION_PLANETS),
5858 ("TRANSPORT", OPTION_PLANETS),
5859 ("MINE", OPTION_PLANETS),
5860 ("CRYSTALS", OPTION_PLANETS),
5861 ("SHUTTLE", OPTION_PLANETS),
5862 ("PLANETS", OPTION_PLANETS),
5867 ("PROBE", OPTION_PROBE),
5869 ("FREEZE", 0), # Synonym for SAVE
5875 ("SOS", 0), # Synonym for MAYDAY
5876 ("CALL", 0), # Synonym for MAYDAY
5883 "Generate a list of legal commands."
5884 prout(_("LEGAL COMMANDS ARE:"))
5886 for (key, opt) in commands:
5887 if not opt or (opt & game.options):
5888 proutn("%-12s " % key)
5890 if emitted % 5 == 4:
5895 "Browse on-line help."
5896 key = scanner.next()
5899 setwnd(prompt_window)
5900 proutn(_("Help on what command? "))
5901 key = scanner.next()
5902 setwnd(message_window)
5905 cmds = map(lambda x: x[0], commands)
5906 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
5913 cmd = scanner.token.upper()
5914 for directory in docpath:
5916 fp = open(os.path.join(directory, "sst.doc"), "r")
5921 prout(_("Spock- \"Captain, that information is missing from the"))
5922 prout(_(" computer. You need to find sst.doc and put it somewhere"))
5923 proutn(_(" in these directories: %s") % ":".join(docpath))
5925 # This used to continue: "You need to find SST.DOC and put
5926 # it in the current directory."
5929 linebuf = fp.readline()
5931 prout(_("Spock- \"Captain, there is no information on that command.\""))
5934 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5935 linebuf = linebuf[3:].strip()
5936 if cmd.upper() == linebuf:
5939 prout(_("Spock- \"Captain, I've found the following information:\""))
5942 linebuf = fp.readline()
5943 if "******" in linebuf:
5949 "Command-interpretation loop."
5950 while True: # command loop
5952 while True: # get a command
5954 game.optime = game.justin = False
5956 setwnd(prompt_window)
5959 if scanner.next() == "IHEOL":
5960 if game.options & OPTION_CURSES:
5963 elif scanner.token == "":
5967 setwnd(message_window)
5969 abandon_passed = False
5970 for (cmd, opt) in commands:
5971 # commands after ABANDON cannot be abbreviated
5972 if cmd == "ABANDON":
5973 abandon_passed = True
5974 if cmd == scanner.token.upper() or (not abandon_passed \
5975 and cmd.startswith(scanner.token.upper())):
5982 if cmd == "SRSCAN": # srscan
5984 elif cmd == "STATUS": # status
5986 elif cmd == "REQUEST": # status request
5988 elif cmd == "LRSCAN": # long range scan
5989 lrscan(silent=False)
5990 elif cmd == "PHASERS": # phasers
5994 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
5998 elif cmd == "MOVE": # move under warp
5999 warp(wcourse=None, involuntary=False)
6000 elif cmd == "SHIELDS": # shields
6001 doshield(shraise=False)
6004 game.shldchg = False
6005 elif cmd == "DOCK": # dock at starbase
6008 attack(torps_ok=False)
6009 elif cmd == "DAMAGES": # damage reports
6011 elif cmd == "CHART": # chart
6013 elif cmd == "IMPULSE": # impulse
6015 elif cmd == "REST": # rest
6019 elif cmd == "WARP": # warp
6021 elif cmd == "SCORE": # score
6023 elif cmd == "SENSORS": # sensors
6025 elif cmd == "ORBIT": # orbit
6029 elif cmd == "TRANSPORT": # transport "beam"
6031 elif cmd == "MINE": # mine
6035 elif cmd == "CRYSTALS": # crystals
6039 elif cmd == "SHUTTLE": # shuttle
6043 elif cmd == "PLANETS": # Planet list
6045 elif cmd == "REPORT": # Game Report
6047 elif cmd == "COMPUTER": # use COMPUTER!
6049 elif cmd == "COMMANDS":
6051 elif cmd == "EMEXIT": # Emergency exit
6052 clrscr() # Hide screen
6053 freeze(True) # forced save
6054 raise SystemExit,1 # And quick exit
6055 elif cmd == "PROBE":
6056 probe() # Launch probe
6059 elif cmd == "ABANDON": # Abandon Ship
6061 elif cmd == "DESTRUCT": # Self Destruct
6063 elif cmd == "SAVE": # Save Game
6066 if game.skill > SKILL_GOOD:
6067 prout(_("WARNING--Saved games produce no plaques!"))
6068 elif cmd == "DEATHRAY": # Try a desparation measure
6072 elif cmd == "DEBUGCMD": # What do we want for debug???
6074 elif cmd == "MAYDAY": # Call for help
6079 game.alldone = True # quit the game
6084 break # Game has ended
6085 if game.optime != 0.0:
6088 break # Events did us in
6089 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6092 if hitme and not game.justin:
6093 attack(torps_ok=True)
6096 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6107 "Emit the name of an enemy or feature."
6108 if type == 'R': s = _("Romulan")
6109 elif type == 'K': s = _("Klingon")
6110 elif type == 'C': s = _("Commander")
6111 elif type == 'S': s = _("Super-commander")
6112 elif type == '*': s = _("Star")
6113 elif type == 'P': s = _("Planet")
6114 elif type == 'B': s = _("Starbase")
6115 elif type == ' ': s = _("Black hole")
6116 elif type == 'T': s = _("Tholian")
6117 elif type == '#': s = _("Tholian web")
6118 elif type == '?': s = _("Stranger")
6119 elif type == '@': s = _("Inhabited World")
6120 else: s = "Unknown??"
6123 def crmena(stars, enemy, loctype, w):
6124 "Emit the name of an enemy and his location."
6128 buf += cramen(enemy) + _(" at ")
6129 if loctype == "quadrant":
6130 buf += _("Quadrant ")
6131 elif loctype == "sector":
6136 "Emit our ship name."
6137 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6140 "Emit a line of stars"
6141 prouts("******************************************************")
6145 return -avrage*math.log(1e-7 + randreal())
6147 def randplace(size):
6148 "Choose a random location."
6150 w.i = randrange(size)
6151 w.j = randrange(size)
6161 # Get a token from the user
6164 # Fill the token quue if nothing here
6165 while not self.inqueue:
6167 if curwnd==prompt_window:
6169 setwnd(message_window)
6176 self.inqueue = line.lstrip().split() + ["\n"]
6177 # From here on in it's all looking at the queue
6178 self.token = self.inqueue.pop(0)
6179 if self.token == "\n":
6183 self.real = float(self.token)
6184 self.type = "IHREAL"
6189 self.token = self.token.lower()
6190 self.type = "IHALPHA"
6193 def append(self, tok):
6194 self.inqueue.append(tok)
6195 def push(self, tok):
6196 self.inqueue.insert(0, tok)
6200 # Demand input for next scan
6202 self.real = self.token = None
6204 # compares s to item and returns true if it matches to the length of s
6205 return s.startswith(self.token)
6207 # Round token value to nearest integer
6208 return int(round(scanner.real))
6212 if scanner.type != "IHREAL":
6215 s.i = scanner.int()-1
6217 if scanner.type != "IHREAL":
6220 s.j = scanner.int()-1
6223 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6226 "Yes-or-no confirmation."
6230 if scanner.token == 'y':
6232 if scanner.token == 'n':
6235 proutn(_("Please answer with \"y\" or \"n\": "))
6238 "Complain about unparseable input."
6241 prout(_("Beg your pardon, Captain?"))
6244 "Access to the internals for debugging."
6245 proutn("Reset levels? ")
6247 if game.energy < game.inenrg:
6248 game.energy = game.inenrg
6249 game.shield = game.inshld
6250 game.torps = game.intorps
6251 game.lsupres = game.inlsr
6252 proutn("Reset damage? ")
6254 for i in range(NDEVICES):
6255 if game.damage[i] > 0.0:
6256 game.damage[i] = 0.0
6257 proutn("Toggle debug flag? ")
6259 game.idebug = not game.idebug
6261 prout("Debug output ON")
6263 prout("Debug output OFF")
6264 proutn("Cause selective damage? ")
6266 for i in range(NDEVICES):
6267 proutn("Kill %s?" % device[i])
6269 key = scanner.next()
6270 if key == "IHALPHA" and scanner.sees("y"):
6271 game.damage[i] = 10.0
6272 proutn("Examine/change events? ")
6277 FSNOVA: "Supernova ",
6280 FBATTAK: "Base Attack ",
6281 FCDBAS: "Base Destroy ",
6282 FSCMOVE: "SC Move ",
6283 FSCDBAS: "SC Base Destroy ",
6284 FDSPROB: "Probe Move ",
6285 FDISTR: "Distress Call ",
6286 FENSLV: "Enslavement ",
6287 FREPRO: "Klingon Build ",
6289 for i in range(1, NEVENTS):
6292 proutn("%.2f" % (scheduled(i)-game.state.date))
6293 if i == FENSLV or i == FREPRO:
6295 proutn(" in %s" % ev.quadrant)
6300 key = scanner.next()
6304 elif key == "IHREAL":
6305 ev = schedule(i, scanner.real)
6306 if i == FENSLV or i == FREPRO:
6308 proutn("In quadrant- ")
6309 key = scanner.next()
6310 # "IHEOL" says to leave coordinates as they are
6313 prout("Event %d canceled, no x coordinate." % (i))
6316 w.i = int(round(scanner.real))
6317 key = scanner.next()
6319 prout("Event %d canceled, no y coordinate." % (i))
6322 w.j = int(round(scanner.real))
6325 proutn("Induce supernova here? ")
6327 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6330 if __name__ == '__main__':
6331 import getopt, socket
6333 global line, thing, game
6337 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6338 if os.getenv("TERM"):
6339 game.options |= OPTION_CURSES
6341 game.options |= OPTION_TTY
6342 seed = int(time.time())
6343 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6345 for (switch, val) in options:
6348 replayfp = open(val, "r")
6350 sys.stderr.write("sst: can't open replay file %s\n" % val)
6353 line = replayfp.readline().strip()
6354 (leader, __, seed) = line.split()
6356 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6357 line = replayfp.readline().strip()
6358 arguments += line.split()[2:]
6361 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6363 game.options |= OPTION_TTY
6364 game.options &=~ OPTION_CURSES
6365 elif switch == '-s':
6367 elif switch == '-t':
6368 game.options |= OPTION_TTY
6369 game.options &=~ OPTION_CURSES
6370 elif switch == '-x':
6372 elif switch == '-V':
6373 print "SST2K", version
6376 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6378 # where to save the input in case of bugs
6379 if "TMPDIR" in os.environ:
6380 tmpdir = os.environ['TMPDIR']
6384 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6386 sys.stderr.write("sst: warning, can't open logfile\n")
6389 logfp.write("# seed %s\n" % seed)
6390 logfp.write("# options %s\n" % " ".join(arguments))
6391 logfp.write("# recorded by %s@%s on %s\n" % \
6392 (getpass.getuser(),socket.gethostname(),time.ctime()))
6394 scanner = sstscanner()
6395 map(scanner.append, arguments)
6398 while True: # Play a game
6399 setwnd(fullscreen_window)
6405 game.alldone = False
6413 if game.tourn and game.alldone:
6414 proutn(_("Do you want your score recorded?"))
6420 proutn(_("Do you want to play again? "))
6424 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6428 except KeyboardInterrupt: