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."
1670 dustfac = randreal(0.9, 1.0)
1671 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1672 kpini = game.enemies[kk].power
1673 kp = math.fabs(kpini)
1674 if PHASEFAC*hit < kp:
1676 if game.enemies[kk].power < 0:
1677 game.enemies[kk].power -= -kp
1679 game.enemies[kk].power -= kp
1680 kpow = game.enemies[kk].power
1681 w = game.enemies[kk].location
1683 if not damaged(DSRSENS):
1685 proutn(_("%d unit hit on ") % int(hit))
1687 proutn(_("Very small hit on "))
1688 ienm = game.quad[w.i][w.j]
1691 proutn(crmena(False, ienm, "sector", w))
1695 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1699 kk -= 1 # don't do the increment
1701 else: # decide whether or not to emasculate klingon
1702 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1703 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1704 prout(_(" has just lost its firepower.\""))
1705 game.enemies[kk].power = -kpow
1710 "Fire phasers at bad guys."
1714 irec = 0 # Cheating inhibitor
1723 # SR sensors and Computer are needed for automode
1724 if damaged(DSRSENS) or damaged(DCOMPTR):
1726 if game.condition == "docked":
1727 prout(_("Phasers can't be fired through base shields."))
1730 if damaged(DPHASER):
1731 prout(_("Phaser control damaged."))
1735 if damaged(DSHCTRL):
1736 prout(_("High speed shield control damaged."))
1739 if game.energy <= 200.0:
1740 prout(_("Insufficient energy to activate high-speed shield control."))
1743 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1745 # Original code so convoluted, I re-did it all
1746 # (That was Tom Almy talking about the C code, I think -- ESR)
1747 while automode == "NOTSET":
1748 key = scanner.next()
1749 if key == "IHALPHA":
1750 if scanner.sees("manual"):
1751 if len(game.enemies)==0:
1752 prout(_("There is no enemy present to select."))
1755 automode = "AUTOMATIC"
1758 key = scanner.next()
1759 elif scanner.sees("automatic"):
1760 if (not itarg) and len(game.enemies) != 0:
1761 automode = "FORCEMAN"
1763 if len(game.enemies)==0:
1764 prout(_("Energy will be expended into space."))
1765 automode = "AUTOMATIC"
1766 key = scanner.next()
1767 elif scanner.sees("no"):
1772 elif key == "IHREAL":
1773 if len(game.enemies)==0:
1774 prout(_("Energy will be expended into space."))
1775 automode = "AUTOMATIC"
1777 automode = "FORCEMAN"
1779 automode = "AUTOMATIC"
1782 if len(game.enemies)==0:
1783 prout(_("Energy will be expended into space."))
1784 automode = "AUTOMATIC"
1786 automode = "FORCEMAN"
1788 proutn(_("Manual or automatic? "))
1793 if automode == "AUTOMATIC":
1794 if key == "IHALPHA" and scanner.sees("no"):
1796 key = scanner.next()
1797 if key != "IHREAL" and len(game.enemies) != 0:
1798 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1803 for i in range(len(game.enemies)):
1804 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1806 proutn(_("%d units required. ") % irec)
1808 proutn(_("Units to fire= "))
1809 key = scanner.next()
1814 proutn(_("Energy available= %.2f") % avail)
1817 if not rpow > avail:
1823 key = scanner.next()
1824 if key == "IHALPHA" and scanner.sees("no"):
1827 game.energy -= 200 # Go and do it!
1828 if checkshctrl(rpow):
1833 if len(game.enemies):
1836 for i in range(len(game.enemies)):
1840 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1841 over = randreal(1.01, 1.06) * hits[i]
1843 powrem -= hits[i] + over
1844 if powrem <= 0 and temp < hits[i]:
1853 if extra > 0 and not game.alldone:
1855 proutn(_("*** Tholian web absorbs "))
1856 if len(game.enemies)>0:
1857 proutn(_("excess "))
1858 prout(_("phaser energy."))
1860 prout(_("%d expended on empty space.") % int(extra))
1861 elif automode == "FORCEMAN":
1864 if damaged(DCOMPTR):
1865 prout(_("Battle computer damaged, manual fire only."))
1868 prouts(_("---WORKING---"))
1870 prout(_("Short-range-sensors-damaged"))
1871 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1872 prout(_("Manual-fire-must-be-used"))
1874 elif automode == "MANUAL":
1876 for k in range(len(game.enemies)):
1877 aim = game.enemies[k].location
1878 ienm = game.quad[aim.i][aim.j]
1880 proutn(_("Energy available= %.2f") % (avail-0.006))
1884 if damaged(DSRSENS) and \
1885 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1886 prout(cramen(ienm) + _(" can't be located without short range scan."))
1889 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
1894 if itarg and k > kz:
1895 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1898 if not damaged(DCOMPTR):
1903 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1904 key = scanner.next()
1905 if key == "IHALPHA" and scanner.sees("no"):
1907 key = scanner.next()
1909 if key == "IHALPHA":
1913 if k == 1: # Let me say I'm baffled by this
1916 if scanner.real < 0:
1920 hits[k] = scanner.real
1921 rpow += scanner.real
1922 # If total requested is too much, inform and start over
1924 prout(_("Available energy exceeded -- try again."))
1927 key = scanner.next() # scan for next value
1930 # zero energy -- abort
1933 if key == "IHALPHA" and scanner.sees("no"):
1938 game.energy -= 200.0
1939 if checkshctrl(rpow):
1943 # Say shield raised or malfunction, if necessary
1950 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1951 prouts(_(" CLICK CLICK POP . . ."))
1952 prout(_(" No response, sir!"))
1955 prout(_("Shields raised."))
1960 # Code from events,c begins here.
1962 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1963 # event of each type active at any given time. Mostly these means we can
1964 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1965 # BSD Trek, from which we swiped the idea, can have up to 5.
1967 def unschedule(evtype):
1968 "Remove an event from the schedule."
1969 game.future[evtype].date = FOREVER
1970 return game.future[evtype]
1972 def is_scheduled(evtype):
1973 "Is an event of specified type scheduled."
1974 return game.future[evtype].date != FOREVER
1976 def scheduled(evtype):
1977 "When will this event happen?"
1978 return game.future[evtype].date
1980 def schedule(evtype, offset):
1981 "Schedule an event of specified type."
1982 game.future[evtype].date = game.state.date + offset
1983 return game.future[evtype]
1985 def postpone(evtype, offset):
1986 "Postpone a scheduled event."
1987 game.future[evtype].date += offset
1990 "Rest period is interrupted by event."
1993 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
1995 game.resting = False
2001 "Run through the event queue looking for things to do."
2003 fintim = game.state.date + game.optime
2012 def tractorbeam(yank):
2013 "Tractor-beaming cases merge here."
2015 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2017 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2018 # If Kirk & Co. screwing around on planet, handle
2019 atover(True) # atover(true) is Grab
2022 if game.icraft: # Caught in Galileo?
2025 # Check to see if shuttle is aboard
2026 if game.iscraft == "offship":
2029 prout(_("Galileo, left on the planet surface, is captured"))
2030 prout(_("by aliens and made into a flying McDonald's."))
2031 game.damage[DSHUTTL] = -10
2032 game.iscraft = "removed"
2034 prout(_("Galileo, left on the planet surface, is well hidden."))
2036 game.quadrant = game.state.kscmdr
2038 game.quadrant = game.state.kcmdr[i]
2039 game.sector = randplace(QUADSIZE)
2040 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2041 % (game.quadrant, game.sector))
2043 prout(_("(Remainder of rest/repair period cancelled.)"))
2044 game.resting = False
2046 if not damaged(DSHIELD) and game.shield > 0:
2047 doshield(shraise=True) # raise shields
2048 game.shldchg = False
2050 prout(_("(Shields not currently useable.)"))
2052 # Adjust finish time to time of tractor beaming
2053 fintim = game.state.date+game.optime
2054 attack(torps_ok=False)
2055 if not game.state.kcmdr:
2058 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2061 "Code merges here for any commander destroying a starbase."
2062 # Not perfect, but will have to do
2063 # Handle case where base is in same quadrant as starship
2064 if game.battle == game.quadrant:
2065 game.state.chart[game.battle.i][game.battle.j].starbase = False
2066 game.quad[game.base.i][game.base.j] = '.'
2067 game.base.invalidate()
2070 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2071 elif game.state.baseq and communicating():
2072 # Get word via subspace radio
2075 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2076 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2078 prout(_("the Klingon Super-Commander"))
2080 prout(_("a Klingon Commander"))
2081 game.state.chart[game.battle.i][game.battle.j].starbase = False
2082 # Remove Starbase from galaxy
2083 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2084 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2086 # reinstate a commander's base attack
2090 game.battle.invalidate()
2092 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2093 for i in range(1, NEVENTS):
2094 if i == FSNOVA: proutn("=== Supernova ")
2095 elif i == FTBEAM: proutn("=== T Beam ")
2096 elif i == FSNAP: proutn("=== Snapshot ")
2097 elif i == FBATTAK: proutn("=== Base Attack ")
2098 elif i == FCDBAS: proutn("=== Base Destroy ")
2099 elif i == FSCMOVE: proutn("=== SC Move ")
2100 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2101 elif i == FDSPROB: proutn("=== Probe Move ")
2102 elif i == FDISTR: proutn("=== Distress Call ")
2103 elif i == FENSLV: proutn("=== Enslavement ")
2104 elif i == FREPRO: proutn("=== Klingon Build ")
2106 prout("%.2f" % (scheduled(i)))
2109 radio_was_broken = damaged(DRADIO)
2112 # Select earliest extraneous event, evcode==0 if no events
2117 for l in range(1, NEVENTS):
2118 if game.future[l].date < datemin:
2121 prout("== Event %d fires" % evcode)
2122 datemin = game.future[l].date
2123 xtime = datemin-game.state.date
2124 game.state.date = datemin
2125 # Decrement Federation resources and recompute remaining time
2126 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2128 if game.state.remtime <= 0:
2131 # Any crew left alive?
2132 if game.state.crew <= 0:
2135 # Is life support adequate?
2136 if damaged(DLIFSUP) and game.condition != "docked":
2137 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2140 game.lsupres -= xtime
2141 if game.damage[DLIFSUP] <= xtime:
2142 game.lsupres = game.inlsr
2145 if game.condition == "docked":
2147 # Don't fix Deathray here
2148 for l in range(NDEVICES):
2149 if game.damage[l] > 0.0 and l != DDRAY:
2150 if game.damage[l]-repair > 0.0:
2151 game.damage[l] -= repair
2153 game.damage[l] = 0.0
2154 # If radio repaired, update star chart and attack reports
2155 if radio_was_broken and not damaged(DRADIO):
2156 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2157 prout(_(" surveillance reports are coming in."))
2159 if not game.iseenit:
2163 prout(_(" The star chart is now up to date.\""))
2165 # Cause extraneous event EVCODE to occur
2166 game.optime -= xtime
2167 if evcode == FSNOVA: # Supernova
2170 schedule(FSNOVA, expran(0.5*game.intime))
2171 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2173 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2174 if game.state.nscrem == 0 or \
2175 ictbeam or istract or \
2176 game.condition == "docked" or game.isatb == 1 or game.iscate:
2178 if game.ientesc or \
2179 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2180 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2181 (damaged(DSHIELD) and \
2182 (game.energy < 2500 or damaged(DPHASER)) and \
2183 (game.torps < 5 or damaged(DPHOTON))):
2185 istract = ictbeam = True
2186 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2189 elif evcode == FTBEAM: # Tractor beam
2190 if not game.state.kcmdr:
2193 i = randrange(len(game.state.kcmdr))
2194 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2195 if istract or game.condition == "docked" or yank == 0:
2196 # Drats! Have to reschedule
2198 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2202 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2203 game.snapsht = copy.deepcopy(game.state)
2204 game.state.snap = True
2205 schedule(FSNAP, expran(0.5 * game.intime))
2206 elif evcode == FBATTAK: # Commander attacks starbase
2207 if not game.state.kcmdr or not game.state.baseq:
2213 for ibq in game.state.baseq:
2214 for cmdr in game.state.kcmdr:
2215 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2218 # no match found -- try later
2219 schedule(FBATTAK, expran(0.3*game.intime))
2224 # commander + starbase combination found -- launch attack
2226 schedule(FCDBAS, randreal(1.0, 4.0))
2227 if game.isatb: # extra time if SC already attacking
2228 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2229 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2230 game.iseenit = False
2231 if not communicating():
2232 continue # No warning :-(
2236 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2237 prout(_(" reports that it is under attack and that it can"))
2238 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2241 elif evcode == FSCDBAS: # Supercommander destroys base
2244 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2245 continue # WAS RETURN!
2247 game.battle = game.state.kscmdr
2249 elif evcode == FCDBAS: # Commander succeeds in destroying base
2250 if evcode == FCDBAS:
2252 if not game.state.baseq() \
2253 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2254 game.battle.invalidate()
2256 # find the lucky pair
2257 for cmdr in game.state.kcmdr:
2258 if cmdr == game.battle:
2261 # No action to take after all
2264 elif evcode == FSCMOVE: # Supercommander moves
2265 schedule(FSCMOVE, 0.2777)
2266 if not game.ientesc and not istract and game.isatb != 1 and \
2267 (not game.iscate or not game.justin):
2269 elif evcode == FDSPROB: # Move deep space probe
2270 schedule(FDSPROB, 0.01)
2271 if not game.probe.next():
2272 if not game.probe.quadrant().valid_quadrant() or \
2273 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2274 # Left galaxy or ran into supernova
2278 proutn(_("Lt. Uhura- \"The deep space probe "))
2279 if not game.probe.quadrant().valid_quadrant():
2280 prout(_("has left the galaxy.\""))
2282 prout(_("is no longer transmitting.\""))
2288 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2289 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2291 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2292 chp.klingons = pdest.klingons
2293 chp.starbase = pdest.starbase
2294 chp.stars = pdest.stars
2295 pdest.charted = True
2296 game.probe.moves -= 1 # One less to travel
2297 if game.probe.arrived() and game.isarmed and pdest.stars:
2298 supernova(game.probe) # fire in the hole!
2300 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2302 elif evcode == FDISTR: # inhabited system issues distress call
2304 # try a whole bunch of times to find something suitable
2305 for i in range(100):
2306 # need a quadrant which is not the current one,
2307 # which has some stars which are inhabited and
2308 # not already under attack, which is not
2309 # supernova'ed, and which has some Klingons in it
2310 w = randplace(GALSIZE)
2311 q = game.state.galaxy[w.i][w.j]
2312 if not (game.quadrant == w or q.planet == None or \
2313 not q.planet.inhabited or \
2314 q.supernova or q.status!="secure" or q.klingons<=0):
2317 # can't seem to find one; ignore this call
2319 prout("=== Couldn't find location for distress event.")
2321 # got one!! Schedule its enslavement
2322 ev = schedule(FENSLV, expran(game.intime))
2324 q.status = "distressed"
2325 # tell the captain about it if we can
2327 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2328 % (q.planet, repr(w)))
2329 prout(_("by a Klingon invasion fleet."))
2332 elif evcode == FENSLV: # starsystem is enslaved
2333 ev = unschedule(FENSLV)
2334 # see if current distress call still active
2335 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2339 q.status = "enslaved"
2341 # play stork and schedule the first baby
2342 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2343 ev2.quadrant = ev.quadrant
2345 # report the disaster if we can
2347 prout(_("Uhura- We've lost contact with starsystem %s") % \
2349 prout(_("in Quadrant %s.\n") % ev.quadrant)
2350 elif evcode == FREPRO: # Klingon reproduces
2351 # If we ever switch to a real event queue, we'll need to
2352 # explicitly retrieve and restore the x and y.
2353 ev = schedule(FREPRO, expran(1.0 * game.intime))
2354 # see if current distress call still active
2355 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2359 if game.state.remkl >= MAXKLGAME:
2360 continue # full right now
2361 # reproduce one Klingon
2364 if game.klhere >= MAXKLQUAD:
2366 # this quadrant not ok, pick an adjacent one
2367 for m.i in range(w.i - 1, w.i + 2):
2368 for m.j in range(w.j - 1, w.j + 2):
2369 if not m.valid_quadrant():
2371 q = game.state.galaxy[m.i][m.j]
2372 # check for this quad ok (not full & no snova)
2373 if q.klingons >= MAXKLQUAD or q.supernova:
2377 continue # search for eligible quadrant failed
2381 game.state.remkl += 1
2383 if game.quadrant == w:
2385 game.enemies.append(newkling())
2386 # recompute time left
2389 if game.quadrant == w:
2390 prout(_("Spock- sensors indicate the Klingons have"))
2391 prout(_("launched a warship from %s.") % q.planet)
2393 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2394 if q.planet != None:
2395 proutn(_("near %s ") % q.planet)
2396 prout(_("in Quadrant %s.") % w)
2402 key = scanner.next()
2405 proutn(_("How long? "))
2410 origTime = delay = scanner.real
2413 if delay >= game.state.remtime or len(game.enemies) != 0:
2414 proutn(_("Are you sure? "))
2417 # Alternate resting periods (events) with attacks
2421 game.resting = False
2422 if not game.resting:
2423 prout(_("%d stardates left.") % int(game.state.remtime))
2425 temp = game.optime = delay
2426 if len(game.enemies):
2427 rtime = randreal(1.0, 2.0)
2431 if game.optime < delay:
2432 attack(torps_ok=False)
2440 # Repair Deathray if long rest at starbase
2441 if origTime-delay >= 9.99 and game.condition == "docked":
2442 game.damage[DDRAY] = 0.0
2443 # leave if quadrant supernovas
2444 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2446 game.resting = False
2451 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2452 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2454 # Wow! We've supernova'ed
2455 supernova(game.quadrant)
2457 # handle initial nova
2458 game.quad[nov.i][nov.j] = '.'
2459 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2460 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2461 game.state.starkl += 1
2462 # Set up queue to recursively trigger adjacent stars
2468 for offset.i in range(-1, 1+1):
2469 for offset.j in range(-1, 1+1):
2470 if offset.j == 0 and offset.i == 0:
2472 neighbor = start + offset
2473 if not neighbor.valid_sector():
2475 iquad = game.quad[neighbor.i][neighbor.j]
2476 # Empty space ends reaction
2477 if iquad in ('.', '?', ' ', 'T', '#'):
2479 elif iquad == '*': # Affect another star
2481 # This star supernovas
2482 supernova(game.quadrant)
2485 hits.append(neighbor)
2486 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2487 game.state.starkl += 1
2488 proutn(crmena(True, '*', "sector", neighbor))
2490 game.quad[neighbor.i][neighbor.j] = '.'
2492 elif iquad in ('P', '@'): # Destroy planet
2493 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2495 game.state.nplankl += 1
2497 game.state.nworldkl += 1
2498 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2499 game.iplnet.pclass = "destroyed"
2501 game.plnet.invalidate()
2505 game.quad[neighbor.i][neighbor.j] = '.'
2506 elif iquad == 'B': # Destroy base
2507 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2508 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2509 game.base.invalidate()
2510 game.state.basekl += 1
2512 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2513 game.quad[neighbor.i][neighbor.j] = '.'
2514 elif iquad in ('E', 'F'): # Buffet ship
2515 prout(_("***Starship buffeted by nova."))
2517 if game.shield >= 2000.0:
2518 game.shield -= 2000.0
2520 diff = 2000.0 - game.shield
2524 prout(_("***Shields knocked out."))
2525 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2527 game.energy -= 2000.0
2528 if game.energy <= 0:
2531 # add in course nova contributes to kicking starship
2532 bump += (game.sector-hits[-1]).sgn()
2533 elif iquad == 'K': # kill klingon
2534 deadkl(neighbor, iquad, neighbor)
2535 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2536 for ll in range(len(game.enemies)):
2537 if game.enemies[ll].location == neighbor:
2539 game.enemies[ll].power -= 800.0 # If firepower is lost, die
2540 if game.enemies[ll].power <= 0.0:
2541 deadkl(neighbor, iquad, neighbor)
2543 newc = neighbor + neighbor - hits[-1]
2544 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2545 if not newc.valid_sector():
2546 # can't leave quadrant
2549 iquad1 = game.quad[newc.i][newc.j]
2551 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2553 deadkl(neighbor, iquad, newc)
2556 # can't move into something else
2559 proutn(_(", buffeted to Sector %s") % newc)
2560 game.quad[neighbor.i][neighbor.j] = '.'
2561 game.quad[newc.i][newc.j] = iquad
2562 game.enemies[ll].move(newc)
2563 # Starship affected by nova -- kick it away.
2565 direc = ncourse[3*(bump.i+1)+bump.j+2]
2570 scourse = course(bearing=direc, distance=dist)
2571 game.optime = scourse.time(warp=4)
2573 prout(_("Force of nova displaces starship."))
2574 imove(scourse, noattack=True)
2575 game.optime = scourse.time(warp=4)
2579 "Star goes supernova."
2584 # Scheduled supernova -- select star at random.
2587 for nq.i in range(GALSIZE):
2588 for nq.j in range(GALSIZE):
2589 stars += game.state.galaxy[nq.i][nq.j].stars
2591 return # nothing to supernova exists
2592 num = randrange(stars) + 1
2593 for nq.i in range(GALSIZE):
2594 for nq.j in range(GALSIZE):
2595 num -= game.state.galaxy[nq.i][nq.j].stars
2601 proutn("=== Super nova here?")
2604 if not nq == game.quadrant or game.justin:
2605 # it isn't here, or we just entered (treat as enroute)
2608 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2609 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2612 # we are in the quadrant!
2613 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2614 for ns.i in range(QUADSIZE):
2615 for ns.j in range(QUADSIZE):
2616 if game.quad[ns.i][ns.j]=='*':
2623 prouts(_("***RED ALERT! RED ALERT!"))
2625 prout(_("***Incipient supernova detected at Sector %s") % ns)
2626 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2627 proutn(_("Emergency override attempts t"))
2628 prouts("***************")
2632 # destroy any Klingons in supernovaed quadrant
2633 kldead = game.state.galaxy[nq.i][nq.j].klingons
2634 game.state.galaxy[nq.i][nq.j].klingons = 0
2635 if nq == game.state.kscmdr:
2636 # did in the Supercommander!
2637 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2641 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2642 comkills = len(game.state.kcmdr) - len(survivors)
2643 game.state.kcmdr = survivors
2645 if not game.state.kcmdr:
2647 game.state.remkl -= kldead
2648 # destroy Romulans and planets in supernovaed quadrant
2649 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2650 game.state.galaxy[nq.i][nq.j].romulans = 0
2651 game.state.nromrem -= nrmdead
2653 for loop in range(game.inplan):
2654 if game.state.planets[loop].quadrant == nq:
2655 game.state.planets[loop].pclass = "destroyed"
2657 # Destroy any base in supernovaed quadrant
2658 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2659 # If starship caused supernova, tally up destruction
2661 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2662 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2663 game.state.nplankl += npdead
2664 # mark supernova in galaxy and in star chart
2665 if game.quadrant == nq or communicating():
2666 game.state.galaxy[nq.i][nq.j].supernova = True
2667 # If supernova destroys last Klingons give special message
2668 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2671 prout(_("Lucky you!"))
2672 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2675 # if some Klingons remain, continue or die in supernova
2680 # Code from finish.c ends here.
2683 "Self-destruct maneuver. Finish with a BANG!"
2685 if damaged(DCOMPTR):
2686 prout(_("Computer damaged; cannot execute destruct sequence."))
2688 prouts(_("---WORKING---")); skip(1)
2689 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2690 prouts(" 10"); skip(1)
2691 prouts(" 9"); skip(1)
2692 prouts(" 8"); skip(1)
2693 prouts(" 7"); skip(1)
2694 prouts(" 6"); skip(1)
2696 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2698 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2700 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2703 if game.passwd != scanner.token:
2704 prouts(_("PASSWORD-REJECTED;"))
2706 prouts(_("CONTINUITY-EFFECTED"))
2709 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2710 prouts(" 5"); skip(1)
2711 prouts(" 4"); skip(1)
2712 prouts(" 3"); skip(1)
2713 prouts(" 2"); skip(1)
2714 prouts(" 1"); skip(1)
2716 prouts(_("GOODBYE-CRUEL-WORLD"))
2724 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2728 if len(game.enemies) != 0:
2729 whammo = 25.0 * game.energy
2730 for l in range(len(game.enemies)):
2731 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2732 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2736 "Compute our rate of kils over time."
2737 elapsed = game.state.date - game.indate
2738 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2741 starting = (game.inkling + game.incom + game.inscom)
2742 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2743 return (starting - remaining)/elapsed
2747 badpt = 5.0*game.state.starkl + \
2749 10.0*game.state.nplankl + \
2750 300*game.state.nworldkl + \
2752 100.0*game.state.basekl +\
2754 if game.ship == 'F':
2756 elif game.ship == None:
2761 # end the game, with appropriate notfications
2765 prout(_("It is stardate %.1f.") % game.state.date)
2767 if ifin == FWON: # Game has been won
2768 if game.state.nromrem != 0:
2769 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2772 prout(_("You have smashed the Klingon invasion fleet and saved"))
2773 prout(_("the Federation."))
2778 badpt = 0.0 # Close enough!
2779 # killsPerDate >= RateMax
2780 if game.state.date-game.indate < 5.0 or \
2781 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2783 prout(_("In fact, you have done so well that Starfleet Command"))
2784 if game.skill == SKILL_NOVICE:
2785 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2786 elif game.skill == SKILL_FAIR:
2787 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2788 elif game.skill == SKILL_GOOD:
2789 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2790 elif game.skill == SKILL_EXPERT:
2791 prout(_("promotes you to Commodore Emeritus."))
2793 prout(_("Now that you think you're really good, try playing"))
2794 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2795 elif game.skill == SKILL_EMERITUS:
2797 proutn(_("Computer- "))
2798 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2800 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2802 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2804 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2806 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2808 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2810 prout(_("Now you can retire and write your own Star Trek game!"))
2812 elif game.skill >= SKILL_EXPERT:
2813 if game.thawed and not game.idebug:
2814 prout(_("You cannot get a citation, so..."))
2816 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2820 # Only grant long life if alive (original didn't!)
2822 prout(_("LIVE LONG AND PROSPER."))
2827 elif ifin == FDEPLETE: # Federation Resources Depleted
2828 prout(_("Your time has run out and the Federation has been"))
2829 prout(_("conquered. Your starship is now Klingon property,"))
2830 prout(_("and you are put on trial as a war criminal. On the"))
2831 proutn(_("basis of your record, you are "))
2832 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2833 prout(_("acquitted."))
2835 prout(_("LIVE LONG AND PROSPER."))
2837 prout(_("found guilty and"))
2838 prout(_("sentenced to death by slow torture."))
2842 elif ifin == FLIFESUP:
2843 prout(_("Your life support reserves have run out, and"))
2844 prout(_("you die of thirst, starvation, and asphyxiation."))
2845 prout(_("Your starship is a derelict in space."))
2847 prout(_("Your energy supply is exhausted."))
2849 prout(_("Your starship is a derelict in space."))
2850 elif ifin == FBATTLE:
2851 prout(_("The %s has been destroyed in battle.") % crmshp())
2853 prout(_("Dulce et decorum est pro patria mori."))
2855 prout(_("You have made three attempts to cross the negative energy"))
2856 prout(_("barrier which surrounds the galaxy."))
2858 prout(_("Your navigation is abominable."))
2861 prout(_("Your starship has been destroyed by a nova."))
2862 prout(_("That was a great shot."))
2864 elif ifin == FSNOVAED:
2865 prout(_("The %s has been fried by a supernova.") % crmshp())
2866 prout(_("...Not even cinders remain..."))
2867 elif ifin == FABANDN:
2868 prout(_("You have been captured by the Klingons. If you still"))
2869 prout(_("had a starbase to be returned to, you would have been"))
2870 prout(_("repatriated and given another chance. Since you have"))
2871 prout(_("no starbases, you will be mercilessly tortured to death."))
2872 elif ifin == FDILITHIUM:
2873 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2874 elif ifin == FMATERIALIZE:
2875 prout(_("Starbase was unable to re-materialize your starship."))
2876 prout(_("Sic transit gloria mundi"))
2877 elif ifin == FPHASER:
2878 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2880 prout(_("You and your landing party have been"))
2881 prout(_("converted to energy, disipating through space."))
2882 elif ifin == FMINING:
2883 prout(_("You are left with your landing party on"))
2884 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2886 prout(_("They are very fond of \"Captain Kirk\" soup."))
2888 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2889 elif ifin == FDPLANET:
2890 prout(_("You and your mining party perish."))
2892 prout(_("That was a great shot."))
2895 prout(_("The Galileo is instantly annihilated by the supernova."))
2896 prout(_("You and your mining party are atomized."))
2898 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2899 prout(_("joins the Romulans, wreaking terror on the Federation."))
2900 elif ifin == FPNOVA:
2901 prout(_("You and your mining party are atomized."))
2903 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2904 prout(_("joins the Romulans, wreaking terror on the Federation."))
2905 elif ifin == FSTRACTOR:
2906 prout(_("The shuttle craft Galileo is also caught,"))
2907 prout(_("and breaks up under the strain."))
2909 prout(_("Your debris is scattered for millions of miles."))
2910 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2912 prout(_("The mutants attack and kill Spock."))
2913 prout(_("Your ship is captured by Klingons, and"))
2914 prout(_("your crew is put on display in a Klingon zoo."))
2915 elif ifin == FTRIBBLE:
2916 prout(_("Tribbles consume all remaining water,"))
2917 prout(_("food, and oxygen on your ship."))
2919 prout(_("You die of thirst, starvation, and asphyxiation."))
2920 prout(_("Your starship is a derelict in space."))
2922 prout(_("Your ship is drawn to the center of the black hole."))
2923 prout(_("You are crushed into extremely dense matter."))
2925 prout(_("Your last crew member has died."))
2926 if game.ship == 'F':
2928 elif game.ship == 'E':
2931 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2932 goodies = game.state.remres/game.inresor
2933 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2934 if goodies/baddies >= randreal(1.0, 1.5):
2935 prout(_("As a result of your actions, a treaty with the Klingon"))
2936 prout(_("Empire has been signed. The terms of the treaty are"))
2937 if goodies/baddies >= randreal(3.0):
2938 prout(_("favorable to the Federation."))
2940 prout(_("Congratulations!"))
2942 prout(_("highly unfavorable to the Federation."))
2944 prout(_("The Federation will be destroyed."))
2946 prout(_("Since you took the last Klingon with you, you are a"))
2947 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2948 prout(_("statue in your memory. Rest in peace, and try not"))
2949 prout(_("to think about pigeons."))
2954 "Compute player's score."
2955 timused = game.state.date - game.indate
2956 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2958 game.perdate = killrate()
2959 ithperd = 500*game.perdate + 0.5
2962 iwon = 100*game.skill
2963 if game.ship == 'E':
2965 elif game.ship == 'F':
2969 game.score = 10*(game.inkling - game.state.remkl) \
2970 + 50*(game.incom - len(game.state.kcmdr)) \
2972 + 20*(game.inrom - game.state.nromrem) \
2973 + 200*(game.inscom - game.state.nscrem) \
2974 - game.state.nromrem \
2979 prout(_("Your score --"))
2980 if game.inrom - game.state.nromrem:
2981 prout(_("%6d Romulans destroyed %5d") %
2982 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
2983 if game.state.nromrem and game.gamewon:
2984 prout(_("%6d Romulans captured %5d") %
2985 (game.state.nromrem, game.state.nromrem))
2986 if game.inkling - game.state.remkl:
2987 prout(_("%6d ordinary Klingons destroyed %5d") %
2988 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
2989 if game.incom - len(game.state.kcmdr):
2990 prout(_("%6d Klingon commanders destroyed %5d") %
2991 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
2992 if game.inscom - game.state.nscrem:
2993 prout(_("%6d Super-Commander destroyed %5d") %
2994 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
2996 prout(_("%6.2f Klingons per stardate %5d") %
2997 (game.perdate, ithperd))
2998 if game.state.starkl:
2999 prout(_("%6d stars destroyed by your action %5d") %
3000 (game.state.starkl, -5*game.state.starkl))
3001 if game.state.nplankl:
3002 prout(_("%6d planets destroyed by your action %5d") %
3003 (game.state.nplankl, -10*game.state.nplankl))
3004 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3005 prout(_("%6d inhabited planets destroyed by your action %5d") %
3006 (game.state.nworldkl, -300*game.state.nworldkl))
3007 if game.state.basekl:
3008 prout(_("%6d bases destroyed by your action %5d") %
3009 (game.state.basekl, -100*game.state.basekl))
3011 prout(_("%6d calls for help from starbase %5d") %
3012 (game.nhelp, -45*game.nhelp))
3014 prout(_("%6d casualties incurred %5d") %
3015 (game.casual, -game.casual))
3017 prout(_("%6d crew abandoned in space %5d") %
3018 (game.abandoned, -3*game.abandoned))
3020 prout(_("%6d ship(s) lost or destroyed %5d") %
3021 (klship, -100*klship))
3023 prout(_("Penalty for getting yourself killed -200"))
3025 proutn(_("Bonus for winning "))
3026 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3027 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3028 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3029 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3030 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3031 prout(" %5d" % iwon)
3033 prout(_("TOTAL SCORE %5d") % game.score)
3036 "Emit winner's commemmorative plaque."
3039 proutn(_("File or device name for your plaque: "))
3042 fp = open(winner, "w")
3045 prout(_("Invalid name."))
3047 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3049 # The 38 below must be 64 for 132-column paper
3050 nskip = 38 - len(winner)/2
3051 fp.write("\n\n\n\n")
3052 # --------DRAW ENTERPRISE PICTURE.
3053 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3054 fp.write(" EEE E : : : E\n" )
3055 fp.write(" EE EEE E : : NCC-1701 : E\n")
3056 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3057 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3058 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3059 fp.write(" EEEEEEE EEEEE E E E E\n")
3060 fp.write(" EEE E E E E\n")
3061 fp.write(" E E E E\n")
3062 fp.write(" EEEEEEEEEEEEE E E\n")
3063 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3064 fp.write(" :E : EEEE E\n")
3065 fp.write(" .-E -:----- E\n")
3066 fp.write(" :E : E\n")
3067 fp.write(" EE : EEEEEEEE\n")
3068 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3070 fp.write(_(" U. S. S. ENTERPRISE\n"))
3071 fp.write("\n\n\n\n")
3072 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3074 fp.write(_(" Starfleet Command bestows to you\n"))
3076 fp.write("%*s%s\n\n" % (nskip, "", winner))
3077 fp.write(_(" the rank of\n\n"))
3078 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3080 if game.skill == SKILL_EXPERT:
3081 fp.write(_(" Expert level\n\n"))
3082 elif game.skill == SKILL_EMERITUS:
3083 fp.write(_("Emeritus level\n\n"))
3085 fp.write(_(" Cheat level\n\n"))
3086 timestring = time.ctime()
3087 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3088 (timestring+4, timestring+20, timestring+11))
3089 fp.write(_(" Your score: %d\n\n") % game.score)
3090 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3093 # Code from io.c begins here
3095 rows = linecount = 0 # for paging
3098 fullscreen_window = None
3099 srscan_window = None
3100 report_window = None
3101 status_window = None
3102 lrscan_window = None
3103 message_window = None
3104 prompt_window = None
3109 "for some recent versions of python2, the following enables UTF8"
3110 "for the older ones we probably need to set C locale, and the python3"
3111 "has no problems at all"
3112 if sys.version_info[0] < 3:
3114 locale.setlocale(locale.LC_ALL, "")
3115 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3116 gettext.textdomain("sst")
3117 if not (game.options & OPTION_CURSES):
3118 ln_env = os.getenv("LINES")
3124 stdscr = curses.initscr()
3128 if game.options & OPTION_COLOR:
3129 curses.start_color()
3130 curses.use_default_colors()
3131 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3132 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3133 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3134 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3135 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3136 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3137 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3138 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3139 global fullscreen_window, srscan_window, report_window, status_window
3140 global lrscan_window, message_window, prompt_window
3141 (rows, columns) = stdscr.getmaxyx()
3142 fullscreen_window = stdscr
3143 srscan_window = curses.newwin(12, 25, 0, 0)
3144 report_window = curses.newwin(11, 0, 1, 25)
3145 status_window = curses.newwin(10, 0, 1, 39)
3146 lrscan_window = curses.newwin(5, 0, 0, 64)
3147 message_window = curses.newwin(0, 0, 12, 0)
3148 prompt_window = curses.newwin(1, 0, rows-2, 0)
3149 message_window.scrollok(True)
3150 setwnd(fullscreen_window)
3154 if game.options & OPTION_CURSES:
3155 stdscr.keypad(False)
3161 "Wait for user action -- OK to do nothing if on a TTY"
3162 if game.options & OPTION_CURSES:
3167 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3171 if game.skill > SKILL_FAIR:
3172 prompt = _("[CONTINUE?]")
3174 prompt = _("[PRESS ENTER TO CONTINUE]")
3176 if game.options & OPTION_CURSES:
3178 setwnd(prompt_window)
3179 prompt_window.clear()
3180 prompt_window.addstr(prompt)
3181 prompt_window.getstr()
3182 prompt_window.clear()
3183 prompt_window.refresh()
3184 setwnd(message_window)
3187 sys.stdout.write('\n')
3191 sys.stdout.write('\n' * rows)
3195 "Skip i lines. Pause game if this would cause a scrolling event."
3196 for dummy in range(i):
3197 if game.options & OPTION_CURSES:
3198 (y, x) = curwnd.getyx()
3201 except curses.error:
3206 if rows and linecount >= rows:
3209 sys.stdout.write('\n')
3212 "Utter a line with no following line feed."
3213 if game.options & OPTION_CURSES:
3214 (y, x) = curwnd.getyx()
3215 (my, mx) = curwnd.getmaxyx()
3216 if curwnd == message_window and y >= my - 2:
3219 # Uncomment this to debug curses problems
3221 logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(line)))
3225 sys.stdout.write(line)
3235 if not replayfp or replayfp.closed: # Don't slow down replays
3238 if game.options & OPTION_CURSES:
3242 if not replayfp or replayfp.closed:
3246 "Get a line of input."
3247 if game.options & OPTION_CURSES:
3248 line = curwnd.getstr() + "\n"
3251 if replayfp and not replayfp.closed:
3253 line = replayfp.readline()
3256 prout("*** Replay finished")
3259 elif line[0] != "#":
3262 line = raw_input() + "\n"
3268 "Change windows -- OK for this to be a no-op in tty mode."
3270 if game.options & OPTION_CURSES:
3271 # Uncomment this to debug curses problems
3273 if wnd == fullscreen_window:
3274 legend = "fullscreen"
3275 elif wnd == srscan_window:
3277 elif wnd == report_window:
3279 elif wnd == status_window:
3281 elif wnd == lrscan_window:
3283 elif wnd == message_window:
3285 elif wnd == prompt_window:
3289 logfp.write("#curses: setwnd(%s)\n" % legend)
3291 # Some curses implementations get confused when you try this.
3293 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3294 except curses.error:
3298 "Clear to end of line -- can be a no-op in tty mode"
3299 if game.options & OPTION_CURSES:
3304 "Clear screen -- can be a no-op in tty mode."
3306 if game.options & OPTION_CURSES:
3312 def textcolor(color=DEFAULT):
3313 if game.options & OPTION_COLOR:
3314 if color == DEFAULT:
3316 elif color == BLACK:
3317 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3319 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3320 elif color == GREEN:
3321 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3323 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3325 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3326 elif color == MAGENTA:
3327 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3328 elif color == BROWN:
3329 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3330 elif color == LIGHTGRAY:
3331 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3332 elif color == DARKGRAY:
3333 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3334 elif color == LIGHTBLUE:
3335 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3336 elif color == LIGHTGREEN:
3337 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3338 elif color == LIGHTCYAN:
3339 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3340 elif color == LIGHTRED:
3341 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3342 elif color == LIGHTMAGENTA:
3343 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3344 elif color == YELLOW:
3345 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3346 elif color == WHITE:
3347 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3350 if game.options & OPTION_COLOR:
3351 curwnd.attron(curses.A_REVERSE)
3354 # Things past this point have policy implications.
3358 "Hook to be called after moving to redraw maps."
3359 if game.options & OPTION_CURSES:
3362 setwnd(srscan_window)
3366 setwnd(status_window)
3367 status_window.clear()
3368 status_window.move(0, 0)
3369 setwnd(report_window)
3370 report_window.clear()
3371 report_window.move(0, 0)
3373 setwnd(lrscan_window)
3374 lrscan_window.clear()
3375 lrscan_window.move(0, 0)
3376 lrscan(silent=False)
3378 def put_srscan_sym(w, sym):
3379 "Emit symbol for short-range scan."
3380 srscan_window.move(w.i+1, w.j*2+2)
3381 srscan_window.addch(sym)
3382 srscan_window.refresh()
3385 "Enemy fall down, go boom."
3386 if game.options & OPTION_CURSES:
3388 setwnd(srscan_window)
3389 srscan_window.attron(curses.A_REVERSE)
3390 put_srscan_sym(w, game.quad[w.i][w.j])
3394 srscan_window.attroff(curses.A_REVERSE)
3395 put_srscan_sym(w, game.quad[w.i][w.j])
3396 curses.delay_output(500)
3397 setwnd(message_window)
3400 "Sound and visual effects for teleportation."
3401 if game.options & OPTION_CURSES:
3403 setwnd(message_window)
3405 prouts(" . . . . . ")
3406 if game.options & OPTION_CURSES:
3407 #curses.delay_output(1000)
3411 def tracktorpedo(w, step, i, n, iquad):
3412 "Torpedo-track animation."
3413 if not game.options & OPTION_CURSES:
3417 proutn(_("Track for torpedo number %d- ") % (i+1))
3420 proutn(_("Torpedo track- "))
3421 elif step==4 or step==9:
3425 if not damaged(DSRSENS) or game.condition=="docked":
3426 if i != 0 and step == 1:
3429 if (iquad=='.') or (iquad==' '):
3430 put_srscan_sym(w, '+')
3434 put_srscan_sym(w, iquad)
3436 curwnd.attron(curses.A_REVERSE)
3437 put_srscan_sym(w, iquad)
3441 curwnd.attroff(curses.A_REVERSE)
3442 put_srscan_sym(w, iquad)
3447 "Display the current galaxy chart."
3448 if game.options & OPTION_CURSES:
3449 setwnd(message_window)
3450 message_window.clear()
3452 if game.options & OPTION_TTY:
3457 def prstat(txt, data):
3459 if game.options & OPTION_CURSES:
3461 setwnd(status_window)
3463 proutn(" " * (NSYM - len(txt)))
3466 if game.options & OPTION_CURSES:
3467 setwnd(report_window)
3469 # Code from moving.c begins here
3471 def imove(icourse=None, noattack=False):
3472 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3475 def newquadrant(noattack):
3476 # Leaving quadrant -- allow final enemy attack
3477 # Don't do it if being pushed by Nova
3478 if len(game.enemies) != 0 and not noattack:
3480 for enemy in game.enemies:
3481 finald = (w - enemy.location).distance()
3482 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3483 # Stas Sergeev added the condition
3484 # that attacks only happen if Klingons
3485 # are present and your skill is good.
3486 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3487 attack(torps_ok=False)
3490 # check for edge of galaxy
3494 if icourse.final.i < 0:
3495 icourse.final.i = -icourse.final.i
3497 if icourse.final.j < 0:
3498 icourse.final.j = -icourse.final.j
3500 if icourse.final.i >= GALSIZE*QUADSIZE:
3501 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3503 if icourse.final.j >= GALSIZE*QUADSIZE:
3504 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3512 if game.nkinks == 3:
3513 # Three strikes -- you're out!
3517 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3518 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3519 prout(_("YOU WILL BE DESTROYED."))
3520 # Compute final position in new quadrant
3521 if trbeam: # Don't bother if we are to be beamed
3523 game.quadrant = icourse.final.quadrant()
3524 game.sector = icourse.final.sector()
3526 prout(_("Entering Quadrant %s.") % game.quadrant)
3527 game.quad[game.sector.i][game.sector.j] = game.ship
3529 if game.skill>SKILL_NOVICE:
3530 attack(torps_ok=False)
3532 def check_collision(h):
3533 iquad = game.quad[h.i][h.j]
3535 # object encountered in flight path
3536 stopegy = 50.0*icourse.distance/game.optime
3537 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3538 for enemy in game.enemies:
3539 if enemy.location == game.sector:
3541 collision(rammed=False, enemy=enemy)
3545 prouts(_("***RED ALERT! RED ALERT!"))
3547 proutn("***" + crmshp())
3548 proutn(_(" pulled into black hole at Sector %s") % h)
3549 # Getting pulled into a black hole was certain
3550 # death in Almy's original. Stas Sergeev added a
3551 # possibility that you'll get timewarped instead.
3553 for m in range(NDEVICES):
3554 if game.damage[m]>0:
3556 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3557 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3567 prout(_(" encounters Tholian web at %s;") % h)
3569 prout(_(" blocked by object at %s;") % h)
3570 proutn(_("Emergency stop required "))
3571 prout(_("%2d units of energy.") % int(stopegy))
3572 game.energy -= stopegy
3573 if game.energy <= 0:
3580 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3581 game.inorbit = False
3582 # If tractor beam is to occur, don't move full distance
3583 if game.state.date+game.optime >= scheduled(FTBEAM):
3585 game.condition = "red"
3586 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3587 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3589 game.quad[game.sector.i][game.sector.j] = '.'
3590 for m in range(icourse.moves):
3592 w = icourse.sector()
3593 if icourse.origin.quadrant() != icourse.location.quadrant():
3594 newquadrant(noattack)
3596 elif check_collision(w):
3597 print "Collision detected"
3601 # We're in destination quadrant -- compute new average enemy distances
3602 game.quad[game.sector.i][game.sector.j] = game.ship
3604 for enemy in game.enemies:
3605 finald = (w-enemy.location).distance()
3606 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3607 enemy.kdist = finald
3609 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3610 attack(torps_ok=False)
3611 for enemy in game.enemies:
3612 enemy.kavgd = enemy.kdist
3615 setwnd(message_window)
3619 "Dock our ship at a starbase."
3621 if game.condition == "docked" and verbose:
3622 prout(_("Already docked."))
3625 prout(_("You must first leave standard orbit."))
3627 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3628 prout(crmshp() + _(" not adjacent to base."))
3630 game.condition = "docked"
3634 if game.energy < game.inenrg:
3635 game.energy = game.inenrg
3636 game.shield = game.inshld
3637 game.torps = game.intorps
3638 game.lsupres = game.inlsr
3639 game.state.crew = FULLCREW
3640 if not damaged(DRADIO) and \
3641 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3642 # get attack report from base
3643 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3647 def cartesian(loc1=None, loc2=None):
3649 return game.quadrant * QUADSIZE + game.sector
3651 return game.quadrant * QUADSIZE + loc1
3653 return loc1 * QUADSIZE + loc2
3655 def getcourse(isprobe):
3656 "Get a course and distance from the user."
3658 dquad = copy.copy(game.quadrant)
3659 navmode = "unspecified"
3663 if game.landed and not isprobe:
3664 prout(_("Dummy! You can't leave standard orbit until you"))
3665 proutn(_("are back aboard the ship."))
3668 while navmode == "unspecified":
3669 if damaged(DNAVSYS):
3671 prout(_("Computer damaged; manual navigation only"))
3673 prout(_("Computer damaged; manual movement only"))
3678 key = scanner.next()
3680 proutn(_("Manual or automatic- "))
3683 elif key == "IHALPHA":
3684 if scanner.sees("manual"):
3686 key = scanner.next()
3688 elif scanner.sees("automatic"):
3689 navmode = "automatic"
3690 key = scanner.next()
3698 prout(_("(Manual navigation assumed.)"))
3700 prout(_("(Manual movement assumed.)"))
3704 if navmode == "automatic":
3705 while key == "IHEOL":
3707 proutn(_("Target quadrant or quadrant§or- "))
3709 proutn(_("Destination sector or quadrant§or- "))
3712 key = scanner.next()
3716 xi = int(round(scanner.real))-1
3717 key = scanner.next()
3721 xj = int(round(scanner.real))-1
3722 key = scanner.next()
3724 # both quadrant and sector specified
3725 xk = int(round(scanner.real))-1
3726 key = scanner.next()
3730 xl = int(round(scanner.real))-1
3736 # only one pair of numbers was specified
3738 # only quadrant specified -- go to center of dest quad
3741 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3743 # only sector specified
3747 if not dquad.valid_quadrant() or not dsect.valid_sector():
3754 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3756 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3757 # the actual deltas get computed here
3758 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3759 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3761 while key == "IHEOL":
3762 proutn(_("X and Y displacements- "))
3765 key = scanner.next()
3770 delta.j = scanner.real
3771 key = scanner.next()
3775 delta.i = scanner.real
3776 # Check for zero movement
3777 if delta.i == 0 and delta.j == 0:
3780 if itemp == "verbose" and not isprobe:
3782 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3784 return course(bearing=delta.bearing(), distance=delta.distance())
3787 def __init__(self, bearing, distance, origin=None):
3788 self.distance = distance
3789 self.bearing = bearing
3791 self.origin = cartesian(game.quadrant, game.sector)
3793 self.origin = origin
3794 # The bearing() code we inherited from FORTRAN is actually computing
3795 # clockface directions!
3796 if self.bearing < 0.0:
3797 self.bearing += 12.0
3798 self.angle = ((15.0 - self.bearing) * 0.5235988)
3800 self.origin = cartesian(game.quadrant, game.sector)
3802 self.origin = cartesian(game.quadrant, origin)
3803 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
3804 bigger = max(abs(self.increment.i), abs(self.increment.j))
3805 self.increment /= bigger
3806 self.moves = int(round(10*self.distance*bigger))
3808 self.final = (self.location + self.moves*self.increment).roundtogrid()
3810 self.location = self.origin
3813 return self.location.roundtogrid() == self.final
3815 "Next step on course."
3817 self.nextlocation = self.location + self.increment
3818 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3819 self.location = self.nextlocation
3822 return self.location.quadrant()
3824 return self.location.sector()
3825 def power(self, warp):
3826 return self.distance*(warp**3)*(game.shldup+1)
3827 def time(self, warp):
3828 return 10.0*self.distance/warp**2
3831 "Move under impulse power."
3833 if damaged(DIMPULS):
3836 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3838 if game.energy > 30.0:
3840 course = getcourse(isprobe=False)
3843 power = 20.0 + 100.0*course.distance
3846 if power >= game.energy:
3847 # Insufficient power for trip
3849 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3850 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3851 if game.energy > 30:
3852 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3853 int(0.01 * (game.energy-20.0)-0.05))
3854 prout(_(" quadrants.\""))
3856 prout(_("quadrant. They are, therefore, useless.\""))
3859 # Make sure enough time is left for the trip
3860 game.optime = course.dist/0.095
3861 if game.optime >= game.state.remtime:
3862 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3863 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3864 proutn(_("we dare spend the time?\" "))
3867 # Activate impulse engines and pay the cost
3868 imove(course, noattack=False)
3872 power = 20.0 + 100.0*course.dist
3873 game.energy -= power
3874 game.optime = course.dist/0.095
3875 if game.energy <= 0:
3879 def warp(wcourse, involuntary):
3880 "ove under warp drive."
3881 blooey = False; twarp = False
3882 if not involuntary: # Not WARPX entry
3884 if game.damage[DWARPEN] > 10.0:
3887 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3889 if damaged(DWARPEN) and game.warpfac > 4.0:
3892 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3893 prout(_(" is repaired, I can only give you warp 4.\""))
3895 # Read in course and distance
3898 wcourse = getcourse(isprobe=False)
3901 # Make sure starship has enough energy for the trip
3902 # Note: this formula is slightly different from the C version,
3903 # and lets you skate a bit closer to the edge.
3904 if wcourse.power(game.warpfac) >= game.energy:
3905 # Insufficient power for trip
3908 prout(_("Engineering to bridge--"))
3909 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
3910 iwarp = (game.energy/(wcourse.dist+0.05)) ** 0.333333333
3912 prout(_("We can't do it, Captain. We don't have enough energy."))
3914 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3917 prout(_("if you'll lower the shields."))
3921 prout(_("We haven't the energy to go that far with the shields up."))
3923 # Make sure enough time is left for the trip
3924 game.optime = wcourse.time(game.warpfac)
3925 if game.optime >= 0.8*game.state.remtime:
3927 prout(_("First Officer Spock- \"Captain, I compute that such"))
3928 proutn(_(" a trip would require approximately %2.0f") %
3929 (100.0*game.optime/game.state.remtime))
3930 prout(_(" percent of our"))
3931 proutn(_(" remaining time. Are you sure this is wise?\" "))
3937 if game.warpfac > 6.0:
3938 # Decide if engine damage will occur
3939 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3940 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
3941 if prob > randreal():
3943 wcourse.distance = randreal(wcourse.distance)
3944 # Decide if time warp will occur
3945 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3947 if game.idebug and game.warpfac==10 and not twarp:
3949 proutn("=== Force time warp? ")
3953 # If time warp or engine damage, check path
3954 # If it is obstructed, don't do warp or damage
3955 look = wcourse.moves
3959 w = wcourse.sector()
3960 if not w.valid_sector():
3962 if game.quad[w.i][w.j] != '.':
3966 # Activate Warp Engines and pay the cost
3967 imove(wcourse, noattack=False)
3970 game.energy -= wcourse.power(game.warpfac)
3971 if game.energy <= 0:
3973 game.optime = wcourse.time(game.warpfac)
3977 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
3979 prout(_("Engineering to bridge--"))
3980 prout(_(" Scott here. The warp engines are damaged."))
3981 prout(_(" We'll have to reduce speed to warp 4."))
3986 "Change the warp factor."
3992 proutn(_("Warp factor- "))
3996 if game.damage[DWARPEN] > 10.0:
3997 prout(_("Warp engines inoperative."))
3999 if damaged(DWARPEN) and scanner.real > 4.0:
4000 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4001 prout(_(" but right now we can only go warp 4.\""))
4003 if scanner.real > 10.0:
4004 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4006 if scanner.real < 1.0:
4007 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4009 oldfac = game.warpfac
4010 game.warpfac = scanner.real
4011 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4012 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4015 if game.warpfac < 8.00:
4016 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4018 if game.warpfac == 10.0:
4019 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4021 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4025 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4027 # is captain on planet?
4029 if damaged(DTRANSP):
4032 prout(_("Scotty rushes to the transporter controls."))
4034 prout(_("But with the shields up it's hopeless."))
4036 prouts(_("His desperate attempt to rescue you . . ."))
4041 prout(_("SUCCEEDS!"))
4044 proutn(_("The crystals mined were "))
4052 # Check to see if captain in shuttle craft
4057 # Inform captain of attempt to reach safety
4061 prouts(_("***RED ALERT! RED ALERT!"))
4063 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4064 prouts(_(" a supernova."))
4066 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4067 prout(_("safely out of quadrant."))
4068 if not damaged(DRADIO):
4069 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4070 # Try to use warp engines
4071 if damaged(DWARPEN):
4073 prout(_("Warp engines damaged."))
4076 game.warpfac = randreal(6.0, 8.0)
4077 prout(_("Warp factor set to %d") % int(game.warpfac))
4078 power = 0.75*game.energy
4079 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4080 dist = max(dist, randreal(math.sqrt(2)))
4081 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4082 game.optime = bugout.time(game.warpfac)
4084 game.inorbit = False
4085 warp(bugout, involuntary=True)
4087 # This is bad news, we didn't leave quadrant.
4091 prout(_("Insufficient energy to leave quadrant."))
4094 # Repeat if another snova
4095 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4097 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4098 finish(FWON) # Snova killed remaining enemy.
4101 "Let's do the time warp again."
4102 prout(_("***TIME WARP ENTERED."))
4103 if game.state.snap and withprob(0.5):
4105 prout(_("You are traveling backwards in time %d stardates.") %
4106 int(game.state.date-game.snapsht.date))
4107 game.state = game.snapsht
4108 game.state.snap = False
4109 if len(game.state.kcmdr):
4110 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4111 schedule(FBATTAK, expran(0.3*game.intime))
4112 schedule(FSNOVA, expran(0.5*game.intime))
4113 # next snapshot will be sooner
4114 schedule(FSNAP, expran(0.25*game.state.remtime))
4116 if game.state.nscrem:
4117 schedule(FSCMOVE, 0.2777)
4121 game.battle.invalidate()
4122 # Make sure Galileo is consistant -- Snapshot may have been taken
4123 # when on planet, which would give us two Galileos!
4125 for l in range(game.inplan):
4126 if game.state.planets[l].known == "shuttle_down":
4128 if game.iscraft == "onship" and game.ship=='E':
4129 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4130 game.iscraft = "offship"
4131 # Likewise, if in the original time the Galileo was abandoned, but
4132 # was on ship earlier, it would have vanished -- let's restore it.
4133 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4134 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4135 game.iscraft = "onship"
4136 # There used to be code to do the actual reconstrction here,
4137 # but the starchart is now part of the snapshotted galaxy state.
4138 prout(_("Spock has reconstructed a correct star chart from memory"))
4140 # Go forward in time
4141 game.optime = expran(0.5*game.intime)
4142 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4143 # cheat to make sure no tractor beams occur during time warp
4144 postpone(FTBEAM, game.optime)
4145 game.damage[DRADIO] += game.optime
4147 events() # Stas Sergeev added this -- do pending events
4150 "Launch deep-space probe."
4151 # New code to launch a deep space probe
4152 if game.nprobes == 0:
4155 if game.ship == 'E':
4156 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4158 prout(_("Ye Faerie Queene has no deep space probes."))
4163 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4165 if is_scheduled(FDSPROB):
4168 if damaged(DRADIO) and game.condition != "docked":
4169 prout(_("Spock- \"Records show the previous probe has not yet"))
4170 prout(_(" reached its destination.\""))
4172 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4174 key = scanner.next()
4176 if game.nprobes == 1:
4177 prout(_("1 probe left."))
4179 prout(_("%d probes left") % game.nprobes)
4180 proutn(_("Are you sure you want to fire a probe? "))
4183 game.isarmed = False
4184 if key == "IHALPHA" and scanner.token == "armed":
4186 key = scanner.next()
4187 elif key == "IHEOL":
4188 proutn(_("Arm NOVAMAX warhead? "))
4190 elif key == "IHREAL": # first element of course
4191 scanner.push(scanner.token)
4193 game.probe = getcourse(isprobe=True)
4197 schedule(FDSPROB, 0.01) # Time to move one sector
4198 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4203 "Yell for help from nearest starbase."
4204 # There's more than one way to move in this game!
4206 # Test for conditions which prevent calling for help
4207 if game.condition == "docked":
4208 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4211 prout(_("Subspace radio damaged."))
4213 if not game.state.baseq:
4214 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4217 prout(_("You must be aboard the %s.") % crmshp())
4219 # OK -- call for help from nearest starbase
4222 # There's one in this quadrant
4223 ddist = (game.base - game.sector).distance()
4226 for ibq in game.state.baseq:
4227 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4230 # Since starbase not in quadrant, set up new quadrant
4233 # dematerialize starship
4234 game.quad[game.sector.i][game.sector.j]='.'
4235 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4236 % (game.quadrant, crmshp()))
4237 game.sector.invalidate()
4238 for m in range(1, 5+1):
4239 w = game.base.scatter()
4240 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4241 # found one -- finish up
4244 if not game.sector.is_valid():
4245 prout(_("You have been lost in space..."))
4246 finish(FMATERIALIZE)
4248 # Give starbase three chances to rematerialize starship
4249 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4250 for m in range(1, 3+1):
4251 if m == 1: proutn(_("1st"))
4252 elif m == 2: proutn(_("2nd"))
4253 elif m == 3: proutn(_("3rd"))
4254 proutn(_(" attempt to re-materialize ") + crmshp())
4255 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4258 if randreal() > probf:
4262 curses.delay_output(500)
4264 game.quad[game.sector.i][game.sector.j]='?'
4267 setwnd(message_window)
4268 finish(FMATERIALIZE)
4270 game.quad[game.sector.i][game.sector.j]=game.ship
4272 prout(_("succeeds."))
4276 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4281 if game.condition=="docked":
4283 prout(_("You cannot abandon Ye Faerie Queene."))
4286 # Must take shuttle craft to exit
4287 if game.damage[DSHUTTL]==-1:
4288 prout(_("Ye Faerie Queene has no shuttle craft."))
4290 if game.damage[DSHUTTL]<0:
4291 prout(_("Shuttle craft now serving Big Macs."))
4293 if game.damage[DSHUTTL]>0:
4294 prout(_("Shuttle craft damaged."))
4297 prout(_("You must be aboard the ship."))
4299 if game.iscraft != "onship":
4300 prout(_("Shuttle craft not currently available."))
4302 # Emit abandon ship messages
4304 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4306 prouts(_("***ALL HANDS ABANDON SHIP!"))
4308 prout(_("Captain and crew escape in shuttle craft."))
4309 if not game.state.baseq:
4310 # Oops! no place to go...
4313 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4315 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4316 prout(_("Remainder of ship's complement beam down"))
4317 prout(_("to nearest habitable planet."))
4318 elif q.planet != None and not damaged(DTRANSP):
4319 prout(_("Remainder of ship's complement beam down to %s.") %
4322 prout(_("Entire crew of %d left to die in outer space.") %
4324 game.casual += game.state.crew
4325 game.abandoned += game.state.crew
4326 # If at least one base left, give 'em the Faerie Queene
4328 game.icrystl = False # crystals are lost
4329 game.nprobes = 0 # No probes
4330 prout(_("You are captured by Klingons and released to"))
4331 prout(_("the Federation in a prisoner-of-war exchange."))
4332 nb = randrange(len(game.state.baseq))
4333 # Set up quadrant and position FQ adjacient to base
4334 if not game.quadrant == game.state.baseq[nb]:
4335 game.quadrant = game.state.baseq[nb]
4336 game.sector.i = game.sector.j = 5
4339 # position next to base by trial and error
4340 game.quad[game.sector.i][game.sector.j] = '.'
4341 for l in range(QUADSIZE):
4342 game.sector = game.base.scatter()
4343 if game.sector.valid_sector() and \
4344 game.quad[game.sector.i][game.sector.j] == '.':
4347 break # found a spot
4348 game.sector.i=QUADSIZE/2
4349 game.sector.j=QUADSIZE/2
4351 # Get new commission
4352 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4353 game.state.crew = FULLCREW
4354 prout(_("Starfleet puts you in command of another ship,"))
4355 prout(_("the Faerie Queene, which is antiquated but,"))
4356 prout(_("still useable."))
4358 prout(_("The dilithium crystals have been moved."))
4360 game.iscraft = "offship" # Galileo disappears
4362 game.condition="docked"
4363 for l in range(NDEVICES):
4364 game.damage[l] = 0.0
4365 game.damage[DSHUTTL] = -1
4366 game.energy = game.inenrg = 3000.0
4367 game.shield = game.inshld = 1250.0
4368 game.torps = game.intorps = 6
4369 game.lsupres=game.inlsr=3.0
4374 # Code from planets.c begins here.
4377 "Abort a lengthy operation if an event interrupts it."
4380 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4385 "Report on (uninhabited) planets in the galaxy."
4389 prout(_("Spock- \"Planet report follows, Captain.\""))
4391 for i in range(game.inplan):
4392 if game.state.planets[i].pclass == "destroyed":
4394 if (game.state.planets[i].known != "unknown" \
4395 and not game.state.planets[i].inhabited) \
4398 if game.idebug and game.state.planets[i].known=="unknown":
4399 proutn("(Unknown) ")
4400 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4401 proutn(_(" class "))
4402 proutn(game.state.planets[i].pclass)
4404 if game.state.planets[i].crystals != "present":
4406 prout(_("dilithium crystals present."))
4407 if game.state.planets[i].known=="shuttle_down":
4408 prout(_(" Shuttle Craft Galileo on surface."))
4410 prout(_("No information available."))
4413 "Enter standard orbit."
4417 prout(_("Already in standard orbit."))
4419 if damaged(DWARPEN) and damaged(DIMPULS):
4420 prout(_("Both warp and impulse engines damaged."))
4422 if not game.plnet.is_valid():
4423 prout("There is no planet in this sector.")
4425 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4426 prout(crmshp() + _(" not adjacent to planet."))
4429 game.optime = randreal(0.02, 0.05)
4430 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4434 game.height = randreal(1400, 8600)
4435 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4440 "Examine planets in this quadrant."
4441 if damaged(DSRSENS):
4442 if game.options & OPTION_TTY:
4443 prout(_("Short range sensors damaged."))
4445 if game.iplnet == None:
4446 if game.options & OPTION_TTY:
4447 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4449 if game.iplnet.known == "unknown":
4450 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4452 prout(_(" Planet at Sector %s is of class %s.") %
4453 (game.plnet, game.iplnet.pclass))
4454 if game.iplnet.known=="shuttle_down":
4455 prout(_(" Sensors show Galileo still on surface."))
4456 proutn(_(" Readings indicate"))
4457 if game.iplnet.crystals != "present":
4459 prout(_(" dilithium crystals present.\""))
4460 if game.iplnet.known == "unknown":
4461 game.iplnet.known = "known"
4462 elif game.iplnet.inhabited:
4463 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4464 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4467 "Use the transporter."
4471 if damaged(DTRANSP):
4472 prout(_("Transporter damaged."))
4473 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4475 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4479 if not game.inorbit:
4480 prout(crmshp() + _(" not in standard orbit."))
4483 prout(_("Impossible to transport through shields."))
4485 if game.iplnet.known=="unknown":
4486 prout(_("Spock- \"Captain, we have no information on this planet"))
4487 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4488 prout(_(" you may not go down.\""))
4490 if not game.landed and game.iplnet.crystals=="absent":
4491 prout(_("Spock- \"Captain, I fail to see the logic in"))
4492 prout(_(" exploring a planet with no dilithium crystals."))
4493 proutn(_(" Are you sure this is wise?\" "))
4497 if not (game.options & OPTION_PLAIN):
4498 nrgneed = 50 * game.skill + game.height / 100.0
4499 if nrgneed > game.energy:
4500 prout(_("Engineering to bridge--"))
4501 prout(_(" Captain, we don't have enough energy for transportation."))
4503 if not game.landed and nrgneed * 2 > game.energy:
4504 prout(_("Engineering to bridge--"))
4505 prout(_(" Captain, we have enough energy only to transport you down to"))
4506 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4507 if game.iplnet.known == "shuttle_down":
4508 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4509 proutn(_(" Are you sure this is wise?\" "))
4514 # Coming from planet
4515 if game.iplnet.known=="shuttle_down":
4516 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4520 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4521 prout(_("Landing party assembled, ready to beam up."))
4523 prout(_("Kirk whips out communicator..."))
4524 prouts(_("BEEP BEEP BEEP"))
4526 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4529 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4531 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4533 prout(_("Kirk- \"Energize.\""))
4536 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4539 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4541 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4544 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4545 game.landed = not game.landed
4546 game.energy -= nrgneed
4548 prout(_("Transport complete."))
4549 if game.landed and game.iplnet.known=="shuttle_down":
4550 prout(_("The shuttle craft Galileo is here!"))
4551 if not game.landed and game.imine:
4558 "Strip-mine a world for dilithium."
4562 prout(_("Mining party not on planet."))
4564 if game.iplnet.crystals == "mined":
4565 prout(_("This planet has already been strip-mined for dilithium."))
4567 elif game.iplnet.crystals == "absent":
4568 prout(_("No dilithium crystals on this planet."))
4571 prout(_("You've already mined enough crystals for this trip."))
4573 if game.icrystl and game.cryprob == 0.05:
4574 prout(_("With all those fresh crystals aboard the ") + crmshp())
4575 prout(_("there's no reason to mine more at this time."))
4577 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4580 prout(_("Mining operation complete."))
4581 game.iplnet.crystals = "mined"
4582 game.imine = game.ididit = True
4585 "Use dilithium crystals."
4589 if not game.icrystl:
4590 prout(_("No dilithium crystals available."))
4592 if game.energy >= 1000:
4593 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4594 prout(_(" except when Condition Yellow exists."))
4596 prout(_("Spock- \"Captain, I must warn you that loading"))
4597 prout(_(" raw dilithium crystals into the ship's power"))
4598 prout(_(" system may risk a severe explosion."))
4599 proutn(_(" Are you sure this is wise?\" "))
4604 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4605 prout(_(" Mr. Spock and I will try it.\""))
4607 prout(_("Spock- \"Crystals in place, Sir."))
4608 prout(_(" Ready to activate circuit.\""))
4610 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4612 if withprob(game.cryprob):
4613 prouts(_(" \"Activating now! - - No good! It's***"))
4615 prouts(_("***RED ALERT! RED A*L********************************"))
4618 prouts(_("****************** KA-BOOM!!!! *******************"))
4622 game.energy += randreal(5000.0, 5500.0)
4623 prouts(_(" \"Activating now! - - "))
4624 prout(_("The instruments"))
4625 prout(_(" are going crazy, but I think it's"))
4626 prout(_(" going to work!! Congratulations, Sir!\""))
4631 "Use shuttlecraft for planetary jaunt."
4634 if damaged(DSHUTTL):
4635 if game.damage[DSHUTTL] == -1.0:
4636 if game.inorbit and game.iplnet.known == "shuttle_down":
4637 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4639 prout(_("Ye Faerie Queene had no shuttle craft."))
4640 elif game.damage[DSHUTTL] > 0:
4641 prout(_("The Galileo is damaged."))
4642 else: # game.damage[DSHUTTL] < 0
4643 prout(_("Shuttle craft is now serving Big Macs."))
4645 if not game.inorbit:
4646 prout(crmshp() + _(" not in standard orbit."))
4648 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4649 prout(_("Shuttle craft not currently available."))
4651 if not game.landed and game.iplnet.known=="shuttle_down":
4652 prout(_("You will have to beam down to retrieve the shuttle craft."))
4654 if game.shldup or game.condition == "docked":
4655 prout(_("Shuttle craft cannot pass through shields."))
4657 if game.iplnet.known=="unknown":
4658 prout(_("Spock- \"Captain, we have no information on this planet"))
4659 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4660 prout(_(" you may not fly down.\""))
4662 game.optime = 3.0e-5*game.height
4663 if game.optime >= 0.8*game.state.remtime:
4664 prout(_("First Officer Spock- \"Captain, I compute that such"))
4665 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4666 int(100*game.optime/game.state.remtime))
4667 prout(_("remaining time."))
4668 proutn(_("Are you sure this is wise?\" "))
4674 if game.iscraft == "onship":
4676 if not damaged(DTRANSP):
4677 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4681 proutn(_("Shuttle crew"))
4683 proutn(_("Rescue party"))
4684 prout(_(" boards Galileo and swoops toward planet surface."))
4685 game.iscraft = "offship"
4689 game.iplnet.known="shuttle_down"
4690 prout(_("Trip complete."))
4693 # Ready to go back to ship
4694 prout(_("You and your mining party board the"))
4695 prout(_("shuttle craft for the trip back to the Enterprise."))
4697 prouts(_("The short hop begins . . ."))
4699 game.iplnet.known="known"
4705 game.iscraft = "onship"
4711 prout(_("Trip complete."))
4714 # Kirk on ship and so is Galileo
4715 prout(_("Mining party assembles in the hangar deck,"))
4716 prout(_("ready to board the shuttle craft \"Galileo\"."))
4718 prouts(_("The hangar doors open; the trip begins."))
4721 game.iscraft = "offship"
4724 game.iplnet.known = "shuttle_down"
4727 prout(_("Trip complete."))
4731 "Use the big zapper."
4735 if game.ship != 'E':
4736 prout(_("Ye Faerie Queene has no death ray."))
4738 if len(game.enemies)==0:
4739 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4742 prout(_("Death Ray is damaged."))
4744 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4745 prout(_(" is highly unpredictible. Considering the alternatives,"))
4746 proutn(_(" are you sure this is wise?\" "))
4749 prout(_("Spock- \"Acknowledged.\""))
4752 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4754 prout(_("Crew scrambles in emergency preparation."))
4755 prout(_("Spock and Scotty ready the death ray and"))
4756 prout(_("prepare to channel all ship's power to the device."))
4758 prout(_("Spock- \"Preparations complete, sir.\""))
4759 prout(_("Kirk- \"Engage!\""))
4761 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4764 if game.options & OPTION_PLAIN:
4768 prouts(_("Sulu- \"Captain! It's working!\""))
4770 while len(game.enemies) > 0:
4771 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4772 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4773 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4775 if (game.options & OPTION_PLAIN) == 0:
4776 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4778 prout(_(" is still operational.\""))
4780 prout(_(" has been rendered nonfunctional.\""))
4781 game.damage[DDRAY] = 39.95
4783 r = randreal() # Pick failure method
4785 prouts(_("Sulu- \"Captain! It's working!\""))
4787 prouts(_("***RED ALERT! RED ALERT!"))
4789 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4791 prouts(_("***RED ALERT! RED A*L********************************"))
4794 prouts(_("****************** KA-BOOM!!!! *******************"))
4799 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4801 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4803 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4804 prout(_(" have apparently been transformed into strange mutations."))
4805 prout(_(" Vulcans do not seem to be affected."))
4807 prout(_("Kirk- \"Raauch! Raauch!\""))
4811 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4813 proutn(_("Spock- \"I believe the word is"))
4814 prouts(_(" *ASTONISHING*"))
4815 prout(_(" Mr. Sulu."))
4816 for i in range(QUADSIZE):
4817 for j in range(QUADSIZE):
4818 if game.quad[i][j] == '.':
4819 game.quad[i][j] = '?'
4820 prout(_(" Captain, our quadrant is now infested with"))
4821 prouts(_(" - - - - - - *THINGS*."))
4823 prout(_(" I have no logical explanation.\""))
4825 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4827 prout(_("Scotty- \"There are so many tribbles down here"))
4828 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4832 # Code from reports.c begins here
4834 def attackreport(curt):
4835 "eport status of bases under attack."
4837 if is_scheduled(FCDBAS):
4838 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4839 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4840 elif game.isatb == 1:
4841 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4842 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4844 prout(_("No Starbase is currently under attack."))
4846 if is_scheduled(FCDBAS):
4847 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4849 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4853 # report on general game status
4855 s1 = (game.thawed and _("thawed ")) or ""
4856 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4857 s3 = (None, _("novice"), _("fair"),
4858 _("good"), _("expert"), _("emeritus"))[game.skill]
4859 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4860 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4861 prout(_("No plaque is allowed."))
4863 prout(_("This is tournament game %d.") % game.tourn)
4864 prout(_("Your secret password is \"%s\"") % game.passwd)
4865 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4866 (game.inkling + game.incom + game.inscom)))
4867 if game.incom - len(game.state.kcmdr):
4868 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4869 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4870 prout(_(", but no Commanders."))
4873 if game.skill > SKILL_FAIR:
4874 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4875 if len(game.state.baseq) != game.inbase:
4877 if game.inbase-len(game.state.baseq)==1:
4878 proutn(_("has been 1 base"))
4880 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4881 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4883 prout(_("There are %d bases.") % game.inbase)
4884 if communicating() or game.iseenit:
4885 # Don't report this if not seen and
4886 # either the radio is dead or not at base!
4890 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4892 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4893 if game.ship == 'E':
4894 proutn(_("You have "))
4896 proutn("%d" % (game.nprobes))
4899 proutn(_(" deep space probe"))
4903 if communicating() and is_scheduled(FDSPROB):
4905 proutn(_("An armed deep space probe is in "))
4907 proutn(_("A deep space probe is in "))
4908 prout("Quadrant %s." % game.probec)
4910 if game.cryprob <= .05:
4911 prout(_("Dilithium crystals aboard ship... not yet used."))
4915 while game.cryprob > ai:
4918 prout(_("Dilithium crystals have been used %d time%s.") % \
4919 (i, (_("s"), "")[i==1]))
4923 "Long-range sensor scan."
4924 if damaged(DLRSENS):
4925 # Now allow base's sensors if docked
4926 if game.condition != "docked":
4928 prout(_("LONG-RANGE SENSORS DAMAGED."))
4931 prout(_("Starbase's long-range scan"))
4933 prout(_("Long-range scan"))
4934 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4937 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4938 if not Coord(x, y).valid_quadrant():
4942 if not damaged(DRADIO):
4943 game.state.galaxy[x][y].charted = True
4944 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4945 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4946 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4947 if not silent and game.state.galaxy[x][y].supernova:
4950 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4958 for i in range(NDEVICES):
4961 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4962 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4964 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4965 game.damage[i]+0.05,
4966 DOCKFAC*game.damage[i]+0.005))
4968 prout(_("All devices functional."))
4971 "Update the chart in the Enterprise's computer from galaxy data."
4972 game.lastchart = game.state.date
4973 for i in range(GALSIZE):
4974 for j in range(GALSIZE):
4975 if game.state.galaxy[i][j].charted:
4976 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
4977 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
4978 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
4981 "Display the star chart."
4983 if (game.options & OPTION_AUTOSCAN):
4985 if not damaged(DRADIO):
4987 if game.lastchart < game.state.date and game.condition == "docked":
4988 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
4990 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
4991 if game.state.date > game.lastchart:
4992 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
4993 prout(" 1 2 3 4 5 6 7 8")
4994 for i in range(GALSIZE):
4995 proutn("%d |" % (i+1))
4996 for j in range(GALSIZE):
4997 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5001 if game.state.galaxy[i][j].supernova:
5003 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5005 elif game.state.galaxy[i][j].charted:
5006 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5010 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5018 def sectscan(goodScan, i, j):
5019 "Light up an individual dot in a sector."
5020 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5021 textcolor({"green":GREEN,
5025 "dead":BROWN}[game.condition])
5026 if game.quad[i][j] != game.ship:
5028 proutn("%c " % game.quad[i][j])
5034 "Emit status report lines"
5035 if not req or req == 1:
5036 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5037 % (game.state.date, game.state.remtime))
5038 if not req or req == 2:
5039 if game.condition != "docked":
5041 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5042 (game.condition.upper(), sum(map(lambda x: x > 0, game.damage))))
5043 if not req or req == 3:
5044 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5045 if not req or req == 4:
5046 if damaged(DLIFSUP):
5047 if game.condition == "docked":
5048 s = _("DAMAGED, Base provides")
5050 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5053 prstat(_("Life Support"), s)
5054 if not req or req == 5:
5055 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5056 if not req or req == 6:
5058 if game.icrystl and (game.options & OPTION_SHOWME):
5059 extra = _(" (have crystals)")
5060 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5061 if not req or req == 7:
5062 prstat(_("Torpedoes"), "%d" % (game.torps))
5063 if not req or req == 8:
5064 if damaged(DSHIELD):
5070 data = _(" %d%% %.1f units") \
5071 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5072 prstat(_("Shields"), s+data)
5073 if not req or req == 9:
5074 prstat(_("Klingons Left"), "%d" \
5075 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5076 if not req or req == 10:
5077 if game.options & OPTION_WORLDS:
5078 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5079 if plnet and plnet.inhabited:
5080 prstat(_("Major system"), plnet.name)
5082 prout(_("Sector is uninhabited"))
5083 elif not req or req == 11:
5084 attackreport(not req)
5087 "Request specified status data, a historical relic from slow TTYs."
5088 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5089 while scanner.next() == "IHEOL":
5090 proutn(_("Information desired? "))
5092 if scanner.token in requests:
5093 status(requests.index(scanner.token))
5095 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5096 prout((" date, condition, position, lsupport, warpfactor,"))
5097 prout((" energy, torpedoes, shields, klingons, system, time."))
5102 if damaged(DSRSENS):
5103 # Allow base's sensors if docked
5104 if game.condition != "docked":
5105 prout(_(" S.R. SENSORS DAMAGED!"))
5108 prout(_(" [Using Base's sensors]"))
5110 prout(_(" Short-range scan"))
5111 if goodScan and not damaged(DRADIO):
5112 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5113 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5114 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5115 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5116 prout(" 1 2 3 4 5 6 7 8 9 10")
5117 if game.condition != "docked":
5119 for i in range(QUADSIZE):
5120 proutn("%2d " % (i+1))
5121 for j in range(QUADSIZE):
5122 sectscan(goodScan, i, j)
5126 "Use computer to get estimated time of arrival for a warp jump."
5127 w1 = Coord(); w2 = Coord()
5129 if damaged(DCOMPTR):
5130 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5133 if scanner.next() != "IHREAL":
5136 proutn(_("Destination quadrant and/or sector? "))
5137 if scanner.next()!="IHREAL":
5140 w1.j = int(scanner.real-0.5)
5141 if scanner.next() != "IHREAL":
5144 w1.i = int(scanner.real-0.5)
5145 if scanner.next() == "IHREAL":
5146 w2.j = int(scanner.real-0.5)
5147 if scanner.next() != "IHREAL":
5150 w2.i = int(scanner.real-0.5)
5152 if game.quadrant.j>w1.i:
5156 if game.quadrant.i>w1.j:
5160 if not w1.valid_quadrant() or not w2.valid_sector():
5163 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5164 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5167 prout(_("Answer \"no\" if you don't know the value:"))
5170 proutn(_("Time or arrival date? "))
5171 if scanner.next()=="IHREAL":
5172 ttime = scanner.real
5173 if ttime > game.state.date:
5174 ttime -= game.state.date # Actually a star date
5175 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5176 if ttime <= 1e-10 or twarp > 10:
5177 prout(_("We'll never make it, sir."))
5184 proutn(_("Warp factor? "))
5185 if scanner.next()== "IHREAL":
5187 twarp = scanner.real
5188 if twarp<1.0 or twarp > 10.0:
5192 prout(_("Captain, certainly you can give me one of these."))
5195 ttime = (10.0*dist)/twarp**2
5196 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5197 if tpower >= game.energy:
5198 prout(_("Insufficient energy, sir."))
5199 if not game.shldup or tpower > game.energy*2.0:
5202 proutn(_("New warp factor to try? "))
5203 if scanner.next() == "IHREAL":
5205 twarp = scanner.real
5206 if twarp<1.0 or twarp > 10.0:
5214 prout(_("But if you lower your shields,"))
5215 proutn(_("remaining"))
5218 proutn(_("Remaining"))
5219 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5221 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5223 prout(_("Any warp speed is adequate."))
5225 prout(_("Minimum warp needed is %.2f,") % (twarp))
5226 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5227 if game.state.remtime < ttime:
5228 prout(_("Unfortunately, the Federation will be destroyed by then."))
5230 prout(_("You'll be taking risks at that speed, Captain"))
5231 if (game.isatb==1 and game.state.kscmdr == w1 and \
5232 scheduled(FSCDBAS)< ttime+game.state.date) or \
5233 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5234 prout(_("The starbase there will be destroyed by then."))
5235 proutn(_("New warp factor to try? "))
5236 if scanner.next() == "IHREAL":
5238 twarp = scanner.real
5239 if twarp<1.0 or twarp > 10.0:
5247 # Code from setup.c begins here
5250 "Issue a historically correct banner."
5252 prout(_("-SUPER- STAR TREK"))
5254 # From the FORTRAN original
5255 # prout(_("Latest update-21 Sept 78"))
5261 scanner.push("emsave.trk")
5262 key = scanner.next()
5264 proutn(_("File name: "))
5265 key = scanner.next()
5266 if key != "IHALPHA":
5269 if '.' not in scanner.token:
5270 scanner.token += ".trk"
5272 fp = open(scanner.token, "wb")
5274 prout(_("Can't freeze game as file %s") % scanner.token)
5276 cPickle.dump(game, fp)
5281 "Retrieve saved game."
5284 key = scanner.next()
5286 proutn(_("File name: "))
5287 key = scanner.next()
5288 if key != "IHALPHA":
5291 if '.' not in scanner.token:
5292 scanner.token += ".trk"
5294 fp = open(scanner.token, "rb")
5296 prout(_("Can't thaw game in %s") % scanner.token)
5298 game = cPickle.load(fp)
5303 # I used <http://www.memory-alpha.org> to find planets
5304 # with references in ST:TOS. Earth and the Alpha Centauri
5305 # Colony have been omitted.
5307 # Some planets marked Class G and P here will be displayed as class M
5308 # because of the way planets are generated. This is a known bug.
5311 _("Andoria (Fesoan)"), # several episodes
5312 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5313 _("Vulcan (T'Khasi)"), # many episodes
5314 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5315 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5316 _("Ardana"), # TOS: "The Cloud Minders"
5317 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5318 _("Gideon"), # TOS: "The Mark of Gideon"
5319 _("Aldebaran III"), # TOS: "The Deadly Years"
5320 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5321 _("Altair IV"), # TOS: "Amok Time
5322 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5323 _("Benecia"), # TOS: "The Conscience of the King"
5324 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5325 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5326 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5327 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5328 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5329 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5330 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5331 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5332 _("Ingraham B"), # TOS: "Operation: Annihilate"
5333 _("Janus IV"), # TOS: "The Devil in the Dark"
5334 _("Makus III"), # TOS: "The Galileo Seven"
5335 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5336 _("Omega IV"), # TOS: "The Omega Glory"
5337 _("Regulus V"), # TOS: "Amok Time
5338 _("Deneva"), # TOS: "Operation -- Annihilate!"
5339 # Worlds from BSD Trek
5340 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5341 _("Beta III"), # TOS: "The Return of the Archons"
5342 _("Triacus"), # TOS: "And the Children Shall Lead",
5343 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5345 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5346 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5347 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5348 # _("Izar"), # TOS: "Whom Gods Destroy"
5349 # _("Tiburon"), # TOS: "The Way to Eden"
5350 # _("Merak II"), # TOS: "The Cloud Minders"
5351 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5352 # _("Iotia"), # TOS: "A Piece of the Action"
5356 _("S. R. Sensors"), \
5357 _("L. R. Sensors"), \
5359 _("Photon Tubes"), \
5360 _("Life Support"), \
5361 _("Warp Engines"), \
5362 _("Impulse Engines"), \
5364 _("Subspace Radio"), \
5365 _("Shuttle Craft"), \
5367 _("Navigation System"), \
5369 _("Shield Control"), \
5375 "Prepare to play, set up cosmos."
5377 # Decide how many of everything
5379 return # frozen game
5380 # Prepare the Enterprise
5381 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5383 game.state.crew = FULLCREW
5384 game.energy = game.inenrg = 5000.0
5385 game.shield = game.inshld = 2500.0
5388 game.quadrant = randplace(GALSIZE)
5389 game.sector = randplace(QUADSIZE)
5390 game.torps = game.intorps = 10
5391 game.nprobes = randrange(2, 5)
5393 for i in range(NDEVICES):
5394 game.damage[i] = 0.0
5395 # Set up assorted game parameters
5396 game.battle = Coord()
5397 game.state.date = game.indate = 100.0 * randreal(20, 51)
5398 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5399 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5400 game.isatb = game.state.nplankl = 0
5401 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5402 game.iscraft = "onship"
5407 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5409 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5411 game.state.planets = [] # Planet information
5412 game.state.baseq = [] # Base quadrant coordinates
5413 game.state.kcmdr = [] # Commander quadrant coordinates
5414 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5416 # Starchart is functional but we've never seen it
5417 game.lastchart = FOREVER
5418 # Put stars in the galaxy
5420 for i in range(GALSIZE):
5421 for j in range(GALSIZE):
5422 k = randrange(1, QUADSIZE**2/10+1)
5424 game.state.galaxy[i][j].stars = k
5425 # Locate star bases in galaxy
5426 for i in range(game.inbase):
5429 w = randplace(GALSIZE)
5430 if not game.state.galaxy[w.i][w.j].starbase:
5433 # C version: for (j = i-1; j > 0; j--)
5434 # so it did them in the opposite order.
5435 for j in range(1, i):
5436 # Improved placement algorithm to spread out bases
5437 distq = (w - game.state.baseq[j]).distance()
5438 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5441 prout("=== Abandoning base #%d at %s" % (i, w))
5443 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5445 prout("=== Saving base #%d, close to #%d" % (i, j))
5448 game.state.baseq.append(w)
5449 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5450 # Position ordinary Klingon Battle Cruisers
5452 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5453 if klumper > MAXKLQUAD:
5457 klump = (1.0 - r*r)*klumper
5462 w = randplace(GALSIZE)
5463 if not game.state.galaxy[w.i][w.j].supernova and \
5464 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5466 game.state.galaxy[w.i][w.j].klingons += int(klump)
5469 # Position Klingon Commander Ships
5470 for i in range(game.incom):
5472 w = randplace(GALSIZE)
5473 if not welcoming(w) or w in game.state.kcmdr:
5475 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5477 game.state.galaxy[w.i][w.j].klingons += 1
5478 game.state.kcmdr.append(w)
5479 # Locate planets in galaxy
5480 for i in range(game.inplan):
5482 w = randplace(GALSIZE)
5483 if game.state.galaxy[w.i][w.j].planet == None:
5487 new.crystals = "absent"
5488 if (game.options & OPTION_WORLDS) and i < NINHAB:
5489 new.pclass = "M" # All inhabited planets are class M
5490 new.crystals = "absent"
5492 new.name = systnames[i]
5493 new.inhabited = True
5495 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5497 new.crystals = "present"
5498 new.known = "unknown"
5499 new.inhabited = False
5500 game.state.galaxy[w.i][w.j].planet = new
5501 game.state.planets.append(new)
5503 for i in range(game.state.nromrem):
5504 w = randplace(GALSIZE)
5505 game.state.galaxy[w.i][w.j].romulans += 1
5506 # Place the Super-Commander if needed
5507 if game.state.nscrem > 0:
5509 w = randplace(GALSIZE)
5512 game.state.kscmdr = w
5513 game.state.galaxy[w.i][w.j].klingons += 1
5514 # Initialize times for extraneous events
5515 schedule(FSNOVA, expran(0.5 * game.intime))
5516 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5517 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5518 schedule(FBATTAK, expran(0.3*game.intime))
5520 if game.state.nscrem:
5521 schedule(FSCMOVE, 0.2777)
5526 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5527 schedule(FDISTR, expran(1.0 + game.intime))
5532 # Place thing (in tournament game, we don't want one!)
5533 # New in SST2K: never place the Thing near a starbase.
5534 # This makes sense and avoids a special case in the old code.
5536 if game.tourn is None:
5538 thing = randplace(GALSIZE)
5539 if thing not in game.state.baseq:
5542 game.state.snap = False
5543 if game.skill == SKILL_NOVICE:
5544 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5545 prout(_("a deadly Klingon invasion force. As captain of the United"))
5546 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5547 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5548 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5549 prout(_("your mission. As you proceed you may be given more time."))
5551 prout(_("You will have %d supporting starbases.") % (game.inbase))
5552 proutn(_("Starbase locations- "))
5554 prout(_("Stardate %d.") % int(game.state.date))
5556 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5557 prout(_("An unknown number of Romulans."))
5558 if game.state.nscrem:
5559 prout(_("And one (GULP) Super-Commander."))
5560 prout(_("%d stardates.") % int(game.intime))
5561 proutn(_("%d starbases in ") % game.inbase)
5562 for i in range(game.inbase):
5563 proutn(`game.state.baseq[i]`)
5566 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5567 proutn(_(" Sector %s") % game.sector)
5569 prout(_("Good Luck!"))
5570 if game.state.nscrem:
5571 prout(_(" YOU'LL NEED IT."))
5574 setwnd(message_window)
5576 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5578 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5579 attack(torps_ok=False)
5582 "Choose your game type."
5584 game.tourn = game.length = 0
5586 game.skill = SKILL_NONE
5588 # if not scanner.inqueue: # Can start with command line options
5589 proutn(_("Would you like a regular, tournament, or saved game? "))
5591 if scanner.sees("tournament"):
5592 while scanner.next() == "IHEOL":
5593 proutn(_("Type in tournament number-"))
5594 if scanner.real == 0:
5596 continue # We don't want a blank entry
5597 game.tourn = int(round(scanner.real))
5598 random.seed(scanner.real)
5600 logfp.write("# random.seed(%d)\n" % scanner.real)
5602 if scanner.sees("saved") or scanner.sees("frozen"):
5606 if game.passwd == None:
5608 if not game.alldone:
5609 game.thawed = True # No plaque if not finished
5613 if scanner.sees("regular"):
5615 proutn(_("What is \"%s\"? ") % scanner.token)
5617 while game.length==0 or game.skill==SKILL_NONE:
5618 if scanner.next() == "IHALPHA":
5619 if scanner.sees("short"):
5621 elif scanner.sees("medium"):
5623 elif scanner.sees("long"):
5625 elif scanner.sees("novice"):
5626 game.skill = SKILL_NOVICE
5627 elif scanner.sees("fair"):
5628 game.skill = SKILL_FAIR
5629 elif scanner.sees("good"):
5630 game.skill = SKILL_GOOD
5631 elif scanner.sees("expert"):
5632 game.skill = SKILL_EXPERT
5633 elif scanner.sees("emeritus"):
5634 game.skill = SKILL_EMERITUS
5636 proutn(_("What is \""))
5637 proutn(scanner.token)
5642 proutn(_("Would you like a Short, Medium, or Long game? "))
5643 elif game.skill == SKILL_NONE:
5644 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5645 # Choose game options -- added by ESR for SST2K
5646 if scanner.next() != "IHALPHA":
5648 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5650 if scanner.sees("plain"):
5651 # Approximates the UT FORTRAN version.
5652 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5653 game.options |= OPTION_PLAIN
5654 elif scanner.sees("almy"):
5655 # Approximates Tom Almy's version.
5656 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5657 game.options |= OPTION_ALMY
5658 elif scanner.sees("fancy") or scanner.sees("\n"):
5660 elif len(scanner.token):
5661 proutn(_("What is \"%s\"?") % scanner.token)
5662 game.options &=~ OPTION_COLOR
5664 if game.passwd == "debug":
5666 prout("=== Debug mode enabled.")
5667 # Use parameters to generate initial values of things
5668 game.damfac = 0.5 * game.skill
5669 game.inbase = randrange(BASEMIN, BASEMAX+1)
5671 if game.options & OPTION_PLANETS:
5672 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5673 if game.options & OPTION_WORLDS:
5674 game.inplan += int(NINHAB)
5675 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5676 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5677 game.state.remtime = 7.0 * game.length
5678 game.intime = game.state.remtime
5679 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5680 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5681 game.state.remres = (game.inkling+4*game.incom)*game.intime
5682 game.inresor = game.state.remres
5683 if game.inkling > 50:
5684 game.state.inbase += 1
5687 def dropin(iquad=None):
5688 "Drop a feature on a random dot in the current quadrant."
5690 w = randplace(QUADSIZE)
5691 if game.quad[w.i][w.j] == '.':
5693 if iquad is not None:
5694 game.quad[w.i][w.j] = iquad
5698 "Update our alert status."
5699 game.condition = "green"
5700 if game.energy < 1000.0:
5701 game.condition = "yellow"
5702 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5703 game.condition = "red"
5705 game.condition="dead"
5708 "Drop new Klingon into current quadrant."
5709 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5712 "Sort enemies by distance so 'nearest' is meaningful."
5713 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
5716 "Set up a new state of quadrant, for when we enter or re-enter it."
5719 game.neutz = game.inorbit = game.landed = False
5720 game.ientesc = game.iseenit = False
5721 # Create a blank quadrant
5722 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5724 # Attempt to escape Super-commander, so tbeam back!
5727 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5728 # cope with supernova
5731 game.klhere = q.klingons
5732 game.irhere = q.romulans
5734 game.quad[game.sector.i][game.sector.j] = game.ship
5737 # Position ordinary Klingons
5738 for i in range(game.klhere):
5740 # If we need a commander, promote a Klingon
5741 for cmdr in game.state.kcmdr:
5742 if cmdr == game.quadrant:
5743 e = game.enemies[game.klhere-1]
5744 game.quad[e.location.i][e.location.j] = 'C'
5745 e.power = randreal(950,1350) + 50.0*game.skill
5747 # If we need a super-commander, promote a Klingon
5748 if game.quadrant == game.state.kscmdr:
5750 game.quad[e.location.i][e.location.j] = 'S'
5751 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5752 game.iscate = (game.state.remkl > 1)
5753 # Put in Romulans if needed
5754 for i in range(q.romulans):
5755 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5756 # If quadrant needs a starbase, put it in
5758 game.base = dropin('B')
5759 # If quadrant needs a planet, put it in
5761 game.iplnet = q.planet
5762 if not q.planet.inhabited:
5763 game.plnet = dropin('P')
5765 game.plnet = dropin('@')
5766 # Check for condition
5769 if game.irhere > 0 and game.klhere == 0:
5771 if not damaged(DRADIO):
5773 prout(_("LT. Uhura- \"Captain, an urgent message."))
5774 prout(_(" I'll put it on audio.\" CLICK"))
5776 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5777 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5778 # Put in THING if needed
5779 if thing == game.quadrant:
5780 Enemy(type='?', loc=dropin(),
5781 power=randreal(6000,6500.0)+250.0*game.skill)
5782 if not damaged(DSRSENS):
5784 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5785 prout(_(" Please examine your short-range scan.\""))
5786 # Decide if quadrant needs a Tholian; lighten up if skill is low
5787 if game.options & OPTION_THOLIAN:
5788 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5789 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5790 (game.skill > SKILL_GOOD and withprob(0.08)):
5793 w.i = withprob(0.5) * (QUADSIZE-1)
5794 w.j = withprob(0.5) * (QUADSIZE-1)
5795 if game.quad[w.i][w.j] == '.':
5797 game.tholian = Enemy(type='T', loc=w,
5798 power=randrange(100, 500) + 25.0*game.skill)
5799 # Reserve unoccupied corners
5800 if game.quad[0][0]=='.':
5801 game.quad[0][0] = 'X'
5802 if game.quad[0][QUADSIZE-1]=='.':
5803 game.quad[0][QUADSIZE-1] = 'X'
5804 if game.quad[QUADSIZE-1][0]=='.':
5805 game.quad[QUADSIZE-1][0] = 'X'
5806 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5807 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5809 # And finally the stars
5810 for i in range(q.stars):
5812 # Put in a few black holes
5813 for i in range(1, 3+1):
5816 # Take out X's in corners if Tholian present
5818 if game.quad[0][0]=='X':
5819 game.quad[0][0] = '.'
5820 if game.quad[0][QUADSIZE-1]=='X':
5821 game.quad[0][QUADSIZE-1] = '.'
5822 if game.quad[QUADSIZE-1][0]=='X':
5823 game.quad[QUADSIZE-1][0] = '.'
5824 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5825 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5828 "Set the self-destruct password."
5829 if game.options & OPTION_PLAIN:
5832 proutn(_("Please type in a secret password- "))
5834 game.passwd = scanner.token
5835 if game.passwd != None:
5839 game.passwd += chr(ord('a')+randrange(26))
5840 game.passwd += chr(ord('a')+randrange(26))
5841 game.passwd += chr(ord('a')+randrange(26))
5843 # Code from sst.c begins here
5846 ("SRSCAN", OPTION_TTY),
5847 ("STATUS", OPTION_TTY),
5848 ("REQUEST", OPTION_TTY),
5849 ("LRSCAN", OPTION_TTY),
5862 ("SENSORS", OPTION_PLANETS),
5863 ("ORBIT", OPTION_PLANETS),
5864 ("TRANSPORT", OPTION_PLANETS),
5865 ("MINE", OPTION_PLANETS),
5866 ("CRYSTALS", OPTION_PLANETS),
5867 ("SHUTTLE", OPTION_PLANETS),
5868 ("PLANETS", OPTION_PLANETS),
5873 ("PROBE", OPTION_PROBE),
5875 ("FREEZE", 0), # Synonym for SAVE
5881 ("SOS", 0), # Synonym for MAYDAY
5882 ("CALL", 0), # Synonym for MAYDAY
5889 "Generate a list of legal commands."
5890 prout(_("LEGAL COMMANDS ARE:"))
5892 for (key, opt) in commands:
5893 if not opt or (opt & game.options):
5894 proutn("%-12s " % key)
5896 if emitted % 5 == 4:
5901 "Browse on-line help."
5902 key = scanner.next()
5905 setwnd(prompt_window)
5906 proutn(_("Help on what command? "))
5907 key = scanner.next()
5908 setwnd(message_window)
5911 cmds = map(lambda x: x[0], commands)
5912 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
5919 cmd = scanner.token.upper()
5920 for directory in docpath:
5922 fp = open(os.path.join(directory, "sst.doc"), "r")
5927 prout(_("Spock- \"Captain, that information is missing from the"))
5928 prout(_(" computer. You need to find sst.doc and put it somewhere"))
5929 proutn(_(" in these directories: %s") % ":".join(docpath))
5931 # This used to continue: "You need to find SST.DOC and put
5932 # it in the current directory."
5935 linebuf = fp.readline()
5937 prout(_("Spock- \"Captain, there is no information on that command.\""))
5940 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5941 linebuf = linebuf[3:].strip()
5942 if cmd.upper() == linebuf:
5945 prout(_("Spock- \"Captain, I've found the following information:\""))
5948 linebuf = fp.readline()
5949 if "******" in linebuf:
5955 "Command-interpretation loop."
5956 while True: # command loop
5958 while True: # get a command
5960 game.optime = game.justin = False
5962 setwnd(prompt_window)
5965 if scanner.next() == "IHEOL":
5966 if game.options & OPTION_CURSES:
5969 elif scanner.token == "":
5973 setwnd(message_window)
5975 abandon_passed = False
5976 for (cmd, opt) in commands:
5977 # commands after ABANDON cannot be abbreviated
5978 if cmd == "ABANDON":
5979 abandon_passed = True
5980 if cmd == scanner.token.upper() or (not abandon_passed \
5981 and cmd.startswith(scanner.token.upper())):
5988 if cmd == "SRSCAN": # srscan
5990 elif cmd == "STATUS": # status
5992 elif cmd == "REQUEST": # status request
5994 elif cmd == "LRSCAN": # long range scan
5995 lrscan(silent=False)
5996 elif cmd == "PHASERS": # phasers
6000 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6004 elif cmd == "MOVE": # move under warp
6005 warp(wcourse=None, involuntary=False)
6006 elif cmd == "SHIELDS": # shields
6007 doshield(shraise=False)
6010 game.shldchg = False
6011 elif cmd == "DOCK": # dock at starbase
6014 attack(torps_ok=False)
6015 elif cmd == "DAMAGES": # damage reports
6017 elif cmd == "CHART": # chart
6019 elif cmd == "IMPULSE": # impulse
6021 elif cmd == "REST": # rest
6025 elif cmd == "WARP": # warp
6027 elif cmd == "SCORE": # score
6029 elif cmd == "SENSORS": # sensors
6031 elif cmd == "ORBIT": # orbit
6035 elif cmd == "TRANSPORT": # transport "beam"
6037 elif cmd == "MINE": # mine
6041 elif cmd == "CRYSTALS": # crystals
6045 elif cmd == "SHUTTLE": # shuttle
6049 elif cmd == "PLANETS": # Planet list
6051 elif cmd == "REPORT": # Game Report
6053 elif cmd == "COMPUTER": # use COMPUTER!
6055 elif cmd == "COMMANDS":
6057 elif cmd == "EMEXIT": # Emergency exit
6058 clrscr() # Hide screen
6059 freeze(True) # forced save
6060 raise SystemExit,1 # And quick exit
6061 elif cmd == "PROBE":
6062 probe() # Launch probe
6065 elif cmd == "ABANDON": # Abandon Ship
6067 elif cmd == "DESTRUCT": # Self Destruct
6069 elif cmd == "SAVE": # Save Game
6072 if game.skill > SKILL_GOOD:
6073 prout(_("WARNING--Saved games produce no plaques!"))
6074 elif cmd == "DEATHRAY": # Try a desparation measure
6078 elif cmd == "DEBUGCMD": # What do we want for debug???
6080 elif cmd == "MAYDAY": # Call for help
6085 game.alldone = True # quit the game
6090 break # Game has ended
6091 if game.optime != 0.0:
6094 break # Events did us in
6095 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6098 if hitme and not game.justin:
6099 attack(torps_ok=True)
6102 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6113 "Emit the name of an enemy or feature."
6114 if type == 'R': s = _("Romulan")
6115 elif type == 'K': s = _("Klingon")
6116 elif type == 'C': s = _("Commander")
6117 elif type == 'S': s = _("Super-commander")
6118 elif type == '*': s = _("Star")
6119 elif type == 'P': s = _("Planet")
6120 elif type == 'B': s = _("Starbase")
6121 elif type == ' ': s = _("Black hole")
6122 elif type == 'T': s = _("Tholian")
6123 elif type == '#': s = _("Tholian web")
6124 elif type == '?': s = _("Stranger")
6125 elif type == '@': s = _("Inhabited World")
6126 else: s = "Unknown??"
6129 def crmena(stars, enemy, loctype, w):
6130 "Emit the name of an enemy and his location."
6134 buf += cramen(enemy) + _(" at ")
6135 if loctype == "quadrant":
6136 buf += _("Quadrant ")
6137 elif loctype == "sector":
6142 "Emit our ship name."
6143 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6146 "Emit a line of stars"
6147 prouts("******************************************************")
6151 return -avrage*math.log(1e-7 + randreal())
6153 def randplace(size):
6154 "Choose a random location."
6156 w.i = randrange(size)
6157 w.j = randrange(size)
6167 # Get a token from the user
6170 # Fill the token quue if nothing here
6171 while not self.inqueue:
6173 if curwnd==prompt_window:
6175 setwnd(message_window)
6182 self.inqueue = line.lstrip().split() + ["\n"]
6183 # From here on in it's all looking at the queue
6184 self.token = self.inqueue.pop(0)
6185 if self.token == "\n":
6189 self.real = float(self.token)
6190 self.type = "IHREAL"
6195 self.token = self.token.lower()
6196 self.type = "IHALPHA"
6199 def append(self, tok):
6200 self.inqueue.append(tok)
6201 def push(self, tok):
6202 self.inqueue.insert(0, tok)
6206 # Demand input for next scan
6208 self.real = self.token = None
6210 # compares s to item and returns true if it matches to the length of s
6211 return s.startswith(self.token)
6213 # Round token value to nearest integer
6214 return int(round(scanner.real))
6218 if scanner.type != "IHREAL":
6221 s.i = scanner.int()-1
6223 if scanner.type != "IHREAL":
6226 s.j = scanner.int()-1
6229 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6232 "Yes-or-no confirmation."
6236 if scanner.token == 'y':
6238 if scanner.token == 'n':
6241 proutn(_("Please answer with \"y\" or \"n\": "))
6244 "Complain about unparseable input."
6247 prout(_("Beg your pardon, Captain?"))
6250 "Access to the internals for debugging."
6251 proutn("Reset levels? ")
6253 if game.energy < game.inenrg:
6254 game.energy = game.inenrg
6255 game.shield = game.inshld
6256 game.torps = game.intorps
6257 game.lsupres = game.inlsr
6258 proutn("Reset damage? ")
6260 for i in range(NDEVICES):
6261 if game.damage[i] > 0.0:
6262 game.damage[i] = 0.0
6263 proutn("Toggle debug flag? ")
6265 game.idebug = not game.idebug
6267 prout("Debug output ON")
6269 prout("Debug output OFF")
6270 proutn("Cause selective damage? ")
6272 for i in range(NDEVICES):
6273 proutn("Kill %s?" % device[i])
6275 key = scanner.next()
6276 if key == "IHALPHA" and scanner.sees("y"):
6277 game.damage[i] = 10.0
6278 proutn("Examine/change events? ")
6283 FSNOVA: "Supernova ",
6286 FBATTAK: "Base Attack ",
6287 FCDBAS: "Base Destroy ",
6288 FSCMOVE: "SC Move ",
6289 FSCDBAS: "SC Base Destroy ",
6290 FDSPROB: "Probe Move ",
6291 FDISTR: "Distress Call ",
6292 FENSLV: "Enslavement ",
6293 FREPRO: "Klingon Build ",
6295 for i in range(1, NEVENTS):
6298 proutn("%.2f" % (scheduled(i)-game.state.date))
6299 if i == FENSLV or i == FREPRO:
6301 proutn(" in %s" % ev.quadrant)
6306 key = scanner.next()
6310 elif key == "IHREAL":
6311 ev = schedule(i, scanner.real)
6312 if i == FENSLV or i == FREPRO:
6314 proutn("In quadrant- ")
6315 key = scanner.next()
6316 # "IHEOL" says to leave coordinates as they are
6319 prout("Event %d canceled, no x coordinate." % (i))
6322 w.i = int(round(scanner.real))
6323 key = scanner.next()
6325 prout("Event %d canceled, no y coordinate." % (i))
6328 w.j = int(round(scanner.real))
6331 proutn("Induce supernova here? ")
6333 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6336 if __name__ == '__main__':
6337 import getopt, socket
6339 global line, thing, game
6343 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6344 if os.getenv("TERM"):
6345 game.options |= OPTION_CURSES
6347 game.options |= OPTION_TTY
6348 seed = int(time.time())
6349 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6351 for (switch, val) in options:
6354 replayfp = open(val, "r")
6356 sys.stderr.write("sst: can't open replay file %s\n" % val)
6359 line = replayfp.readline().strip()
6360 (leader, __, seed) = line.split()
6362 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6363 line = replayfp.readline().strip()
6364 arguments += line.split()[2:]
6367 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6369 game.options |= OPTION_TTY
6370 game.options &=~ OPTION_CURSES
6371 elif switch == '-s':
6373 elif switch == '-t':
6374 game.options |= OPTION_TTY
6375 game.options &=~ OPTION_CURSES
6376 elif switch == '-x':
6378 elif switch == '-V':
6379 print "SST2K", version
6382 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6384 # where to save the input in case of bugs
6385 if "TMPDIR" in os.environ:
6386 tmpdir = os.environ['TMPDIR']
6390 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6392 sys.stderr.write("sst: warning, can't open logfile\n")
6395 logfp.write("# seed %s\n" % seed)
6396 logfp.write("# options %s\n" % " ".join(arguments))
6397 logfp.write("# recorded by %s@%s on %s\n" % \
6398 (getpass.getuser(),socket.gethostname(),time.ctime()))
6400 scanner = sstscanner()
6401 map(scanner.append, arguments)
6404 while True: # Play a game
6405 setwnd(fullscreen_window)
6411 game.alldone = False
6419 if game.tourn and game.alldone:
6420 proutn(_("Do you want your score recorded?"))
6426 proutn(_("Do you want to play again? "))
6430 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6434 except KeyboardInterrupt: