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':
703 if game.condition != "docked":
706 # check for a helpful planet
707 for i in range(game.inplan):
708 if game.state.planets[i].quadrant == game.state.kscmdr and \
709 game.state.planets[i].crystals == "present":
711 game.state.planets[i].pclass = "destroyed"
712 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
715 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
716 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
717 prout(_(" by the Super-commander.\""))
719 return True # looks good!
721 def supercommander():
722 "Move the Super Commander."
729 prout("== SUPERCOMMANDER")
730 # Decide on being active or passive
731 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 \
732 (game.state.date-game.indate) < 3.0)
733 if not game.iscate and avoid:
734 # compute move away from Enterprise
735 idelta = game.state.kscmdr-game.quadrant
736 if idelta.distance() > 2.0:
738 idelta.i = game.state.kscmdr.j-game.quadrant.j
739 idelta.j = game.quadrant.i-game.state.kscmdr.i
741 # compute distances to starbases
742 if not game.state.baseq:
746 sc = game.state.kscmdr
747 for (i, base) in enumerate(game.state.baseq):
748 basetbl.append((i, (base - sc).distance()))
749 if game.state.baseq > 1:
750 basetbl.sort(lambda x, y: cmp(x[1], y[1]))
751 # look for nearest base without a commander, no Enterprise, and
752 # without too many Klingons, and not already under attack.
753 ifindit = iwhichb = 0
754 for (i2, base) in enumerate(game.state.baseq):
755 i = basetbl[i2][0] # bug in original had it not finding nearest
756 if base == game.quadrant or base == game.battle or not welcoming(base):
758 # if there is a commander, and no other base is appropriate,
759 # we will take the one with the commander
760 for cmdr in game.state.kcmdr:
761 if base == cmdr and ifindit != 2:
765 else: # no commander -- use this one
770 return # Nothing suitable -- wait until next time
771 ibq = game.state.baseq[iwhichb]
772 # decide how to move toward base
773 idelta = ibq - game.state.kscmdr
774 # Maximum movement is 1 quadrant in either or both axes
775 idelta = idelta.sgn()
776 # try moving in both x and y directions
777 # there was what looked like a bug in the Almy C code here,
778 # but it might be this translation is just wrong.
779 iq = game.state.kscmdr + idelta
780 if not movescom(iq, avoid):
781 # failed -- try some other maneuvers
782 if idelta.i == 0 or idelta.j == 0:
785 iq.j = game.state.kscmdr.j + 1
786 if not movescom(iq, avoid):
787 iq.j = game.state.kscmdr.j - 1
790 iq.i = game.state.kscmdr.i + 1
791 if not movescom(iq, avoid):
792 iq.i = game.state.kscmdr.i - 1
795 # try moving just in x or y
796 iq.j = game.state.kscmdr.j
797 if not movescom(iq, avoid):
798 iq.j = game.state.kscmdr.j + idelta.j
799 iq.i = game.state.kscmdr.i
802 if len(game.state.baseq) == 0:
805 for ibq in game.state.baseq:
806 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
809 return # no, don't attack base!
812 schedule(FSCDBAS, randreal(1.0, 3.0))
813 if is_scheduled(FCDBAS):
814 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
815 if not communicating():
819 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
821 prout(_(" reports that it is under attack from the Klingon Super-commander."))
822 proutn(_(" It can survive until stardate %d.\"") \
823 % int(scheduled(FSCDBAS)))
826 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
830 game.optime = 0.0 # actually finished
832 # Check for intelligence report
833 if not game.idebug and \
835 (not communicating()) or \
836 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
839 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
840 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
845 if not game.tholian or game.justin:
848 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
851 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
854 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
857 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
861 # something is wrong!
862 game.tholian.move(None)
863 prout("***Internal error: Tholian in a bad spot.")
865 # do nothing if we are blocked
866 if game.quad[tid.i][tid.j] not in ('.', '#'):
868 here = copy.copy(game.tholian.location)
869 delta = (tid - game.tholian.location).sgn()
871 while here.i != tid.i:
873 if game.quad[here.i][here.j] == '.':
874 game.tholian.move(here)
876 while here.j != tid.j:
878 if game.quad[here.i][here.j] == '.':
879 game.tholian.move(here)
880 # check to see if all holes plugged
881 for i in range(QUADSIZE):
882 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
884 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
886 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
888 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
890 # All plugged up -- Tholian splits
891 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
893 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
894 game.tholian.move(None)
897 # Code from battle.c begins here
899 def doshield(shraise):
900 "Change shield status."
908 if scanner.sees("transfer"):
912 prout(_("Shields damaged and down."))
914 if scanner.sees("up"):
916 elif scanner.sees("down"):
919 proutn(_("Do you wish to change shield energy? "))
922 elif damaged(DSHIELD):
923 prout(_("Shields damaged and down."))
926 proutn(_("Shields are up. Do you want them down? "))
933 proutn(_("Shields are down. Do you want them up? "))
939 if action == "SHUP": # raise shields
941 prout(_("Shields already up."))
945 if game.condition != "docked":
947 prout(_("Shields raised."))
950 prout(_("Shields raising uses up last of energy."))
955 elif action == "SHDN":
957 prout(_("Shields already down."))
961 prout(_("Shields lowered."))
964 elif action == "NRG":
965 while scanner.next() != "IHREAL":
967 proutn(_("Energy to transfer to shields- "))
972 if nrg > game.energy:
973 prout(_("Insufficient ship energy."))
976 if game.shield+nrg >= game.inshld:
977 prout(_("Shield energy maximized."))
978 if game.shield+nrg > game.inshld:
979 prout(_("Excess energy requested returned to ship energy"))
980 game.energy -= game.inshld-game.shield
981 game.shield = game.inshld
983 if nrg < 0.0 and game.energy-nrg > game.inenrg:
984 # Prevent shield drain loophole
986 prout(_("Engineering to bridge--"))
987 prout(_(" Scott here. Power circuit problem, Captain."))
988 prout(_(" I can't drain the shields."))
991 if game.shield+nrg < 0:
992 prout(_("All shield energy transferred to ship."))
993 game.energy += game.shield
996 proutn(_("Scotty- \""))
998 prout(_("Transferring energy to shields.\""))
1000 prout(_("Draining energy from shields.\""))
1006 "Choose a device to damage, at random."
1008 105, # DSRSENS: short range scanners 10.5%
1009 105, # DLRSENS: long range scanners 10.5%
1010 120, # DPHASER: phasers 12.0%
1011 120, # DPHOTON: photon torpedoes 12.0%
1012 25, # DLIFSUP: life support 2.5%
1013 65, # DWARPEN: warp drive 6.5%
1014 70, # DIMPULS: impulse engines 6.5%
1015 145, # DSHIELD: deflector shields 14.5%
1016 30, # DRADIO: subspace radio 3.0%
1017 45, # DSHUTTL: shuttle 4.5%
1018 15, # DCOMPTR: computer 1.5%
1019 20, # NAVCOMP: navigation system 2.0%
1020 75, # DTRANSP: transporter 7.5%
1021 20, # DSHCTRL: high-speed shield controller 2.0%
1022 10, # DDRAY: death ray 1.0%
1023 30, # DDSP: deep-space probes 3.0%
1025 assert(sum(weights) == 1000)
1026 idx = randrange(1000)
1028 for (i, w) in enumerate(weights):
1032 return None # we should never get here
1034 def collision(rammed, enemy):
1035 "Collision handling fot rammong events."
1036 prouts(_("***RED ALERT! RED ALERT!"))
1038 prout(_("***COLLISION IMMINENT."))
1042 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1044 proutn(_(" rammed by "))
1047 proutn(crmena(False, enemy.type, "sector", enemy.location))
1049 proutn(_(" (original position)"))
1051 deadkl(enemy.location, enemy.type, game.sector)
1052 proutn("***" + crmshp() + " heavily damaged.")
1053 icas = randrange(10, 30)
1054 prout(_("***Sickbay reports %d casualties") % icas)
1056 game.state.crew -= icas
1057 # In the pre-SST2K version, all devices got equiprobably damaged,
1058 # which was silly. Instead, pick up to half the devices at
1059 # random according to our weighting table,
1060 ncrits = randrange(NDEVICES/2)
1064 if game.damage[dev] < 0:
1066 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1067 # Damage for at least time of travel!
1068 game.damage[dev] += game.optime + extradm
1070 prout(_("***Shields are down."))
1071 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1078 def torpedo(origin, bearing, dispersion, number, nburst):
1079 "Let a photon torpedo fly"
1080 if not damaged(DSRSENS) or game.condition == "docked":
1081 setwnd(srscan_window)
1083 setwnd(message_window)
1084 ac = bearing + 0.25*dispersion # dispersion is a random variable
1085 bullseye = (15.0 - bearing)*0.5235988
1086 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1087 bumpto = Coord(0, 0)
1088 # Loop to move a single torpedo
1089 setwnd(message_window)
1090 for step in range(1, QUADSIZE*2):
1091 if not track.next():
1094 if not w.valid_sector():
1096 iquad = game.quad[w.i][w.j]
1097 tracktorpedo(w, step, number, nburst, iquad)
1101 setwnd(message_window)
1102 if not damaged(DSRSENS) or game.condition == "docked":
1103 skip(1) # start new line after text track
1104 if iquad in ('E', 'F'): # Hit our ship
1106 prout(_("Torpedo hits %s.") % crmshp())
1107 hit = 700.0 + randreal(100) - \
1108 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1109 newcnd() # we're blown out of dock
1110 if game.landed or game.condition == "docked":
1111 return hit # Cheat if on a planet
1112 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1113 # is 143 degrees, which is almost exactly 4.8 clockface units
1114 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1116 bumpto = displacement.sector()
1117 if not bumpto.valid_sector():
1119 if game.quad[bumpto.i][bumpto.j] == ' ':
1122 if game.quad[bumpto.i][bumpto.j] != '.':
1123 # can't move into object
1125 game.sector = bumpto
1127 game.quad[w.i][w.j] = '.'
1128 game.quad[bumpto.i][bumpto.j] = iquad
1129 prout(_(" displaced by blast to Sector %s ") % bumpto)
1130 for enemy in game.enemies:
1131 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1134 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1136 if iquad in ('C', 'S') and withprob(0.05):
1137 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1138 prout(_(" torpedo neutralized."))
1140 for enemy in game.enemies:
1141 if w == enemy.location:
1142 kp = math.fabs(enemy.power)
1143 h1 = 700.0 + randrange(100) - \
1144 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1152 if enemy.power == 0:
1155 proutn(crmena(True, iquad, "sector", w))
1156 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1158 bumpto = displacement.sector()
1159 if not bumpto.valid_sector():
1160 prout(_(" damaged but not destroyed."))
1162 if game.quad[bumpto.i][bumpto.j] == ' ':
1163 prout(_(" buffeted into black hole."))
1164 deadkl(w, iquad, bumpto)
1165 if game.quad[bumpto.i][bumpto.j] != '.':
1166 prout(_(" damaged but not destroyed."))
1168 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1169 enemy.location = bumpto
1170 game.quad[w.i][w.j] = '.'
1171 game.quad[bumpto.i][bumpto.j] = iquad
1172 for enemy in game.enemies:
1173 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1177 prout("Internal error, no enemy where expected!")
1180 elif iquad == 'B': # Hit a base
1182 prout(_("***STARBASE DESTROYED.."))
1183 game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
1184 game.quad[w.i][w.j] = '.'
1185 game.base.invalidate()
1186 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1
1187 game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1
1188 game.state.basekl += 1
1191 elif iquad == 'P': # Hit a planet
1192 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1193 game.state.nplankl += 1
1194 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1195 game.iplnet.pclass = "destroyed"
1197 game.plnet.invalidate()
1198 game.quad[w.i][w.j] = '.'
1200 # captain perishes on planet
1203 elif iquad == '@': # Hit an inhabited world -- very bad!
1204 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1205 game.state.nworldkl += 1
1206 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1207 game.iplnet.pclass = "destroyed"
1209 game.plnet.invalidate()
1210 game.quad[w.i][w.j] = '.'
1212 # captain perishes on planet
1214 prout(_("The torpedo destroyed an inhabited planet."))
1216 elif iquad == '*': # Hit a star
1220 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1222 elif iquad == '?': # Hit a thingy
1223 if not (game.options & OPTION_THINGY) or withprob(0.3):
1225 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1227 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1229 proutn(_("Mr. Spock-"))
1230 prouts(_(" \"Fascinating!\""))
1234 # Stas Sergeev added the possibility that
1235 # you can shove the Thingy and piss it off.
1236 # It then becomes an enemy and may fire at you.
1239 elif iquad == ' ': # Black hole
1241 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1243 elif iquad == '#': # hit the web
1245 prout(_("***Torpedo absorbed by Tholian web."))
1247 elif iquad == 'T': # Hit a Tholian
1248 h1 = 700.0 + randrange(100) - \
1249 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1252 game.quad[w.i][w.j] = '.'
1257 proutn(crmena(True, 'T', "sector", w))
1259 prout(_(" survives photon blast."))
1261 prout(_(" disappears."))
1262 game.tholian.move(None)
1263 game.quad[w.i][w.j] = '#'
1268 proutn("Don't know how to handle torpedo collision with ")
1269 proutn(crmena(True, iquad, "sector", w))
1274 prout(_("Torpedo missed."))
1278 "Critical-hit resolution."
1279 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1281 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1282 proutn(_("***CRITICAL HIT--"))
1283 # Select devices and cause damage
1289 # Cheat to prevent shuttle damage unless on ship
1290 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship")):
1293 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1294 game.damage[j] += extradm
1296 for (i, j) in enumerate(cdam):
1298 if skipcount % 3 == 2 and i < len(cdam)-1:
1303 prout(_(" damaged."))
1304 if damaged(DSHIELD) and game.shldup:
1305 prout(_("***Shields knocked down."))
1308 def attack(torps_ok):
1309 # bad guy attacks us
1310 # torps_ok == False forces use of phasers in an attack
1311 # game could be over at this point, check
1321 prout("=== ATTACK!")
1322 # Tholian gets to move before attacking
1325 # if you have just entered the RNZ, you'll get a warning
1326 if game.neutz: # The one chance not to be attacked
1329 # commanders get a chance to tac-move towards you
1330 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:
1332 # if no enemies remain after movement, we're done
1333 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing == game.quadrant and not thing.angered):
1335 # set up partial hits if attack happens during shield status change
1336 pfac = 1.0/game.inshld
1338 chgfac = 0.25 + randreal(0.5)
1340 # message verbosity control
1341 if game.skill <= SKILL_FAIR:
1343 for enemy in game.enemies:
1345 continue # too weak to attack
1346 # compute hit strength and diminish shield power
1348 # Increase chance of photon torpedos if docked or enemy energy is low
1349 if game.condition == "docked":
1351 if enemy.power < 500:
1353 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1355 # different enemies have different probabilities of throwing a torp
1356 usephasers = not torps_ok or \
1357 (enemy.type == 'K' and r > 0.0005) or \
1358 (enemy.type == 'C' and r > 0.015) or \
1359 (enemy.type == 'R' and r > 0.3) or \
1360 (enemy.type == 'S' and r > 0.07) or \
1361 (enemy.type == '?' and r > 0.05)
1362 if usephasers: # Enemy uses phasers
1363 if game.condition == "docked":
1364 continue # Don't waste the effort!
1365 attempt = True # Attempt to attack
1366 dustfac = randreal(0.8, 0.85)
1367 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1369 else: # Enemy uses photon torpedo
1370 # We should be able to make the bearing() method work here
1371 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1373 proutn(_("***TORPEDO INCOMING"))
1374 if not damaged(DSRSENS):
1375 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1378 dispersion = (randreal()+randreal())*0.5 - 0.5
1379 dispersion += 0.002*enemy.power*dispersion
1380 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1381 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1382 finish(FWON) # Klingons did themselves in!
1383 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1384 return # Supernova or finished
1387 # incoming phaser or torpedo, shields may dissipate it
1388 if game.shldup or game.shldchg or game.condition == "docked":
1389 # shields will take hits
1390 propor = pfac * game.shield
1391 if game.condition == "docked":
1395 hitsh = propor*chgfac*hit+1.0
1397 if absorb > game.shield:
1398 absorb = game.shield
1399 game.shield -= absorb
1401 # taking a hit blasts us out of a starbase dock
1402 if game.condition == "docked":
1404 # but the shields may take care of it
1405 if propor > 0.1 and hit < 0.005*game.energy:
1407 # hit from this opponent got through shields, so take damage
1409 proutn(_("%d unit hit") % int(hit))
1410 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1411 proutn(_(" on the ") + crmshp())
1412 if not damaged(DSRSENS) and usephasers:
1413 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1415 # Decide if hit is critical
1421 if game.energy <= 0:
1422 # Returning home upon your shield, not with it...
1425 if not attempt and game.condition == "docked":
1426 prout(_("***Enemies decide against attacking your ship."))
1427 percent = 100.0*pfac*game.shield+0.5
1429 # Shields fully protect ship
1430 proutn(_("Enemy attack reduces shield strength to "))
1432 # Emit message if starship suffered hit(s)
1434 proutn(_("Energy left %2d shields ") % int(game.energy))
1437 elif not damaged(DSHIELD):
1440 proutn(_("damaged, "))
1441 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1442 # Check if anyone was hurt
1443 if hitmax >= 200 or hittot >= 500:
1444 icas = randrange(int(hittot * 0.015))
1447 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1448 prout(_(" in that last attack.\""))
1450 game.state.crew -= icas
1451 # After attack, reset average distance to enemies
1452 for enemy in game.enemies:
1453 enemy.kavgd = enemy.kdist
1457 def deadkl(w, etype, mv):
1458 "Kill a Klingon, Tholian, Romulan, or Thingy."
1459 # Added mv to allow enemy to "move" before dying
1460 proutn(crmena(True, etype, "sector", mv))
1461 # Decide what kind of enemy it is and update appropriately
1463 # Chalk up a Romulan
1464 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1466 game.state.nromrem -= 1
1475 # Killed some type of Klingon
1476 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1479 game.state.kcmdr.remove(game.quadrant)
1481 if game.state.kcmdr:
1482 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1483 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1486 game.state.remkl -= 1
1488 game.state.nscrem -= 1
1489 game.state.kscmdr.invalidate()
1494 # For each kind of enemy, finish message to player
1495 prout(_(" destroyed."))
1496 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1499 # Remove enemy ship from arrays describing local conditions
1500 for e in game.enemies:
1507 "Return None if target is invalid, otherwise return a course angle."
1508 if not w.valid_sector():
1512 # C code this was translated from is wacky -- why the sign reversal?
1513 delta.j = (w.j - game.sector.j)
1514 delta.i = (game.sector.i - w.i)
1515 if delta == Coord(0, 0):
1517 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1518 prout(_(" I recommend an immediate review of"))
1519 prout(_(" the Captain's psychological profile.\""))
1522 return delta.bearing()
1525 "Launch photon torpedo salvo."
1528 if damaged(DPHOTON):
1529 prout(_("Photon tubes damaged."))
1533 prout(_("No torpedoes left."))
1536 # First, get torpedo count
1539 if scanner.token == "IHALPHA":
1542 elif scanner.token == "IHEOL" or not scanner.waiting():
1543 prout(_("%d torpedoes left.") % game.torps)
1545 proutn(_("Number of torpedoes to fire- "))
1546 continue # Go back around to get a number
1547 else: # key == "IHREAL"
1549 if n <= 0: # abort command
1554 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1557 scanner.chew() # User requested more torps than available
1558 continue # Go back around
1559 break # All is good, go to next stage
1563 key = scanner.next()
1564 if i == 0 and key == "IHEOL":
1565 break # no coordinate waiting, we will try prompting
1566 if i == 1 and key == "IHEOL":
1567 # direct all torpedoes at one target
1569 target.append(target[0])
1570 tcourse.append(tcourse[0])
1573 scanner.push(scanner.token)
1574 target.append(scanner.getcoord())
1575 if target[-1] == None:
1577 tcourse.append(targetcheck(target[-1]))
1578 if tcourse[-1] == None:
1581 if len(target) == 0:
1582 # prompt for each one
1584 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1586 target.append(scanner.getcoord())
1587 if target[-1] == None:
1589 tcourse.append(targetcheck(target[-1]))
1590 if tcourse[-1] == None:
1593 # Loop for moving <n> torpedoes
1595 if game.condition != "docked":
1597 dispersion = (randreal()+randreal())*0.5 -0.5
1598 if math.fabs(dispersion) >= 0.47:
1600 dispersion *= randreal(1.2, 2.2)
1602 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1604 prouts(_("***TORPEDO MISFIRES."))
1607 prout(_(" Remainder of burst aborted."))
1609 prout(_("***Photon tubes damaged by misfire."))
1610 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1612 if game.shldup or game.condition == "docked":
1613 dispersion *= 1.0 + 0.0001*game.shield
1614 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1615 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1617 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1621 "Check for phasers overheating."
1623 checkburn = (rpow-1500.0)*0.00038
1624 if withprob(checkburn):
1625 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1626 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1628 def checkshctrl(rpow):
1629 "Check shield control."
1632 prout(_("Shields lowered."))
1634 # Something bad has happened
1635 prouts(_("***RED ALERT! RED ALERT!"))
1637 hit = rpow*game.shield/game.inshld
1638 game.energy -= rpow+hit*0.8
1639 game.shield -= hit*0.2
1640 if game.energy <= 0.0:
1641 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1646 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1648 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1649 icas = randrange(int(hit*0.012))
1654 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1655 prout(_(" %d casualties so far.\"") % icas)
1657 game.state.crew -= icas
1659 prout(_("Phaser energy dispersed by shields."))
1660 prout(_("Enemy unaffected."))
1665 "Register a phaser hit on Klingons and Romulans."
1672 dustfac = randreal(0.9, 1.0)
1673 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1674 kpini = game.enemies[kk].power
1675 kp = math.fabs(kpini)
1676 if PHASEFAC*hit < kp:
1678 if game.enemies[kk].power < 0:
1679 game.enemies[kk].power -= -kp
1681 game.enemies[kk].power -= kp
1682 kpow = game.enemies[kk].power
1683 w = game.enemies[kk].location
1685 if not damaged(DSRSENS):
1687 proutn(_("%d unit hit on ") % int(hit))
1689 proutn(_("Very small hit on "))
1690 ienm = game.quad[w.i][w.j]
1693 proutn(crmena(False, ienm, "sector", w))
1697 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1701 kk -= 1 # don't do the increment
1703 else: # decide whether or not to emasculate klingon
1704 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1705 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1706 prout(_(" has just lost its firepower.\""))
1707 game.enemies[kk].power = -kpow
1712 "Fire phasers at bad guys."
1716 irec = 0 # Cheating inhibitor
1725 # SR sensors and Computer are needed for automode
1726 if damaged(DSRSENS) or damaged(DCOMPTR):
1728 if game.condition == "docked":
1729 prout(_("Phasers can't be fired through base shields."))
1732 if damaged(DPHASER):
1733 prout(_("Phaser control damaged."))
1737 if damaged(DSHCTRL):
1738 prout(_("High speed shield control damaged."))
1741 if game.energy <= 200.0:
1742 prout(_("Insufficient energy to activate high-speed shield control."))
1745 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1747 # Original code so convoluted, I re-did it all
1748 # (That was Tom Almy talking about the C code, I think -- ESR)
1749 while automode == "NOTSET":
1750 key = scanner.next()
1751 if key == "IHALPHA":
1752 if scanner.sees("manual"):
1753 if len(game.enemies)==0:
1754 prout(_("There is no enemy present to select."))
1757 automode = "AUTOMATIC"
1760 key = scanner.next()
1761 elif scanner.sees("automatic"):
1762 if (not itarg) and len(game.enemies) != 0:
1763 automode = "FORCEMAN"
1765 if len(game.enemies)==0:
1766 prout(_("Energy will be expended into space."))
1767 automode = "AUTOMATIC"
1768 key = scanner.next()
1769 elif scanner.sees("no"):
1774 elif key == "IHREAL":
1775 if len(game.enemies)==0:
1776 prout(_("Energy will be expended into space."))
1777 automode = "AUTOMATIC"
1779 automode = "FORCEMAN"
1781 automode = "AUTOMATIC"
1784 if len(game.enemies)==0:
1785 prout(_("Energy will be expended into space."))
1786 automode = "AUTOMATIC"
1788 automode = "FORCEMAN"
1790 proutn(_("Manual or automatic? "))
1795 if automode == "AUTOMATIC":
1796 if key == "IHALPHA" and scanner.sees("no"):
1798 key = scanner.next()
1799 if key != "IHREAL" and len(game.enemies) != 0:
1800 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1805 for i in range(len(game.enemies)):
1806 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1808 proutn(_("%d units required. ") % irec)
1810 proutn(_("Units to fire= "))
1811 key = scanner.next()
1816 proutn(_("Energy available= %.2f") % avail)
1819 if not rpow > avail:
1825 key = scanner.next()
1826 if key == "IHALPHA" and scanner.sees("no"):
1829 game.energy -= 200 # Go and do it!
1830 if checkshctrl(rpow):
1835 if len(game.enemies):
1838 for i in range(len(game.enemies)):
1842 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1843 over = randreal(1.01, 1.06) * hits[i]
1845 powrem -= hits[i] + over
1846 if powrem <= 0 and temp < hits[i]:
1855 if extra > 0 and not game.alldone:
1857 proutn(_("*** Tholian web absorbs "))
1858 if len(game.enemies)>0:
1859 proutn(_("excess "))
1860 prout(_("phaser energy."))
1862 prout(_("%d expended on empty space.") % int(extra))
1863 elif automode == "FORCEMAN":
1866 if damaged(DCOMPTR):
1867 prout(_("Battle computer damaged, manual fire only."))
1870 prouts(_("---WORKING---"))
1872 prout(_("Short-range-sensors-damaged"))
1873 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1874 prout(_("Manual-fire-must-be-used"))
1876 elif automode == "MANUAL":
1878 for k in range(len(game.enemies)):
1879 aim = game.enemies[k].location
1880 ienm = game.quad[aim.i][aim.j]
1882 proutn(_("Energy available= %.2f") % (avail-0.006))
1886 if damaged(DSRSENS) and \
1887 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1888 prout(cramen(ienm) + _(" can't be located without short range scan."))
1891 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
1896 if itarg and k > kz:
1897 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1900 if not damaged(DCOMPTR):
1905 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1906 key = scanner.next()
1907 if key == "IHALPHA" and scanner.sees("no"):
1909 key = scanner.next()
1911 if key == "IHALPHA":
1915 if k == 1: # Let me say I'm baffled by this
1918 if scanner.real < 0:
1922 hits[k] = scanner.real
1923 rpow += scanner.real
1924 # If total requested is too much, inform and start over
1926 prout(_("Available energy exceeded -- try again."))
1929 key = scanner.next() # scan for next value
1932 # zero energy -- abort
1935 if key == "IHALPHA" and scanner.sees("no"):
1940 game.energy -= 200.0
1941 if checkshctrl(rpow):
1945 # Say shield raised or malfunction, if necessary
1952 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1953 prouts(_(" CLICK CLICK POP . . ."))
1954 prout(_(" No response, sir!"))
1957 prout(_("Shields raised."))
1962 # Code from events,c begins here.
1964 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1965 # event of each type active at any given time. Mostly these means we can
1966 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1967 # BSD Trek, from which we swiped the idea, can have up to 5.
1969 def unschedule(evtype):
1970 "Remove an event from the schedule."
1971 game.future[evtype].date = FOREVER
1972 return game.future[evtype]
1974 def is_scheduled(evtype):
1975 "Is an event of specified type scheduled."
1976 return game.future[evtype].date != FOREVER
1978 def scheduled(evtype):
1979 "When will this event happen?"
1980 return game.future[evtype].date
1982 def schedule(evtype, offset):
1983 "Schedule an event of specified type."
1984 game.future[evtype].date = game.state.date + offset
1985 return game.future[evtype]
1987 def postpone(evtype, offset):
1988 "Postpone a scheduled event."
1989 game.future[evtype].date += offset
1992 "Rest period is interrupted by event."
1995 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
1997 game.resting = False
2003 "Run through the event queue looking for things to do."
2005 fintim = game.state.date + game.optime
2014 def tractorbeam(yank):
2015 "Tractor-beaming cases merge here."
2017 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2019 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2020 # If Kirk & Co. screwing around on planet, handle
2021 atover(True) # atover(true) is Grab
2024 if game.icraft: # Caught in Galileo?
2027 # Check to see if shuttle is aboard
2028 if game.iscraft == "offship":
2031 prout(_("Galileo, left on the planet surface, is captured"))
2032 prout(_("by aliens and made into a flying McDonald's."))
2033 game.damage[DSHUTTL] = -10
2034 game.iscraft = "removed"
2036 prout(_("Galileo, left on the planet surface, is well hidden."))
2038 game.quadrant = game.state.kscmdr
2040 game.quadrant = game.state.kcmdr[i]
2041 game.sector = randplace(QUADSIZE)
2042 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2043 % (game.quadrant, game.sector))
2045 prout(_("(Remainder of rest/repair period cancelled.)"))
2046 game.resting = False
2048 if not damaged(DSHIELD) and game.shield > 0:
2049 doshield(shraise=True) # raise shields
2050 game.shldchg = False
2052 prout(_("(Shields not currently useable.)"))
2054 # Adjust finish time to time of tractor beaming
2055 fintim = game.state.date+game.optime
2056 attack(torps_ok=False)
2057 if not game.state.kcmdr:
2060 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2063 "Code merges here for any commander destroying a starbase."
2064 # Not perfect, but will have to do
2065 # Handle case where base is in same quadrant as starship
2066 if game.battle == game.quadrant:
2067 game.state.chart[game.battle.i][game.battle.j].starbase = False
2068 game.quad[game.base.i][game.base.j] = '.'
2069 game.base.invalidate()
2072 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2073 elif game.state.baseq and communicating():
2074 # Get word via subspace radio
2077 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2078 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2080 prout(_("the Klingon Super-Commander"))
2082 prout(_("a Klingon Commander"))
2083 game.state.chart[game.battle.i][game.battle.j].starbase = False
2084 # Remove Starbase from galaxy
2085 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2086 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2088 # reinstate a commander's base attack
2092 game.battle.invalidate()
2094 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2095 for i in range(1, NEVENTS):
2096 if i == FSNOVA: proutn("=== Supernova ")
2097 elif i == FTBEAM: proutn("=== T Beam ")
2098 elif i == FSNAP: proutn("=== Snapshot ")
2099 elif i == FBATTAK: proutn("=== Base Attack ")
2100 elif i == FCDBAS: proutn("=== Base Destroy ")
2101 elif i == FSCMOVE: proutn("=== SC Move ")
2102 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2103 elif i == FDSPROB: proutn("=== Probe Move ")
2104 elif i == FDISTR: proutn("=== Distress Call ")
2105 elif i == FENSLV: proutn("=== Enslavement ")
2106 elif i == FREPRO: proutn("=== Klingon Build ")
2108 prout("%.2f" % (scheduled(i)))
2111 radio_was_broken = damaged(DRADIO)
2114 # Select earliest extraneous event, evcode==0 if no events
2119 for l in range(1, NEVENTS):
2120 if game.future[l].date < datemin:
2123 prout("== Event %d fires" % evcode)
2124 datemin = game.future[l].date
2125 xtime = datemin-game.state.date
2126 game.state.date = datemin
2127 # Decrement Federation resources and recompute remaining time
2128 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2130 if game.state.remtime <= 0:
2133 # Any crew left alive?
2134 if game.state.crew <= 0:
2137 # Is life support adequate?
2138 if damaged(DLIFSUP) and game.condition != "docked":
2139 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2142 game.lsupres -= xtime
2143 if game.damage[DLIFSUP] <= xtime:
2144 game.lsupres = game.inlsr
2147 if game.condition == "docked":
2149 # Don't fix Deathray here
2150 for l in range(NDEVICES):
2151 if game.damage[l] > 0.0 and l != DDRAY:
2152 if game.damage[l]-repair > 0.0:
2153 game.damage[l] -= repair
2155 game.damage[l] = 0.0
2156 # If radio repaired, update star chart and attack reports
2157 if radio_was_broken and not damaged(DRADIO):
2158 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2159 prout(_(" surveillance reports are coming in."))
2161 if not game.iseenit:
2165 prout(_(" The star chart is now up to date.\""))
2167 # Cause extraneous event EVCODE to occur
2168 game.optime -= xtime
2169 if evcode == FSNOVA: # Supernova
2172 schedule(FSNOVA, expran(0.5*game.intime))
2173 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2175 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2176 if game.state.nscrem == 0 or \
2177 ictbeam or istract or \
2178 game.condition == "docked" or game.isatb == 1 or game.iscate:
2180 if game.ientesc or \
2181 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2182 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2183 (damaged(DSHIELD) and \
2184 (game.energy < 2500 or damaged(DPHASER)) and \
2185 (game.torps < 5 or damaged(DPHOTON))):
2187 istract = ictbeam = True
2188 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2191 elif evcode == FTBEAM: # Tractor beam
2192 if not game.state.kcmdr:
2195 i = randrange(len(game.state.kcmdr))
2196 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2197 if istract or game.condition == "docked" or yank == 0:
2198 # Drats! Have to reschedule
2200 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2204 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2205 game.snapsht = copy.deepcopy(game.state)
2206 game.state.snap = True
2207 schedule(FSNAP, expran(0.5 * game.intime))
2208 elif evcode == FBATTAK: # Commander attacks starbase
2209 if not game.state.kcmdr or not game.state.baseq:
2215 for ibq in game.state.baseq:
2216 for cmdr in game.state.kcmdr:
2217 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2220 # no match found -- try later
2221 schedule(FBATTAK, expran(0.3*game.intime))
2226 # commander + starbase combination found -- launch attack
2228 schedule(FCDBAS, randreal(1.0, 4.0))
2229 if game.isatb: # extra time if SC already attacking
2230 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2231 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2232 game.iseenit = False
2233 if not communicating():
2234 continue # No warning :-(
2238 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2239 prout(_(" reports that it is under attack and that it can"))
2240 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2243 elif evcode == FSCDBAS: # Supercommander destroys base
2246 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2247 continue # WAS RETURN!
2249 game.battle = game.state.kscmdr
2251 elif evcode == FCDBAS: # Commander succeeds in destroying base
2252 if evcode == FCDBAS:
2254 if not game.state.baseq() \
2255 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2256 game.battle.invalidate()
2258 # find the lucky pair
2259 for cmdr in game.state.kcmdr:
2260 if cmdr == game.battle:
2263 # No action to take after all
2266 elif evcode == FSCMOVE: # Supercommander moves
2267 schedule(FSCMOVE, 0.2777)
2268 if not game.ientesc and not istract and game.isatb != 1 and \
2269 (not game.iscate or not game.justin):
2271 elif evcode == FDSPROB: # Move deep space probe
2272 schedule(FDSPROB, 0.01)
2273 if not game.probe.next():
2274 if not game.probe.quadrant().valid_quadrant() or \
2275 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2276 # Left galaxy or ran into supernova
2280 proutn(_("Lt. Uhura- \"The deep space probe "))
2281 if not game.probe.quadrant().valid_quadrant():
2282 prout(_("has left the galaxy.\""))
2284 prout(_("is no longer transmitting.\""))
2290 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2291 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2293 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2294 chp.klingons = pdest.klingons
2295 chp.starbase = pdest.starbase
2296 chp.stars = pdest.stars
2297 pdest.charted = True
2298 game.probe.moves -= 1 # One less to travel
2299 if game.probe.arrived() and game.isarmed and pdest.stars:
2300 supernova(game.probe) # fire in the hole!
2302 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2304 elif evcode == FDISTR: # inhabited system issues distress call
2306 # try a whole bunch of times to find something suitable
2307 for i in range(100):
2308 # need a quadrant which is not the current one,
2309 # which has some stars which are inhabited and
2310 # not already under attack, which is not
2311 # supernova'ed, and which has some Klingons in it
2312 w = randplace(GALSIZE)
2313 q = game.state.galaxy[w.i][w.j]
2314 if not (game.quadrant == w or q.planet == None or \
2315 not q.planet.inhabited or \
2316 q.supernova or q.status!="secure" or q.klingons<=0):
2319 # can't seem to find one; ignore this call
2321 prout("=== Couldn't find location for distress event.")
2323 # got one!! Schedule its enslavement
2324 ev = schedule(FENSLV, expran(game.intime))
2326 q.status = "distressed"
2327 # tell the captain about it if we can
2329 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2330 % (q.planet, repr(w)))
2331 prout(_("by a Klingon invasion fleet."))
2334 elif evcode == FENSLV: # starsystem is enslaved
2335 ev = unschedule(FENSLV)
2336 # see if current distress call still active
2337 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2341 q.status = "enslaved"
2343 # play stork and schedule the first baby
2344 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2345 ev2.quadrant = ev.quadrant
2347 # report the disaster if we can
2349 prout(_("Uhura- We've lost contact with starsystem %s") % \
2351 prout(_("in Quadrant %s.\n") % ev.quadrant)
2352 elif evcode == FREPRO: # Klingon reproduces
2353 # If we ever switch to a real event queue, we'll need to
2354 # explicitly retrieve and restore the x and y.
2355 ev = schedule(FREPRO, expran(1.0 * game.intime))
2356 # see if current distress call still active
2357 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2361 if game.state.remkl >= MAXKLGAME:
2362 continue # full right now
2363 # reproduce one Klingon
2366 if game.klhere >= MAXKLQUAD:
2368 # this quadrant not ok, pick an adjacent one
2369 for m.i in range(w.i - 1, w.i + 2):
2370 for m.j in range(w.j - 1, w.j + 2):
2371 if not m.valid_quadrant():
2373 q = game.state.galaxy[m.i][m.j]
2374 # check for this quad ok (not full & no snova)
2375 if q.klingons >= MAXKLQUAD or q.supernova:
2379 continue # search for eligible quadrant failed
2383 game.state.remkl += 1
2385 if game.quadrant == w:
2387 game.enemies.append(newkling())
2388 # recompute time left
2391 if game.quadrant == w:
2392 prout(_("Spock- sensors indicate the Klingons have"))
2393 prout(_("launched a warship from %s.") % q.planet)
2395 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2396 if q.planet != None:
2397 proutn(_("near %s ") % q.planet)
2398 prout(_("in Quadrant %s.") % w)
2404 key = scanner.next()
2407 proutn(_("How long? "))
2412 origTime = delay = scanner.real
2415 if delay >= game.state.remtime or len(game.enemies) != 0:
2416 proutn(_("Are you sure? "))
2419 # Alternate resting periods (events) with attacks
2423 game.resting = False
2424 if not game.resting:
2425 prout(_("%d stardates left.") % int(game.state.remtime))
2427 temp = game.optime = delay
2428 if len(game.enemies):
2429 rtime = randreal(1.0, 2.0)
2433 if game.optime < delay:
2434 attack(torps_ok=False)
2442 # Repair Deathray if long rest at starbase
2443 if origTime-delay >= 9.99 and game.condition == "docked":
2444 game.damage[DDRAY] = 0.0
2445 # leave if quadrant supernovas
2446 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2448 game.resting = False
2453 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2454 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2456 # Wow! We've supernova'ed
2457 supernova(game.quadrant)
2459 # handle initial nova
2460 game.quad[nov.i][nov.j] = '.'
2461 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2462 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2463 game.state.starkl += 1
2464 # Set up queue to recursively trigger adjacent stars
2470 for offset.i in range(-1, 1+1):
2471 for offset.j in range(-1, 1+1):
2472 if offset.j == 0 and offset.i == 0:
2474 neighbor = start + offset
2475 if not neighbor.valid_sector():
2477 iquad = game.quad[neighbor.i][neighbor.j]
2478 # Empty space ends reaction
2479 if iquad in ('.', '?', ' ', 'T', '#'):
2481 elif iquad == '*': # Affect another star
2483 # This star supernovas
2484 supernova(game.quadrant)
2487 hits.append(neighbor)
2488 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2489 game.state.starkl += 1
2490 proutn(crmena(True, '*', "sector", neighbor))
2492 game.quad[neighbor.i][neighbor.j] = '.'
2494 elif iquad in ('P', '@'): # Destroy planet
2495 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2497 game.state.nplankl += 1
2499 game.state.nworldkl += 1
2500 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2501 game.iplnet.pclass = "destroyed"
2503 game.plnet.invalidate()
2507 game.quad[neighbor.i][neighbor.j] = '.'
2508 elif iquad == 'B': # Destroy base
2509 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2510 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2511 game.base.invalidate()
2512 game.state.basekl += 1
2514 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2515 game.quad[neighbor.i][neighbor.j] = '.'
2516 elif iquad in ('E', 'F'): # Buffet ship
2517 prout(_("***Starship buffeted by nova."))
2519 if game.shield >= 2000.0:
2520 game.shield -= 2000.0
2522 diff = 2000.0 - game.shield
2526 prout(_("***Shields knocked out."))
2527 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2529 game.energy -= 2000.0
2530 if game.energy <= 0:
2533 # add in course nova contributes to kicking starship
2534 bump += (game.sector-hits[-1]).sgn()
2535 elif iquad == 'K': # kill klingon
2536 deadkl(neighbor, iquad, neighbor)
2537 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2538 for ll in range(len(game.enemies)):
2539 if game.enemies[ll].location == neighbor:
2541 game.enemies[ll].power -= 800.0 # If firepower is lost, die
2542 if game.enemies[ll].power <= 0.0:
2543 deadkl(neighbor, iquad, neighbor)
2545 newc = neighbor + neighbor - hits[-1]
2546 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2547 if not newc.valid_sector():
2548 # can't leave quadrant
2551 iquad1 = game.quad[newc.i][newc.j]
2553 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2555 deadkl(neighbor, iquad, newc)
2558 # can't move into something else
2561 proutn(_(", buffeted to Sector %s") % newc)
2562 game.quad[neighbor.i][neighbor.j] = '.'
2563 game.quad[newc.i][newc.j] = iquad
2564 game.enemies[ll].move(newc)
2565 # Starship affected by nova -- kick it away.
2567 direc = ncourse[3*(bump.i+1)+bump.j+2]
2572 scourse = course(bearing=direc, distance=dist)
2573 game.optime = scourse.time(warp=4)
2575 prout(_("Force of nova displaces starship."))
2576 imove(scourse, noattack=True)
2577 game.optime = scourse.time(warp=4)
2581 "Star goes supernova."
2586 # Scheduled supernova -- select star at random.
2589 for nq.i in range(GALSIZE):
2590 for nq.j in range(GALSIZE):
2591 stars += game.state.galaxy[nq.i][nq.j].stars
2593 return # nothing to supernova exists
2594 num = randrange(stars) + 1
2595 for nq.i in range(GALSIZE):
2596 for nq.j in range(GALSIZE):
2597 num -= game.state.galaxy[nq.i][nq.j].stars
2603 proutn("=== Super nova here?")
2606 if not nq == game.quadrant or game.justin:
2607 # it isn't here, or we just entered (treat as enroute)
2610 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2611 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2614 # we are in the quadrant!
2615 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2616 for ns.i in range(QUADSIZE):
2617 for ns.j in range(QUADSIZE):
2618 if game.quad[ns.i][ns.j]=='*':
2625 prouts(_("***RED ALERT! RED ALERT!"))
2627 prout(_("***Incipient supernova detected at Sector %s") % ns)
2628 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2629 proutn(_("Emergency override attempts t"))
2630 prouts("***************")
2634 # destroy any Klingons in supernovaed quadrant
2635 kldead = game.state.galaxy[nq.i][nq.j].klingons
2636 game.state.galaxy[nq.i][nq.j].klingons = 0
2637 if nq == game.state.kscmdr:
2638 # did in the Supercommander!
2639 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2643 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2644 comkills = len(game.state.kcmdr) - len(survivors)
2645 game.state.kcmdr = survivors
2647 if not game.state.kcmdr:
2649 game.state.remkl -= kldead
2650 # destroy Romulans and planets in supernovaed quadrant
2651 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2652 game.state.galaxy[nq.i][nq.j].romulans = 0
2653 game.state.nromrem -= nrmdead
2655 for loop in range(game.inplan):
2656 if game.state.planets[loop].quadrant == nq:
2657 game.state.planets[loop].pclass = "destroyed"
2659 # Destroy any base in supernovaed quadrant
2660 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2661 # If starship caused supernova, tally up destruction
2663 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2664 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2665 game.state.nplankl += npdead
2666 # mark supernova in galaxy and in star chart
2667 if game.quadrant == nq or communicating():
2668 game.state.galaxy[nq.i][nq.j].supernova = True
2669 # If supernova destroys last Klingons give special message
2670 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2673 prout(_("Lucky you!"))
2674 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2677 # if some Klingons remain, continue or die in supernova
2682 # Code from finish.c ends here.
2685 "Self-destruct maneuver. Finish with a BANG!"
2687 if damaged(DCOMPTR):
2688 prout(_("Computer damaged; cannot execute destruct sequence."))
2690 prouts(_("---WORKING---")); skip(1)
2691 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2692 prouts(" 10"); skip(1)
2693 prouts(" 9"); skip(1)
2694 prouts(" 8"); skip(1)
2695 prouts(" 7"); skip(1)
2696 prouts(" 6"); skip(1)
2698 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2700 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2702 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2705 if game.passwd != scanner.token:
2706 prouts(_("PASSWORD-REJECTED;"))
2708 prouts(_("CONTINUITY-EFFECTED"))
2711 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2712 prouts(" 5"); skip(1)
2713 prouts(" 4"); skip(1)
2714 prouts(" 3"); skip(1)
2715 prouts(" 2"); skip(1)
2716 prouts(" 1"); skip(1)
2718 prouts(_("GOODBYE-CRUEL-WORLD"))
2726 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2730 if len(game.enemies) != 0:
2731 whammo = 25.0 * game.energy
2732 for l in range(len(game.enemies)):
2733 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2734 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2738 "Compute our rate of kils over time."
2739 elapsed = game.state.date - game.indate
2740 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2743 starting = (game.inkling + game.incom + game.inscom)
2744 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2745 return (starting - remaining)/elapsed
2749 badpt = 5.0*game.state.starkl + \
2751 10.0*game.state.nplankl + \
2752 300*game.state.nworldkl + \
2754 100.0*game.state.basekl +\
2756 if game.ship == 'F':
2758 elif game.ship == None:
2763 # end the game, with appropriate notfications
2767 prout(_("It is stardate %.1f.") % game.state.date)
2769 if ifin == FWON: # Game has been won
2770 if game.state.nromrem != 0:
2771 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2774 prout(_("You have smashed the Klingon invasion fleet and saved"))
2775 prout(_("the Federation."))
2780 badpt = 0.0 # Close enough!
2781 # killsPerDate >= RateMax
2782 if game.state.date-game.indate < 5.0 or \
2783 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2785 prout(_("In fact, you have done so well that Starfleet Command"))
2786 if game.skill == SKILL_NOVICE:
2787 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2788 elif game.skill == SKILL_FAIR:
2789 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2790 elif game.skill == SKILL_GOOD:
2791 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2792 elif game.skill == SKILL_EXPERT:
2793 prout(_("promotes you to Commodore Emeritus."))
2795 prout(_("Now that you think you're really good, try playing"))
2796 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2797 elif game.skill == SKILL_EMERITUS:
2799 proutn(_("Computer- "))
2800 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2802 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2804 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2806 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2808 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2810 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2812 prout(_("Now you can retire and write your own Star Trek game!"))
2814 elif game.skill >= SKILL_EXPERT:
2815 if game.thawed and not game.idebug:
2816 prout(_("You cannot get a citation, so..."))
2818 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2822 # Only grant long life if alive (original didn't!)
2824 prout(_("LIVE LONG AND PROSPER."))
2829 elif ifin == FDEPLETE: # Federation Resources Depleted
2830 prout(_("Your time has run out and the Federation has been"))
2831 prout(_("conquered. Your starship is now Klingon property,"))
2832 prout(_("and you are put on trial as a war criminal. On the"))
2833 proutn(_("basis of your record, you are "))
2834 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2835 prout(_("acquitted."))
2837 prout(_("LIVE LONG AND PROSPER."))
2839 prout(_("found guilty and"))
2840 prout(_("sentenced to death by slow torture."))
2844 elif ifin == FLIFESUP:
2845 prout(_("Your life support reserves have run out, and"))
2846 prout(_("you die of thirst, starvation, and asphyxiation."))
2847 prout(_("Your starship is a derelict in space."))
2849 prout(_("Your energy supply is exhausted."))
2851 prout(_("Your starship is a derelict in space."))
2852 elif ifin == FBATTLE:
2853 prout(_("The %s has been destroyed in battle.") % crmshp())
2855 prout(_("Dulce et decorum est pro patria mori."))
2857 prout(_("You have made three attempts to cross the negative energy"))
2858 prout(_("barrier which surrounds the galaxy."))
2860 prout(_("Your navigation is abominable."))
2863 prout(_("Your starship has been destroyed by a nova."))
2864 prout(_("That was a great shot."))
2866 elif ifin == FSNOVAED:
2867 prout(_("The %s has been fried by a supernova.") % crmshp())
2868 prout(_("...Not even cinders remain..."))
2869 elif ifin == FABANDN:
2870 prout(_("You have been captured by the Klingons. If you still"))
2871 prout(_("had a starbase to be returned to, you would have been"))
2872 prout(_("repatriated and given another chance. Since you have"))
2873 prout(_("no starbases, you will be mercilessly tortured to death."))
2874 elif ifin == FDILITHIUM:
2875 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2876 elif ifin == FMATERIALIZE:
2877 prout(_("Starbase was unable to re-materialize your starship."))
2878 prout(_("Sic transit gloria mundi"))
2879 elif ifin == FPHASER:
2880 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2882 prout(_("You and your landing party have been"))
2883 prout(_("converted to energy, disipating through space."))
2884 elif ifin == FMINING:
2885 prout(_("You are left with your landing party on"))
2886 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2888 prout(_("They are very fond of \"Captain Kirk\" soup."))
2890 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2891 elif ifin == FDPLANET:
2892 prout(_("You and your mining party perish."))
2894 prout(_("That was a great shot."))
2897 prout(_("The Galileo is instantly annihilated by the supernova."))
2898 prout(_("You and your mining party are atomized."))
2900 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2901 prout(_("joins the Romulans, wreaking terror on the Federation."))
2902 elif ifin == FPNOVA:
2903 prout(_("You and your mining party are atomized."))
2905 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2906 prout(_("joins the Romulans, wreaking terror on the Federation."))
2907 elif ifin == FSTRACTOR:
2908 prout(_("The shuttle craft Galileo is also caught,"))
2909 prout(_("and breaks up under the strain."))
2911 prout(_("Your debris is scattered for millions of miles."))
2912 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2914 prout(_("The mutants attack and kill Spock."))
2915 prout(_("Your ship is captured by Klingons, and"))
2916 prout(_("your crew is put on display in a Klingon zoo."))
2917 elif ifin == FTRIBBLE:
2918 prout(_("Tribbles consume all remaining water,"))
2919 prout(_("food, and oxygen on your ship."))
2921 prout(_("You die of thirst, starvation, and asphyxiation."))
2922 prout(_("Your starship is a derelict in space."))
2924 prout(_("Your ship is drawn to the center of the black hole."))
2925 prout(_("You are crushed into extremely dense matter."))
2927 prout(_("Your last crew member has died."))
2928 if game.ship == 'F':
2930 elif game.ship == 'E':
2933 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2934 goodies = game.state.remres/game.inresor
2935 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2936 if goodies/baddies >= randreal(1.0, 1.5):
2937 prout(_("As a result of your actions, a treaty with the Klingon"))
2938 prout(_("Empire has been signed. The terms of the treaty are"))
2939 if goodies/baddies >= randreal(3.0):
2940 prout(_("favorable to the Federation."))
2942 prout(_("Congratulations!"))
2944 prout(_("highly unfavorable to the Federation."))
2946 prout(_("The Federation will be destroyed."))
2948 prout(_("Since you took the last Klingon with you, you are a"))
2949 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2950 prout(_("statue in your memory. Rest in peace, and try not"))
2951 prout(_("to think about pigeons."))
2956 "Compute player's score."
2957 timused = game.state.date - game.indate
2958 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2960 game.perdate = killrate()
2961 ithperd = 500*game.perdate + 0.5
2964 iwon = 100*game.skill
2965 if game.ship == 'E':
2967 elif game.ship == 'F':
2971 game.score = 10*(game.inkling - game.state.remkl) \
2972 + 50*(game.incom - len(game.state.kcmdr)) \
2974 + 20*(game.inrom - game.state.nromrem) \
2975 + 200*(game.inscom - game.state.nscrem) \
2976 - game.state.nromrem \
2981 prout(_("Your score --"))
2982 if game.inrom - game.state.nromrem:
2983 prout(_("%6d Romulans destroyed %5d") %
2984 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
2985 if game.state.nromrem and game.gamewon:
2986 prout(_("%6d Romulans captured %5d") %
2987 (game.state.nromrem, game.state.nromrem))
2988 if game.inkling - game.state.remkl:
2989 prout(_("%6d ordinary Klingons destroyed %5d") %
2990 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
2991 if game.incom - len(game.state.kcmdr):
2992 prout(_("%6d Klingon commanders destroyed %5d") %
2993 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
2994 if game.inscom - game.state.nscrem:
2995 prout(_("%6d Super-Commander destroyed %5d") %
2996 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
2998 prout(_("%6.2f Klingons per stardate %5d") %
2999 (game.perdate, ithperd))
3000 if game.state.starkl:
3001 prout(_("%6d stars destroyed by your action %5d") %
3002 (game.state.starkl, -5*game.state.starkl))
3003 if game.state.nplankl:
3004 prout(_("%6d planets destroyed by your action %5d") %
3005 (game.state.nplankl, -10*game.state.nplankl))
3006 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3007 prout(_("%6d inhabited planets destroyed by your action %5d") %
3008 (game.state.nworldkl, -300*game.state.nworldkl))
3009 if game.state.basekl:
3010 prout(_("%6d bases destroyed by your action %5d") %
3011 (game.state.basekl, -100*game.state.basekl))
3013 prout(_("%6d calls for help from starbase %5d") %
3014 (game.nhelp, -45*game.nhelp))
3016 prout(_("%6d casualties incurred %5d") %
3017 (game.casual, -game.casual))
3019 prout(_("%6d crew abandoned in space %5d") %
3020 (game.abandoned, -3*game.abandoned))
3022 prout(_("%6d ship(s) lost or destroyed %5d") %
3023 (klship, -100*klship))
3025 prout(_("Penalty for getting yourself killed -200"))
3027 proutn(_("Bonus for winning "))
3028 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3029 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3030 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3031 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3032 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3033 prout(" %5d" % iwon)
3035 prout(_("TOTAL SCORE %5d") % game.score)
3038 "Emit winner's commemmorative plaque."
3041 proutn(_("File or device name for your plaque: "))
3044 fp = open(winner, "w")
3047 prout(_("Invalid name."))
3049 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3051 # The 38 below must be 64 for 132-column paper
3052 nskip = 38 - len(winner)/2
3053 fp.write("\n\n\n\n")
3054 # --------DRAW ENTERPRISE PICTURE.
3055 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3056 fp.write(" EEE E : : : E\n" )
3057 fp.write(" EE EEE E : : NCC-1701 : E\n")
3058 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3059 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3060 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3061 fp.write(" EEEEEEE EEEEE E E E E\n")
3062 fp.write(" EEE E E E E\n")
3063 fp.write(" E E E E\n")
3064 fp.write(" EEEEEEEEEEEEE E E\n")
3065 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3066 fp.write(" :E : EEEE E\n")
3067 fp.write(" .-E -:----- E\n")
3068 fp.write(" :E : E\n")
3069 fp.write(" EE : EEEEEEEE\n")
3070 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3072 fp.write(_(" U. S. S. ENTERPRISE\n"))
3073 fp.write("\n\n\n\n")
3074 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3076 fp.write(_(" Starfleet Command bestows to you\n"))
3078 fp.write("%*s%s\n\n" % (nskip, "", winner))
3079 fp.write(_(" the rank of\n\n"))
3080 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3082 if game.skill == SKILL_EXPERT:
3083 fp.write(_(" Expert level\n\n"))
3084 elif game.skill == SKILL_EMERITUS:
3085 fp.write(_("Emeritus level\n\n"))
3087 fp.write(_(" Cheat level\n\n"))
3088 timestring = time.ctime()
3089 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3090 (timestring+4, timestring+20, timestring+11))
3091 fp.write(_(" Your score: %d\n\n") % game.score)
3092 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3095 # Code from io.c begins here
3097 rows = linecount = 0 # for paging
3100 fullscreen_window = None
3101 srscan_window = None
3102 report_window = None
3103 status_window = None
3104 lrscan_window = None
3105 message_window = None
3106 prompt_window = None
3111 "for some recent versions of python2, the following enables UTF8"
3112 "for the older ones we probably need to set C locale, and the python3"
3113 "has no problems at all"
3114 if sys.version_info[0] < 3:
3116 locale.setlocale(locale.LC_ALL, "")
3117 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3118 gettext.textdomain("sst")
3119 if not (game.options & OPTION_CURSES):
3120 ln_env = os.getenv("LINES")
3126 stdscr = curses.initscr()
3130 if game.options & OPTION_COLOR:
3131 curses.start_color()
3132 curses.use_default_colors()
3133 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3134 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3135 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3136 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3137 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3138 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3139 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3140 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3141 global fullscreen_window, srscan_window, report_window, status_window
3142 global lrscan_window, message_window, prompt_window
3143 (rows, columns) = stdscr.getmaxyx()
3144 fullscreen_window = stdscr
3145 srscan_window = curses.newwin(12, 25, 0, 0)
3146 report_window = curses.newwin(11, 0, 1, 25)
3147 status_window = curses.newwin(10, 0, 1, 39)
3148 lrscan_window = curses.newwin(5, 0, 0, 64)
3149 message_window = curses.newwin(0, 0, 12, 0)
3150 prompt_window = curses.newwin(1, 0, rows-2, 0)
3151 message_window.scrollok(True)
3152 setwnd(fullscreen_window)
3156 if game.options & OPTION_CURSES:
3157 stdscr.keypad(False)
3163 "Wait for user action -- OK to do nothing if on a TTY"
3164 if game.options & OPTION_CURSES:
3169 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3173 if game.skill > SKILL_FAIR:
3174 prompt = _("[CONTINUE?]")
3176 prompt = _("[PRESS ENTER TO CONTINUE]")
3178 if game.options & OPTION_CURSES:
3180 setwnd(prompt_window)
3181 prompt_window.clear()
3182 prompt_window.addstr(prompt)
3183 prompt_window.getstr()
3184 prompt_window.clear()
3185 prompt_window.refresh()
3186 setwnd(message_window)
3189 sys.stdout.write('\n')
3193 sys.stdout.write('\n' * rows)
3197 "Skip i lines. Pause game if this would cause a scrolling event."
3198 for dummy in range(i):
3199 if game.options & OPTION_CURSES:
3200 (y, x) = curwnd.getyx()
3203 except curses.error:
3208 if rows and linecount >= rows:
3211 sys.stdout.write('\n')
3214 "Utter a line with no following line feed."
3215 if game.options & OPTION_CURSES:
3216 (y, x) = curwnd.getyx()
3217 (my, mx) = curwnd.getmaxyx()
3218 if curwnd == message_window and y >= my - 2:
3221 # Uncomment this to debug curses problems
3223 logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(line)))
3227 sys.stdout.write(line)
3237 if not replayfp or replayfp.closed: # Don't slow down replays
3240 if game.options & OPTION_CURSES:
3244 if not replayfp or replayfp.closed:
3248 "Get a line of input."
3249 if game.options & OPTION_CURSES:
3250 line = curwnd.getstr() + "\n"
3253 if replayfp and not replayfp.closed:
3255 line = replayfp.readline()
3258 prout("*** Replay finished")
3261 elif line[0] != "#":
3264 line = raw_input() + "\n"
3270 "Change windows -- OK for this to be a no-op in tty mode."
3272 if game.options & OPTION_CURSES:
3273 # Uncomment this to debug curses problems
3275 if wnd == fullscreen_window:
3276 legend = "fullscreen"
3277 elif wnd == srscan_window:
3279 elif wnd == report_window:
3281 elif wnd == status_window:
3283 elif wnd == lrscan_window:
3285 elif wnd == message_window:
3287 elif wnd == prompt_window:
3291 logfp.write("#curses: setwnd(%s)\n" % legend)
3293 # Some curses implementations get confused when you try this.
3295 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3296 except curses.error:
3300 "Clear to end of line -- can be a no-op in tty mode"
3301 if game.options & OPTION_CURSES:
3306 "Clear screen -- can be a no-op in tty mode."
3308 if game.options & OPTION_CURSES:
3314 def textcolor(color=DEFAULT):
3315 if game.options & OPTION_COLOR:
3316 if color == DEFAULT:
3318 elif color == BLACK:
3319 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3321 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3322 elif color == GREEN:
3323 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3325 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3327 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3328 elif color == MAGENTA:
3329 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3330 elif color == BROWN:
3331 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3332 elif color == LIGHTGRAY:
3333 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3334 elif color == DARKGRAY:
3335 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3336 elif color == LIGHTBLUE:
3337 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3338 elif color == LIGHTGREEN:
3339 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3340 elif color == LIGHTCYAN:
3341 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3342 elif color == LIGHTRED:
3343 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3344 elif color == LIGHTMAGENTA:
3345 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3346 elif color == YELLOW:
3347 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3348 elif color == WHITE:
3349 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3352 if game.options & OPTION_COLOR:
3353 curwnd.attron(curses.A_REVERSE)
3356 # Things past this point have policy implications.
3360 "Hook to be called after moving to redraw maps."
3361 if game.options & OPTION_CURSES:
3364 setwnd(srscan_window)
3368 setwnd(status_window)
3369 status_window.clear()
3370 status_window.move(0, 0)
3371 setwnd(report_window)
3372 report_window.clear()
3373 report_window.move(0, 0)
3375 setwnd(lrscan_window)
3376 lrscan_window.clear()
3377 lrscan_window.move(0, 0)
3378 lrscan(silent=False)
3380 def put_srscan_sym(w, sym):
3381 "Emit symbol for short-range scan."
3382 srscan_window.move(w.i+1, w.j*2+2)
3383 srscan_window.addch(sym)
3384 srscan_window.refresh()
3387 "Enemy fall down, go boom."
3388 if game.options & OPTION_CURSES:
3390 setwnd(srscan_window)
3391 srscan_window.attron(curses.A_REVERSE)
3392 put_srscan_sym(w, game.quad[w.i][w.j])
3396 srscan_window.attroff(curses.A_REVERSE)
3397 put_srscan_sym(w, game.quad[w.i][w.j])
3398 curses.delay_output(500)
3399 setwnd(message_window)
3402 "Sound and visual effects for teleportation."
3403 if game.options & OPTION_CURSES:
3405 setwnd(message_window)
3407 prouts(" . . . . . ")
3408 if game.options & OPTION_CURSES:
3409 #curses.delay_output(1000)
3413 def tracktorpedo(w, step, i, n, iquad):
3414 "Torpedo-track animation."
3415 if not game.options & OPTION_CURSES:
3419 proutn(_("Track for torpedo number %d- ") % (i+1))
3422 proutn(_("Torpedo track- "))
3423 elif step==4 or step==9:
3427 if not damaged(DSRSENS) or game.condition=="docked":
3428 if i != 0 and step == 1:
3431 if (iquad=='.') or (iquad==' '):
3432 put_srscan_sym(w, '+')
3436 put_srscan_sym(w, iquad)
3438 curwnd.attron(curses.A_REVERSE)
3439 put_srscan_sym(w, iquad)
3443 curwnd.attroff(curses.A_REVERSE)
3444 put_srscan_sym(w, iquad)
3449 "Display the current galaxy chart."
3450 if game.options & OPTION_CURSES:
3451 setwnd(message_window)
3452 message_window.clear()
3454 if game.options & OPTION_TTY:
3459 def prstat(txt, data):
3461 if game.options & OPTION_CURSES:
3463 setwnd(status_window)
3465 proutn(" " * (NSYM - len(txt)))
3468 if game.options & OPTION_CURSES:
3469 setwnd(report_window)
3471 # Code from moving.c begins here
3473 def imove(icourse=None, noattack=False):
3474 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3477 def newquadrant(noattack):
3478 # Leaving quadrant -- allow final enemy attack
3479 # Don't do it if being pushed by Nova
3480 if len(game.enemies) != 0 and not noattack:
3482 for enemy in game.enemies:
3483 finald = (w - enemy.location).distance()
3484 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3485 # Stas Sergeev added the condition
3486 # that attacks only happen if Klingons
3487 # are present and your skill is good.
3488 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3489 attack(torps_ok=False)
3492 # check for edge of galaxy
3496 if icourse.final.i < 0:
3497 icourse.final.i = -icourse.final.i
3499 if icourse.final.j < 0:
3500 icourse.final.j = -icourse.final.j
3502 if icourse.final.i >= GALSIZE*QUADSIZE:
3503 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3505 if icourse.final.j >= GALSIZE*QUADSIZE:
3506 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3514 if game.nkinks == 3:
3515 # Three strikes -- you're out!
3519 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3520 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3521 prout(_("YOU WILL BE DESTROYED."))
3522 # Compute final position in new quadrant
3523 if trbeam: # Don't bother if we are to be beamed
3525 game.quadrant = icourse.final.quadrant()
3526 game.sector = icourse.final.sector()
3528 prout(_("Entering Quadrant %s.") % game.quadrant)
3529 game.quad[game.sector.i][game.sector.j] = game.ship
3531 if game.skill>SKILL_NOVICE:
3532 attack(torps_ok=False)
3534 def check_collision(h):
3535 iquad = game.quad[h.i][h.j]
3537 # object encountered in flight path
3538 stopegy = 50.0*icourse.distance/game.optime
3539 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3540 for enemy in game.enemies:
3541 if enemy.location == game.sector:
3543 collision(rammed=False, enemy=enemy)
3547 prouts(_("***RED ALERT! RED ALERT!"))
3549 proutn("***" + crmshp())
3550 proutn(_(" pulled into black hole at Sector %s") % h)
3551 # Getting pulled into a black hole was certain
3552 # death in Almy's original. Stas Sergeev added a
3553 # possibility that you'll get timewarped instead.
3555 for m in range(NDEVICES):
3556 if game.damage[m]>0:
3558 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3559 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3569 prout(_(" encounters Tholian web at %s;") % h)
3571 prout(_(" blocked by object at %s;") % h)
3572 proutn(_("Emergency stop required "))
3573 prout(_("%2d units of energy.") % int(stopegy))
3574 game.energy -= stopegy
3575 if game.energy <= 0:
3582 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3583 game.inorbit = False
3584 # If tractor beam is to occur, don't move full distance
3585 if game.state.date+game.optime >= scheduled(FTBEAM):
3587 game.condition = "red"
3588 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3589 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3591 game.quad[game.sector.i][game.sector.j] = '.'
3592 for m in range(icourse.moves):
3594 w = icourse.sector()
3595 if icourse.origin.quadrant() != icourse.location.quadrant():
3596 newquadrant(noattack)
3598 elif check_collision(w):
3599 print "Collision detected"
3603 # We're in destination quadrant -- compute new average enemy distances
3604 game.quad[game.sector.i][game.sector.j] = game.ship
3606 for enemy in game.enemies:
3607 finald = (w-enemy.location).distance()
3608 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3609 enemy.kdist = finald
3611 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3612 attack(torps_ok=False)
3613 for enemy in game.enemies:
3614 enemy.kavgd = enemy.kdist
3617 setwnd(message_window)
3621 "Dock our ship at a starbase."
3623 if game.condition == "docked" and verbose:
3624 prout(_("Already docked."))
3627 prout(_("You must first leave standard orbit."))
3629 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3630 prout(crmshp() + _(" not adjacent to base."))
3632 game.condition = "docked"
3636 if game.energy < game.inenrg:
3637 game.energy = game.inenrg
3638 game.shield = game.inshld
3639 game.torps = game.intorps
3640 game.lsupres = game.inlsr
3641 game.state.crew = FULLCREW
3642 if not damaged(DRADIO) and \
3643 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3644 # get attack report from base
3645 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3649 def cartesian(loc1=None, loc2=None):
3651 return game.quadrant * QUADSIZE + game.sector
3653 return game.quadrant * QUADSIZE + loc1
3655 return loc1 * QUADSIZE + loc2
3657 def getcourse(isprobe):
3658 "Get a course and distance from the user."
3660 dquad = copy.copy(game.quadrant)
3661 navmode = "unspecified"
3665 if game.landed and not isprobe:
3666 prout(_("Dummy! You can't leave standard orbit until you"))
3667 proutn(_("are back aboard the ship."))
3670 while navmode == "unspecified":
3671 if damaged(DNAVSYS):
3673 prout(_("Computer damaged; manual navigation only"))
3675 prout(_("Computer damaged; manual movement only"))
3680 key = scanner.next()
3682 proutn(_("Manual or automatic- "))
3685 elif key == "IHALPHA":
3686 if scanner.sees("manual"):
3688 key = scanner.next()
3690 elif scanner.sees("automatic"):
3691 navmode = "automatic"
3692 key = scanner.next()
3700 prout(_("(Manual navigation assumed.)"))
3702 prout(_("(Manual movement assumed.)"))
3706 if navmode == "automatic":
3707 while key == "IHEOL":
3709 proutn(_("Target quadrant or quadrant§or- "))
3711 proutn(_("Destination sector or quadrant§or- "))
3714 key = scanner.next()
3718 xi = int(round(scanner.real))-1
3719 key = scanner.next()
3723 xj = int(round(scanner.real))-1
3724 key = scanner.next()
3726 # both quadrant and sector specified
3727 xk = int(round(scanner.real))-1
3728 key = scanner.next()
3732 xl = int(round(scanner.real))-1
3738 # only one pair of numbers was specified
3740 # only quadrant specified -- go to center of dest quad
3743 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3745 # only sector specified
3749 if not dquad.valid_quadrant() or not dsect.valid_sector():
3756 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3758 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3759 # the actual deltas get computed here
3760 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3761 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3763 while key == "IHEOL":
3764 proutn(_("X and Y displacements- "))
3767 key = scanner.next()
3772 delta.j = scanner.real
3773 key = scanner.next()
3777 delta.i = scanner.real
3778 # Check for zero movement
3779 if delta.i == 0 and delta.j == 0:
3782 if itemp == "verbose" and not isprobe:
3784 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3786 return course(bearing=delta.bearing(), distance=delta.distance())
3789 def __init__(self, bearing, distance, origin=None):
3790 self.distance = distance
3791 self.bearing = bearing
3793 self.origin = cartesian(game.quadrant, game.sector)
3795 self.origin = origin
3796 # The bearing() code we inherited from FORTRAN is actually computing
3797 # clockface directions!
3798 if self.bearing < 0.0:
3799 self.bearing += 12.0
3800 self.angle = ((15.0 - self.bearing) * 0.5235988)
3802 self.origin = cartesian(game.quadrant, game.sector)
3804 self.origin = cartesian(game.quadrant, origin)
3805 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
3806 bigger = max(abs(self.increment.i), abs(self.increment.j))
3807 self.increment /= bigger
3808 self.moves = int(round(10*self.distance*bigger))
3810 self.final = (self.location + self.moves*self.increment).roundtogrid()
3812 self.location = self.origin
3815 return self.location.roundtogrid() == self.final
3817 "Next step on course."
3819 self.nextlocation = self.location + self.increment
3820 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3821 self.location = self.nextlocation
3824 return self.location.quadrant()
3826 return self.location.sector()
3827 def power(self, warp):
3828 return self.distance*(warp**3)*(game.shldup+1)
3829 def time(self, warp):
3830 return 10.0*self.distance/warp**2
3833 "Move under impulse power."
3835 if damaged(DIMPULS):
3838 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3840 if game.energy > 30.0:
3842 course = getcourse(isprobe=False)
3845 power = 20.0 + 100.0*course.distance
3848 if power >= game.energy:
3849 # Insufficient power for trip
3851 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3852 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3853 if game.energy > 30:
3854 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3855 int(0.01 * (game.energy-20.0)-0.05))
3856 prout(_(" quadrants.\""))
3858 prout(_("quadrant. They are, therefore, useless.\""))
3861 # Make sure enough time is left for the trip
3862 game.optime = course.dist/0.095
3863 if game.optime >= game.state.remtime:
3864 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3865 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3866 proutn(_("we dare spend the time?\" "))
3869 # Activate impulse engines and pay the cost
3870 imove(course, noattack=False)
3874 power = 20.0 + 100.0*course.dist
3875 game.energy -= power
3876 game.optime = course.dist/0.095
3877 if game.energy <= 0:
3881 def warp(wcourse, involuntary):
3882 "ove under warp drive."
3883 blooey = False; twarp = False
3884 if not involuntary: # Not WARPX entry
3886 if game.damage[DWARPEN] > 10.0:
3889 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3891 if damaged(DWARPEN) and game.warpfac > 4.0:
3894 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3895 prout(_(" is repaired, I can only give you warp 4.\""))
3897 # Read in course and distance
3900 wcourse = getcourse(isprobe=False)
3903 # Make sure starship has enough energy for the trip
3904 # Note: this formula is slightly different from the C version,
3905 # and lets you skate a bit closer to the edge.
3906 if wcourse.power(game.warpfac) >= game.energy:
3907 # Insufficient power for trip
3910 prout(_("Engineering to bridge--"))
3911 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
3912 iwarp = (game.energy/(wcourse.dist+0.05)) ** 0.333333333
3914 prout(_("We can't do it, Captain. We don't have enough energy."))
3916 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3919 prout(_("if you'll lower the shields."))
3923 prout(_("We haven't the energy to go that far with the shields up."))
3925 # Make sure enough time is left for the trip
3926 game.optime = wcourse.time(game.warpfac)
3927 if game.optime >= 0.8*game.state.remtime:
3929 prout(_("First Officer Spock- \"Captain, I compute that such"))
3930 proutn(_(" a trip would require approximately %2.0f") %
3931 (100.0*game.optime/game.state.remtime))
3932 prout(_(" percent of our"))
3933 proutn(_(" remaining time. Are you sure this is wise?\" "))
3939 if game.warpfac > 6.0:
3940 # Decide if engine damage will occur
3941 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3942 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
3943 if prob > randreal():
3945 wcourse.distance = randreal(wcourse.distance)
3946 # Decide if time warp will occur
3947 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3949 if game.idebug and game.warpfac==10 and not twarp:
3951 proutn("=== Force time warp? ")
3955 # If time warp or engine damage, check path
3956 # If it is obstructed, don't do warp or damage
3957 look = wcourse.moves
3961 w = wcourse.sector()
3962 if not w.valid_sector():
3964 if game.quad[w.i][w.j] != '.':
3968 # Activate Warp Engines and pay the cost
3969 imove(wcourse, noattack=False)
3972 game.energy -= wcourse.power(game.warpfac)
3973 if game.energy <= 0:
3975 game.optime = wcourse.time(game.warpfac)
3979 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
3981 prout(_("Engineering to bridge--"))
3982 prout(_(" Scott here. The warp engines are damaged."))
3983 prout(_(" We'll have to reduce speed to warp 4."))
3988 "Change the warp factor."
3994 proutn(_("Warp factor- "))
3998 if game.damage[DWARPEN] > 10.0:
3999 prout(_("Warp engines inoperative."))
4001 if damaged(DWARPEN) and scanner.real > 4.0:
4002 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4003 prout(_(" but right now we can only go warp 4.\""))
4005 if scanner.real > 10.0:
4006 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4008 if scanner.real < 1.0:
4009 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4011 oldfac = game.warpfac
4012 game.warpfac = scanner.real
4013 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4014 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4017 if game.warpfac < 8.00:
4018 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4020 if game.warpfac == 10.0:
4021 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4023 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4027 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4029 # is captain on planet?
4031 if damaged(DTRANSP):
4034 prout(_("Scotty rushes to the transporter controls."))
4036 prout(_("But with the shields up it's hopeless."))
4038 prouts(_("His desperate attempt to rescue you . . ."))
4043 prout(_("SUCCEEDS!"))
4046 proutn(_("The crystals mined were "))
4054 # Check to see if captain in shuttle craft
4059 # Inform captain of attempt to reach safety
4063 prouts(_("***RED ALERT! RED ALERT!"))
4065 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4066 prouts(_(" a supernova."))
4068 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4069 prout(_("safely out of quadrant."))
4070 if not damaged(DRADIO):
4071 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4072 # Try to use warp engines
4073 if damaged(DWARPEN):
4075 prout(_("Warp engines damaged."))
4078 game.warpfac = randreal(6.0, 8.0)
4079 prout(_("Warp factor set to %d") % int(game.warpfac))
4080 power = 0.75*game.energy
4081 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4082 dist = max(dist, randreal(math.sqrt(2)))
4083 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4084 game.optime = bugout.time(game.warpfac)
4086 game.inorbit = False
4087 warp(bugout, involuntary=True)
4089 # This is bad news, we didn't leave quadrant.
4093 prout(_("Insufficient energy to leave quadrant."))
4096 # Repeat if another snova
4097 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4099 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4100 finish(FWON) # Snova killed remaining enemy.
4103 "Let's do the time warp again."
4104 prout(_("***TIME WARP ENTERED."))
4105 if game.state.snap and withprob(0.5):
4107 prout(_("You are traveling backwards in time %d stardates.") %
4108 int(game.state.date-game.snapsht.date))
4109 game.state = game.snapsht
4110 game.state.snap = False
4111 if len(game.state.kcmdr):
4112 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4113 schedule(FBATTAK, expran(0.3*game.intime))
4114 schedule(FSNOVA, expran(0.5*game.intime))
4115 # next snapshot will be sooner
4116 schedule(FSNAP, expran(0.25*game.state.remtime))
4118 if game.state.nscrem:
4119 schedule(FSCMOVE, 0.2777)
4123 game.battle.invalidate()
4124 # Make sure Galileo is consistant -- Snapshot may have been taken
4125 # when on planet, which would give us two Galileos!
4127 for l in range(game.inplan):
4128 if game.state.planets[l].known == "shuttle_down":
4130 if game.iscraft == "onship" and game.ship=='E':
4131 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4132 game.iscraft = "offship"
4133 # Likewise, if in the original time the Galileo was abandoned, but
4134 # was on ship earlier, it would have vanished -- let's restore it.
4135 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4136 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4137 game.iscraft = "onship"
4138 # There used to be code to do the actual reconstrction here,
4139 # but the starchart is now part of the snapshotted galaxy state.
4140 prout(_("Spock has reconstructed a correct star chart from memory"))
4142 # Go forward in time
4143 game.optime = expran(0.5*game.intime)
4144 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4145 # cheat to make sure no tractor beams occur during time warp
4146 postpone(FTBEAM, game.optime)
4147 game.damage[DRADIO] += game.optime
4149 events() # Stas Sergeev added this -- do pending events
4152 "Launch deep-space probe."
4153 # New code to launch a deep space probe
4154 if game.nprobes == 0:
4157 if game.ship == 'E':
4158 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4160 prout(_("Ye Faerie Queene has no deep space probes."))
4165 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4167 if is_scheduled(FDSPROB):
4170 if damaged(DRADIO) and game.condition != "docked":
4171 prout(_("Spock- \"Records show the previous probe has not yet"))
4172 prout(_(" reached its destination.\""))
4174 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4176 key = scanner.next()
4178 if game.nprobes == 1:
4179 prout(_("1 probe left."))
4181 prout(_("%d probes left") % game.nprobes)
4182 proutn(_("Are you sure you want to fire a probe? "))
4185 game.isarmed = False
4186 if key == "IHALPHA" and scanner.token == "armed":
4188 key = scanner.next()
4189 elif key == "IHEOL":
4190 proutn(_("Arm NOVAMAX warhead? "))
4192 elif key == "IHREAL": # first element of course
4193 scanner.push(scanner.token)
4195 game.probe = getcourse(isprobe=True)
4199 schedule(FDSPROB, 0.01) # Time to move one sector
4200 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4205 "Yell for help from nearest starbase."
4206 # There's more than one way to move in this game!
4208 # Test for conditions which prevent calling for help
4209 if game.condition == "docked":
4210 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4213 prout(_("Subspace radio damaged."))
4215 if not game.state.baseq:
4216 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4219 prout(_("You must be aboard the %s.") % crmshp())
4221 # OK -- call for help from nearest starbase
4224 # There's one in this quadrant
4225 ddist = (game.base - game.sector).distance()
4228 for ibq in game.state.baseq:
4229 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4232 # Since starbase not in quadrant, set up new quadrant
4235 # dematerialize starship
4236 game.quad[game.sector.i][game.sector.j]='.'
4237 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4238 % (game.quadrant, crmshp()))
4239 game.sector.invalidate()
4240 for m in range(1, 5+1):
4241 w = game.base.scatter()
4242 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4243 # found one -- finish up
4246 if not game.sector.is_valid():
4247 prout(_("You have been lost in space..."))
4248 finish(FMATERIALIZE)
4250 # Give starbase three chances to rematerialize starship
4251 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4252 for m in range(1, 3+1):
4253 if m == 1: proutn(_("1st"))
4254 elif m == 2: proutn(_("2nd"))
4255 elif m == 3: proutn(_("3rd"))
4256 proutn(_(" attempt to re-materialize ") + crmshp())
4257 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4260 if randreal() > probf:
4264 curses.delay_output(500)
4266 game.quad[game.sector.i][game.sector.j]='?'
4269 setwnd(message_window)
4270 finish(FMATERIALIZE)
4272 game.quad[game.sector.i][game.sector.j]=game.ship
4274 prout(_("succeeds."))
4278 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4283 if game.condition=="docked":
4285 prout(_("You cannot abandon Ye Faerie Queene."))
4288 # Must take shuttle craft to exit
4289 if game.damage[DSHUTTL]==-1:
4290 prout(_("Ye Faerie Queene has no shuttle craft."))
4292 if game.damage[DSHUTTL]<0:
4293 prout(_("Shuttle craft now serving Big Macs."))
4295 if game.damage[DSHUTTL]>0:
4296 prout(_("Shuttle craft damaged."))
4299 prout(_("You must be aboard the ship."))
4301 if game.iscraft != "onship":
4302 prout(_("Shuttle craft not currently available."))
4304 # Emit abandon ship messages
4306 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4308 prouts(_("***ALL HANDS ABANDON SHIP!"))
4310 prout(_("Captain and crew escape in shuttle craft."))
4311 if not game.state.baseq:
4312 # Oops! no place to go...
4315 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4317 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4318 prout(_("Remainder of ship's complement beam down"))
4319 prout(_("to nearest habitable planet."))
4320 elif q.planet != None and not damaged(DTRANSP):
4321 prout(_("Remainder of ship's complement beam down to %s.") %
4324 prout(_("Entire crew of %d left to die in outer space.") %
4326 game.casual += game.state.crew
4327 game.abandoned += game.state.crew
4328 # If at least one base left, give 'em the Faerie Queene
4330 game.icrystl = False # crystals are lost
4331 game.nprobes = 0 # No probes
4332 prout(_("You are captured by Klingons and released to"))
4333 prout(_("the Federation in a prisoner-of-war exchange."))
4334 nb = randrange(len(game.state.baseq))
4335 # Set up quadrant and position FQ adjacient to base
4336 if not game.quadrant == game.state.baseq[nb]:
4337 game.quadrant = game.state.baseq[nb]
4338 game.sector.i = game.sector.j = 5
4341 # position next to base by trial and error
4342 game.quad[game.sector.i][game.sector.j] = '.'
4343 for l in range(QUADSIZE):
4344 game.sector = game.base.scatter()
4345 if game.sector.valid_sector() and \
4346 game.quad[game.sector.i][game.sector.j] == '.':
4349 break # found a spot
4350 game.sector.i=QUADSIZE/2
4351 game.sector.j=QUADSIZE/2
4353 # Get new commission
4354 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4355 game.state.crew = FULLCREW
4356 prout(_("Starfleet puts you in command of another ship,"))
4357 prout(_("the Faerie Queene, which is antiquated but,"))
4358 prout(_("still useable."))
4360 prout(_("The dilithium crystals have been moved."))
4362 game.iscraft = "offship" # Galileo disappears
4364 game.condition="docked"
4365 for l in range(NDEVICES):
4366 game.damage[l] = 0.0
4367 game.damage[DSHUTTL] = -1
4368 game.energy = game.inenrg = 3000.0
4369 game.shield = game.inshld = 1250.0
4370 game.torps = game.intorps = 6
4371 game.lsupres=game.inlsr=3.0
4376 # Code from planets.c begins here.
4379 "Abort a lengthy operation if an event interrupts it."
4382 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4387 "Report on (uninhabited) planets in the galaxy."
4391 prout(_("Spock- \"Planet report follows, Captain.\""))
4393 for i in range(game.inplan):
4394 if game.state.planets[i].pclass == "destroyed":
4396 if (game.state.planets[i].known != "unknown" \
4397 and not game.state.planets[i].inhabited) \
4400 if game.idebug and game.state.planets[i].known=="unknown":
4401 proutn("(Unknown) ")
4402 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4403 proutn(_(" class "))
4404 proutn(game.state.planets[i].pclass)
4406 if game.state.planets[i].crystals != "present":
4408 prout(_("dilithium crystals present."))
4409 if game.state.planets[i].known=="shuttle_down":
4410 prout(_(" Shuttle Craft Galileo on surface."))
4412 prout(_("No information available."))
4415 "Enter standard orbit."
4419 prout(_("Already in standard orbit."))
4421 if damaged(DWARPEN) and damaged(DIMPULS):
4422 prout(_("Both warp and impulse engines damaged."))
4424 if not game.plnet.is_valid():
4425 prout("There is no planet in this sector.")
4427 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4428 prout(crmshp() + _(" not adjacent to planet."))
4431 game.optime = randreal(0.02, 0.05)
4432 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4436 game.height = randreal(1400, 8600)
4437 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4442 "Examine planets in this quadrant."
4443 if damaged(DSRSENS):
4444 if game.options & OPTION_TTY:
4445 prout(_("Short range sensors damaged."))
4447 if game.iplnet == None:
4448 if game.options & OPTION_TTY:
4449 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4451 if game.iplnet.known == "unknown":
4452 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4454 prout(_(" Planet at Sector %s is of class %s.") %
4455 (game.plnet, game.iplnet.pclass))
4456 if game.iplnet.known=="shuttle_down":
4457 prout(_(" Sensors show Galileo still on surface."))
4458 proutn(_(" Readings indicate"))
4459 if game.iplnet.crystals != "present":
4461 prout(_(" dilithium crystals present.\""))
4462 if game.iplnet.known == "unknown":
4463 game.iplnet.known = "known"
4464 elif game.iplnet.inhabited:
4465 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4466 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4469 "Use the transporter."
4473 if damaged(DTRANSP):
4474 prout(_("Transporter damaged."))
4475 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4477 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4481 if not game.inorbit:
4482 prout(crmshp() + _(" not in standard orbit."))
4485 prout(_("Impossible to transport through shields."))
4487 if game.iplnet.known=="unknown":
4488 prout(_("Spock- \"Captain, we have no information on this planet"))
4489 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4490 prout(_(" you may not go down.\""))
4492 if not game.landed and game.iplnet.crystals=="absent":
4493 prout(_("Spock- \"Captain, I fail to see the logic in"))
4494 prout(_(" exploring a planet with no dilithium crystals."))
4495 proutn(_(" Are you sure this is wise?\" "))
4499 if not (game.options & OPTION_PLAIN):
4500 nrgneed = 50 * game.skill + game.height / 100.0
4501 if nrgneed > game.energy:
4502 prout(_("Engineering to bridge--"))
4503 prout(_(" Captain, we don't have enough energy for transportation."))
4505 if not game.landed and nrgneed * 2 > game.energy:
4506 prout(_("Engineering to bridge--"))
4507 prout(_(" Captain, we have enough energy only to transport you down to"))
4508 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4509 if game.iplnet.known == "shuttle_down":
4510 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4511 proutn(_(" Are you sure this is wise?\" "))
4516 # Coming from planet
4517 if game.iplnet.known=="shuttle_down":
4518 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4522 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4523 prout(_("Landing party assembled, ready to beam up."))
4525 prout(_("Kirk whips out communicator..."))
4526 prouts(_("BEEP BEEP BEEP"))
4528 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4531 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4533 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4535 prout(_("Kirk- \"Energize.\""))
4538 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4541 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4543 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4546 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4547 game.landed = not game.landed
4548 game.energy -= nrgneed
4550 prout(_("Transport complete."))
4551 if game.landed and game.iplnet.known=="shuttle_down":
4552 prout(_("The shuttle craft Galileo is here!"))
4553 if not game.landed and game.imine:
4560 "Strip-mine a world for dilithium."
4564 prout(_("Mining party not on planet."))
4566 if game.iplnet.crystals == "mined":
4567 prout(_("This planet has already been strip-mined for dilithium."))
4569 elif game.iplnet.crystals == "absent":
4570 prout(_("No dilithium crystals on this planet."))
4573 prout(_("You've already mined enough crystals for this trip."))
4575 if game.icrystl and game.cryprob == 0.05:
4576 prout(_("With all those fresh crystals aboard the ") + crmshp())
4577 prout(_("there's no reason to mine more at this time."))
4579 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4582 prout(_("Mining operation complete."))
4583 game.iplnet.crystals = "mined"
4584 game.imine = game.ididit = True
4587 "Use dilithium crystals."
4591 if not game.icrystl:
4592 prout(_("No dilithium crystals available."))
4594 if game.energy >= 1000:
4595 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4596 prout(_(" except when Condition Yellow exists."))
4598 prout(_("Spock- \"Captain, I must warn you that loading"))
4599 prout(_(" raw dilithium crystals into the ship's power"))
4600 prout(_(" system may risk a severe explosion."))
4601 proutn(_(" Are you sure this is wise?\" "))
4606 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4607 prout(_(" Mr. Spock and I will try it.\""))
4609 prout(_("Spock- \"Crystals in place, Sir."))
4610 prout(_(" Ready to activate circuit.\""))
4612 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4614 if withprob(game.cryprob):
4615 prouts(_(" \"Activating now! - - No good! It's***"))
4617 prouts(_("***RED ALERT! RED A*L********************************"))
4620 prouts(_("****************** KA-BOOM!!!! *******************"))
4624 game.energy += randreal(5000.0, 5500.0)
4625 prouts(_(" \"Activating now! - - "))
4626 prout(_("The instruments"))
4627 prout(_(" are going crazy, but I think it's"))
4628 prout(_(" going to work!! Congratulations, Sir!\""))
4633 "Use shuttlecraft for planetary jaunt."
4636 if damaged(DSHUTTL):
4637 if game.damage[DSHUTTL] == -1.0:
4638 if game.inorbit and game.iplnet.known == "shuttle_down":
4639 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4641 prout(_("Ye Faerie Queene had no shuttle craft."))
4642 elif game.damage[DSHUTTL] > 0:
4643 prout(_("The Galileo is damaged."))
4644 else: # game.damage[DSHUTTL] < 0
4645 prout(_("Shuttle craft is now serving Big Macs."))
4647 if not game.inorbit:
4648 prout(crmshp() + _(" not in standard orbit."))
4650 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4651 prout(_("Shuttle craft not currently available."))
4653 if not game.landed and game.iplnet.known=="shuttle_down":
4654 prout(_("You will have to beam down to retrieve the shuttle craft."))
4656 if game.shldup or game.condition == "docked":
4657 prout(_("Shuttle craft cannot pass through shields."))
4659 if game.iplnet.known=="unknown":
4660 prout(_("Spock- \"Captain, we have no information on this planet"))
4661 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4662 prout(_(" you may not fly down.\""))
4664 game.optime = 3.0e-5*game.height
4665 if game.optime >= 0.8*game.state.remtime:
4666 prout(_("First Officer Spock- \"Captain, I compute that such"))
4667 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4668 int(100*game.optime/game.state.remtime))
4669 prout(_("remaining time."))
4670 proutn(_("Are you sure this is wise?\" "))
4676 if game.iscraft == "onship":
4678 if not damaged(DTRANSP):
4679 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4683 proutn(_("Shuttle crew"))
4685 proutn(_("Rescue party"))
4686 prout(_(" boards Galileo and swoops toward planet surface."))
4687 game.iscraft = "offship"
4691 game.iplnet.known="shuttle_down"
4692 prout(_("Trip complete."))
4695 # Ready to go back to ship
4696 prout(_("You and your mining party board the"))
4697 prout(_("shuttle craft for the trip back to the Enterprise."))
4699 prouts(_("The short hop begins . . ."))
4701 game.iplnet.known="known"
4707 game.iscraft = "onship"
4713 prout(_("Trip complete."))
4716 # Kirk on ship and so is Galileo
4717 prout(_("Mining party assembles in the hangar deck,"))
4718 prout(_("ready to board the shuttle craft \"Galileo\"."))
4720 prouts(_("The hangar doors open; the trip begins."))
4723 game.iscraft = "offship"
4726 game.iplnet.known = "shuttle_down"
4729 prout(_("Trip complete."))
4733 "Use the big zapper."
4737 if game.ship != 'E':
4738 prout(_("Ye Faerie Queene has no death ray."))
4740 if len(game.enemies)==0:
4741 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4744 prout(_("Death Ray is damaged."))
4746 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4747 prout(_(" is highly unpredictible. Considering the alternatives,"))
4748 proutn(_(" are you sure this is wise?\" "))
4751 prout(_("Spock- \"Acknowledged.\""))
4754 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4756 prout(_("Crew scrambles in emergency preparation."))
4757 prout(_("Spock and Scotty ready the death ray and"))
4758 prout(_("prepare to channel all ship's power to the device."))
4760 prout(_("Spock- \"Preparations complete, sir.\""))
4761 prout(_("Kirk- \"Engage!\""))
4763 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4766 if game.options & OPTION_PLAIN:
4770 prouts(_("Sulu- \"Captain! It's working!\""))
4772 while len(game.enemies) > 0:
4773 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4774 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4775 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4777 if (game.options & OPTION_PLAIN) == 0:
4778 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4780 prout(_(" is still operational.\""))
4782 prout(_(" has been rendered nonfunctional.\""))
4783 game.damage[DDRAY] = 39.95
4785 r = randreal() # Pick failure method
4787 prouts(_("Sulu- \"Captain! It's working!\""))
4789 prouts(_("***RED ALERT! RED ALERT!"))
4791 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4793 prouts(_("***RED ALERT! RED A*L********************************"))
4796 prouts(_("****************** KA-BOOM!!!! *******************"))
4801 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4803 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4805 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4806 prout(_(" have apparently been transformed into strange mutations."))
4807 prout(_(" Vulcans do not seem to be affected."))
4809 prout(_("Kirk- \"Raauch! Raauch!\""))
4813 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4815 proutn(_("Spock- \"I believe the word is"))
4816 prouts(_(" *ASTONISHING*"))
4817 prout(_(" Mr. Sulu."))
4818 for i in range(QUADSIZE):
4819 for j in range(QUADSIZE):
4820 if game.quad[i][j] == '.':
4821 game.quad[i][j] = '?'
4822 prout(_(" Captain, our quadrant is now infested with"))
4823 prouts(_(" - - - - - - *THINGS*."))
4825 prout(_(" I have no logical explanation.\""))
4827 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4829 prout(_("Scotty- \"There are so many tribbles down here"))
4830 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4834 # Code from reports.c begins here
4836 def attackreport(curt):
4837 "eport status of bases under attack."
4839 if is_scheduled(FCDBAS):
4840 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4841 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4842 elif game.isatb == 1:
4843 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4844 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4846 prout(_("No Starbase is currently under attack."))
4848 if is_scheduled(FCDBAS):
4849 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4851 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4855 # report on general game status
4857 s1 = (game.thawed and _("thawed ")) or ""
4858 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4859 s3 = (None, _("novice"), _("fair"),
4860 _("good"), _("expert"), _("emeritus"))[game.skill]
4861 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4862 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4863 prout(_("No plaque is allowed."))
4865 prout(_("This is tournament game %d.") % game.tourn)
4866 prout(_("Your secret password is \"%s\"") % game.passwd)
4867 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4868 (game.inkling + game.incom + game.inscom)))
4869 if game.incom - len(game.state.kcmdr):
4870 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4871 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4872 prout(_(", but no Commanders."))
4875 if game.skill > SKILL_FAIR:
4876 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4877 if len(game.state.baseq) != game.inbase:
4879 if game.inbase-len(game.state.baseq)==1:
4880 proutn(_("has been 1 base"))
4882 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4883 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4885 prout(_("There are %d bases.") % game.inbase)
4886 if communicating() or game.iseenit:
4887 # Don't report this if not seen and
4888 # either the radio is dead or not at base!
4892 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4894 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4895 if game.ship == 'E':
4896 proutn(_("You have "))
4898 proutn("%d" % (game.nprobes))
4901 proutn(_(" deep space probe"))
4905 if communicating() and is_scheduled(FDSPROB):
4907 proutn(_("An armed deep space probe is in "))
4909 proutn(_("A deep space probe is in "))
4910 prout("Quadrant %s." % game.probec)
4912 if game.cryprob <= .05:
4913 prout(_("Dilithium crystals aboard ship... not yet used."))
4917 while game.cryprob > ai:
4920 prout(_("Dilithium crystals have been used %d time%s.") % \
4921 (i, (_("s"), "")[i==1]))
4925 "Long-range sensor scan."
4926 if damaged(DLRSENS):
4927 # Now allow base's sensors if docked
4928 if game.condition != "docked":
4930 prout(_("LONG-RANGE SENSORS DAMAGED."))
4933 prout(_("Starbase's long-range scan"))
4935 prout(_("Long-range scan"))
4936 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4939 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4940 if not Coord(x, y).valid_quadrant():
4944 if not damaged(DRADIO):
4945 game.state.galaxy[x][y].charted = True
4946 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4947 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4948 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4949 if not silent and game.state.galaxy[x][y].supernova:
4952 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4960 for i in range(NDEVICES):
4963 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4964 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4966 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4967 game.damage[i]+0.05,
4968 DOCKFAC*game.damage[i]+0.005))
4970 prout(_("All devices functional."))
4973 "Update the chart in the Enterprise's computer from galaxy data."
4974 game.lastchart = game.state.date
4975 for i in range(GALSIZE):
4976 for j in range(GALSIZE):
4977 if game.state.galaxy[i][j].charted:
4978 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
4979 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
4980 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
4983 "Display the star chart."
4985 if (game.options & OPTION_AUTOSCAN):
4987 if not damaged(DRADIO):
4989 if game.lastchart < game.state.date and game.condition == "docked":
4990 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
4992 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
4993 if game.state.date > game.lastchart:
4994 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
4995 prout(" 1 2 3 4 5 6 7 8")
4996 for i in range(GALSIZE):
4997 proutn("%d |" % (i+1))
4998 for j in range(GALSIZE):
4999 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5003 if game.state.galaxy[i][j].supernova:
5005 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5007 elif game.state.galaxy[i][j].charted:
5008 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5012 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5020 def sectscan(goodScan, i, j):
5021 "Light up an individual dot in a sector."
5022 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5023 textcolor({"green":GREEN,
5027 "dead":BROWN}[game.condition])
5028 if game.quad[i][j] != game.ship:
5030 proutn("%c " % game.quad[i][j])
5036 "Emit status report lines"
5037 if not req or req == 1:
5038 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5039 % (game.state.date, game.state.remtime))
5040 if not req or req == 2:
5041 if game.condition != "docked":
5043 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5044 (game.condition.upper(), sum(map(lambda x: x > 0, game.damage))))
5045 if not req or req == 3:
5046 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5047 if not req or req == 4:
5048 if damaged(DLIFSUP):
5049 if game.condition == "docked":
5050 s = _("DAMAGED, Base provides")
5052 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5055 prstat(_("Life Support"), s)
5056 if not req or req == 5:
5057 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5058 if not req or req == 6:
5060 if game.icrystl and (game.options & OPTION_SHOWME):
5061 extra = _(" (have crystals)")
5062 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5063 if not req or req == 7:
5064 prstat(_("Torpedoes"), "%d" % (game.torps))
5065 if not req or req == 8:
5066 if damaged(DSHIELD):
5072 data = _(" %d%% %.1f units") \
5073 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5074 prstat(_("Shields"), s+data)
5075 if not req or req == 9:
5076 prstat(_("Klingons Left"), "%d" \
5077 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5078 if not req or req == 10:
5079 if game.options & OPTION_WORLDS:
5080 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5081 if plnet and plnet.inhabited:
5082 prstat(_("Major system"), plnet.name)
5084 prout(_("Sector is uninhabited"))
5085 elif not req or req == 11:
5086 attackreport(not req)
5089 "Request specified status data, a historical relic from slow TTYs."
5090 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5091 while scanner.next() == "IHEOL":
5092 proutn(_("Information desired? "))
5094 if scanner.token in requests:
5095 status(requests.index(scanner.token))
5097 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5098 prout((" date, condition, position, lsupport, warpfactor,"))
5099 prout((" energy, torpedoes, shields, klingons, system, time."))
5104 if damaged(DSRSENS):
5105 # Allow base's sensors if docked
5106 if game.condition != "docked":
5107 prout(_(" S.R. SENSORS DAMAGED!"))
5110 prout(_(" [Using Base's sensors]"))
5112 prout(_(" Short-range scan"))
5113 if goodScan and not damaged(DRADIO):
5114 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5115 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5116 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5117 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5118 prout(" 1 2 3 4 5 6 7 8 9 10")
5119 if game.condition != "docked":
5121 for i in range(QUADSIZE):
5122 proutn("%2d " % (i+1))
5123 for j in range(QUADSIZE):
5124 sectscan(goodScan, i, j)
5128 "Use computer to get estimated time of arrival for a warp jump."
5129 w1 = Coord(); w2 = Coord()
5131 if damaged(DCOMPTR):
5132 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5135 if scanner.next() != "IHREAL":
5138 proutn(_("Destination quadrant and/or sector? "))
5139 if scanner.next()!="IHREAL":
5142 w1.j = int(scanner.real-0.5)
5143 if scanner.next() != "IHREAL":
5146 w1.i = int(scanner.real-0.5)
5147 if scanner.next() == "IHREAL":
5148 w2.j = int(scanner.real-0.5)
5149 if scanner.next() != "IHREAL":
5152 w2.i = int(scanner.real-0.5)
5154 if game.quadrant.j>w1.i:
5158 if game.quadrant.i>w1.j:
5162 if not w1.valid_quadrant() or not w2.valid_sector():
5165 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5166 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5169 prout(_("Answer \"no\" if you don't know the value:"))
5172 proutn(_("Time or arrival date? "))
5173 if scanner.next()=="IHREAL":
5174 ttime = scanner.real
5175 if ttime > game.state.date:
5176 ttime -= game.state.date # Actually a star date
5177 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5178 if ttime <= 1e-10 or twarp > 10:
5179 prout(_("We'll never make it, sir."))
5186 proutn(_("Warp factor? "))
5187 if scanner.next()== "IHREAL":
5189 twarp = scanner.real
5190 if twarp<1.0 or twarp > 10.0:
5194 prout(_("Captain, certainly you can give me one of these."))
5197 ttime = (10.0*dist)/twarp**2
5198 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5199 if tpower >= game.energy:
5200 prout(_("Insufficient energy, sir."))
5201 if not game.shldup or tpower > game.energy*2.0:
5204 proutn(_("New warp factor to try? "))
5205 if scanner.next() == "IHREAL":
5207 twarp = scanner.real
5208 if twarp<1.0 or twarp > 10.0:
5216 prout(_("But if you lower your shields,"))
5217 proutn(_("remaining"))
5220 proutn(_("Remaining"))
5221 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5223 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5225 prout(_("Any warp speed is adequate."))
5227 prout(_("Minimum warp needed is %.2f,") % (twarp))
5228 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5229 if game.state.remtime < ttime:
5230 prout(_("Unfortunately, the Federation will be destroyed by then."))
5232 prout(_("You'll be taking risks at that speed, Captain"))
5233 if (game.isatb==1 and game.state.kscmdr == w1 and \
5234 scheduled(FSCDBAS)< ttime+game.state.date) or \
5235 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5236 prout(_("The starbase there will be destroyed by then."))
5237 proutn(_("New warp factor to try? "))
5238 if scanner.next() == "IHREAL":
5240 twarp = scanner.real
5241 if twarp<1.0 or twarp > 10.0:
5249 # Code from setup.c begins here
5252 "Issue a historically correct banner."
5254 prout(_("-SUPER- STAR TREK"))
5256 # From the FORTRAN original
5257 # prout(_("Latest update-21 Sept 78"))
5263 scanner.push("emsave.trk")
5264 key = scanner.next()
5266 proutn(_("File name: "))
5267 key = scanner.next()
5268 if key != "IHALPHA":
5271 if '.' not in scanner.token:
5272 scanner.token += ".trk"
5274 fp = open(scanner.token, "wb")
5276 prout(_("Can't freeze game as file %s") % scanner.token)
5278 cPickle.dump(game, fp)
5283 "Retrieve saved game."
5286 key = scanner.next()
5288 proutn(_("File name: "))
5289 key = scanner.next()
5290 if key != "IHALPHA":
5293 if '.' not in scanner.token:
5294 scanner.token += ".trk"
5296 fp = open(scanner.token, "rb")
5298 prout(_("Can't thaw game in %s") % scanner.token)
5300 game = cPickle.load(fp)
5305 # I used <http://www.memory-alpha.org> to find planets
5306 # with references in ST:TOS. Earth and the Alpha Centauri
5307 # Colony have been omitted.
5309 # Some planets marked Class G and P here will be displayed as class M
5310 # because of the way planets are generated. This is a known bug.
5313 _("Andoria (Fesoan)"), # several episodes
5314 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5315 _("Vulcan (T'Khasi)"), # many episodes
5316 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5317 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5318 _("Ardana"), # TOS: "The Cloud Minders"
5319 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5320 _("Gideon"), # TOS: "The Mark of Gideon"
5321 _("Aldebaran III"), # TOS: "The Deadly Years"
5322 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5323 _("Altair IV"), # TOS: "Amok Time
5324 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5325 _("Benecia"), # TOS: "The Conscience of the King"
5326 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5327 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5328 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5329 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5330 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5331 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5332 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5333 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5334 _("Ingraham B"), # TOS: "Operation: Annihilate"
5335 _("Janus IV"), # TOS: "The Devil in the Dark"
5336 _("Makus III"), # TOS: "The Galileo Seven"
5337 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5338 _("Omega IV"), # TOS: "The Omega Glory"
5339 _("Regulus V"), # TOS: "Amok Time
5340 _("Deneva"), # TOS: "Operation -- Annihilate!"
5341 # Worlds from BSD Trek
5342 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5343 _("Beta III"), # TOS: "The Return of the Archons"
5344 _("Triacus"), # TOS: "And the Children Shall Lead",
5345 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5347 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5348 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5349 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5350 # _("Izar"), # TOS: "Whom Gods Destroy"
5351 # _("Tiburon"), # TOS: "The Way to Eden"
5352 # _("Merak II"), # TOS: "The Cloud Minders"
5353 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5354 # _("Iotia"), # TOS: "A Piece of the Action"
5358 _("S. R. Sensors"), \
5359 _("L. R. Sensors"), \
5361 _("Photon Tubes"), \
5362 _("Life Support"), \
5363 _("Warp Engines"), \
5364 _("Impulse Engines"), \
5366 _("Subspace Radio"), \
5367 _("Shuttle Craft"), \
5369 _("Navigation System"), \
5371 _("Shield Control"), \
5377 "Prepare to play, set up cosmos."
5379 # Decide how many of everything
5381 return # frozen game
5382 # Prepare the Enterprise
5383 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5385 game.state.crew = FULLCREW
5386 game.energy = game.inenrg = 5000.0
5387 game.shield = game.inshld = 2500.0
5390 game.quadrant = randplace(GALSIZE)
5391 game.sector = randplace(QUADSIZE)
5392 game.torps = game.intorps = 10
5393 game.nprobes = randrange(2, 5)
5395 for i in range(NDEVICES):
5396 game.damage[i] = 0.0
5397 # Set up assorted game parameters
5398 game.battle = Coord()
5399 game.state.date = game.indate = 100.0 * randreal(20, 51)
5400 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5401 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5402 game.isatb = game.state.nplankl = 0
5403 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5404 game.iscraft = "onship"
5409 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5411 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5413 game.state.planets = [] # Planet information
5414 game.state.baseq = [] # Base quadrant coordinates
5415 game.state.kcmdr = [] # Commander quadrant coordinates
5416 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5418 # Starchart is functional but we've never seen it
5419 game.lastchart = FOREVER
5420 # Put stars in the galaxy
5422 for i in range(GALSIZE):
5423 for j in range(GALSIZE):
5424 k = randrange(1, QUADSIZE**2/10+1)
5426 game.state.galaxy[i][j].stars = k
5427 # Locate star bases in galaxy
5428 for i in range(game.inbase):
5431 w = randplace(GALSIZE)
5432 if not game.state.galaxy[w.i][w.j].starbase:
5435 # C version: for (j = i-1; j > 0; j--)
5436 # so it did them in the opposite order.
5437 for j in range(1, i):
5438 # Improved placement algorithm to spread out bases
5439 distq = (w - game.state.baseq[j]).distance()
5440 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5443 prout("=== Abandoning base #%d at %s" % (i, w))
5445 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5447 prout("=== Saving base #%d, close to #%d" % (i, j))
5450 game.state.baseq.append(w)
5451 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5452 # Position ordinary Klingon Battle Cruisers
5454 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5455 if klumper > MAXKLQUAD:
5459 klump = (1.0 - r*r)*klumper
5464 w = randplace(GALSIZE)
5465 if not game.state.galaxy[w.i][w.j].supernova and \
5466 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5468 game.state.galaxy[w.i][w.j].klingons += int(klump)
5471 # Position Klingon Commander Ships
5472 for i in range(game.incom):
5474 w = randplace(GALSIZE)
5475 if not welcoming(w) or w in game.state.kcmdr:
5477 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5479 game.state.galaxy[w.i][w.j].klingons += 1
5480 game.state.kcmdr.append(w)
5481 # Locate planets in galaxy
5482 for i in range(game.inplan):
5484 w = randplace(GALSIZE)
5485 if game.state.galaxy[w.i][w.j].planet == None:
5489 new.crystals = "absent"
5490 if (game.options & OPTION_WORLDS) and i < NINHAB:
5491 new.pclass = "M" # All inhabited planets are class M
5492 new.crystals = "absent"
5494 new.name = systnames[i]
5495 new.inhabited = True
5497 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5499 new.crystals = "present"
5500 new.known = "unknown"
5501 new.inhabited = False
5502 game.state.galaxy[w.i][w.j].planet = new
5503 game.state.planets.append(new)
5505 for i in range(game.state.nromrem):
5506 w = randplace(GALSIZE)
5507 game.state.galaxy[w.i][w.j].romulans += 1
5508 # Place the Super-Commander if needed
5509 if game.state.nscrem > 0:
5511 w = randplace(GALSIZE)
5514 game.state.kscmdr = w
5515 game.state.galaxy[w.i][w.j].klingons += 1
5516 # Initialize times for extraneous events
5517 schedule(FSNOVA, expran(0.5 * game.intime))
5518 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5519 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5520 schedule(FBATTAK, expran(0.3*game.intime))
5522 if game.state.nscrem:
5523 schedule(FSCMOVE, 0.2777)
5528 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5529 schedule(FDISTR, expran(1.0 + game.intime))
5534 # Place thing (in tournament game, we don't want one!)
5535 # New in SST2K: never place the Thing near a starbase.
5536 # This makes sense and avoids a special case in the old code.
5538 if game.tourn is None:
5540 thing = randplace(GALSIZE)
5541 if thing not in game.state.baseq:
5544 game.state.snap = False
5545 if game.skill == SKILL_NOVICE:
5546 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5547 prout(_("a deadly Klingon invasion force. As captain of the United"))
5548 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5549 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5550 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5551 prout(_("your mission. As you proceed you may be given more time."))
5553 prout(_("You will have %d supporting starbases.") % (game.inbase))
5554 proutn(_("Starbase locations- "))
5556 prout(_("Stardate %d.") % int(game.state.date))
5558 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5559 prout(_("An unknown number of Romulans."))
5560 if game.state.nscrem:
5561 prout(_("And one (GULP) Super-Commander."))
5562 prout(_("%d stardates.") % int(game.intime))
5563 proutn(_("%d starbases in ") % game.inbase)
5564 for i in range(game.inbase):
5565 proutn(`game.state.baseq[i]`)
5568 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5569 proutn(_(" Sector %s") % game.sector)
5571 prout(_("Good Luck!"))
5572 if game.state.nscrem:
5573 prout(_(" YOU'LL NEED IT."))
5576 setwnd(message_window)
5578 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5580 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5581 attack(torps_ok=False)
5584 "Choose your game type."
5586 game.tourn = game.length = 0
5588 game.skill = SKILL_NONE
5590 # if not scanner.inqueue: # Can start with command line options
5591 proutn(_("Would you like a regular, tournament, or saved game? "))
5593 if scanner.sees("tournament"):
5594 while scanner.next() == "IHEOL":
5595 proutn(_("Type in tournament number-"))
5596 if scanner.real == 0:
5598 continue # We don't want a blank entry
5599 game.tourn = int(round(scanner.real))
5600 random.seed(scanner.real)
5602 logfp.write("# random.seed(%d)\n" % scanner.real)
5604 if scanner.sees("saved") or scanner.sees("frozen"):
5608 if game.passwd == None:
5610 if not game.alldone:
5611 game.thawed = True # No plaque if not finished
5615 if scanner.sees("regular"):
5617 proutn(_("What is \"%s\"? ") % scanner.token)
5619 while game.length==0 or game.skill==SKILL_NONE:
5620 if scanner.next() == "IHALPHA":
5621 if scanner.sees("short"):
5623 elif scanner.sees("medium"):
5625 elif scanner.sees("long"):
5627 elif scanner.sees("novice"):
5628 game.skill = SKILL_NOVICE
5629 elif scanner.sees("fair"):
5630 game.skill = SKILL_FAIR
5631 elif scanner.sees("good"):
5632 game.skill = SKILL_GOOD
5633 elif scanner.sees("expert"):
5634 game.skill = SKILL_EXPERT
5635 elif scanner.sees("emeritus"):
5636 game.skill = SKILL_EMERITUS
5638 proutn(_("What is \""))
5639 proutn(scanner.token)
5644 proutn(_("Would you like a Short, Medium, or Long game? "))
5645 elif game.skill == SKILL_NONE:
5646 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5647 # Choose game options -- added by ESR for SST2K
5648 if scanner.next() != "IHALPHA":
5650 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5652 if scanner.sees("plain"):
5653 # Approximates the UT FORTRAN version.
5654 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5655 game.options |= OPTION_PLAIN
5656 elif scanner.sees("almy"):
5657 # Approximates Tom Almy's version.
5658 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5659 game.options |= OPTION_ALMY
5660 elif scanner.sees("fancy") or scanner.sees("\n"):
5662 elif len(scanner.token):
5663 proutn(_("What is \"%s\"?") % scanner.token)
5664 game.options &=~ OPTION_COLOR
5666 if game.passwd == "debug":
5668 prout("=== Debug mode enabled.")
5669 # Use parameters to generate initial values of things
5670 game.damfac = 0.5 * game.skill
5671 game.inbase = randrange(BASEMIN, BASEMAX+1)
5673 if game.options & OPTION_PLANETS:
5674 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5675 if game.options & OPTION_WORLDS:
5676 game.inplan += int(NINHAB)
5677 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5678 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5679 game.state.remtime = 7.0 * game.length
5680 game.intime = game.state.remtime
5681 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5682 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5683 game.state.remres = (game.inkling+4*game.incom)*game.intime
5684 game.inresor = game.state.remres
5685 if game.inkling > 50:
5686 game.state.inbase += 1
5689 def dropin(iquad=None):
5690 "Drop a feature on a random dot in the current quadrant."
5692 w = randplace(QUADSIZE)
5693 if game.quad[w.i][w.j] == '.':
5695 if iquad is not None:
5696 game.quad[w.i][w.j] = iquad
5700 "Update our alert status."
5701 game.condition = "green"
5702 if game.energy < 1000.0:
5703 game.condition = "yellow"
5704 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5705 game.condition = "red"
5707 game.condition="dead"
5710 "Drop new Klingon into current quadrant."
5711 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5714 "Sort enemies by distance so 'nearest' is meaningful."
5715 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
5718 "Set up a new state of quadrant, for when we enter or re-enter it."
5721 game.neutz = game.inorbit = game.landed = False
5722 game.ientesc = game.iseenit = False
5723 # Create a blank quadrant
5724 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5726 # Attempt to escape Super-commander, so tbeam back!
5729 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5730 # cope with supernova
5733 game.klhere = q.klingons
5734 game.irhere = q.romulans
5736 game.quad[game.sector.i][game.sector.j] = game.ship
5739 # Position ordinary Klingons
5740 for i in range(game.klhere):
5742 # If we need a commander, promote a Klingon
5743 for cmdr in game.state.kcmdr:
5744 if cmdr == game.quadrant:
5745 e = game.enemies[game.klhere-1]
5746 game.quad[e.location.i][e.location.j] = 'C'
5747 e.power = randreal(950,1350) + 50.0*game.skill
5749 # If we need a super-commander, promote a Klingon
5750 if game.quadrant == game.state.kscmdr:
5752 game.quad[e.location.i][e.location.j] = 'S'
5753 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5754 game.iscate = (game.state.remkl > 1)
5755 # Put in Romulans if needed
5756 for i in range(q.romulans):
5757 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5758 # If quadrant needs a starbase, put it in
5760 game.base = dropin('B')
5761 # If quadrant needs a planet, put it in
5763 game.iplnet = q.planet
5764 if not q.planet.inhabited:
5765 game.plnet = dropin('P')
5767 game.plnet = dropin('@')
5768 # Check for condition
5771 if game.irhere > 0 and game.klhere == 0:
5773 if not damaged(DRADIO):
5775 prout(_("LT. Uhura- \"Captain, an urgent message."))
5776 prout(_(" I'll put it on audio.\" CLICK"))
5778 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5779 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5780 # Put in THING if needed
5781 if thing == game.quadrant:
5782 Enemy(type='?', loc=dropin(),
5783 power=randreal(6000,6500.0)+250.0*game.skill)
5784 if not damaged(DSRSENS):
5786 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5787 prout(_(" Please examine your short-range scan.\""))
5788 # Decide if quadrant needs a Tholian; lighten up if skill is low
5789 if game.options & OPTION_THOLIAN:
5790 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5791 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5792 (game.skill > SKILL_GOOD and withprob(0.08)):
5795 w.i = withprob(0.5) * (QUADSIZE-1)
5796 w.j = withprob(0.5) * (QUADSIZE-1)
5797 if game.quad[w.i][w.j] == '.':
5799 game.tholian = Enemy(type='T', loc=w,
5800 power=randrange(100, 500) + 25.0*game.skill)
5801 # Reserve unoccupied corners
5802 if game.quad[0][0]=='.':
5803 game.quad[0][0] = 'X'
5804 if game.quad[0][QUADSIZE-1]=='.':
5805 game.quad[0][QUADSIZE-1] = 'X'
5806 if game.quad[QUADSIZE-1][0]=='.':
5807 game.quad[QUADSIZE-1][0] = 'X'
5808 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5809 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5811 # And finally the stars
5812 for i in range(q.stars):
5814 # Put in a few black holes
5815 for i in range(1, 3+1):
5818 # Take out X's in corners if Tholian present
5820 if game.quad[0][0]=='X':
5821 game.quad[0][0] = '.'
5822 if game.quad[0][QUADSIZE-1]=='X':
5823 game.quad[0][QUADSIZE-1] = '.'
5824 if game.quad[QUADSIZE-1][0]=='X':
5825 game.quad[QUADSIZE-1][0] = '.'
5826 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5827 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5830 "Set the self-destruct password."
5831 if game.options & OPTION_PLAIN:
5834 proutn(_("Please type in a secret password- "))
5836 game.passwd = scanner.token
5837 if game.passwd != None:
5841 game.passwd += chr(ord('a')+randrange(26))
5842 game.passwd += chr(ord('a')+randrange(26))
5843 game.passwd += chr(ord('a')+randrange(26))
5845 # Code from sst.c begins here
5848 ("SRSCAN", OPTION_TTY),
5849 ("STATUS", OPTION_TTY),
5850 ("REQUEST", OPTION_TTY),
5851 ("LRSCAN", OPTION_TTY),
5864 ("SENSORS", OPTION_PLANETS),
5865 ("ORBIT", OPTION_PLANETS),
5866 ("TRANSPORT", OPTION_PLANETS),
5867 ("MINE", OPTION_PLANETS),
5868 ("CRYSTALS", OPTION_PLANETS),
5869 ("SHUTTLE", OPTION_PLANETS),
5870 ("PLANETS", OPTION_PLANETS),
5875 ("PROBE", OPTION_PROBE),
5877 ("FREEZE", 0), # Synonym for SAVE
5883 ("SOS", 0), # Synonym for MAYDAY
5884 ("CALL", 0), # Synonym for MAYDAY
5891 "Generate a list of legal commands."
5892 prout(_("LEGAL COMMANDS ARE:"))
5894 for (key, opt) in commands:
5895 if not opt or (opt & game.options):
5896 proutn("%-12s " % key)
5898 if emitted % 5 == 4:
5903 "Browse on-line help."
5904 key = scanner.next()
5907 setwnd(prompt_window)
5908 proutn(_("Help on what command? "))
5909 key = scanner.next()
5910 setwnd(message_window)
5913 cmds = map(lambda x: x[0], commands)
5914 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
5921 cmd = scanner.token.upper()
5922 for directory in docpath:
5924 fp = open(os.path.join(directory, "sst.doc"), "r")
5929 prout(_("Spock- \"Captain, that information is missing from the"))
5930 prout(_(" computer. You need to find sst.doc and put it somewhere"))
5931 proutn(_(" in these directories: %s") % ":".join(docpath))
5933 # This used to continue: "You need to find SST.DOC and put
5934 # it in the current directory."
5937 linebuf = fp.readline()
5939 prout(_("Spock- \"Captain, there is no information on that command.\""))
5942 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5943 linebuf = linebuf[3:].strip()
5944 if cmd.upper() == linebuf:
5947 prout(_("Spock- \"Captain, I've found the following information:\""))
5950 linebuf = fp.readline()
5951 if "******" in linebuf:
5957 "Command-interpretation loop."
5958 while True: # command loop
5960 while True: # get a command
5962 game.optime = game.justin = False
5964 setwnd(prompt_window)
5967 if scanner.next() == "IHEOL":
5968 if game.options & OPTION_CURSES:
5971 elif scanner.token == "":
5975 setwnd(message_window)
5977 abandon_passed = False
5978 for (cmd, opt) in commands:
5979 # commands after ABANDON cannot be abbreviated
5980 if cmd == "ABANDON":
5981 abandon_passed = True
5982 if cmd == scanner.token.upper() or (not abandon_passed \
5983 and cmd.startswith(scanner.token.upper())):
5990 if cmd == "SRSCAN": # srscan
5992 elif cmd == "STATUS": # status
5994 elif cmd == "REQUEST": # status request
5996 elif cmd == "LRSCAN": # long range scan
5997 lrscan(silent=False)
5998 elif cmd == "PHASERS": # phasers
6002 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6006 elif cmd == "MOVE": # move under warp
6007 warp(wcourse=None, involuntary=False)
6008 elif cmd == "SHIELDS": # shields
6009 doshield(shraise=False)
6012 game.shldchg = False
6013 elif cmd == "DOCK": # dock at starbase
6016 attack(torps_ok=False)
6017 elif cmd == "DAMAGES": # damage reports
6019 elif cmd == "CHART": # chart
6021 elif cmd == "IMPULSE": # impulse
6023 elif cmd == "REST": # rest
6027 elif cmd == "WARP": # warp
6029 elif cmd == "SCORE": # score
6031 elif cmd == "SENSORS": # sensors
6033 elif cmd == "ORBIT": # orbit
6037 elif cmd == "TRANSPORT": # transport "beam"
6039 elif cmd == "MINE": # mine
6043 elif cmd == "CRYSTALS": # crystals
6047 elif cmd == "SHUTTLE": # shuttle
6051 elif cmd == "PLANETS": # Planet list
6053 elif cmd == "REPORT": # Game Report
6055 elif cmd == "COMPUTER": # use COMPUTER!
6057 elif cmd == "COMMANDS":
6059 elif cmd == "EMEXIT": # Emergency exit
6060 clrscr() # Hide screen
6061 freeze(True) # forced save
6062 raise SystemExit,1 # And quick exit
6063 elif cmd == "PROBE":
6064 probe() # Launch probe
6067 elif cmd == "ABANDON": # Abandon Ship
6069 elif cmd == "DESTRUCT": # Self Destruct
6071 elif cmd == "SAVE": # Save Game
6074 if game.skill > SKILL_GOOD:
6075 prout(_("WARNING--Saved games produce no plaques!"))
6076 elif cmd == "DEATHRAY": # Try a desparation measure
6080 elif cmd == "DEBUGCMD": # What do we want for debug???
6082 elif cmd == "MAYDAY": # Call for help
6087 game.alldone = True # quit the game
6092 break # Game has ended
6093 if game.optime != 0.0:
6096 break # Events did us in
6097 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6100 if hitme and not game.justin:
6101 attack(torps_ok=True)
6104 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6115 "Emit the name of an enemy or feature."
6116 if type == 'R': s = _("Romulan")
6117 elif type == 'K': s = _("Klingon")
6118 elif type == 'C': s = _("Commander")
6119 elif type == 'S': s = _("Super-commander")
6120 elif type == '*': s = _("Star")
6121 elif type == 'P': s = _("Planet")
6122 elif type == 'B': s = _("Starbase")
6123 elif type == ' ': s = _("Black hole")
6124 elif type == 'T': s = _("Tholian")
6125 elif type == '#': s = _("Tholian web")
6126 elif type == '?': s = _("Stranger")
6127 elif type == '@': s = _("Inhabited World")
6128 else: s = "Unknown??"
6131 def crmena(stars, enemy, loctype, w):
6132 "Emit the name of an enemy and his location."
6136 buf += cramen(enemy) + _(" at ")
6137 if loctype == "quadrant":
6138 buf += _("Quadrant ")
6139 elif loctype == "sector":
6144 "Emit our ship name."
6145 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6148 "Emit a line of stars"
6149 prouts("******************************************************")
6153 return -avrage*math.log(1e-7 + randreal())
6155 def randplace(size):
6156 "Choose a random location."
6158 w.i = randrange(size)
6159 w.j = randrange(size)
6169 # Get a token from the user
6172 # Fill the token quue if nothing here
6173 while not self.inqueue:
6175 if curwnd==prompt_window:
6177 setwnd(message_window)
6184 self.inqueue = line.lstrip().split() + ["\n"]
6185 # From here on in it's all looking at the queue
6186 self.token = self.inqueue.pop(0)
6187 if self.token == "\n":
6191 self.real = float(self.token)
6192 self.type = "IHREAL"
6197 self.token = self.token.lower()
6198 self.type = "IHALPHA"
6201 def append(self, tok):
6202 self.inqueue.append(tok)
6203 def push(self, tok):
6204 self.inqueue.insert(0, tok)
6208 # Demand input for next scan
6210 self.real = self.token = None
6212 # compares s to item and returns true if it matches to the length of s
6213 return s.startswith(self.token)
6215 # Round token value to nearest integer
6216 return int(round(scanner.real))
6220 if scanner.type != "IHREAL":
6223 s.i = scanner.int()-1
6225 if scanner.type != "IHREAL":
6228 s.j = scanner.int()-1
6231 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6234 "Yes-or-no confirmation."
6238 if scanner.token == 'y':
6240 if scanner.token == 'n':
6243 proutn(_("Please answer with \"y\" or \"n\": "))
6246 "Complain about unparseable input."
6249 prout(_("Beg your pardon, Captain?"))
6252 "Access to the internals for debugging."
6253 proutn("Reset levels? ")
6255 if game.energy < game.inenrg:
6256 game.energy = game.inenrg
6257 game.shield = game.inshld
6258 game.torps = game.intorps
6259 game.lsupres = game.inlsr
6260 proutn("Reset damage? ")
6262 for i in range(NDEVICES):
6263 if game.damage[i] > 0.0:
6264 game.damage[i] = 0.0
6265 proutn("Toggle debug flag? ")
6267 game.idebug = not game.idebug
6269 prout("Debug output ON")
6271 prout("Debug output OFF")
6272 proutn("Cause selective damage? ")
6274 for i in range(NDEVICES):
6275 proutn("Kill %s?" % device[i])
6277 key = scanner.next()
6278 if key == "IHALPHA" and scanner.sees("y"):
6279 game.damage[i] = 10.0
6280 proutn("Examine/change events? ")
6285 FSNOVA: "Supernova ",
6288 FBATTAK: "Base Attack ",
6289 FCDBAS: "Base Destroy ",
6290 FSCMOVE: "SC Move ",
6291 FSCDBAS: "SC Base Destroy ",
6292 FDSPROB: "Probe Move ",
6293 FDISTR: "Distress Call ",
6294 FENSLV: "Enslavement ",
6295 FREPRO: "Klingon Build ",
6297 for i in range(1, NEVENTS):
6300 proutn("%.2f" % (scheduled(i)-game.state.date))
6301 if i == FENSLV or i == FREPRO:
6303 proutn(" in %s" % ev.quadrant)
6308 key = scanner.next()
6312 elif key == "IHREAL":
6313 ev = schedule(i, scanner.real)
6314 if i == FENSLV or i == FREPRO:
6316 proutn("In quadrant- ")
6317 key = scanner.next()
6318 # "IHEOL" says to leave coordinates as they are
6321 prout("Event %d canceled, no x coordinate." % (i))
6324 w.i = int(round(scanner.real))
6325 key = scanner.next()
6327 prout("Event %d canceled, no y coordinate." % (i))
6330 w.j = int(round(scanner.real))
6333 proutn("Induce supernova here? ")
6335 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6338 if __name__ == '__main__':
6339 import getopt, socket
6341 global line, thing, game
6345 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6346 if os.getenv("TERM"):
6347 game.options |= OPTION_CURSES
6349 game.options |= OPTION_TTY
6350 seed = int(time.time())
6351 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6353 for (switch, val) in options:
6356 replayfp = open(val, "r")
6358 sys.stderr.write("sst: can't open replay file %s\n" % val)
6361 line = replayfp.readline().strip()
6362 (leader, __, seed) = line.split()
6364 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6365 line = replayfp.readline().strip()
6366 arguments += line.split()[2:]
6369 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6371 game.options |= OPTION_TTY
6372 game.options &=~ OPTION_CURSES
6373 elif switch == '-s':
6375 elif switch == '-t':
6376 game.options |= OPTION_TTY
6377 game.options &=~ OPTION_CURSES
6378 elif switch == '-x':
6380 elif switch == '-V':
6381 print "SST2K", version
6384 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6386 # where to save the input in case of bugs
6387 if "TMPDIR" in os.environ:
6388 tmpdir = os.environ['TMPDIR']
6392 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6394 sys.stderr.write("sst: warning, can't open logfile\n")
6397 logfp.write("# seed %s\n" % seed)
6398 logfp.write("# options %s\n" % " ".join(arguments))
6399 logfp.write("# recorded by %s@%s on %s\n" % \
6400 (getpass.getuser(),socket.gethostname(),time.ctime()))
6402 scanner = sstscanner()
6403 map(scanner.append, arguments)
6406 while True: # Play a game
6407 setwnd(fullscreen_window)
6413 game.alldone = False
6421 if game.tourn and game.alldone:
6422 proutn(_("Do you want your score recorded?"))
6428 proutn(_("Do you want to play again? "))
6432 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6436 except KeyboardInterrupt: