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()
280 self.power = power # enemy energy level
281 game.enemies.append(self)
283 motion = (loc != self.location)
284 if self.location.i is not None and self.location.j is not None:
287 game.quad[self.location.i][self.location.j] = '#'
289 game.quad[self.location.i][self.location.j] = '.'
291 self.location = copy.copy(loc)
292 game.quad[self.location.i][self.location.j] = self.type
293 self.kdist = self.kavgd = (game.sector - loc).distance()
295 self.location = Coord()
296 self.kdist = self.kavgd = None
297 game.enemies.remove(self)
300 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
304 self.options = None # Game options
305 self.state = Snapshot() # A snapshot structure
306 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
307 self.quad = None # contents of our quadrant
308 self.damage = [0.0] * NDEVICES # damage encountered
309 self.future = [] # future events
313 self.future.append(Event())
314 self.passwd = None # Self Destruct password
316 self.quadrant = None # where we are in the large
317 self.sector = None # where we are in the small
318 self.tholian = None # Tholian enemy object
319 self.base = None # position of base in current quadrant
320 self.battle = None # base coordinates being attacked
321 self.plnet = None # location of planet in quadrant
322 self.gamewon = False # Finished!
323 self.ididit = False # action taken -- allows enemy to attack
324 self.alive = False # we are alive (not killed)
325 self.justin = False # just entered quadrant
326 self.shldup = False # shields are up
327 self.shldchg = False # shield is changing (affects efficiency)
328 self.iscate = False # super commander is here
329 self.ientesc = False # attempted escape from supercommander
330 self.resting = False # rest time
331 self.icraft = False # Kirk in Galileo
332 self.landed = False # party on planet (true), on ship (false)
333 self.alldone = False # game is now finished
334 self.neutz = False # Romulan Neutral Zone
335 self.isarmed = False # probe is armed
336 self.inorbit = False # orbiting a planet
337 self.imine = False # mining
338 self.icrystl = False # dilithium crystals aboard
339 self.iseenit = False # seen base attack report
340 self.thawed = False # thawed game
341 self.condition = None # "green", "yellow", "red", "docked", "dead"
342 self.iscraft = None # "onship", "offship", "removed"
343 self.skill = None # Player skill level
344 self.inkling = 0 # initial number of klingons
345 self.inbase = 0 # initial number of bases
346 self.incom = 0 # initial number of commanders
347 self.inscom = 0 # initial number of commanders
348 self.inrom = 0 # initial number of commanders
349 self.instar = 0 # initial stars
350 self.intorps = 0 # initial/max torpedoes
351 self.torps = 0 # number of torpedoes
352 self.ship = 0 # ship type -- 'E' is Enterprise
353 self.abandoned = 0 # count of crew abandoned in space
354 self.length = 0 # length of game
355 self.klhere = 0 # klingons here
356 self.casual = 0 # causalties
357 self.nhelp = 0 # calls for help
358 self.nkinks = 0 # count of energy-barrier crossings
359 self.iplnet = None # planet # in quadrant
360 self.inplan = 0 # initial planets
361 self.irhere = 0 # Romulans in quadrant
362 self.isatb = 0 # =2 if super commander is attacking base
363 self.tourn = None # tournament number
364 self.nprobes = 0 # number of probes available
365 self.inresor = 0.0 # initial resources
366 self.intime = 0.0 # initial time
367 self.inenrg = 0.0 # initial/max energy
368 self.inshld = 0.0 # initial/max shield
369 self.inlsr = 0.0 # initial life support resources
370 self.indate = 0.0 # initial date
371 self.energy = 0.0 # energy level
372 self.shield = 0.0 # shield level
373 self.warpfac = 0.0 # warp speed
374 self.lsupres = 0.0 # life support reserves
375 self.optime = 0.0 # time taken by current operation
376 self.damfac = 0.0 # damage factor
377 self.lastchart = 0.0 # time star chart was last updated
378 self.cryprob = 0.0 # probability that crystal will work
379 self.probe = None # object holding probe course info
380 self.height = 0.0 # height of orbit around planet
381 self.score = 0.0 # overall score
382 self.perdate = 0.0 # rate of kills
383 self.idebug = False # Debugging instrumentation enabled?
384 self.statekscmdr = None # No SuperCommander coordinates yet.
386 # Stas thinks this should be (C expression):
387 # game.state.remkl + len(game.state.kcmdr) > 0 ?
388 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
389 # He says the existing expression is prone to divide-by-zero errors
390 # after killing the last klingon when score is shown -- perhaps also
391 # if the only remaining klingon is SCOM.
392 self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.state.kcmdr))
418 return random.random() < p
420 def randrange(*args):
421 return random.randrange(*args)
426 v *= args[0] # from [0, args[0])
428 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
431 # Code from ai.c begins here
434 "Would this quadrant welcome another Klingon?"
435 return iq.valid_quadrant() and \
436 not game.state.galaxy[iq.i][iq.j].supernova and \
437 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
439 def tryexit(enemy, look, irun):
440 "A bad guy attempts to bug out."
442 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
443 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
444 if not welcoming(iq):
446 if enemy.type == 'R':
447 return False # Romulans cannot escape!
449 # avoid intruding on another commander's territory
450 if enemy.type == 'C':
451 if iq in game.state.kcmdr:
453 # refuse to leave if currently attacking starbase
454 if game.battle == game.quadrant:
456 # don't leave if over 1000 units of energy
457 if enemy.power > 1000.0:
459 # emit escape message and move out of quadrant.
460 # we know this if either short or long range sensors are working
461 if not damaged(DSRSENS) or not damaged(DLRSENS) or \
462 game.condition == "docked":
463 prout(crmena(True, enemy.type, "sector", enemy.location) + \
464 (_(" escapes to Quadrant %s (and regains strength).") % iq))
465 # handle local matters related to escape
468 if game.condition != "docked":
470 # Handle global matters related to escape
471 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
472 game.state.galaxy[iq.i][iq.j].klingons += 1
473 if enemy.type == 'S':
477 schedule(FSCMOVE, 0.2777)
479 game.state.kscmdr = iq
481 for cmdr in game.state.kcmdr:
482 if cmdr == game.quadrant:
483 game.state.kcmdr.append(iq)
485 return True # success
487 # The bad-guy movement algorithm:
489 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
490 # If both are operating full strength, force is 1000. If both are damaged,
491 # force is -1000. Having shields down subtracts an additional 1000.
493 # 2. Enemy has forces equal to the energy of the attacker plus
494 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
495 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
497 # Attacker Initial energy levels (nominal):
498 # Klingon Romulan Commander Super-Commander
499 # Novice 400 700 1200
501 # Good 450 800 1300 1750
502 # Expert 475 850 1350 1875
503 # Emeritus 500 900 1400 2000
504 # VARIANCE 75 200 200 200
506 # Enemy vessels only move prior to their attack. In Novice - Good games
507 # only commanders move. In Expert games, all enemy vessels move if there
508 # is a commander present. In Emeritus games all enemy vessels move.
510 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
511 # forces are 1000 greater than Enterprise.
513 # Agressive action on average cuts the distance between the ship and
514 # the enemy to 1/4 the original.
516 # 4. At lower energy advantage, movement units are proportional to the
517 # advantage with a 650 advantage being to hold ground, 800 to move forward
518 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
520 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
521 # retreat, especially at high skill levels.
523 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
525 def movebaddy(enemy):
526 "Tactical movement for the bad guys."
530 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
531 if game.skill >= SKILL_EXPERT:
532 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
534 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
536 mdist = int(dist1 + 0.5) # Nearest integer distance
537 # If SC, check with spy to see if should hi-tail it
538 if enemy.type == 'S' and \
539 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
543 # decide whether to advance, retreat, or hold position
544 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
546 forces += 1000 # Good for enemy if shield is down!
547 if not damaged(DPHASER) or not damaged(DPHOTON):
548 if damaged(DPHASER): # phasers damaged
551 forces -= 0.2*(game.energy - 2500.0)
552 if damaged(DPHOTON): # photon torpedoes damaged
555 forces -= 50.0*game.torps
557 # phasers and photon tubes both out!
560 if forces <= 1000.0 and game.condition != "docked": # Typical situation
561 motion = ((forces + randreal(200))/150.0) - 5.0
563 if forces > 1000.0: # Very strong -- move in for kill
564 motion = (1.0 - randreal())**2 * dist1 + 1.0
565 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
566 motion -= game.skill*(2.0-randreal()**2)
568 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
569 # don't move if no motion
572 # Limit motion according to skill
573 if abs(motion) > game.skill:
578 # calculate preferred number of steps
579 nsteps = abs(int(motion))
580 if motion > 0 and nsteps > mdist:
581 nsteps = mdist # don't overshoot
582 if nsteps > QUADSIZE:
583 nsteps = QUADSIZE # This shouldn't be necessary
585 nsteps = 1 # This shouldn't be necessary
587 proutn("NSTEPS = %d:" % nsteps)
588 # Compute preferred values of delta X and Y
589 m = game.sector - enemy.location
590 if 2.0 * abs(m.i) < abs(m.j):
592 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
594 m = (motion * m).sgn()
595 goto = enemy.location
597 for ll in range(nsteps):
599 proutn(" %d" % (ll+1))
600 # Check if preferred position available
611 attempts = 0 # Settle mysterious hang problem
612 while attempts < 20 and not success:
614 if look.i < 0 or look.i >= QUADSIZE:
615 if motion < 0 and tryexit(enemy, look, irun):
617 if krawli == m.i or m.j == 0:
619 look.i = goto.i + krawli
621 elif look.j < 0 or look.j >= QUADSIZE:
622 if motion < 0 and tryexit(enemy, look, irun):
624 if krawlj == m.j or m.i == 0:
626 look.j = goto.j + krawlj
628 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
629 # See if enemy should ram ship
630 if game.quad[look.i][look.j] == game.ship and \
631 (enemy.type == 'C' or enemy.type == 'S'):
632 collision(rammed=True, enemy=enemy)
634 if krawli != m.i and m.j != 0:
635 look.i = goto.i + krawli
637 elif krawlj != m.j and m.i != 0:
638 look.j = goto.j + krawlj
641 break # we have failed
653 if not damaged(DSRSENS) or game.condition == "docked":
654 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
655 if enemy.kdist < dist1:
656 proutn(_(" advances to "))
658 proutn(_(" retreats to "))
659 prout("Sector %s." % goto)
662 "Sequence Klingon tactical movement."
665 # Figure out which Klingon is the commander (or Supercommander)
667 if game.quadrant in game.state.kcmdr:
668 for enemy in game.enemies:
669 if enemy.type == 'C':
671 if game.state.kscmdr == game.quadrant:
672 for enemy in game.enemies:
673 if enemy.type == 'S':
676 # If skill level is high, move other Klingons and Romulans too!
677 # Move these last so they can base their actions on what the
679 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
680 for enemy in game.enemies:
681 if enemy.type in ('K', 'R'):
685 def movescom(iq, avoid):
686 "Commander movement helper."
687 # Avoid quadrants with bases if we want to avoid Enterprise
688 if not welcoming(iq) or (avoid and iq in game.state.baseq):
690 if game.justin and not game.iscate:
693 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
694 game.state.kscmdr = iq
695 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
696 if game.state.kscmdr == game.quadrant:
697 # SC has scooted, remove him from current quadrant
702 for enemy in game.enemies:
703 if enemy.type == 'S':
706 if game.condition != "docked":
709 # check for a helpful planet
710 for i in range(game.inplan):
711 if game.state.planets[i].quadrant == game.state.kscmdr and \
712 game.state.planets[i].crystals == "present":
714 game.state.planets[i].pclass = "destroyed"
715 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
718 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
719 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
720 prout(_(" by the Super-commander.\""))
722 return True # looks good!
724 def supercommander():
725 "Move the Super Commander."
732 prout("== SUPERCOMMANDER")
733 # Decide on being active or passive
734 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 \
735 (game.state.date-game.indate) < 3.0)
736 if not game.iscate and avoid:
737 # compute move away from Enterprise
738 idelta = game.state.kscmdr-game.quadrant
739 if idelta.distance() > 2.0:
741 idelta.i = game.state.kscmdr.j-game.quadrant.j
742 idelta.j = game.quadrant.i-game.state.kscmdr.i
744 # compute distances to starbases
745 if not game.state.baseq:
749 sc = game.state.kscmdr
750 for (i, base) in enumerate(game.state.baseq):
751 basetbl.append((i, (base - sc).distance()))
752 if game.state.baseq > 1:
753 basetbl.sort(lambda x, y: cmp(x[1], y[1]))
754 # look for nearest base without a commander, no Enterprise, and
755 # without too many Klingons, and not already under attack.
756 ifindit = iwhichb = 0
757 for (i2, base) in enumerate(game.state.baseq):
758 i = basetbl[i2][0] # bug in original had it not finding nearest
759 if base == game.quadrant or base == game.battle or not welcoming(base):
761 # if there is a commander, and no other base is appropriate,
762 # we will take the one with the commander
763 for cmdr in game.state.kcmdr:
764 if base == cmdr and ifindit != 2:
768 else: # no commander -- use this one
773 return # Nothing suitable -- wait until next time
774 ibq = game.state.baseq[iwhichb]
775 # decide how to move toward base
776 idelta = ibq - game.state.kscmdr
777 # Maximum movement is 1 quadrant in either or both axes
778 idelta = idelta.sgn()
779 # try moving in both x and y directions
780 # there was what looked like a bug in the Almy C code here,
781 # but it might be this translation is just wrong.
782 iq = game.state.kscmdr + idelta
783 if not movescom(iq, avoid):
784 # failed -- try some other maneuvers
785 if idelta.i == 0 or idelta.j == 0:
788 iq.j = game.state.kscmdr.j + 1
789 if not movescom(iq, avoid):
790 iq.j = game.state.kscmdr.j - 1
793 iq.i = game.state.kscmdr.i + 1
794 if not movescom(iq, avoid):
795 iq.i = game.state.kscmdr.i - 1
798 # try moving just in x or y
799 iq.j = game.state.kscmdr.j
800 if not movescom(iq, avoid):
801 iq.j = game.state.kscmdr.j + idelta.j
802 iq.i = game.state.kscmdr.i
805 if len(game.state.baseq) == 0:
808 for ibq in game.state.baseq:
809 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
812 return # no, don't attack base!
815 schedule(FSCDBAS, randreal(1.0, 3.0))
816 if is_scheduled(FCDBAS):
817 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
818 if not communicating():
822 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
824 prout(_(" reports that it is under attack from the Klingon Super-commander."))
825 proutn(_(" It can survive until stardate %d.\"") \
826 % int(scheduled(FSCDBAS)))
829 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
833 game.optime = 0.0 # actually finished
835 # Check for intelligence report
836 if not game.idebug and \
838 (not communicating()) or \
839 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
842 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
843 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
848 if not game.tholian or game.justin:
851 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
854 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
857 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
860 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
864 # something is wrong!
865 game.tholian.move(None)
866 prout("***Internal error: Tholian in a bad spot.")
868 # do nothing if we are blocked
869 if game.quad[tid.i][tid.j] not in ('.', '#'):
871 here = copy.copy(game.tholian.location)
872 delta = (tid - game.tholian.location).sgn()
874 while here.i != tid.i:
876 if game.quad[here.i][here.j] == '.':
877 game.tholian.move(here)
879 while here.j != tid.j:
881 if game.quad[here.i][here.j] == '.':
882 game.tholian.move(here)
883 # check to see if all holes plugged
884 for i in range(QUADSIZE):
885 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
887 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
889 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
891 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
893 # All plugged up -- Tholian splits
894 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
896 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
897 game.tholian.move(None)
900 # Code from battle.c begins here
902 def doshield(shraise):
903 "Change shield status."
911 if scanner.sees("transfer"):
915 prout(_("Shields damaged and down."))
917 if scanner.sees("up"):
919 elif scanner.sees("down"):
922 proutn(_("Do you wish to change shield energy? "))
925 elif damaged(DSHIELD):
926 prout(_("Shields damaged and down."))
929 proutn(_("Shields are up. Do you want them down? "))
936 proutn(_("Shields are down. Do you want them up? "))
942 if action == "SHUP": # raise shields
944 prout(_("Shields already up."))
948 if game.condition != "docked":
950 prout(_("Shields raised."))
953 prout(_("Shields raising uses up last of energy."))
958 elif action == "SHDN":
960 prout(_("Shields already down."))
964 prout(_("Shields lowered."))
967 elif action == "NRG":
968 while scanner.next() != "IHREAL":
970 proutn(_("Energy to transfer to shields- "))
975 if nrg > game.energy:
976 prout(_("Insufficient ship energy."))
979 if game.shield+nrg >= game.inshld:
980 prout(_("Shield energy maximized."))
981 if game.shield+nrg > game.inshld:
982 prout(_("Excess energy requested returned to ship energy"))
983 game.energy -= game.inshld-game.shield
984 game.shield = game.inshld
986 if nrg < 0.0 and game.energy-nrg > game.inenrg:
987 # Prevent shield drain loophole
989 prout(_("Engineering to bridge--"))
990 prout(_(" Scott here. Power circuit problem, Captain."))
991 prout(_(" I can't drain the shields."))
994 if game.shield+nrg < 0:
995 prout(_("All shield energy transferred to ship."))
996 game.energy += game.shield
999 proutn(_("Scotty- \""))
1001 prout(_("Transferring energy to shields.\""))
1003 prout(_("Draining energy from shields.\""))
1009 "Choose a device to damage, at random."
1011 105, # DSRSENS: short range scanners 10.5%
1012 105, # DLRSENS: long range scanners 10.5%
1013 120, # DPHASER: phasers 12.0%
1014 120, # DPHOTON: photon torpedoes 12.0%
1015 25, # DLIFSUP: life support 2.5%
1016 65, # DWARPEN: warp drive 6.5%
1017 70, # DIMPULS: impulse engines 6.5%
1018 145, # DSHIELD: deflector shields 14.5%
1019 30, # DRADIO: subspace radio 3.0%
1020 45, # DSHUTTL: shuttle 4.5%
1021 15, # DCOMPTR: computer 1.5%
1022 20, # NAVCOMP: navigation system 2.0%
1023 75, # DTRANSP: transporter 7.5%
1024 20, # DSHCTRL: high-speed shield controller 2.0%
1025 10, # DDRAY: death ray 1.0%
1026 30, # DDSP: deep-space probes 3.0%
1028 assert(sum(weights) == 1000)
1029 idx = randrange(1000)
1031 for (i, w) in enumerate(weights):
1035 return None # we should never get here
1037 def collision(rammed, enemy):
1038 "Collision handling fot rammong events."
1039 prouts(_("***RED ALERT! RED ALERT!"))
1041 prout(_("***COLLISION IMMINENT."))
1045 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1047 proutn(_(" rammed by "))
1050 proutn(crmena(False, enemy.type, "sector", enemy.location))
1052 proutn(_(" (original position)"))
1054 deadkl(enemy.location, enemy.type, game.sector)
1055 proutn("***" + crmshp() + " heavily damaged.")
1056 icas = randrange(10, 30)
1057 prout(_("***Sickbay reports %d casualties") % icas)
1059 game.state.crew -= icas
1060 # In the pre-SST2K version, all devices got equiprobably damaged,
1061 # which was silly. Instead, pick up to half the devices at
1062 # random according to our weighting table,
1063 ncrits = randrange(NDEVICES/2)
1067 if game.damage[dev] < 0:
1069 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1070 # Damage for at least time of travel!
1071 game.damage[dev] += game.optime + extradm
1073 prout(_("***Shields are down."))
1074 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1081 def torpedo(origin, bearing, dispersion, number, nburst):
1082 "Let a photon torpedo fly"
1083 if not damaged(DSRSENS) or game.condition == "docked":
1084 setwnd(srscan_window)
1086 setwnd(message_window)
1087 ac = bearing + 0.25*dispersion # dispersion is a random variable
1088 bullseye = (15.0 - bearing)*0.5235988
1089 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1090 bumpto = Coord(0, 0)
1091 # Loop to move a single torpedo
1092 setwnd(message_window)
1093 for step in range(1, QUADSIZE*2):
1094 if not track.next():
1097 if not w.valid_sector():
1099 iquad = game.quad[w.i][w.j]
1100 tracktorpedo(w, step, number, nburst, iquad)
1104 setwnd(message_window)
1105 if not damaged(DSRSENS) or game.condition == "docked":
1106 skip(1) # start new line after text track
1107 if iquad in ('E', 'F'): # Hit our ship
1109 prout(_("Torpedo hits %s.") % crmshp())
1110 hit = 700.0 + randreal(100) - \
1111 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1112 newcnd() # we're blown out of dock
1113 if game.landed or game.condition == "docked":
1114 return hit # Cheat if on a planet
1115 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1116 # is 143 degrees, which is almost exactly 4.8 clockface units
1117 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1119 bumpto = displacement.sector()
1120 if not bumpto.valid_sector():
1122 if game.quad[bumpto.i][bumpto.j] == ' ':
1125 if game.quad[bumpto.i][bumpto.j] != '.':
1126 # can't move into object
1128 game.sector = bumpto
1130 game.quad[w.i][w.j] = '.'
1131 game.quad[bumpto.i][bumpto.j] = iquad
1132 prout(_(" displaced by blast to Sector %s ") % bumpto)
1133 for enemy in game.enemies:
1134 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1137 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1139 if iquad in ('C', 'S') and withprob(0.05):
1140 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1141 prout(_(" torpedo neutralized."))
1143 for enemy in game.enemies:
1144 if w == enemy.location:
1145 kp = math.fabs(enemy.power)
1146 h1 = 700.0 + randrange(100) - \
1147 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1155 if enemy.power == 0:
1158 proutn(crmena(True, iquad, "sector", w))
1159 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1161 bumpto = displacement.sector()
1162 if not bumpto.valid_sector():
1163 prout(_(" damaged but not destroyed."))
1165 if game.quad[bumpto.i][bumpto.j] == ' ':
1166 prout(_(" buffeted into black hole."))
1167 deadkl(w, iquad, bumpto)
1168 if game.quad[bumpto.i][bumpto.j] != '.':
1169 prout(_(" damaged but not destroyed."))
1171 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1172 enemy.location = bumpto
1173 game.quad[w.i][w.j] = '.'
1174 game.quad[bumpto.i][bumpto.j] = iquad
1175 for enemy in game.enemies:
1176 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1180 prout("Internal error, no enemy where expected!")
1183 elif iquad == 'B': # Hit a base
1185 prout(_("***STARBASE DESTROYED.."))
1186 game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
1187 game.quad[w.i][w.j] = '.'
1188 game.base.invalidate()
1189 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1
1190 game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1
1191 game.state.basekl += 1
1194 elif iquad == 'P': # Hit a planet
1195 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1196 game.state.nplankl += 1
1197 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1198 game.iplnet.pclass = "destroyed"
1200 game.plnet.invalidate()
1201 game.quad[w.i][w.j] = '.'
1203 # captain perishes on planet
1206 elif iquad == '@': # Hit an inhabited world -- very bad!
1207 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1208 game.state.nworldkl += 1
1209 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1210 game.iplnet.pclass = "destroyed"
1212 game.plnet.invalidate()
1213 game.quad[w.i][w.j] = '.'
1215 # captain perishes on planet
1217 prout(_("The torpedo destroyed an inhabited planet."))
1219 elif iquad == '*': # Hit a star
1223 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1225 elif iquad == '?': # Hit a thingy
1226 if not (game.options & OPTION_THINGY) or withprob(0.3):
1228 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1230 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1232 proutn(_("Mr. Spock-"))
1233 prouts(_(" \"Fascinating!\""))
1237 # Stas Sergeev added the possibility that
1238 # you can shove the Thingy and piss it off.
1239 # It then becomes an enemy and may fire at you.
1242 elif iquad == ' ': # Black hole
1244 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1246 elif iquad == '#': # hit the web
1248 prout(_("***Torpedo absorbed by Tholian web."))
1250 elif iquad == 'T': # Hit a Tholian
1251 h1 = 700.0 + randrange(100) - \
1252 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1255 game.quad[w.i][w.j] = '.'
1260 proutn(crmena(True, 'T', "sector", w))
1262 prout(_(" survives photon blast."))
1264 prout(_(" disappears."))
1265 game.tholian.move(None)
1266 game.quad[w.i][w.j] = '#'
1271 proutn("Don't know how to handle torpedo collision with ")
1272 proutn(crmena(True, iquad, "sector", w))
1277 prout(_("Torpedo missed."))
1281 "Critical-hit resolution."
1282 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1284 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1285 proutn(_("***CRITICAL HIT--"))
1286 # Select devices and cause damage
1292 # Cheat to prevent shuttle damage unless on ship
1293 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship")):
1296 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1297 game.damage[j] += extradm
1299 for (i, j) in enumerate(cdam):
1301 if skipcount % 3 == 2 and i < len(cdam)-1:
1306 prout(_(" damaged."))
1307 if damaged(DSHIELD) and game.shldup:
1308 prout(_("***Shields knocked down."))
1311 def attack(torps_ok):
1312 # bad guy attacks us
1313 # torps_ok == False forces use of phasers in an attack
1314 # game could be over at this point, check
1324 prout("=== ATTACK!")
1325 # Tholian gets to move before attacking
1328 # if you have just entered the RNZ, you'll get a warning
1329 if game.neutz: # The one chance not to be attacked
1332 # commanders get a chance to tac-move towards you
1333 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:
1335 # if no enemies remain after movement, we're done
1336 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing == game.quadrant and not thing.angered):
1338 # set up partial hits if attack happens during shield status change
1339 pfac = 1.0/game.inshld
1341 chgfac = 0.25 + randreal(0.5)
1343 # message verbosity control
1344 if game.skill <= SKILL_FAIR:
1346 for enemy in game.enemies:
1348 continue # too weak to attack
1349 # compute hit strength and diminish shield power
1351 # Increase chance of photon torpedos if docked or enemy energy is low
1352 if game.condition == "docked":
1354 if enemy.power < 500:
1356 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1358 # different enemies have different probabilities of throwing a torp
1359 usephasers = not torps_ok or \
1360 (enemy.type == 'K' and r > 0.0005) or \
1361 (enemy.type == 'C' and r > 0.015) or \
1362 (enemy.type == 'R' and r > 0.3) or \
1363 (enemy.type == 'S' and r > 0.07) or \
1364 (enemy.type == '?' and r > 0.05)
1365 if usephasers: # Enemy uses phasers
1366 if game.condition == "docked":
1367 continue # Don't waste the effort!
1368 attempt = True # Attempt to attack
1369 dustfac = randreal(0.8, 0.85)
1370 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1372 else: # Enemy uses photon torpedo
1373 # We should be able to make the bearing() method work here
1374 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1376 proutn(_("***TORPEDO INCOMING"))
1377 if not damaged(DSRSENS):
1378 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1381 dispersion = (randreal()+randreal())*0.5 - 0.5
1382 dispersion += 0.002*enemy.power*dispersion
1383 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1384 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1385 finish(FWON) # Klingons did themselves in!
1386 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1387 return # Supernova or finished
1390 # incoming phaser or torpedo, shields may dissipate it
1391 if game.shldup or game.shldchg or game.condition == "docked":
1392 # shields will take hits
1393 propor = pfac * game.shield
1394 if game.condition == "docked":
1398 hitsh = propor*chgfac*hit+1.0
1400 if absorb > game.shield:
1401 absorb = game.shield
1402 game.shield -= absorb
1404 # taking a hit blasts us out of a starbase dock
1405 if game.condition == "docked":
1407 # but the shields may take care of it
1408 if propor > 0.1 and hit < 0.005*game.energy:
1410 # hit from this opponent got through shields, so take damage
1412 proutn(_("%d unit hit") % int(hit))
1413 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1414 proutn(_(" on the ") + crmshp())
1415 if not damaged(DSRSENS) and usephasers:
1416 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1418 # Decide if hit is critical
1424 if game.energy <= 0:
1425 # Returning home upon your shield, not with it...
1428 if not attempt and game.condition == "docked":
1429 prout(_("***Enemies decide against attacking your ship."))
1430 percent = 100.0*pfac*game.shield+0.5
1432 # Shields fully protect ship
1433 proutn(_("Enemy attack reduces shield strength to "))
1435 # Emit message if starship suffered hit(s)
1437 proutn(_("Energy left %2d shields ") % int(game.energy))
1440 elif not damaged(DSHIELD):
1443 proutn(_("damaged, "))
1444 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1445 # Check if anyone was hurt
1446 if hitmax >= 200 or hittot >= 500:
1447 icas = randrange(int(hittot * 0.015))
1450 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1451 prout(_(" in that last attack.\""))
1453 game.state.crew -= icas
1454 # After attack, reset average distance to enemies
1455 for enemy in game.enemies:
1456 enemy.kavgd = enemy.kdist
1460 def deadkl(w, etype, mv):
1461 "Kill a Klingon, Tholian, Romulan, or Thingy."
1462 # Added mv to allow enemy to "move" before dying
1463 proutn(crmena(True, etype, "sector", mv))
1464 # Decide what kind of enemy it is and update appropriately
1466 # Chalk up a Romulan
1467 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1469 game.state.nromrem -= 1
1478 # Killed some type of Klingon
1479 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1482 game.state.kcmdr.remove(game.quadrant)
1484 if game.state.kcmdr:
1485 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1486 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1489 game.state.remkl -= 1
1491 game.state.nscrem -= 1
1492 game.state.kscmdr.invalidate()
1497 # For each kind of enemy, finish message to player
1498 prout(_(" destroyed."))
1499 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1502 # Remove enemy ship from arrays describing local conditions
1503 for e in game.enemies:
1510 "Return None if target is invalid, otherwise return a course angle."
1511 if not w.valid_sector():
1515 # C code this was translated from is wacky -- why the sign reversal?
1516 delta.j = (w.j - game.sector.j)
1517 delta.i = (game.sector.i - w.i)
1518 if delta == Coord(0, 0):
1520 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1521 prout(_(" I recommend an immediate review of"))
1522 prout(_(" the Captain's psychological profile.\""))
1525 return delta.bearing()
1528 "Launch photon torpedo salvo."
1531 if damaged(DPHOTON):
1532 prout(_("Photon tubes damaged."))
1536 prout(_("No torpedoes left."))
1539 # First, get torpedo count
1542 if scanner.token == "IHALPHA":
1545 elif scanner.token == "IHEOL" or not scanner.waiting():
1546 prout(_("%d torpedoes left.") % game.torps)
1548 proutn(_("Number of torpedoes to fire- "))
1549 continue # Go back around to get a number
1550 else: # key == "IHREAL"
1552 if n <= 0: # abort command
1557 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1560 scanner.chew() # User requested more torps than available
1561 continue # Go back around
1562 break # All is good, go to next stage
1566 key = scanner.next()
1567 if i == 0 and key == "IHEOL":
1568 break # no coordinate waiting, we will try prompting
1569 if i == 1 and key == "IHEOL":
1570 # direct all torpedoes at one target
1572 target.append(target[0])
1573 tcourse.append(tcourse[0])
1576 scanner.push(scanner.token)
1577 target.append(scanner.getcoord())
1578 if target[-1] == None:
1580 tcourse.append(targetcheck(target[-1]))
1581 if tcourse[-1] == None:
1584 if len(target) == 0:
1585 # prompt for each one
1587 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1589 target.append(scanner.getcoord())
1590 if target[-1] == None:
1592 tcourse.append(targetcheck(target[-1]))
1593 if tcourse[-1] == None:
1596 # Loop for moving <n> torpedoes
1598 if game.condition != "docked":
1600 dispersion = (randreal()+randreal())*0.5 -0.5
1601 if math.fabs(dispersion) >= 0.47:
1603 dispersion *= randreal(1.2, 2.2)
1605 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1607 prouts(_("***TORPEDO MISFIRES."))
1610 prout(_(" Remainder of burst aborted."))
1612 prout(_("***Photon tubes damaged by misfire."))
1613 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1615 if game.shldup or game.condition == "docked":
1616 dispersion *= 1.0 + 0.0001*game.shield
1617 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1618 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1620 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1624 "Check for phasers overheating."
1626 checkburn = (rpow-1500.0)*0.00038
1627 if withprob(checkburn):
1628 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1629 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1631 def checkshctrl(rpow):
1632 "Check shield control."
1635 prout(_("Shields lowered."))
1637 # Something bad has happened
1638 prouts(_("***RED ALERT! RED ALERT!"))
1640 hit = rpow*game.shield/game.inshld
1641 game.energy -= rpow+hit*0.8
1642 game.shield -= hit*0.2
1643 if game.energy <= 0.0:
1644 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1649 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1651 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1652 icas = randrange(int(hit*0.012))
1657 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1658 prout(_(" %d casualties so far.\"") % icas)
1660 game.state.crew -= icas
1662 prout(_("Phaser energy dispersed by shields."))
1663 prout(_("Enemy unaffected."))
1668 "Register a phaser hit on Klingons and Romulans."
1675 dustfac = randreal(0.9, 1.0)
1676 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1677 kpini = game.enemies[kk].power
1678 kp = math.fabs(kpini)
1679 if PHASEFAC*hit < kp:
1681 if game.enemies[kk].power < 0:
1682 game.enemies[kk].power -= -kp
1684 game.enemies[kk].power -= kp
1685 kpow = game.enemies[kk].power
1686 w = game.enemies[kk].location
1688 if not damaged(DSRSENS):
1690 proutn(_("%d unit hit on ") % int(hit))
1692 proutn(_("Very small hit on "))
1693 ienm = game.quad[w.i][w.j]
1696 proutn(crmena(False, ienm, "sector", w))
1700 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1704 kk -= 1 # don't do the increment
1706 else: # decide whether or not to emasculate klingon
1707 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1708 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1709 prout(_(" has just lost its firepower.\""))
1710 game.enemies[kk].power = -kpow
1715 "Fire phasers at bad guys."
1719 irec = 0 # Cheating inhibitor
1728 # SR sensors and Computer are needed for automode
1729 if damaged(DSRSENS) or damaged(DCOMPTR):
1731 if game.condition == "docked":
1732 prout(_("Phasers can't be fired through base shields."))
1735 if damaged(DPHASER):
1736 prout(_("Phaser control damaged."))
1740 if damaged(DSHCTRL):
1741 prout(_("High speed shield control damaged."))
1744 if game.energy <= 200.0:
1745 prout(_("Insufficient energy to activate high-speed shield control."))
1748 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1750 # Original code so convoluted, I re-did it all
1751 # (That was Tom Almy talking about the C code, I think -- ESR)
1752 while automode == "NOTSET":
1753 key = scanner.next()
1754 if key == "IHALPHA":
1755 if scanner.sees("manual"):
1756 if len(game.enemies)==0:
1757 prout(_("There is no enemy present to select."))
1760 automode = "AUTOMATIC"
1763 key = scanner.next()
1764 elif scanner.sees("automatic"):
1765 if (not itarg) and len(game.enemies) != 0:
1766 automode = "FORCEMAN"
1768 if len(game.enemies)==0:
1769 prout(_("Energy will be expended into space."))
1770 automode = "AUTOMATIC"
1771 key = scanner.next()
1772 elif scanner.sees("no"):
1777 elif key == "IHREAL":
1778 if len(game.enemies)==0:
1779 prout(_("Energy will be expended into space."))
1780 automode = "AUTOMATIC"
1782 automode = "FORCEMAN"
1784 automode = "AUTOMATIC"
1787 if len(game.enemies)==0:
1788 prout(_("Energy will be expended into space."))
1789 automode = "AUTOMATIC"
1791 automode = "FORCEMAN"
1793 proutn(_("Manual or automatic? "))
1798 if automode == "AUTOMATIC":
1799 if key == "IHALPHA" and scanner.sees("no"):
1801 key = scanner.next()
1802 if key != "IHREAL" and len(game.enemies) != 0:
1803 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1808 for i in range(len(game.enemies)):
1809 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1811 proutn(_("%d units required. ") % irec)
1813 proutn(_("Units to fire= "))
1814 key = scanner.next()
1819 proutn(_("Energy available= %.2f") % avail)
1822 if not rpow > avail:
1828 key = scanner.next()
1829 if key == "IHALPHA" and scanner.sees("no"):
1832 game.energy -= 200 # Go and do it!
1833 if checkshctrl(rpow):
1838 if len(game.enemies):
1841 for i in range(len(game.enemies)):
1845 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1846 over = randreal(1.01, 1.06) * hits[i]
1848 powrem -= hits[i] + over
1849 if powrem <= 0 and temp < hits[i]:
1858 if extra > 0 and not game.alldone:
1860 proutn(_("*** Tholian web absorbs "))
1861 if len(game.enemies)>0:
1862 proutn(_("excess "))
1863 prout(_("phaser energy."))
1865 prout(_("%d expended on empty space.") % int(extra))
1866 elif automode == "FORCEMAN":
1869 if damaged(DCOMPTR):
1870 prout(_("Battle computer damaged, manual fire only."))
1873 prouts(_("---WORKING---"))
1875 prout(_("Short-range-sensors-damaged"))
1876 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1877 prout(_("Manual-fire-must-be-used"))
1879 elif automode == "MANUAL":
1881 for k in range(len(game.enemies)):
1882 aim = game.enemies[k].location
1883 ienm = game.quad[aim.i][aim.j]
1885 proutn(_("Energy available= %.2f") % (avail-0.006))
1889 if damaged(DSRSENS) and \
1890 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1891 prout(cramen(ienm) + _(" can't be located without short range scan."))
1894 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
1899 if itarg and k > kz:
1900 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1903 if not damaged(DCOMPTR):
1908 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1909 key = scanner.next()
1910 if key == "IHALPHA" and scanner.sees("no"):
1912 key = scanner.next()
1914 if key == "IHALPHA":
1918 if k == 1: # Let me say I'm baffled by this
1921 if scanner.real < 0:
1925 hits[k] = scanner.real
1926 rpow += scanner.real
1927 # If total requested is too much, inform and start over
1929 prout(_("Available energy exceeded -- try again."))
1932 key = scanner.next() # scan for next value
1935 # zero energy -- abort
1938 if key == "IHALPHA" and scanner.sees("no"):
1943 game.energy -= 200.0
1944 if checkshctrl(rpow):
1948 # Say shield raised or malfunction, if necessary
1955 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1956 prouts(_(" CLICK CLICK POP . . ."))
1957 prout(_(" No response, sir!"))
1960 prout(_("Shields raised."))
1965 # Code from events,c begins here.
1967 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1968 # event of each type active at any given time. Mostly these means we can
1969 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1970 # BSD Trek, from which we swiped the idea, can have up to 5.
1972 def unschedule(evtype):
1973 "Remove an event from the schedule."
1974 game.future[evtype].date = FOREVER
1975 return game.future[evtype]
1977 def is_scheduled(evtype):
1978 "Is an event of specified type scheduled."
1979 return game.future[evtype].date != FOREVER
1981 def scheduled(evtype):
1982 "When will this event happen?"
1983 return game.future[evtype].date
1985 def schedule(evtype, offset):
1986 "Schedule an event of specified type."
1987 game.future[evtype].date = game.state.date + offset
1988 return game.future[evtype]
1990 def postpone(evtype, offset):
1991 "Postpone a scheduled event."
1992 game.future[evtype].date += offset
1995 "Rest period is interrupted by event."
1998 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2000 game.resting = False
2006 "Run through the event queue looking for things to do."
2008 fintim = game.state.date + game.optime
2017 def tractorbeam(yank):
2018 "Tractor-beaming cases merge here."
2020 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2022 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2023 # If Kirk & Co. screwing around on planet, handle
2024 atover(True) # atover(true) is Grab
2027 if game.icraft: # Caught in Galileo?
2030 # Check to see if shuttle is aboard
2031 if game.iscraft == "offship":
2034 prout(_("Galileo, left on the planet surface, is captured"))
2035 prout(_("by aliens and made into a flying McDonald's."))
2036 game.damage[DSHUTTL] = -10
2037 game.iscraft = "removed"
2039 prout(_("Galileo, left on the planet surface, is well hidden."))
2041 game.quadrant = game.state.kscmdr
2043 game.quadrant = game.state.kcmdr[i]
2044 game.sector = randplace(QUADSIZE)
2045 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2046 % (game.quadrant, game.sector))
2048 prout(_("(Remainder of rest/repair period cancelled.)"))
2049 game.resting = False
2051 if not damaged(DSHIELD) and game.shield > 0:
2052 doshield(shraise=True) # raise shields
2053 game.shldchg = False
2055 prout(_("(Shields not currently useable.)"))
2057 # Adjust finish time to time of tractor beaming?
2058 # fintim = game.state.date+game.optime
2059 attack(torps_ok=False)
2060 if not game.state.kcmdr:
2063 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2066 "Code merges here for any commander destroying a starbase."
2067 # Not perfect, but will have to do
2068 # Handle case where base is in same quadrant as starship
2069 if game.battle == game.quadrant:
2070 game.state.chart[game.battle.i][game.battle.j].starbase = False
2071 game.quad[game.base.i][game.base.j] = '.'
2072 game.base.invalidate()
2075 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2076 elif game.state.baseq and communicating():
2077 # Get word via subspace radio
2080 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2081 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2083 prout(_("the Klingon Super-Commander"))
2085 prout(_("a Klingon Commander"))
2086 game.state.chart[game.battle.i][game.battle.j].starbase = False
2087 # Remove Starbase from galaxy
2088 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2089 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2091 # reinstate a commander's base attack
2095 game.battle.invalidate()
2097 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2098 for i in range(1, NEVENTS):
2099 if i == FSNOVA: proutn("=== Supernova ")
2100 elif i == FTBEAM: proutn("=== T Beam ")
2101 elif i == FSNAP: proutn("=== Snapshot ")
2102 elif i == FBATTAK: proutn("=== Base Attack ")
2103 elif i == FCDBAS: proutn("=== Base Destroy ")
2104 elif i == FSCMOVE: proutn("=== SC Move ")
2105 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2106 elif i == FDSPROB: proutn("=== Probe Move ")
2107 elif i == FDISTR: proutn("=== Distress Call ")
2108 elif i == FENSLV: proutn("=== Enslavement ")
2109 elif i == FREPRO: proutn("=== Klingon Build ")
2111 prout("%.2f" % (scheduled(i)))
2114 radio_was_broken = damaged(DRADIO)
2117 # Select earliest extraneous event, evcode==0 if no events
2122 for l in range(1, NEVENTS):
2123 if game.future[l].date < datemin:
2126 prout("== Event %d fires" % evcode)
2127 datemin = game.future[l].date
2128 xtime = datemin-game.state.date
2129 game.state.date = datemin
2130 # Decrement Federation resources and recompute remaining time
2131 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2133 if game.state.remtime <= 0:
2136 # Any crew left alive?
2137 if game.state.crew <= 0:
2140 # Is life support adequate?
2141 if damaged(DLIFSUP) and game.condition != "docked":
2142 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2145 game.lsupres -= xtime
2146 if game.damage[DLIFSUP] <= xtime:
2147 game.lsupres = game.inlsr
2150 if game.condition == "docked":
2152 # Don't fix Deathray here
2153 for l in range(NDEVICES):
2154 if game.damage[l] > 0.0 and l != DDRAY:
2155 if game.damage[l]-repair > 0.0:
2156 game.damage[l] -= repair
2158 game.damage[l] = 0.0
2159 # If radio repaired, update star chart and attack reports
2160 if radio_was_broken and not damaged(DRADIO):
2161 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2162 prout(_(" surveillance reports are coming in."))
2164 if not game.iseenit:
2168 prout(_(" The star chart is now up to date.\""))
2170 # Cause extraneous event EVCODE to occur
2171 game.optime -= xtime
2172 if evcode == FSNOVA: # Supernova
2175 schedule(FSNOVA, expran(0.5*game.intime))
2176 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2178 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2179 if game.state.nscrem == 0 or \
2180 ictbeam or istract or \
2181 game.condition == "docked" or game.isatb == 1 or game.iscate:
2183 if game.ientesc or \
2184 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2185 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2186 (damaged(DSHIELD) and \
2187 (game.energy < 2500 or damaged(DPHASER)) and \
2188 (game.torps < 5 or damaged(DPHOTON))):
2190 istract = ictbeam = True
2191 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2194 elif evcode == FTBEAM: # Tractor beam
2195 if not game.state.kcmdr:
2198 i = randrange(len(game.state.kcmdr))
2199 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2200 if istract or game.condition == "docked" or yank == 0:
2201 # Drats! Have to reschedule
2203 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2207 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2208 game.snapsht = copy.deepcopy(game.state)
2209 game.state.snap = True
2210 schedule(FSNAP, expran(0.5 * game.intime))
2211 elif evcode == FBATTAK: # Commander attacks starbase
2212 if not game.state.kcmdr or not game.state.baseq:
2218 for ibq in game.state.baseq:
2219 for cmdr in game.state.kcmdr:
2220 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2223 # no match found -- try later
2224 schedule(FBATTAK, expran(0.3*game.intime))
2229 # commander + starbase combination found -- launch attack
2231 schedule(FCDBAS, randreal(1.0, 4.0))
2232 if game.isatb: # extra time if SC already attacking
2233 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2234 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2235 game.iseenit = False
2236 if not communicating():
2237 continue # No warning :-(
2241 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2242 prout(_(" reports that it is under attack and that it can"))
2243 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2246 elif evcode == FSCDBAS: # Supercommander destroys base
2249 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2250 continue # WAS RETURN!
2252 game.battle = game.state.kscmdr
2254 elif evcode == FCDBAS: # Commander succeeds in destroying base
2255 if evcode == FCDBAS:
2257 if not game.state.baseq() \
2258 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2259 game.battle.invalidate()
2261 # find the lucky pair
2262 for cmdr in game.state.kcmdr:
2263 if cmdr == game.battle:
2266 # No action to take after all
2269 elif evcode == FSCMOVE: # Supercommander moves
2270 schedule(FSCMOVE, 0.2777)
2271 if not game.ientesc and not istract and game.isatb != 1 and \
2272 (not game.iscate or not game.justin):
2274 elif evcode == FDSPROB: # Move deep space probe
2275 schedule(FDSPROB, 0.01)
2276 if not game.probe.next():
2277 if not game.probe.quadrant().valid_quadrant() or \
2278 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2279 # Left galaxy or ran into supernova
2283 proutn(_("Lt. Uhura- \"The deep space probe "))
2284 if not game.probe.quadrant().valid_quadrant():
2285 prout(_("has left the galaxy.\""))
2287 prout(_("is no longer transmitting.\""))
2293 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2294 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2296 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2297 chp.klingons = pdest.klingons
2298 chp.starbase = pdest.starbase
2299 chp.stars = pdest.stars
2300 pdest.charted = True
2301 game.probe.moves -= 1 # One less to travel
2302 if game.probe.arrived() and game.isarmed and pdest.stars:
2303 supernova(game.probe) # fire in the hole!
2305 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2307 elif evcode == FDISTR: # inhabited system issues distress call
2309 # try a whole bunch of times to find something suitable
2310 for i in range(100):
2311 # need a quadrant which is not the current one,
2312 # which has some stars which are inhabited and
2313 # not already under attack, which is not
2314 # supernova'ed, and which has some Klingons in it
2315 w = randplace(GALSIZE)
2316 q = game.state.galaxy[w.i][w.j]
2317 if not (game.quadrant == w or q.planet == None or \
2318 not q.planet.inhabited or \
2319 q.supernova or q.status!="secure" or q.klingons<=0):
2322 # can't seem to find one; ignore this call
2324 prout("=== Couldn't find location for distress event.")
2326 # got one!! Schedule its enslavement
2327 ev = schedule(FENSLV, expran(game.intime))
2329 q.status = "distressed"
2330 # tell the captain about it if we can
2332 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2333 % (q.planet, repr(w)))
2334 prout(_("by a Klingon invasion fleet."))
2337 elif evcode == FENSLV: # starsystem is enslaved
2338 ev = unschedule(FENSLV)
2339 # see if current distress call still active
2340 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2344 q.status = "enslaved"
2346 # play stork and schedule the first baby
2347 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2348 ev2.quadrant = ev.quadrant
2350 # report the disaster if we can
2352 prout(_("Uhura- We've lost contact with starsystem %s") % \
2354 prout(_("in Quadrant %s.\n") % ev.quadrant)
2355 elif evcode == FREPRO: # Klingon reproduces
2356 # If we ever switch to a real event queue, we'll need to
2357 # explicitly retrieve and restore the x and y.
2358 ev = schedule(FREPRO, expran(1.0 * game.intime))
2359 # see if current distress call still active
2360 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2364 if game.state.remkl >= MAXKLGAME:
2365 continue # full right now
2366 # reproduce one Klingon
2369 if game.klhere >= MAXKLQUAD:
2371 # this quadrant not ok, pick an adjacent one
2372 for m.i in range(w.i - 1, w.i + 2):
2373 for m.j in range(w.j - 1, w.j + 2):
2374 if not m.valid_quadrant():
2376 q = game.state.galaxy[m.i][m.j]
2377 # check for this quad ok (not full & no snova)
2378 if q.klingons >= MAXKLQUAD or q.supernova:
2382 continue # search for eligible quadrant failed
2386 game.state.remkl += 1
2388 if game.quadrant == w:
2390 game.enemies.append(newkling())
2391 # recompute time left
2394 if game.quadrant == w:
2395 prout(_("Spock- sensors indicate the Klingons have"))
2396 prout(_("launched a warship from %s.") % q.planet)
2398 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2399 if q.planet != None:
2400 proutn(_("near %s ") % q.planet)
2401 prout(_("in Quadrant %s.") % w)
2407 key = scanner.next()
2410 proutn(_("How long? "))
2415 origTime = delay = scanner.real
2418 if delay >= game.state.remtime or len(game.enemies) != 0:
2419 proutn(_("Are you sure? "))
2422 # Alternate resting periods (events) with attacks
2426 game.resting = False
2427 if not game.resting:
2428 prout(_("%d stardates left.") % int(game.state.remtime))
2430 temp = game.optime = delay
2431 if len(game.enemies):
2432 rtime = randreal(1.0, 2.0)
2436 if game.optime < delay:
2437 attack(torps_ok=False)
2445 # Repair Deathray if long rest at starbase
2446 if origTime-delay >= 9.99 and game.condition == "docked":
2447 game.damage[DDRAY] = 0.0
2448 # leave if quadrant supernovas
2449 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2451 game.resting = False
2456 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2457 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2459 # Wow! We've supernova'ed
2460 supernova(game.quadrant)
2462 # handle initial nova
2463 game.quad[nov.i][nov.j] = '.'
2464 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2465 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2466 game.state.starkl += 1
2467 # Set up queue to recursively trigger adjacent stars
2473 for offset.i in range(-1, 1+1):
2474 for offset.j in range(-1, 1+1):
2475 if offset.j == 0 and offset.i == 0:
2477 neighbor = start + offset
2478 if not neighbor.valid_sector():
2480 iquad = game.quad[neighbor.i][neighbor.j]
2481 # Empty space ends reaction
2482 if iquad in ('.', '?', ' ', 'T', '#'):
2484 elif iquad == '*': # Affect another star
2486 # This star supernovas
2487 supernova(game.quadrant)
2490 hits.append(neighbor)
2491 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2492 game.state.starkl += 1
2493 proutn(crmena(True, '*', "sector", neighbor))
2495 game.quad[neighbor.i][neighbor.j] = '.'
2497 elif iquad in ('P', '@'): # Destroy planet
2498 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2500 game.state.nplankl += 1
2502 game.state.nworldkl += 1
2503 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2504 game.iplnet.pclass = "destroyed"
2506 game.plnet.invalidate()
2510 game.quad[neighbor.i][neighbor.j] = '.'
2511 elif iquad == 'B': # Destroy base
2512 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2513 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2514 game.base.invalidate()
2515 game.state.basekl += 1
2517 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2518 game.quad[neighbor.i][neighbor.j] = '.'
2519 elif iquad in ('E', 'F'): # Buffet ship
2520 prout(_("***Starship buffeted by nova."))
2522 if game.shield >= 2000.0:
2523 game.shield -= 2000.0
2525 diff = 2000.0 - game.shield
2529 prout(_("***Shields knocked out."))
2530 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2532 game.energy -= 2000.0
2533 if game.energy <= 0:
2536 # add in course nova contributes to kicking starship
2537 bump += (game.sector-hits[-1]).sgn()
2538 elif iquad == 'K': # kill klingon
2539 deadkl(neighbor, iquad, neighbor)
2540 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2541 for ll in range(len(game.enemies)):
2542 if game.enemies[ll].location == neighbor:
2544 game.enemies[ll].power -= 800.0 # If firepower is lost, die
2545 if game.enemies[ll].power <= 0.0:
2546 deadkl(neighbor, iquad, neighbor)
2548 newc = neighbor + neighbor - hits[-1]
2549 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2550 if not newc.valid_sector():
2551 # can't leave quadrant
2554 iquad1 = game.quad[newc.i][newc.j]
2556 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2558 deadkl(neighbor, iquad, newc)
2561 # can't move into something else
2564 proutn(_(", buffeted to Sector %s") % newc)
2565 game.quad[neighbor.i][neighbor.j] = '.'
2566 game.quad[newc.i][newc.j] = iquad
2567 game.enemies[ll].move(newc)
2568 # Starship affected by nova -- kick it away.
2570 direc = ncourse[3*(bump.i+1)+bump.j+2]
2575 scourse = course(bearing=direc, distance=dist)
2576 game.optime = scourse.time(warp=4)
2578 prout(_("Force of nova displaces starship."))
2579 imove(scourse, noattack=True)
2580 game.optime = scourse.time(warp=4)
2584 "Star goes supernova."
2589 # Scheduled supernova -- select star at random.
2592 for nq.i in range(GALSIZE):
2593 for nq.j in range(GALSIZE):
2594 stars += game.state.galaxy[nq.i][nq.j].stars
2596 return # nothing to supernova exists
2597 num = randrange(stars) + 1
2598 for nq.i in range(GALSIZE):
2599 for nq.j in range(GALSIZE):
2600 num -= game.state.galaxy[nq.i][nq.j].stars
2606 proutn("=== Super nova here?")
2609 if not nq == game.quadrant or game.justin:
2610 # it isn't here, or we just entered (treat as enroute)
2613 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2614 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2617 # we are in the quadrant!
2618 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2619 for ns.i in range(QUADSIZE):
2620 for ns.j in range(QUADSIZE):
2621 if game.quad[ns.i][ns.j]=='*':
2628 prouts(_("***RED ALERT! RED ALERT!"))
2630 prout(_("***Incipient supernova detected at Sector %s") % ns)
2631 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2632 proutn(_("Emergency override attempts t"))
2633 prouts("***************")
2637 # destroy any Klingons in supernovaed quadrant
2638 kldead = game.state.galaxy[nq.i][nq.j].klingons
2639 game.state.galaxy[nq.i][nq.j].klingons = 0
2640 if nq == game.state.kscmdr:
2641 # did in the Supercommander!
2642 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2646 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2647 comkills = len(game.state.kcmdr) - len(survivors)
2648 game.state.kcmdr = survivors
2650 if not game.state.kcmdr:
2652 game.state.remkl -= kldead
2653 # destroy Romulans and planets in supernovaed quadrant
2654 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2655 game.state.galaxy[nq.i][nq.j].romulans = 0
2656 game.state.nromrem -= nrmdead
2658 for loop in range(game.inplan):
2659 if game.state.planets[loop].quadrant == nq:
2660 game.state.planets[loop].pclass = "destroyed"
2662 # Destroy any base in supernovaed quadrant
2663 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2664 # If starship caused supernova, tally up destruction
2666 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2667 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2668 game.state.nplankl += npdead
2669 # mark supernova in galaxy and in star chart
2670 if game.quadrant == nq or communicating():
2671 game.state.galaxy[nq.i][nq.j].supernova = True
2672 # If supernova destroys last Klingons give special message
2673 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2676 prout(_("Lucky you!"))
2677 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2680 # if some Klingons remain, continue or die in supernova
2685 # Code from finish.c ends here.
2688 "Self-destruct maneuver. Finish with a BANG!"
2690 if damaged(DCOMPTR):
2691 prout(_("Computer damaged; cannot execute destruct sequence."))
2693 prouts(_("---WORKING---")); skip(1)
2694 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2695 prouts(" 10"); skip(1)
2696 prouts(" 9"); skip(1)
2697 prouts(" 8"); skip(1)
2698 prouts(" 7"); skip(1)
2699 prouts(" 6"); skip(1)
2701 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2703 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2705 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2708 if game.passwd != scanner.token:
2709 prouts(_("PASSWORD-REJECTED;"))
2711 prouts(_("CONTINUITY-EFFECTED"))
2714 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2715 prouts(" 5"); skip(1)
2716 prouts(" 4"); skip(1)
2717 prouts(" 3"); skip(1)
2718 prouts(" 2"); skip(1)
2719 prouts(" 1"); skip(1)
2721 prouts(_("GOODBYE-CRUEL-WORLD"))
2729 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2733 if len(game.enemies) != 0:
2734 whammo = 25.0 * game.energy
2735 for l in range(len(game.enemies)):
2736 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2737 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2741 "Compute our rate of kils over time."
2742 elapsed = game.state.date - game.indate
2743 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2746 starting = (game.inkling + game.incom + game.inscom)
2747 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2748 return (starting - remaining)/elapsed
2752 badpt = 5.0*game.state.starkl + \
2754 10.0*game.state.nplankl + \
2755 300*game.state.nworldkl + \
2757 100.0*game.state.basekl +\
2759 if game.ship == 'F':
2761 elif game.ship == None:
2766 # end the game, with appropriate notfications
2770 prout(_("It is stardate %.1f.") % game.state.date)
2772 if ifin == FWON: # Game has been won
2773 if game.state.nromrem != 0:
2774 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2777 prout(_("You have smashed the Klingon invasion fleet and saved"))
2778 prout(_("the Federation."))
2783 badpt = 0.0 # Close enough!
2784 # killsPerDate >= RateMax
2785 if game.state.date-game.indate < 5.0 or \
2786 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2788 prout(_("In fact, you have done so well that Starfleet Command"))
2789 if game.skill == SKILL_NOVICE:
2790 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2791 elif game.skill == SKILL_FAIR:
2792 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2793 elif game.skill == SKILL_GOOD:
2794 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2795 elif game.skill == SKILL_EXPERT:
2796 prout(_("promotes you to Commodore Emeritus."))
2798 prout(_("Now that you think you're really good, try playing"))
2799 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2800 elif game.skill == SKILL_EMERITUS:
2802 proutn(_("Computer- "))
2803 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2805 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2807 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2809 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2811 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2813 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2815 prout(_("Now you can retire and write your own Star Trek game!"))
2817 elif game.skill >= SKILL_EXPERT:
2818 if game.thawed and not game.idebug:
2819 prout(_("You cannot get a citation, so..."))
2821 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2825 # Only grant long life if alive (original didn't!)
2827 prout(_("LIVE LONG AND PROSPER."))
2832 elif ifin == FDEPLETE: # Federation Resources Depleted
2833 prout(_("Your time has run out and the Federation has been"))
2834 prout(_("conquered. Your starship is now Klingon property,"))
2835 prout(_("and you are put on trial as a war criminal. On the"))
2836 proutn(_("basis of your record, you are "))
2837 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2838 prout(_("acquitted."))
2840 prout(_("LIVE LONG AND PROSPER."))
2842 prout(_("found guilty and"))
2843 prout(_("sentenced to death by slow torture."))
2847 elif ifin == FLIFESUP:
2848 prout(_("Your life support reserves have run out, and"))
2849 prout(_("you die of thirst, starvation, and asphyxiation."))
2850 prout(_("Your starship is a derelict in space."))
2852 prout(_("Your energy supply is exhausted."))
2854 prout(_("Your starship is a derelict in space."))
2855 elif ifin == FBATTLE:
2856 prout(_("The %s has been destroyed in battle.") % crmshp())
2858 prout(_("Dulce et decorum est pro patria mori."))
2860 prout(_("You have made three attempts to cross the negative energy"))
2861 prout(_("barrier which surrounds the galaxy."))
2863 prout(_("Your navigation is abominable."))
2866 prout(_("Your starship has been destroyed by a nova."))
2867 prout(_("That was a great shot."))
2869 elif ifin == FSNOVAED:
2870 prout(_("The %s has been fried by a supernova.") % crmshp())
2871 prout(_("...Not even cinders remain..."))
2872 elif ifin == FABANDN:
2873 prout(_("You have been captured by the Klingons. If you still"))
2874 prout(_("had a starbase to be returned to, you would have been"))
2875 prout(_("repatriated and given another chance. Since you have"))
2876 prout(_("no starbases, you will be mercilessly tortured to death."))
2877 elif ifin == FDILITHIUM:
2878 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2879 elif ifin == FMATERIALIZE:
2880 prout(_("Starbase was unable to re-materialize your starship."))
2881 prout(_("Sic transit gloria mundi"))
2882 elif ifin == FPHASER:
2883 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2885 prout(_("You and your landing party have been"))
2886 prout(_("converted to energy, disipating through space."))
2887 elif ifin == FMINING:
2888 prout(_("You are left with your landing party on"))
2889 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2891 prout(_("They are very fond of \"Captain Kirk\" soup."))
2893 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2894 elif ifin == FDPLANET:
2895 prout(_("You and your mining party perish."))
2897 prout(_("That was a great shot."))
2900 prout(_("The Galileo is instantly annihilated by the supernova."))
2901 prout(_("You and your mining party are atomized."))
2903 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2904 prout(_("joins the Romulans, wreaking terror on the Federation."))
2905 elif ifin == FPNOVA:
2906 prout(_("You and your mining party are atomized."))
2908 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2909 prout(_("joins the Romulans, wreaking terror on the Federation."))
2910 elif ifin == FSTRACTOR:
2911 prout(_("The shuttle craft Galileo is also caught,"))
2912 prout(_("and breaks up under the strain."))
2914 prout(_("Your debris is scattered for millions of miles."))
2915 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2917 prout(_("The mutants attack and kill Spock."))
2918 prout(_("Your ship is captured by Klingons, and"))
2919 prout(_("your crew is put on display in a Klingon zoo."))
2920 elif ifin == FTRIBBLE:
2921 prout(_("Tribbles consume all remaining water,"))
2922 prout(_("food, and oxygen on your ship."))
2924 prout(_("You die of thirst, starvation, and asphyxiation."))
2925 prout(_("Your starship is a derelict in space."))
2927 prout(_("Your ship is drawn to the center of the black hole."))
2928 prout(_("You are crushed into extremely dense matter."))
2930 prout(_("Your last crew member has died."))
2931 if game.ship == 'F':
2933 elif game.ship == 'E':
2936 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2937 goodies = game.state.remres/game.inresor
2938 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2939 if goodies/baddies >= randreal(1.0, 1.5):
2940 prout(_("As a result of your actions, a treaty with the Klingon"))
2941 prout(_("Empire has been signed. The terms of the treaty are"))
2942 if goodies/baddies >= randreal(3.0):
2943 prout(_("favorable to the Federation."))
2945 prout(_("Congratulations!"))
2947 prout(_("highly unfavorable to the Federation."))
2949 prout(_("The Federation will be destroyed."))
2951 prout(_("Since you took the last Klingon with you, you are a"))
2952 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2953 prout(_("statue in your memory. Rest in peace, and try not"))
2954 prout(_("to think about pigeons."))
2959 "Compute player's score."
2960 timused = game.state.date - game.indate
2961 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2963 game.perdate = killrate()
2964 ithperd = 500*game.perdate + 0.5
2967 iwon = 100*game.skill
2968 if game.ship == 'E':
2970 elif game.ship == 'F':
2974 game.score = 10*(game.inkling - game.state.remkl) \
2975 + 50*(game.incom - len(game.state.kcmdr)) \
2977 + 20*(game.inrom - game.state.nromrem) \
2978 + 200*(game.inscom - game.state.nscrem) \
2979 - game.state.nromrem \
2984 prout(_("Your score --"))
2985 if game.inrom - game.state.nromrem:
2986 prout(_("%6d Romulans destroyed %5d") %
2987 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
2988 if game.state.nromrem and game.gamewon:
2989 prout(_("%6d Romulans captured %5d") %
2990 (game.state.nromrem, game.state.nromrem))
2991 if game.inkling - game.state.remkl:
2992 prout(_("%6d ordinary Klingons destroyed %5d") %
2993 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
2994 if game.incom - len(game.state.kcmdr):
2995 prout(_("%6d Klingon commanders destroyed %5d") %
2996 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
2997 if game.inscom - game.state.nscrem:
2998 prout(_("%6d Super-Commander destroyed %5d") %
2999 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3001 prout(_("%6.2f Klingons per stardate %5d") %
3002 (game.perdate, ithperd))
3003 if game.state.starkl:
3004 prout(_("%6d stars destroyed by your action %5d") %
3005 (game.state.starkl, -5*game.state.starkl))
3006 if game.state.nplankl:
3007 prout(_("%6d planets destroyed by your action %5d") %
3008 (game.state.nplankl, -10*game.state.nplankl))
3009 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3010 prout(_("%6d inhabited planets destroyed by your action %5d") %
3011 (game.state.nworldkl, -300*game.state.nworldkl))
3012 if game.state.basekl:
3013 prout(_("%6d bases destroyed by your action %5d") %
3014 (game.state.basekl, -100*game.state.basekl))
3016 prout(_("%6d calls for help from starbase %5d") %
3017 (game.nhelp, -45*game.nhelp))
3019 prout(_("%6d casualties incurred %5d") %
3020 (game.casual, -game.casual))
3022 prout(_("%6d crew abandoned in space %5d") %
3023 (game.abandoned, -3*game.abandoned))
3025 prout(_("%6d ship(s) lost or destroyed %5d") %
3026 (klship, -100*klship))
3028 prout(_("Penalty for getting yourself killed -200"))
3030 proutn(_("Bonus for winning "))
3031 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3032 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3033 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3034 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3035 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3036 prout(" %5d" % iwon)
3038 prout(_("TOTAL SCORE %5d") % game.score)
3041 "Emit winner's commemmorative plaque."
3044 proutn(_("File or device name for your plaque: "))
3047 fp = open(winner, "w")
3050 prout(_("Invalid name."))
3052 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3054 # The 38 below must be 64 for 132-column paper
3055 nskip = 38 - len(winner)/2
3056 fp.write("\n\n\n\n")
3057 # --------DRAW ENTERPRISE PICTURE.
3058 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3059 fp.write(" EEE E : : : E\n" )
3060 fp.write(" EE EEE E : : NCC-1701 : E\n")
3061 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3062 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3063 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3064 fp.write(" EEEEEEE EEEEE E E E E\n")
3065 fp.write(" EEE E E E E\n")
3066 fp.write(" E E E E\n")
3067 fp.write(" EEEEEEEEEEEEE E E\n")
3068 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3069 fp.write(" :E : EEEE E\n")
3070 fp.write(" .-E -:----- E\n")
3071 fp.write(" :E : E\n")
3072 fp.write(" EE : EEEEEEEE\n")
3073 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3075 fp.write(_(" U. S. S. ENTERPRISE\n"))
3076 fp.write("\n\n\n\n")
3077 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3079 fp.write(_(" Starfleet Command bestows to you\n"))
3081 fp.write("%*s%s\n\n" % (nskip, "", winner))
3082 fp.write(_(" the rank of\n\n"))
3083 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3085 if game.skill == SKILL_EXPERT:
3086 fp.write(_(" Expert level\n\n"))
3087 elif game.skill == SKILL_EMERITUS:
3088 fp.write(_("Emeritus level\n\n"))
3090 fp.write(_(" Cheat level\n\n"))
3091 timestring = time.ctime()
3092 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3093 (timestring+4, timestring+20, timestring+11))
3094 fp.write(_(" Your score: %d\n\n") % game.score)
3095 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3098 # Code from io.c begins here
3100 rows = linecount = 0 # for paging
3103 fullscreen_window = None
3104 srscan_window = None
3105 report_window = None
3106 status_window = None
3107 lrscan_window = None
3108 message_window = None
3109 prompt_window = None
3114 "for some recent versions of python2, the following enables UTF8"
3115 "for the older ones we probably need to set C locale, and the python3"
3116 "has no problems at all"
3117 if sys.version_info[0] < 3:
3119 locale.setlocale(locale.LC_ALL, "")
3120 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3121 gettext.textdomain("sst")
3122 if not (game.options & OPTION_CURSES):
3123 ln_env = os.getenv("LINES")
3129 stdscr = curses.initscr()
3133 if game.options & OPTION_COLOR:
3134 curses.start_color()
3135 curses.use_default_colors()
3136 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3137 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3138 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3139 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3140 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3141 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3142 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3143 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3144 global fullscreen_window, srscan_window, report_window, status_window
3145 global lrscan_window, message_window, prompt_window
3146 (rows, columns) = stdscr.getmaxyx()
3147 fullscreen_window = stdscr
3148 srscan_window = curses.newwin(12, 25, 0, 0)
3149 report_window = curses.newwin(11, 0, 1, 25)
3150 status_window = curses.newwin(10, 0, 1, 39)
3151 lrscan_window = curses.newwin(5, 0, 0, 64)
3152 message_window = curses.newwin(0, 0, 12, 0)
3153 prompt_window = curses.newwin(1, 0, rows-2, 0)
3154 message_window.scrollok(True)
3155 setwnd(fullscreen_window)
3159 if game.options & OPTION_CURSES:
3160 stdscr.keypad(False)
3166 "Wait for user action -- OK to do nothing if on a TTY"
3167 if game.options & OPTION_CURSES:
3172 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3176 if game.skill > SKILL_FAIR:
3177 prompt = _("[CONTINUE?]")
3179 prompt = _("[PRESS ENTER TO CONTINUE]")
3181 if game.options & OPTION_CURSES:
3183 setwnd(prompt_window)
3184 prompt_window.clear()
3185 prompt_window.addstr(prompt)
3186 prompt_window.getstr()
3187 prompt_window.clear()
3188 prompt_window.refresh()
3189 setwnd(message_window)
3192 sys.stdout.write('\n')
3196 sys.stdout.write('\n' * rows)
3200 "Skip i lines. Pause game if this would cause a scrolling event."
3201 for dummy in range(i):
3202 if game.options & OPTION_CURSES:
3203 (y, x) = curwnd.getyx()
3206 except curses.error:
3211 if rows and linecount >= rows:
3214 sys.stdout.write('\n')
3217 "Utter a line with no following line feed."
3218 if game.options & OPTION_CURSES:
3219 (y, x) = curwnd.getyx()
3220 (my, mx) = curwnd.getmaxyx()
3221 if curwnd == message_window and y >= my - 2:
3224 # Uncomment this to debug curses problems
3226 logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(line)))
3230 sys.stdout.write(line)
3240 if not replayfp or replayfp.closed: # Don't slow down replays
3243 if game.options & OPTION_CURSES:
3247 if not replayfp or replayfp.closed:
3251 "Get a line of input."
3252 if game.options & OPTION_CURSES:
3253 line = curwnd.getstr() + "\n"
3256 if replayfp and not replayfp.closed:
3258 line = replayfp.readline()
3261 prout("*** Replay finished")
3264 elif line[0] != "#":
3267 line = raw_input() + "\n"
3273 "Change windows -- OK for this to be a no-op in tty mode."
3275 if game.options & OPTION_CURSES:
3276 # Uncomment this to debug curses problems
3278 if wnd == fullscreen_window:
3279 legend = "fullscreen"
3280 elif wnd == srscan_window:
3282 elif wnd == report_window:
3284 elif wnd == status_window:
3286 elif wnd == lrscan_window:
3288 elif wnd == message_window:
3290 elif wnd == prompt_window:
3294 logfp.write("#curses: setwnd(%s)\n" % legend)
3296 # Some curses implementations get confused when you try this.
3298 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3299 except curses.error:
3303 "Clear to end of line -- can be a no-op in tty mode"
3304 if game.options & OPTION_CURSES:
3309 "Clear screen -- can be a no-op in tty mode."
3311 if game.options & OPTION_CURSES:
3317 def textcolor(color=DEFAULT):
3318 if game.options & OPTION_COLOR:
3319 if color == DEFAULT:
3321 elif color == BLACK:
3322 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3324 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3325 elif color == GREEN:
3326 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3328 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3330 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3331 elif color == MAGENTA:
3332 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3333 elif color == BROWN:
3334 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3335 elif color == LIGHTGRAY:
3336 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3337 elif color == DARKGRAY:
3338 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3339 elif color == LIGHTBLUE:
3340 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3341 elif color == LIGHTGREEN:
3342 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3343 elif color == LIGHTCYAN:
3344 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3345 elif color == LIGHTRED:
3346 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3347 elif color == LIGHTMAGENTA:
3348 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3349 elif color == YELLOW:
3350 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3351 elif color == WHITE:
3352 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3355 if game.options & OPTION_COLOR:
3356 curwnd.attron(curses.A_REVERSE)
3359 # Things past this point have policy implications.
3363 "Hook to be called after moving to redraw maps."
3364 if game.options & OPTION_CURSES:
3367 setwnd(srscan_window)
3371 setwnd(status_window)
3372 status_window.clear()
3373 status_window.move(0, 0)
3374 setwnd(report_window)
3375 report_window.clear()
3376 report_window.move(0, 0)
3378 setwnd(lrscan_window)
3379 lrscan_window.clear()
3380 lrscan_window.move(0, 0)
3381 lrscan(silent=False)
3383 def put_srscan_sym(w, sym):
3384 "Emit symbol for short-range scan."
3385 srscan_window.move(w.i+1, w.j*2+2)
3386 srscan_window.addch(sym)
3387 srscan_window.refresh()
3390 "Enemy fall down, go boom."
3391 if game.options & OPTION_CURSES:
3393 setwnd(srscan_window)
3394 srscan_window.attron(curses.A_REVERSE)
3395 put_srscan_sym(w, game.quad[w.i][w.j])
3399 srscan_window.attroff(curses.A_REVERSE)
3400 put_srscan_sym(w, game.quad[w.i][w.j])
3401 curses.delay_output(500)
3402 setwnd(message_window)
3405 "Sound and visual effects for teleportation."
3406 if game.options & OPTION_CURSES:
3408 setwnd(message_window)
3410 prouts(" . . . . . ")
3411 if game.options & OPTION_CURSES:
3412 #curses.delay_output(1000)
3416 def tracktorpedo(w, step, i, n, iquad):
3417 "Torpedo-track animation."
3418 if not game.options & OPTION_CURSES:
3422 proutn(_("Track for torpedo number %d- ") % (i+1))
3425 proutn(_("Torpedo track- "))
3426 elif step==4 or step==9:
3430 if not damaged(DSRSENS) or game.condition=="docked":
3431 if i != 0 and step == 1:
3434 if (iquad=='.') or (iquad==' '):
3435 put_srscan_sym(w, '+')
3439 put_srscan_sym(w, iquad)
3441 curwnd.attron(curses.A_REVERSE)
3442 put_srscan_sym(w, iquad)
3446 curwnd.attroff(curses.A_REVERSE)
3447 put_srscan_sym(w, iquad)
3452 "Display the current galaxy chart."
3453 if game.options & OPTION_CURSES:
3454 setwnd(message_window)
3455 message_window.clear()
3457 if game.options & OPTION_TTY:
3462 def prstat(txt, data):
3464 if game.options & OPTION_CURSES:
3466 setwnd(status_window)
3468 proutn(" " * (NSYM - len(txt)))
3471 if game.options & OPTION_CURSES:
3472 setwnd(report_window)
3474 # Code from moving.c begins here
3476 def imove(icourse=None, noattack=False):
3477 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3480 def newquadrant(noattack):
3481 # Leaving quadrant -- allow final enemy attack
3482 # Don't do it if being pushed by Nova
3483 if len(game.enemies) != 0 and not noattack:
3485 for enemy in game.enemies:
3486 finald = (w - enemy.location).distance()
3487 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3488 # Stas Sergeev added the condition
3489 # that attacks only happen if Klingons
3490 # are present and your skill is good.
3491 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3492 attack(torps_ok=False)
3495 # check for edge of galaxy
3499 if icourse.final.i < 0:
3500 icourse.final.i = -icourse.final.i
3502 if icourse.final.j < 0:
3503 icourse.final.j = -icourse.final.j
3505 if icourse.final.i >= GALSIZE*QUADSIZE:
3506 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3508 if icourse.final.j >= GALSIZE*QUADSIZE:
3509 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3517 if game.nkinks == 3:
3518 # Three strikes -- you're out!
3522 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3523 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3524 prout(_("YOU WILL BE DESTROYED."))
3525 # Compute final position in new quadrant
3526 if trbeam: # Don't bother if we are to be beamed
3528 game.quadrant = icourse.final.quadrant()
3529 game.sector = icourse.final.sector()
3531 prout(_("Entering Quadrant %s.") % game.quadrant)
3532 game.quad[game.sector.i][game.sector.j] = game.ship
3534 if game.skill>SKILL_NOVICE:
3535 attack(torps_ok=False)
3537 def check_collision(h):
3538 iquad = game.quad[h.i][h.j]
3540 # object encountered in flight path
3541 stopegy = 50.0*icourse.distance/game.optime
3542 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3543 for enemy in game.enemies:
3544 if enemy.location == game.sector:
3546 collision(rammed=False, enemy=enemy)
3550 prouts(_("***RED ALERT! RED ALERT!"))
3552 proutn("***" + crmshp())
3553 proutn(_(" pulled into black hole at Sector %s") % h)
3554 # Getting pulled into a black hole was certain
3555 # death in Almy's original. Stas Sergeev added a
3556 # possibility that you'll get timewarped instead.
3558 for m in range(NDEVICES):
3559 if game.damage[m]>0:
3561 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3562 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3572 prout(_(" encounters Tholian web at %s;") % h)
3574 prout(_(" blocked by object at %s;") % h)
3575 proutn(_("Emergency stop required "))
3576 prout(_("%2d units of energy.") % int(stopegy))
3577 game.energy -= stopegy
3578 if game.energy <= 0:
3585 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3586 game.inorbit = False
3587 # If tractor beam is to occur, don't move full distance
3588 if game.state.date+game.optime >= scheduled(FTBEAM):
3590 game.condition = "red"
3591 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3592 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3594 game.quad[game.sector.i][game.sector.j] = '.'
3595 for m in range(icourse.moves):
3597 w = icourse.sector()
3598 if icourse.origin.quadrant() != icourse.location.quadrant():
3599 newquadrant(noattack)
3601 elif check_collision(w):
3602 print "Collision detected"
3606 # We're in destination quadrant -- compute new average enemy distances
3607 game.quad[game.sector.i][game.sector.j] = game.ship
3609 for enemy in game.enemies:
3610 finald = (w-enemy.location).distance()
3611 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3612 enemy.kdist = finald
3614 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3615 attack(torps_ok=False)
3616 for enemy in game.enemies:
3617 enemy.kavgd = enemy.kdist
3620 setwnd(message_window)
3624 "Dock our ship at a starbase."
3626 if game.condition == "docked" and verbose:
3627 prout(_("Already docked."))
3630 prout(_("You must first leave standard orbit."))
3632 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3633 prout(crmshp() + _(" not adjacent to base."))
3635 game.condition = "docked"
3639 if game.energy < game.inenrg:
3640 game.energy = game.inenrg
3641 game.shield = game.inshld
3642 game.torps = game.intorps
3643 game.lsupres = game.inlsr
3644 game.state.crew = FULLCREW
3645 if not damaged(DRADIO) and \
3646 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3647 # get attack report from base
3648 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3652 def cartesian(loc1=None, loc2=None):
3654 return game.quadrant * QUADSIZE + game.sector
3656 return game.quadrant * QUADSIZE + loc1
3658 return loc1 * QUADSIZE + loc2
3660 def getcourse(isprobe):
3661 "Get a course and distance from the user."
3663 dquad = copy.copy(game.quadrant)
3664 navmode = "unspecified"
3668 if game.landed and not isprobe:
3669 prout(_("Dummy! You can't leave standard orbit until you"))
3670 proutn(_("are back aboard the ship."))
3673 while navmode == "unspecified":
3674 if damaged(DNAVSYS):
3676 prout(_("Computer damaged; manual navigation only"))
3678 prout(_("Computer damaged; manual movement only"))
3683 key = scanner.next()
3685 proutn(_("Manual or automatic- "))
3688 elif key == "IHALPHA":
3689 if scanner.sees("manual"):
3691 key = scanner.next()
3693 elif scanner.sees("automatic"):
3694 navmode = "automatic"
3695 key = scanner.next()
3703 prout(_("(Manual navigation assumed.)"))
3705 prout(_("(Manual movement assumed.)"))
3709 if navmode == "automatic":
3710 while key == "IHEOL":
3712 proutn(_("Target quadrant or quadrant§or- "))
3714 proutn(_("Destination sector or quadrant§or- "))
3717 key = scanner.next()
3721 xi = int(round(scanner.real))-1
3722 key = scanner.next()
3726 xj = int(round(scanner.real))-1
3727 key = scanner.next()
3729 # both quadrant and sector specified
3730 xk = int(round(scanner.real))-1
3731 key = scanner.next()
3735 xl = int(round(scanner.real))-1
3741 # only one pair of numbers was specified
3743 # only quadrant specified -- go to center of dest quad
3746 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3748 # only sector specified
3752 if not dquad.valid_quadrant() or not dsect.valid_sector():
3759 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3761 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3762 # the actual deltas get computed here
3763 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3764 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3766 while key == "IHEOL":
3767 proutn(_("X and Y displacements- "))
3770 key = scanner.next()
3775 delta.j = scanner.real
3776 key = scanner.next()
3780 delta.i = scanner.real
3781 # Check for zero movement
3782 if delta.i == 0 and delta.j == 0:
3785 if itemp == "verbose" and not isprobe:
3787 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3789 return course(bearing=delta.bearing(), distance=delta.distance())
3792 def __init__(self, bearing, distance, origin=None):
3793 self.distance = distance
3794 self.bearing = bearing
3796 self.origin = cartesian(game.quadrant, game.sector)
3798 self.origin = origin
3799 # The bearing() code we inherited from FORTRAN is actually computing
3800 # clockface directions!
3801 if self.bearing < 0.0:
3802 self.bearing += 12.0
3803 self.angle = ((15.0 - self.bearing) * 0.5235988)
3805 self.origin = cartesian(game.quadrant, game.sector)
3807 self.origin = cartesian(game.quadrant, origin)
3808 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
3809 bigger = max(abs(self.increment.i), abs(self.increment.j))
3810 self.increment /= bigger
3811 self.moves = int(round(10*self.distance*bigger))
3813 self.final = (self.location + self.moves*self.increment).roundtogrid()
3815 self.location = self.origin
3818 return self.location.roundtogrid() == self.final
3820 "Next step on course."
3822 self.nextlocation = self.location + self.increment
3823 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3824 self.location = self.nextlocation
3827 return self.location.quadrant()
3829 return self.location.sector()
3830 def power(self, warp):
3831 return self.distance*(warp**3)*(game.shldup+1)
3832 def time(self, warp):
3833 return 10.0*self.distance/warp**2
3836 "Move under impulse power."
3838 if damaged(DIMPULS):
3841 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3843 if game.energy > 30.0:
3845 course = getcourse(isprobe=False)
3848 power = 20.0 + 100.0*course.distance
3851 if power >= game.energy:
3852 # Insufficient power for trip
3854 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3855 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3856 if game.energy > 30:
3857 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3858 int(0.01 * (game.energy-20.0)-0.05))
3859 prout(_(" quadrants.\""))
3861 prout(_("quadrant. They are, therefore, useless.\""))
3864 # Make sure enough time is left for the trip
3865 game.optime = course.dist/0.095
3866 if game.optime >= game.state.remtime:
3867 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3868 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3869 proutn(_("we dare spend the time?\" "))
3872 # Activate impulse engines and pay the cost
3873 imove(course, noattack=False)
3877 power = 20.0 + 100.0*course.dist
3878 game.energy -= power
3879 game.optime = course.dist/0.095
3880 if game.energy <= 0:
3884 def warp(wcourse, involuntary):
3885 "ove under warp drive."
3886 blooey = False; twarp = False
3887 if not involuntary: # Not WARPX entry
3889 if game.damage[DWARPEN] > 10.0:
3892 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3894 if damaged(DWARPEN) and game.warpfac > 4.0:
3897 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3898 prout(_(" is repaired, I can only give you warp 4.\""))
3900 # Read in course and distance
3903 wcourse = getcourse(isprobe=False)
3906 # Make sure starship has enough energy for the trip
3907 # Note: this formula is slightly different from the C version,
3908 # and lets you skate a bit closer to the edge.
3909 if wcourse.power(game.warpfac) >= game.energy:
3910 # Insufficient power for trip
3913 prout(_("Engineering to bridge--"))
3914 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
3915 iwarp = (game.energy/(wcourse.dist+0.05)) ** 0.333333333
3917 prout(_("We can't do it, Captain. We don't have enough energy."))
3919 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3922 prout(_("if you'll lower the shields."))
3926 prout(_("We haven't the energy to go that far with the shields up."))
3928 # Make sure enough time is left for the trip
3929 game.optime = wcourse.time(game.warpfac)
3930 if game.optime >= 0.8*game.state.remtime:
3932 prout(_("First Officer Spock- \"Captain, I compute that such"))
3933 proutn(_(" a trip would require approximately %2.0f") %
3934 (100.0*game.optime/game.state.remtime))
3935 prout(_(" percent of our"))
3936 proutn(_(" remaining time. Are you sure this is wise?\" "))
3942 if game.warpfac > 6.0:
3943 # Decide if engine damage will occur
3944 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3945 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
3946 if prob > randreal():
3948 wcourse.distance = randreal(wcourse.distance)
3949 # Decide if time warp will occur
3950 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3952 if game.idebug and game.warpfac==10 and not twarp:
3954 proutn("=== Force time warp? ")
3958 # If time warp or engine damage, check path
3959 # If it is obstructed, don't do warp or damage
3960 look = wcourse.moves
3964 w = wcourse.sector()
3965 if not w.valid_sector():
3967 if game.quad[w.i][w.j] != '.':
3971 # Activate Warp Engines and pay the cost
3972 imove(wcourse, noattack=False)
3975 game.energy -= wcourse.power(game.warpfac)
3976 if game.energy <= 0:
3978 game.optime = wcourse.time(game.warpfac)
3982 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
3984 prout(_("Engineering to bridge--"))
3985 prout(_(" Scott here. The warp engines are damaged."))
3986 prout(_(" We'll have to reduce speed to warp 4."))
3991 "Change the warp factor."
3997 proutn(_("Warp factor- "))
4001 if game.damage[DWARPEN] > 10.0:
4002 prout(_("Warp engines inoperative."))
4004 if damaged(DWARPEN) and scanner.real > 4.0:
4005 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4006 prout(_(" but right now we can only go warp 4.\""))
4008 if scanner.real > 10.0:
4009 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4011 if scanner.real < 1.0:
4012 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4014 oldfac = game.warpfac
4015 game.warpfac = scanner.real
4016 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4017 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4020 if game.warpfac < 8.00:
4021 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4023 if game.warpfac == 10.0:
4024 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4026 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4030 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4032 # is captain on planet?
4034 if damaged(DTRANSP):
4037 prout(_("Scotty rushes to the transporter controls."))
4039 prout(_("But with the shields up it's hopeless."))
4041 prouts(_("His desperate attempt to rescue you . . ."))
4046 prout(_("SUCCEEDS!"))
4049 proutn(_("The crystals mined were "))
4057 # Check to see if captain in shuttle craft
4062 # Inform captain of attempt to reach safety
4066 prouts(_("***RED ALERT! RED ALERT!"))
4068 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4069 prouts(_(" a supernova."))
4071 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4072 prout(_("safely out of quadrant."))
4073 if not damaged(DRADIO):
4074 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4075 # Try to use warp engines
4076 if damaged(DWARPEN):
4078 prout(_("Warp engines damaged."))
4081 game.warpfac = randreal(6.0, 8.0)
4082 prout(_("Warp factor set to %d") % int(game.warpfac))
4083 power = 0.75*game.energy
4084 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4085 dist = max(dist, randreal(math.sqrt(2)))
4086 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4087 game.optime = bugout.time(game.warpfac)
4089 game.inorbit = False
4090 warp(bugout, involuntary=True)
4092 # This is bad news, we didn't leave quadrant.
4096 prout(_("Insufficient energy to leave quadrant."))
4099 # Repeat if another snova
4100 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4102 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4103 finish(FWON) # Snova killed remaining enemy.
4106 "Let's do the time warp again."
4107 prout(_("***TIME WARP ENTERED."))
4108 if game.state.snap and withprob(0.5):
4110 prout(_("You are traveling backwards in time %d stardates.") %
4111 int(game.state.date-game.snapsht.date))
4112 game.state = game.snapsht
4113 game.state.snap = False
4114 if len(game.state.kcmdr):
4115 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4116 schedule(FBATTAK, expran(0.3*game.intime))
4117 schedule(FSNOVA, expran(0.5*game.intime))
4118 # next snapshot will be sooner
4119 schedule(FSNAP, expran(0.25*game.state.remtime))
4121 if game.state.nscrem:
4122 schedule(FSCMOVE, 0.2777)
4126 game.battle.invalidate()
4127 # Make sure Galileo is consistant -- Snapshot may have been taken
4128 # when on planet, which would give us two Galileos!
4130 for l in range(game.inplan):
4131 if game.state.planets[l].known == "shuttle_down":
4133 if game.iscraft == "onship" and game.ship=='E':
4134 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4135 game.iscraft = "offship"
4136 # Likewise, if in the original time the Galileo was abandoned, but
4137 # was on ship earlier, it would have vanished -- let's restore it.
4138 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4139 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4140 game.iscraft = "onship"
4141 # There used to be code to do the actual reconstrction here,
4142 # but the starchart is now part of the snapshotted galaxy state.
4143 prout(_("Spock has reconstructed a correct star chart from memory"))
4145 # Go forward in time
4146 game.optime = expran(0.5*game.intime)
4147 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4148 # cheat to make sure no tractor beams occur during time warp
4149 postpone(FTBEAM, game.optime)
4150 game.damage[DRADIO] += game.optime
4152 events() # Stas Sergeev added this -- do pending events
4155 "Launch deep-space probe."
4156 # New code to launch a deep space probe
4157 if game.nprobes == 0:
4160 if game.ship == 'E':
4161 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4163 prout(_("Ye Faerie Queene has no deep space probes."))
4168 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4170 if is_scheduled(FDSPROB):
4173 if damaged(DRADIO) and game.condition != "docked":
4174 prout(_("Spock- \"Records show the previous probe has not yet"))
4175 prout(_(" reached its destination.\""))
4177 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4179 key = scanner.next()
4181 if game.nprobes == 1:
4182 prout(_("1 probe left."))
4184 prout(_("%d probes left") % game.nprobes)
4185 proutn(_("Are you sure you want to fire a probe? "))
4188 game.isarmed = False
4189 if key == "IHALPHA" and scanner.token == "armed":
4191 key = scanner.next()
4192 elif key == "IHEOL":
4193 proutn(_("Arm NOVAMAX warhead? "))
4195 elif key == "IHREAL": # first element of course
4196 scanner.push(scanner.token)
4198 game.probe = getcourse(isprobe=True)
4202 schedule(FDSPROB, 0.01) # Time to move one sector
4203 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4208 "Yell for help from nearest starbase."
4209 # There's more than one way to move in this game!
4211 # Test for conditions which prevent calling for help
4212 if game.condition == "docked":
4213 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4216 prout(_("Subspace radio damaged."))
4218 if not game.state.baseq:
4219 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4222 prout(_("You must be aboard the %s.") % crmshp())
4224 # OK -- call for help from nearest starbase
4227 # There's one in this quadrant
4228 ddist = (game.base - game.sector).distance()
4231 for ibq in game.state.baseq:
4232 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4235 # Since starbase not in quadrant, set up new quadrant
4238 # dematerialize starship
4239 game.quad[game.sector.i][game.sector.j]='.'
4240 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4241 % (game.quadrant, crmshp()))
4242 game.sector.invalidate()
4243 for m in range(1, 5+1):
4244 w = game.base.scatter()
4245 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4246 # found one -- finish up
4249 if not game.sector.is_valid():
4250 prout(_("You have been lost in space..."))
4251 finish(FMATERIALIZE)
4253 # Give starbase three chances to rematerialize starship
4254 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4255 for m in range(1, 3+1):
4256 if m == 1: proutn(_("1st"))
4257 elif m == 2: proutn(_("2nd"))
4258 elif m == 3: proutn(_("3rd"))
4259 proutn(_(" attempt to re-materialize ") + crmshp())
4260 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4263 if randreal() > probf:
4267 curses.delay_output(500)
4269 game.quad[game.sector.i][game.sector.j]='?'
4272 setwnd(message_window)
4273 finish(FMATERIALIZE)
4275 game.quad[game.sector.i][game.sector.j]=game.ship
4277 prout(_("succeeds."))
4281 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4286 if game.condition=="docked":
4288 prout(_("You cannot abandon Ye Faerie Queene."))
4291 # Must take shuttle craft to exit
4292 if game.damage[DSHUTTL]==-1:
4293 prout(_("Ye Faerie Queene has no shuttle craft."))
4295 if game.damage[DSHUTTL]<0:
4296 prout(_("Shuttle craft now serving Big Macs."))
4298 if game.damage[DSHUTTL]>0:
4299 prout(_("Shuttle craft damaged."))
4302 prout(_("You must be aboard the ship."))
4304 if game.iscraft != "onship":
4305 prout(_("Shuttle craft not currently available."))
4307 # Emit abandon ship messages
4309 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4311 prouts(_("***ALL HANDS ABANDON SHIP!"))
4313 prout(_("Captain and crew escape in shuttle craft."))
4314 if not game.state.baseq:
4315 # Oops! no place to go...
4318 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4320 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4321 prout(_("Remainder of ship's complement beam down"))
4322 prout(_("to nearest habitable planet."))
4323 elif q.planet != None and not damaged(DTRANSP):
4324 prout(_("Remainder of ship's complement beam down to %s.") %
4327 prout(_("Entire crew of %d left to die in outer space.") %
4329 game.casual += game.state.crew
4330 game.abandoned += game.state.crew
4331 # If at least one base left, give 'em the Faerie Queene
4333 game.icrystl = False # crystals are lost
4334 game.nprobes = 0 # No probes
4335 prout(_("You are captured by Klingons and released to"))
4336 prout(_("the Federation in a prisoner-of-war exchange."))
4337 nb = randrange(len(game.state.baseq))
4338 # Set up quadrant and position FQ adjacient to base
4339 if not game.quadrant == game.state.baseq[nb]:
4340 game.quadrant = game.state.baseq[nb]
4341 game.sector.i = game.sector.j = 5
4344 # position next to base by trial and error
4345 game.quad[game.sector.i][game.sector.j] = '.'
4346 for l in range(QUADSIZE):
4347 game.sector = game.base.scatter()
4348 if game.sector.valid_sector() and \
4349 game.quad[game.sector.i][game.sector.j] == '.':
4352 break # found a spot
4353 game.sector.i=QUADSIZE/2
4354 game.sector.j=QUADSIZE/2
4356 # Get new commission
4357 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4358 game.state.crew = FULLCREW
4359 prout(_("Starfleet puts you in command of another ship,"))
4360 prout(_("the Faerie Queene, which is antiquated but,"))
4361 prout(_("still useable."))
4363 prout(_("The dilithium crystals have been moved."))
4365 game.iscraft = "offship" # Galileo disappears
4367 game.condition="docked"
4368 for l in range(NDEVICES):
4369 game.damage[l] = 0.0
4370 game.damage[DSHUTTL] = -1
4371 game.energy = game.inenrg = 3000.0
4372 game.shield = game.inshld = 1250.0
4373 game.torps = game.intorps = 6
4374 game.lsupres=game.inlsr=3.0
4379 # Code from planets.c begins here.
4382 "Abort a lengthy operation if an event interrupts it."
4385 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4390 "Report on (uninhabited) planets in the galaxy."
4394 prout(_("Spock- \"Planet report follows, Captain.\""))
4396 for i in range(game.inplan):
4397 if game.state.planets[i].pclass == "destroyed":
4399 if (game.state.planets[i].known != "unknown" \
4400 and not game.state.planets[i].inhabited) \
4403 if game.idebug and game.state.planets[i].known=="unknown":
4404 proutn("(Unknown) ")
4405 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4406 proutn(_(" class "))
4407 proutn(game.state.planets[i].pclass)
4409 if game.state.planets[i].crystals != "present":
4411 prout(_("dilithium crystals present."))
4412 if game.state.planets[i].known=="shuttle_down":
4413 prout(_(" Shuttle Craft Galileo on surface."))
4415 prout(_("No information available."))
4418 "Enter standard orbit."
4422 prout(_("Already in standard orbit."))
4424 if damaged(DWARPEN) and damaged(DIMPULS):
4425 prout(_("Both warp and impulse engines damaged."))
4427 if not game.plnet.is_valid():
4428 prout("There is no planet in this sector.")
4430 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4431 prout(crmshp() + _(" not adjacent to planet."))
4434 game.optime = randreal(0.02, 0.05)
4435 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4439 game.height = randreal(1400, 8600)
4440 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4445 "Examine planets in this quadrant."
4446 if damaged(DSRSENS):
4447 if game.options & OPTION_TTY:
4448 prout(_("Short range sensors damaged."))
4450 if game.iplnet == None:
4451 if game.options & OPTION_TTY:
4452 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4454 if game.iplnet.known == "unknown":
4455 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4457 prout(_(" Planet at Sector %s is of class %s.") %
4458 (game.plnet, game.iplnet.pclass))
4459 if game.iplnet.known=="shuttle_down":
4460 prout(_(" Sensors show Galileo still on surface."))
4461 proutn(_(" Readings indicate"))
4462 if game.iplnet.crystals != "present":
4464 prout(_(" dilithium crystals present.\""))
4465 if game.iplnet.known == "unknown":
4466 game.iplnet.known = "known"
4467 elif game.iplnet.inhabited:
4468 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4469 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4472 "Use the transporter."
4476 if damaged(DTRANSP):
4477 prout(_("Transporter damaged."))
4478 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4480 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4484 if not game.inorbit:
4485 prout(crmshp() + _(" not in standard orbit."))
4488 prout(_("Impossible to transport through shields."))
4490 if game.iplnet.known=="unknown":
4491 prout(_("Spock- \"Captain, we have no information on this planet"))
4492 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4493 prout(_(" you may not go down.\""))
4495 if not game.landed and game.iplnet.crystals=="absent":
4496 prout(_("Spock- \"Captain, I fail to see the logic in"))
4497 prout(_(" exploring a planet with no dilithium crystals."))
4498 proutn(_(" Are you sure this is wise?\" "))
4502 if not (game.options & OPTION_PLAIN):
4503 nrgneed = 50 * game.skill + game.height / 100.0
4504 if nrgneed > game.energy:
4505 prout(_("Engineering to bridge--"))
4506 prout(_(" Captain, we don't have enough energy for transportation."))
4508 if not game.landed and nrgneed * 2 > game.energy:
4509 prout(_("Engineering to bridge--"))
4510 prout(_(" Captain, we have enough energy only to transport you down to"))
4511 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4512 if game.iplnet.known == "shuttle_down":
4513 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4514 proutn(_(" Are you sure this is wise?\" "))
4519 # Coming from planet
4520 if game.iplnet.known=="shuttle_down":
4521 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4525 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4526 prout(_("Landing party assembled, ready to beam up."))
4528 prout(_("Kirk whips out communicator..."))
4529 prouts(_("BEEP BEEP BEEP"))
4531 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4534 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4536 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4538 prout(_("Kirk- \"Energize.\""))
4541 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4544 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4546 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4549 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4550 game.landed = not game.landed
4551 game.energy -= nrgneed
4553 prout(_("Transport complete."))
4554 if game.landed and game.iplnet.known=="shuttle_down":
4555 prout(_("The shuttle craft Galileo is here!"))
4556 if not game.landed and game.imine:
4563 "Strip-mine a world for dilithium."
4567 prout(_("Mining party not on planet."))
4569 if game.iplnet.crystals == "mined":
4570 prout(_("This planet has already been strip-mined for dilithium."))
4572 elif game.iplnet.crystals == "absent":
4573 prout(_("No dilithium crystals on this planet."))
4576 prout(_("You've already mined enough crystals for this trip."))
4578 if game.icrystl and game.cryprob == 0.05:
4579 prout(_("With all those fresh crystals aboard the ") + crmshp())
4580 prout(_("there's no reason to mine more at this time."))
4582 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4585 prout(_("Mining operation complete."))
4586 game.iplnet.crystals = "mined"
4587 game.imine = game.ididit = True
4590 "Use dilithium crystals."
4594 if not game.icrystl:
4595 prout(_("No dilithium crystals available."))
4597 if game.energy >= 1000:
4598 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4599 prout(_(" except when Condition Yellow exists."))
4601 prout(_("Spock- \"Captain, I must warn you that loading"))
4602 prout(_(" raw dilithium crystals into the ship's power"))
4603 prout(_(" system may risk a severe explosion."))
4604 proutn(_(" Are you sure this is wise?\" "))
4609 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4610 prout(_(" Mr. Spock and I will try it.\""))
4612 prout(_("Spock- \"Crystals in place, Sir."))
4613 prout(_(" Ready to activate circuit.\""))
4615 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4617 if withprob(game.cryprob):
4618 prouts(_(" \"Activating now! - - No good! It's***"))
4620 prouts(_("***RED ALERT! RED A*L********************************"))
4623 prouts(_("****************** KA-BOOM!!!! *******************"))
4627 game.energy += randreal(5000.0, 5500.0)
4628 prouts(_(" \"Activating now! - - "))
4629 prout(_("The instruments"))
4630 prout(_(" are going crazy, but I think it's"))
4631 prout(_(" going to work!! Congratulations, Sir!\""))
4636 "Use shuttlecraft for planetary jaunt."
4639 if damaged(DSHUTTL):
4640 if game.damage[DSHUTTL] == -1.0:
4641 if game.inorbit and game.iplnet.known == "shuttle_down":
4642 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4644 prout(_("Ye Faerie Queene had no shuttle craft."))
4645 elif game.damage[DSHUTTL] > 0:
4646 prout(_("The Galileo is damaged."))
4647 else: # game.damage[DSHUTTL] < 0
4648 prout(_("Shuttle craft is now serving Big Macs."))
4650 if not game.inorbit:
4651 prout(crmshp() + _(" not in standard orbit."))
4653 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4654 prout(_("Shuttle craft not currently available."))
4656 if not game.landed and game.iplnet.known=="shuttle_down":
4657 prout(_("You will have to beam down to retrieve the shuttle craft."))
4659 if game.shldup or game.condition == "docked":
4660 prout(_("Shuttle craft cannot pass through shields."))
4662 if game.iplnet.known=="unknown":
4663 prout(_("Spock- \"Captain, we have no information on this planet"))
4664 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4665 prout(_(" you may not fly down.\""))
4667 game.optime = 3.0e-5*game.height
4668 if game.optime >= 0.8*game.state.remtime:
4669 prout(_("First Officer Spock- \"Captain, I compute that such"))
4670 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4671 int(100*game.optime/game.state.remtime))
4672 prout(_("remaining time."))
4673 proutn(_("Are you sure this is wise?\" "))
4679 if game.iscraft == "onship":
4681 if not damaged(DTRANSP):
4682 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4686 proutn(_("Shuttle crew"))
4688 proutn(_("Rescue party"))
4689 prout(_(" boards Galileo and swoops toward planet surface."))
4690 game.iscraft = "offship"
4694 game.iplnet.known="shuttle_down"
4695 prout(_("Trip complete."))
4698 # Ready to go back to ship
4699 prout(_("You and your mining party board the"))
4700 prout(_("shuttle craft for the trip back to the Enterprise."))
4702 prouts(_("The short hop begins . . ."))
4704 game.iplnet.known="known"
4710 game.iscraft = "onship"
4716 prout(_("Trip complete."))
4719 # Kirk on ship and so is Galileo
4720 prout(_("Mining party assembles in the hangar deck,"))
4721 prout(_("ready to board the shuttle craft \"Galileo\"."))
4723 prouts(_("The hangar doors open; the trip begins."))
4726 game.iscraft = "offship"
4729 game.iplnet.known = "shuttle_down"
4732 prout(_("Trip complete."))
4736 "Use the big zapper."
4740 if game.ship != 'E':
4741 prout(_("Ye Faerie Queene has no death ray."))
4743 if len(game.enemies)==0:
4744 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4747 prout(_("Death Ray is damaged."))
4749 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4750 prout(_(" is highly unpredictible. Considering the alternatives,"))
4751 proutn(_(" are you sure this is wise?\" "))
4754 prout(_("Spock- \"Acknowledged.\""))
4757 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4759 prout(_("Crew scrambles in emergency preparation."))
4760 prout(_("Spock and Scotty ready the death ray and"))
4761 prout(_("prepare to channel all ship's power to the device."))
4763 prout(_("Spock- \"Preparations complete, sir.\""))
4764 prout(_("Kirk- \"Engage!\""))
4766 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4769 if game.options & OPTION_PLAIN:
4773 prouts(_("Sulu- \"Captain! It's working!\""))
4775 while len(game.enemies) > 0:
4776 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4777 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4778 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4780 if (game.options & OPTION_PLAIN) == 0:
4781 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4783 prout(_(" is still operational.\""))
4785 prout(_(" has been rendered nonfunctional.\""))
4786 game.damage[DDRAY] = 39.95
4788 r = randreal() # Pick failure method
4790 prouts(_("Sulu- \"Captain! It's working!\""))
4792 prouts(_("***RED ALERT! RED ALERT!"))
4794 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4796 prouts(_("***RED ALERT! RED A*L********************************"))
4799 prouts(_("****************** KA-BOOM!!!! *******************"))
4804 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4806 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4808 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4809 prout(_(" have apparently been transformed into strange mutations."))
4810 prout(_(" Vulcans do not seem to be affected."))
4812 prout(_("Kirk- \"Raauch! Raauch!\""))
4816 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4818 proutn(_("Spock- \"I believe the word is"))
4819 prouts(_(" *ASTONISHING*"))
4820 prout(_(" Mr. Sulu."))
4821 for i in range(QUADSIZE):
4822 for j in range(QUADSIZE):
4823 if game.quad[i][j] == '.':
4824 game.quad[i][j] = '?'
4825 prout(_(" Captain, our quadrant is now infested with"))
4826 prouts(_(" - - - - - - *THINGS*."))
4828 prout(_(" I have no logical explanation.\""))
4830 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4832 prout(_("Scotty- \"There are so many tribbles down here"))
4833 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4837 # Code from reports.c begins here
4839 def attackreport(curt):
4840 "eport status of bases under attack."
4842 if is_scheduled(FCDBAS):
4843 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4844 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4845 elif game.isatb == 1:
4846 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4847 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4849 prout(_("No Starbase is currently under attack."))
4851 if is_scheduled(FCDBAS):
4852 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4854 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4858 # report on general game status
4860 s1 = (game.thawed and _("thawed ")) or ""
4861 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4862 s3 = (None, _("novice"), _("fair"),
4863 _("good"), _("expert"), _("emeritus"))[game.skill]
4864 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4865 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4866 prout(_("No plaque is allowed."))
4868 prout(_("This is tournament game %d.") % game.tourn)
4869 prout(_("Your secret password is \"%s\"") % game.passwd)
4870 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4871 (game.inkling + game.incom + game.inscom)))
4872 if game.incom - len(game.state.kcmdr):
4873 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4874 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4875 prout(_(", but no Commanders."))
4878 if game.skill > SKILL_FAIR:
4879 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4880 if len(game.state.baseq) != game.inbase:
4882 if game.inbase-len(game.state.baseq)==1:
4883 proutn(_("has been 1 base"))
4885 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4886 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4888 prout(_("There are %d bases.") % game.inbase)
4889 if communicating() or game.iseenit:
4890 # Don't report this if not seen and
4891 # either the radio is dead or not at base!
4895 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4897 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4898 if game.ship == 'E':
4899 proutn(_("You have "))
4901 proutn("%d" % (game.nprobes))
4904 proutn(_(" deep space probe"))
4908 if communicating() and is_scheduled(FDSPROB):
4910 proutn(_("An armed deep space probe is in "))
4912 proutn(_("A deep space probe is in "))
4913 prout("Quadrant %s." % game.probec)
4915 if game.cryprob <= .05:
4916 prout(_("Dilithium crystals aboard ship... not yet used."))
4920 while game.cryprob > ai:
4923 prout(_("Dilithium crystals have been used %d time%s.") % \
4924 (i, (_("s"), "")[i==1]))
4928 "Long-range sensor scan."
4929 if damaged(DLRSENS):
4930 # Now allow base's sensors if docked
4931 if game.condition != "docked":
4933 prout(_("LONG-RANGE SENSORS DAMAGED."))
4936 prout(_("Starbase's long-range scan"))
4938 prout(_("Long-range scan"))
4939 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4942 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4943 if not Coord(x, y).valid_quadrant():
4947 if not damaged(DRADIO):
4948 game.state.galaxy[x][y].charted = True
4949 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4950 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4951 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4952 if not silent and game.state.galaxy[x][y].supernova:
4955 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4963 for i in range(NDEVICES):
4966 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4967 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4969 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4970 game.damage[i]+0.05,
4971 DOCKFAC*game.damage[i]+0.005))
4973 prout(_("All devices functional."))
4976 "Update the chart in the Enterprise's computer from galaxy data."
4977 game.lastchart = game.state.date
4978 for i in range(GALSIZE):
4979 for j in range(GALSIZE):
4980 if game.state.galaxy[i][j].charted:
4981 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
4982 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
4983 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
4986 "Display the star chart."
4988 if (game.options & OPTION_AUTOSCAN):
4990 if not damaged(DRADIO):
4992 if game.lastchart < game.state.date and game.condition == "docked":
4993 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
4995 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
4996 if game.state.date > game.lastchart:
4997 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
4998 prout(" 1 2 3 4 5 6 7 8")
4999 for i in range(GALSIZE):
5000 proutn("%d |" % (i+1))
5001 for j in range(GALSIZE):
5002 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5006 if game.state.galaxy[i][j].supernova:
5008 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5010 elif game.state.galaxy[i][j].charted:
5011 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5015 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5023 def sectscan(goodScan, i, j):
5024 "Light up an individual dot in a sector."
5025 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5026 textcolor({"green":GREEN,
5030 "dead":BROWN}[game.condition])
5031 if game.quad[i][j] != game.ship:
5033 proutn("%c " % game.quad[i][j])
5039 "Emit status report lines"
5040 if not req or req == 1:
5041 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5042 % (game.state.date, game.state.remtime))
5043 if not req or req == 2:
5044 if game.condition != "docked":
5046 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5047 (game.condition.upper(), sum(map(lambda x: x > 0, game.damage))))
5048 if not req or req == 3:
5049 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5050 if not req or req == 4:
5051 if damaged(DLIFSUP):
5052 if game.condition == "docked":
5053 s = _("DAMAGED, Base provides")
5055 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5058 prstat(_("Life Support"), s)
5059 if not req or req == 5:
5060 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5061 if not req or req == 6:
5063 if game.icrystl and (game.options & OPTION_SHOWME):
5064 extra = _(" (have crystals)")
5065 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5066 if not req or req == 7:
5067 prstat(_("Torpedoes"), "%d" % (game.torps))
5068 if not req or req == 8:
5069 if damaged(DSHIELD):
5075 data = _(" %d%% %.1f units") \
5076 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5077 prstat(_("Shields"), s+data)
5078 if not req or req == 9:
5079 prstat(_("Klingons Left"), "%d" \
5080 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5081 if not req or req == 10:
5082 if game.options & OPTION_WORLDS:
5083 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5084 if plnet and plnet.inhabited:
5085 prstat(_("Major system"), plnet.name)
5087 prout(_("Sector is uninhabited"))
5088 elif not req or req == 11:
5089 attackreport(not req)
5092 "Request specified status data, a historical relic from slow TTYs."
5093 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5094 while scanner.next() == "IHEOL":
5095 proutn(_("Information desired? "))
5097 if scanner.token in requests:
5098 status(requests.index(scanner.token))
5100 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5101 prout((" date, condition, position, lsupport, warpfactor,"))
5102 prout((" energy, torpedoes, shields, klingons, system, time."))
5107 if damaged(DSRSENS):
5108 # Allow base's sensors if docked
5109 if game.condition != "docked":
5110 prout(_(" S.R. SENSORS DAMAGED!"))
5113 prout(_(" [Using Base's sensors]"))
5115 prout(_(" Short-range scan"))
5116 if goodScan and not damaged(DRADIO):
5117 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5118 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5119 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5120 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5121 prout(" 1 2 3 4 5 6 7 8 9 10")
5122 if game.condition != "docked":
5124 for i in range(QUADSIZE):
5125 proutn("%2d " % (i+1))
5126 for j in range(QUADSIZE):
5127 sectscan(goodScan, i, j)
5131 "Use computer to get estimated time of arrival for a warp jump."
5132 w1 = Coord(); w2 = Coord()
5134 if damaged(DCOMPTR):
5135 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5138 if scanner.next() != "IHREAL":
5141 proutn(_("Destination quadrant and/or sector? "))
5142 if scanner.next()!="IHREAL":
5145 w1.j = int(scanner.real-0.5)
5146 if scanner.next() != "IHREAL":
5149 w1.i = int(scanner.real-0.5)
5150 if scanner.next() == "IHREAL":
5151 w2.j = int(scanner.real-0.5)
5152 if scanner.next() != "IHREAL":
5155 w2.i = int(scanner.real-0.5)
5157 if game.quadrant.j>w1.i:
5161 if game.quadrant.i>w1.j:
5165 if not w1.valid_quadrant() or not w2.valid_sector():
5168 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5169 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5172 prout(_("Answer \"no\" if you don't know the value:"))
5175 proutn(_("Time or arrival date? "))
5176 if scanner.next()=="IHREAL":
5177 ttime = scanner.real
5178 if ttime > game.state.date:
5179 ttime -= game.state.date # Actually a star date
5180 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5181 if ttime <= 1e-10 or twarp > 10:
5182 prout(_("We'll never make it, sir."))
5189 proutn(_("Warp factor? "))
5190 if scanner.next()== "IHREAL":
5192 twarp = scanner.real
5193 if twarp<1.0 or twarp > 10.0:
5197 prout(_("Captain, certainly you can give me one of these."))
5200 ttime = (10.0*dist)/twarp**2
5201 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5202 if tpower >= game.energy:
5203 prout(_("Insufficient energy, sir."))
5204 if not game.shldup or tpower > game.energy*2.0:
5207 proutn(_("New warp factor to try? "))
5208 if scanner.next() == "IHREAL":
5210 twarp = scanner.real
5211 if twarp<1.0 or twarp > 10.0:
5219 prout(_("But if you lower your shields,"))
5220 proutn(_("remaining"))
5223 proutn(_("Remaining"))
5224 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5226 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5228 prout(_("Any warp speed is adequate."))
5230 prout(_("Minimum warp needed is %.2f,") % (twarp))
5231 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5232 if game.state.remtime < ttime:
5233 prout(_("Unfortunately, the Federation will be destroyed by then."))
5235 prout(_("You'll be taking risks at that speed, Captain"))
5236 if (game.isatb==1 and game.state.kscmdr == w1 and \
5237 scheduled(FSCDBAS)< ttime+game.state.date) or \
5238 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5239 prout(_("The starbase there will be destroyed by then."))
5240 proutn(_("New warp factor to try? "))
5241 if scanner.next() == "IHREAL":
5243 twarp = scanner.real
5244 if twarp<1.0 or twarp > 10.0:
5252 # Code from setup.c begins here
5255 "Issue a historically correct banner."
5257 prout(_("-SUPER- STAR TREK"))
5259 # From the FORTRAN original
5260 # prout(_("Latest update-21 Sept 78"))
5266 scanner.push("emsave.trk")
5267 key = scanner.next()
5269 proutn(_("File name: "))
5270 key = scanner.next()
5271 if key != "IHALPHA":
5274 if '.' not in scanner.token:
5275 scanner.token += ".trk"
5277 fp = open(scanner.token, "wb")
5279 prout(_("Can't freeze game as file %s") % scanner.token)
5281 cPickle.dump(game, fp)
5286 "Retrieve saved game."
5289 key = scanner.next()
5291 proutn(_("File name: "))
5292 key = scanner.next()
5293 if key != "IHALPHA":
5296 if '.' not in scanner.token:
5297 scanner.token += ".trk"
5299 fp = open(scanner.token, "rb")
5301 prout(_("Can't thaw game in %s") % scanner.token)
5303 game = cPickle.load(fp)
5308 # I used <http://www.memory-alpha.org> to find planets
5309 # with references in ST:TOS. Earth and the Alpha Centauri
5310 # Colony have been omitted.
5312 # Some planets marked Class G and P here will be displayed as class M
5313 # because of the way planets are generated. This is a known bug.
5316 _("Andoria (Fesoan)"), # several episodes
5317 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5318 _("Vulcan (T'Khasi)"), # many episodes
5319 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5320 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5321 _("Ardana"), # TOS: "The Cloud Minders"
5322 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5323 _("Gideon"), # TOS: "The Mark of Gideon"
5324 _("Aldebaran III"), # TOS: "The Deadly Years"
5325 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5326 _("Altair IV"), # TOS: "Amok Time
5327 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5328 _("Benecia"), # TOS: "The Conscience of the King"
5329 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5330 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5331 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5332 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5333 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5334 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5335 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5336 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5337 _("Ingraham B"), # TOS: "Operation: Annihilate"
5338 _("Janus IV"), # TOS: "The Devil in the Dark"
5339 _("Makus III"), # TOS: "The Galileo Seven"
5340 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5341 _("Omega IV"), # TOS: "The Omega Glory"
5342 _("Regulus V"), # TOS: "Amok Time
5343 _("Deneva"), # TOS: "Operation -- Annihilate!"
5344 # Worlds from BSD Trek
5345 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5346 _("Beta III"), # TOS: "The Return of the Archons"
5347 _("Triacus"), # TOS: "And the Children Shall Lead",
5348 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5350 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5351 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5352 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5353 # _("Izar"), # TOS: "Whom Gods Destroy"
5354 # _("Tiburon"), # TOS: "The Way to Eden"
5355 # _("Merak II"), # TOS: "The Cloud Minders"
5356 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5357 # _("Iotia"), # TOS: "A Piece of the Action"
5361 _("S. R. Sensors"), \
5362 _("L. R. Sensors"), \
5364 _("Photon Tubes"), \
5365 _("Life Support"), \
5366 _("Warp Engines"), \
5367 _("Impulse Engines"), \
5369 _("Subspace Radio"), \
5370 _("Shuttle Craft"), \
5372 _("Navigation System"), \
5374 _("Shield Control"), \
5380 "Prepare to play, set up cosmos."
5382 # Decide how many of everything
5384 return # frozen game
5385 # Prepare the Enterprise
5386 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5388 game.state.crew = FULLCREW
5389 game.energy = game.inenrg = 5000.0
5390 game.shield = game.inshld = 2500.0
5393 game.quadrant = randplace(GALSIZE)
5394 game.sector = randplace(QUADSIZE)
5395 game.torps = game.intorps = 10
5396 game.nprobes = randrange(2, 5)
5398 for i in range(NDEVICES):
5399 game.damage[i] = 0.0
5400 # Set up assorted game parameters
5401 game.battle = Coord()
5402 game.state.date = game.indate = 100.0 * randreal(20, 51)
5403 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5404 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5405 game.isatb = game.state.nplankl = 0
5406 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5407 game.iscraft = "onship"
5412 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5414 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5416 game.state.planets = [] # Planet information
5417 game.state.baseq = [] # Base quadrant coordinates
5418 game.state.kcmdr = [] # Commander quadrant coordinates
5419 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5421 # Starchart is functional but we've never seen it
5422 game.lastchart = FOREVER
5423 # Put stars in the galaxy
5425 for i in range(GALSIZE):
5426 for j in range(GALSIZE):
5427 k = randrange(1, QUADSIZE**2/10+1)
5429 game.state.galaxy[i][j].stars = k
5430 # Locate star bases in galaxy
5431 for i in range(game.inbase):
5434 w = randplace(GALSIZE)
5435 if not game.state.galaxy[w.i][w.j].starbase:
5438 # C version: for (j = i-1; j > 0; j--)
5439 # so it did them in the opposite order.
5440 for j in range(1, i):
5441 # Improved placement algorithm to spread out bases
5442 distq = (w - game.state.baseq[j]).distance()
5443 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5446 prout("=== Abandoning base #%d at %s" % (i, w))
5448 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5450 prout("=== Saving base #%d, close to #%d" % (i, j))
5453 game.state.baseq.append(w)
5454 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5455 # Position ordinary Klingon Battle Cruisers
5457 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5458 if klumper > MAXKLQUAD:
5462 klump = (1.0 - r*r)*klumper
5467 w = randplace(GALSIZE)
5468 if not game.state.galaxy[w.i][w.j].supernova and \
5469 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5471 game.state.galaxy[w.i][w.j].klingons += int(klump)
5474 # Position Klingon Commander Ships
5475 for i in range(game.incom):
5477 w = randplace(GALSIZE)
5478 if not welcoming(w) or w in game.state.kcmdr:
5480 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5482 game.state.galaxy[w.i][w.j].klingons += 1
5483 game.state.kcmdr.append(w)
5484 # Locate planets in galaxy
5485 for i in range(game.inplan):
5487 w = randplace(GALSIZE)
5488 if game.state.galaxy[w.i][w.j].planet == None:
5492 new.crystals = "absent"
5493 if (game.options & OPTION_WORLDS) and i < NINHAB:
5494 new.pclass = "M" # All inhabited planets are class M
5495 new.crystals = "absent"
5497 new.name = systnames[i]
5498 new.inhabited = True
5500 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5502 new.crystals = "present"
5503 new.known = "unknown"
5504 new.inhabited = False
5505 game.state.galaxy[w.i][w.j].planet = new
5506 game.state.planets.append(new)
5508 for i in range(game.state.nromrem):
5509 w = randplace(GALSIZE)
5510 game.state.galaxy[w.i][w.j].romulans += 1
5511 # Place the Super-Commander if needed
5512 if game.state.nscrem > 0:
5514 w = randplace(GALSIZE)
5517 game.state.kscmdr = w
5518 game.state.galaxy[w.i][w.j].klingons += 1
5519 # Initialize times for extraneous events
5520 schedule(FSNOVA, expran(0.5 * game.intime))
5521 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5522 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5523 schedule(FBATTAK, expran(0.3*game.intime))
5525 if game.state.nscrem:
5526 schedule(FSCMOVE, 0.2777)
5531 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5532 schedule(FDISTR, expran(1.0 + game.intime))
5537 # Place thing (in tournament game, we don't want one!)
5538 # New in SST2K: never place the Thing near a starbase.
5539 # This makes sense and avoids a special case in the old code.
5541 if game.tourn is None:
5543 thing = randplace(GALSIZE)
5544 if thing not in game.state.baseq:
5547 game.state.snap = False
5548 if game.skill == SKILL_NOVICE:
5549 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5550 prout(_("a deadly Klingon invasion force. As captain of the United"))
5551 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5552 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5553 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5554 prout(_("your mission. As you proceed you may be given more time."))
5556 prout(_("You will have %d supporting starbases.") % (game.inbase))
5557 proutn(_("Starbase locations- "))
5559 prout(_("Stardate %d.") % int(game.state.date))
5561 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5562 prout(_("An unknown number of Romulans."))
5563 if game.state.nscrem:
5564 prout(_("And one (GULP) Super-Commander."))
5565 prout(_("%d stardates.") % int(game.intime))
5566 proutn(_("%d starbases in ") % game.inbase)
5567 for i in range(game.inbase):
5568 proutn(`game.state.baseq[i]`)
5571 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5572 proutn(_(" Sector %s") % game.sector)
5574 prout(_("Good Luck!"))
5575 if game.state.nscrem:
5576 prout(_(" YOU'LL NEED IT."))
5579 setwnd(message_window)
5581 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5583 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5584 attack(torps_ok=False)
5587 "Choose your game type."
5589 game.tourn = game.length = 0
5591 game.skill = SKILL_NONE
5593 # if not scanner.inqueue: # Can start with command line options
5594 proutn(_("Would you like a regular, tournament, or saved game? "))
5596 if scanner.sees("tournament"):
5597 while scanner.next() == "IHEOL":
5598 proutn(_("Type in tournament number-"))
5599 if scanner.real == 0:
5601 continue # We don't want a blank entry
5602 game.tourn = int(round(scanner.real))
5603 random.seed(scanner.real)
5605 logfp.write("# random.seed(%d)\n" % scanner.real)
5607 if scanner.sees("saved") or scanner.sees("frozen"):
5611 if game.passwd == None:
5613 if not game.alldone:
5614 game.thawed = True # No plaque if not finished
5618 if scanner.sees("regular"):
5620 proutn(_("What is \"%s\"? ") % scanner.token)
5622 while game.length==0 or game.skill==SKILL_NONE:
5623 if scanner.next() == "IHALPHA":
5624 if scanner.sees("short"):
5626 elif scanner.sees("medium"):
5628 elif scanner.sees("long"):
5630 elif scanner.sees("novice"):
5631 game.skill = SKILL_NOVICE
5632 elif scanner.sees("fair"):
5633 game.skill = SKILL_FAIR
5634 elif scanner.sees("good"):
5635 game.skill = SKILL_GOOD
5636 elif scanner.sees("expert"):
5637 game.skill = SKILL_EXPERT
5638 elif scanner.sees("emeritus"):
5639 game.skill = SKILL_EMERITUS
5641 proutn(_("What is \""))
5642 proutn(scanner.token)
5647 proutn(_("Would you like a Short, Medium, or Long game? "))
5648 elif game.skill == SKILL_NONE:
5649 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5650 # Choose game options -- added by ESR for SST2K
5651 if scanner.next() != "IHALPHA":
5653 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5655 if scanner.sees("plain"):
5656 # Approximates the UT FORTRAN version.
5657 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5658 game.options |= OPTION_PLAIN
5659 elif scanner.sees("almy"):
5660 # Approximates Tom Almy's version.
5661 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5662 game.options |= OPTION_ALMY
5663 elif scanner.sees("fancy") or scanner.sees("\n"):
5665 elif len(scanner.token):
5666 proutn(_("What is \"%s\"?") % scanner.token)
5667 game.options &=~ OPTION_COLOR
5669 if game.passwd == "debug":
5671 prout("=== Debug mode enabled.")
5672 # Use parameters to generate initial values of things
5673 game.damfac = 0.5 * game.skill
5674 game.inbase = randrange(BASEMIN, BASEMAX+1)
5676 if game.options & OPTION_PLANETS:
5677 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5678 if game.options & OPTION_WORLDS:
5679 game.inplan += int(NINHAB)
5680 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5681 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5682 game.state.remtime = 7.0 * game.length
5683 game.intime = game.state.remtime
5684 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5685 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5686 game.state.remres = (game.inkling+4*game.incom)*game.intime
5687 game.inresor = game.state.remres
5688 if game.inkling > 50:
5689 game.state.inbase += 1
5692 def dropin(iquad=None):
5693 "Drop a feature on a random dot in the current quadrant."
5695 w = randplace(QUADSIZE)
5696 if game.quad[w.i][w.j] == '.':
5698 if iquad is not None:
5699 game.quad[w.i][w.j] = iquad
5703 "Update our alert status."
5704 game.condition = "green"
5705 if game.energy < 1000.0:
5706 game.condition = "yellow"
5707 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5708 game.condition = "red"
5710 game.condition="dead"
5713 "Drop new Klingon into current quadrant."
5714 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5717 "Sort enemies by distance so 'nearest' is meaningful."
5718 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
5721 "Set up a new state of quadrant, for when we enter or re-enter it."
5724 game.neutz = game.inorbit = game.landed = False
5725 game.ientesc = game.iseenit = False
5726 # Create a blank quadrant
5727 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5729 # Attempt to escape Super-commander, so tbeam back!
5732 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5733 # cope with supernova
5736 game.klhere = q.klingons
5737 game.irhere = q.romulans
5739 game.quad[game.sector.i][game.sector.j] = game.ship
5742 # Position ordinary Klingons
5743 for i in range(game.klhere):
5745 # If we need a commander, promote a Klingon
5746 for cmdr in game.state.kcmdr:
5747 if cmdr == game.quadrant:
5748 e = game.enemies[game.klhere-1]
5749 game.quad[e.location.i][e.location.j] = 'C'
5750 e.power = randreal(950,1350) + 50.0*game.skill
5752 # If we need a super-commander, promote a Klingon
5753 if game.quadrant == game.state.kscmdr:
5755 game.quad[e.location.i][e.location.j] = 'S'
5756 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5757 game.iscate = (game.state.remkl > 1)
5758 # Put in Romulans if needed
5759 for i in range(q.romulans):
5760 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5761 # If quadrant needs a starbase, put it in
5763 game.base = dropin('B')
5764 # If quadrant needs a planet, put it in
5766 game.iplnet = q.planet
5767 if not q.planet.inhabited:
5768 game.plnet = dropin('P')
5770 game.plnet = dropin('@')
5771 # Check for condition
5774 if game.irhere > 0 and game.klhere == 0:
5776 if not damaged(DRADIO):
5778 prout(_("LT. Uhura- \"Captain, an urgent message."))
5779 prout(_(" I'll put it on audio.\" CLICK"))
5781 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5782 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5783 # Put in THING if needed
5784 if thing == game.quadrant:
5785 Enemy(type='?', loc=dropin(),
5786 power=randreal(6000,6500.0)+250.0*game.skill)
5787 if not damaged(DSRSENS):
5789 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5790 prout(_(" Please examine your short-range scan.\""))
5791 # Decide if quadrant needs a Tholian; lighten up if skill is low
5792 if game.options & OPTION_THOLIAN:
5793 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5794 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5795 (game.skill > SKILL_GOOD and withprob(0.08)):
5798 w.i = withprob(0.5) * (QUADSIZE-1)
5799 w.j = withprob(0.5) * (QUADSIZE-1)
5800 if game.quad[w.i][w.j] == '.':
5802 game.tholian = Enemy(type='T', loc=w,
5803 power=randrange(100, 500) + 25.0*game.skill)
5804 # Reserve unoccupied corners
5805 if game.quad[0][0]=='.':
5806 game.quad[0][0] = 'X'
5807 if game.quad[0][QUADSIZE-1]=='.':
5808 game.quad[0][QUADSIZE-1] = 'X'
5809 if game.quad[QUADSIZE-1][0]=='.':
5810 game.quad[QUADSIZE-1][0] = 'X'
5811 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5812 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5814 # And finally the stars
5815 for i in range(q.stars):
5817 # Put in a few black holes
5818 for i in range(1, 3+1):
5821 # Take out X's in corners if Tholian present
5823 if game.quad[0][0]=='X':
5824 game.quad[0][0] = '.'
5825 if game.quad[0][QUADSIZE-1]=='X':
5826 game.quad[0][QUADSIZE-1] = '.'
5827 if game.quad[QUADSIZE-1][0]=='X':
5828 game.quad[QUADSIZE-1][0] = '.'
5829 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5830 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5833 "Set the self-destruct password."
5834 if game.options & OPTION_PLAIN:
5837 proutn(_("Please type in a secret password- "))
5839 game.passwd = scanner.token
5840 if game.passwd != None:
5844 game.passwd += chr(ord('a')+randrange(26))
5845 game.passwd += chr(ord('a')+randrange(26))
5846 game.passwd += chr(ord('a')+randrange(26))
5848 # Code from sst.c begins here
5851 ("SRSCAN", OPTION_TTY),
5852 ("STATUS", OPTION_TTY),
5853 ("REQUEST", OPTION_TTY),
5854 ("LRSCAN", OPTION_TTY),
5867 ("SENSORS", OPTION_PLANETS),
5868 ("ORBIT", OPTION_PLANETS),
5869 ("TRANSPORT", OPTION_PLANETS),
5870 ("MINE", OPTION_PLANETS),
5871 ("CRYSTALS", OPTION_PLANETS),
5872 ("SHUTTLE", OPTION_PLANETS),
5873 ("PLANETS", OPTION_PLANETS),
5878 ("PROBE", OPTION_PROBE),
5880 ("FREEZE", 0), # Synonym for SAVE
5886 ("SOS", 0), # Synonym for MAYDAY
5887 ("CALL", 0), # Synonym for MAYDAY
5894 "Generate a list of legal commands."
5895 prout(_("LEGAL COMMANDS ARE:"))
5897 for (key, opt) in commands:
5898 if not opt or (opt & game.options):
5899 proutn("%-12s " % key)
5901 if emitted % 5 == 4:
5906 "Browse on-line help."
5907 key = scanner.next()
5910 setwnd(prompt_window)
5911 proutn(_("Help on what command? "))
5912 key = scanner.next()
5913 setwnd(message_window)
5916 cmds = map(lambda x: x[0], commands)
5917 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
5924 cmd = scanner.token.upper()
5925 for directory in docpath:
5927 fp = open(os.path.join(directory, "sst.doc"), "r")
5932 prout(_("Spock- \"Captain, that information is missing from the"))
5933 prout(_(" computer. You need to find sst.doc and put it somewhere"))
5934 proutn(_(" in these directories: %s") % ":".join(docpath))
5936 # This used to continue: "You need to find SST.DOC and put
5937 # it in the current directory."
5940 linebuf = fp.readline()
5942 prout(_("Spock- \"Captain, there is no information on that command.\""))
5945 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5946 linebuf = linebuf[3:].strip()
5947 if cmd.upper() == linebuf:
5950 prout(_("Spock- \"Captain, I've found the following information:\""))
5953 linebuf = fp.readline()
5954 if "******" in linebuf:
5960 "Command-interpretation loop."
5961 while True: # command loop
5963 while True: # get a command
5965 game.optime = game.justin = False
5967 setwnd(prompt_window)
5970 if scanner.next() == "IHEOL":
5971 if game.options & OPTION_CURSES:
5974 elif scanner.token == "":
5978 setwnd(message_window)
5980 abandon_passed = False
5981 for (cmd, opt) in commands:
5982 # commands after ABANDON cannot be abbreviated
5983 if cmd == "ABANDON":
5984 abandon_passed = True
5985 if cmd == scanner.token.upper() or (not abandon_passed \
5986 and cmd.startswith(scanner.token.upper())):
5993 if cmd == "SRSCAN": # srscan
5995 elif cmd == "STATUS": # status
5997 elif cmd == "REQUEST": # status request
5999 elif cmd == "LRSCAN": # long range scan
6000 lrscan(silent=False)
6001 elif cmd == "PHASERS": # phasers
6005 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6009 elif cmd == "MOVE": # move under warp
6010 warp(wcourse=None, involuntary=False)
6011 elif cmd == "SHIELDS": # shields
6012 doshield(shraise=False)
6015 game.shldchg = False
6016 elif cmd == "DOCK": # dock at starbase
6019 attack(torps_ok=False)
6020 elif cmd == "DAMAGES": # damage reports
6022 elif cmd == "CHART": # chart
6024 elif cmd == "IMPULSE": # impulse
6026 elif cmd == "REST": # rest
6030 elif cmd == "WARP": # warp
6032 elif cmd == "SCORE": # score
6034 elif cmd == "SENSORS": # sensors
6036 elif cmd == "ORBIT": # orbit
6040 elif cmd == "TRANSPORT": # transport "beam"
6042 elif cmd == "MINE": # mine
6046 elif cmd == "CRYSTALS": # crystals
6050 elif cmd == "SHUTTLE": # shuttle
6054 elif cmd == "PLANETS": # Planet list
6056 elif cmd == "REPORT": # Game Report
6058 elif cmd == "COMPUTER": # use COMPUTER!
6060 elif cmd == "COMMANDS":
6062 elif cmd == "EMEXIT": # Emergency exit
6063 clrscr() # Hide screen
6064 freeze(True) # forced save
6065 raise SystemExit,1 # And quick exit
6066 elif cmd == "PROBE":
6067 probe() # Launch probe
6070 elif cmd == "ABANDON": # Abandon Ship
6072 elif cmd == "DESTRUCT": # Self Destruct
6074 elif cmd == "SAVE": # Save Game
6077 if game.skill > SKILL_GOOD:
6078 prout(_("WARNING--Saved games produce no plaques!"))
6079 elif cmd == "DEATHRAY": # Try a desparation measure
6083 elif cmd == "DEBUGCMD": # What do we want for debug???
6085 elif cmd == "MAYDAY": # Call for help
6090 game.alldone = True # quit the game
6095 break # Game has ended
6096 if game.optime != 0.0:
6099 break # Events did us in
6100 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6103 if hitme and not game.justin:
6104 attack(torps_ok=True)
6107 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6118 "Emit the name of an enemy or feature."
6119 if type == 'R': s = _("Romulan")
6120 elif type == 'K': s = _("Klingon")
6121 elif type == 'C': s = _("Commander")
6122 elif type == 'S': s = _("Super-commander")
6123 elif type == '*': s = _("Star")
6124 elif type == 'P': s = _("Planet")
6125 elif type == 'B': s = _("Starbase")
6126 elif type == ' ': s = _("Black hole")
6127 elif type == 'T': s = _("Tholian")
6128 elif type == '#': s = _("Tholian web")
6129 elif type == '?': s = _("Stranger")
6130 elif type == '@': s = _("Inhabited World")
6131 else: s = "Unknown??"
6134 def crmena(stars, enemy, loctype, w):
6135 "Emit the name of an enemy and his location."
6139 buf += cramen(enemy) + _(" at ")
6140 if loctype == "quadrant":
6141 buf += _("Quadrant ")
6142 elif loctype == "sector":
6147 "Emit our ship name."
6148 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6151 "Emit a line of stars"
6152 prouts("******************************************************")
6156 return -avrage*math.log(1e-7 + randreal())
6158 def randplace(size):
6159 "Choose a random location."
6161 w.i = randrange(size)
6162 w.j = randrange(size)
6172 # Get a token from the user
6175 # Fill the token quue if nothing here
6176 while not self.inqueue:
6178 if curwnd==prompt_window:
6180 setwnd(message_window)
6187 self.inqueue = line.lstrip().split() + ["\n"]
6188 # From here on in it's all looking at the queue
6189 self.token = self.inqueue.pop(0)
6190 if self.token == "\n":
6194 self.real = float(self.token)
6195 self.type = "IHREAL"
6200 self.token = self.token.lower()
6201 self.type = "IHALPHA"
6204 def append(self, tok):
6205 self.inqueue.append(tok)
6206 def push(self, tok):
6207 self.inqueue.insert(0, tok)
6211 # Demand input for next scan
6213 self.real = self.token = None
6215 # compares s to item and returns true if it matches to the length of s
6216 return s.startswith(self.token)
6218 # Round token value to nearest integer
6219 return int(round(scanner.real))
6223 if scanner.type != "IHREAL":
6226 s.i = scanner.int()-1
6228 if scanner.type != "IHREAL":
6231 s.j = scanner.int()-1
6234 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6237 "Yes-or-no confirmation."
6241 if scanner.token == 'y':
6243 if scanner.token == 'n':
6246 proutn(_("Please answer with \"y\" or \"n\": "))
6249 "Complain about unparseable input."
6252 prout(_("Beg your pardon, Captain?"))
6255 "Access to the internals for debugging."
6256 proutn("Reset levels? ")
6258 if game.energy < game.inenrg:
6259 game.energy = game.inenrg
6260 game.shield = game.inshld
6261 game.torps = game.intorps
6262 game.lsupres = game.inlsr
6263 proutn("Reset damage? ")
6265 for i in range(NDEVICES):
6266 if game.damage[i] > 0.0:
6267 game.damage[i] = 0.0
6268 proutn("Toggle debug flag? ")
6270 game.idebug = not game.idebug
6272 prout("Debug output ON")
6274 prout("Debug output OFF")
6275 proutn("Cause selective damage? ")
6277 for i in range(NDEVICES):
6278 proutn("Kill %s?" % device[i])
6280 key = scanner.next()
6281 if key == "IHALPHA" and scanner.sees("y"):
6282 game.damage[i] = 10.0
6283 proutn("Examine/change events? ")
6288 FSNOVA: "Supernova ",
6291 FBATTAK: "Base Attack ",
6292 FCDBAS: "Base Destroy ",
6293 FSCMOVE: "SC Move ",
6294 FSCDBAS: "SC Base Destroy ",
6295 FDSPROB: "Probe Move ",
6296 FDISTR: "Distress Call ",
6297 FENSLV: "Enslavement ",
6298 FREPRO: "Klingon Build ",
6300 for i in range(1, NEVENTS):
6303 proutn("%.2f" % (scheduled(i)-game.state.date))
6304 if i == FENSLV or i == FREPRO:
6306 proutn(" in %s" % ev.quadrant)
6311 key = scanner.next()
6315 elif key == "IHREAL":
6316 ev = schedule(i, scanner.real)
6317 if i == FENSLV or i == FREPRO:
6319 proutn("In quadrant- ")
6320 key = scanner.next()
6321 # "IHEOL" says to leave coordinates as they are
6324 prout("Event %d canceled, no x coordinate." % (i))
6327 w.i = int(round(scanner.real))
6328 key = scanner.next()
6330 prout("Event %d canceled, no y coordinate." % (i))
6333 w.j = int(round(scanner.real))
6336 proutn("Induce supernova here? ")
6338 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6341 if __name__ == '__main__':
6342 import getopt, socket
6344 global line, thing, game
6348 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6349 if os.getenv("TERM"):
6350 game.options |= OPTION_CURSES
6352 game.options |= OPTION_TTY
6353 seed = int(time.time())
6354 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6356 for (switch, val) in options:
6359 replayfp = open(val, "r")
6361 sys.stderr.write("sst: can't open replay file %s\n" % val)
6364 line = replayfp.readline().strip()
6365 (leader, __, seed) = line.split()
6367 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6368 line = replayfp.readline().strip()
6369 arguments += line.split()[2:]
6372 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6374 game.options |= OPTION_TTY
6375 game.options &=~ OPTION_CURSES
6376 elif switch == '-s':
6378 elif switch == '-t':
6379 game.options |= OPTION_TTY
6380 game.options &=~ OPTION_CURSES
6381 elif switch == '-x':
6383 elif switch == '-V':
6384 print "SST2K", version
6387 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6389 # where to save the input in case of bugs
6390 if "TMPDIR" in os.environ:
6391 tmpdir = os.environ['TMPDIR']
6395 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6397 sys.stderr.write("sst: warning, can't open logfile\n")
6400 logfp.write("# seed %s\n" % seed)
6401 logfp.write("# options %s\n" % " ".join(arguments))
6402 logfp.write("# recorded by %s@%s on %s\n" % \
6403 (getpass.getuser(),socket.gethostname(),time.ctime()))
6405 scanner = sstscanner()
6406 map(scanner.append, arguments)
6409 while True: # Play a game
6410 setwnd(fullscreen_window)
6416 game.alldone = False
6424 if game.tourn and game.alldone:
6425 proutn(_("Do you want your score recorded?"))
6431 proutn(_("Do you want to play again? "))
6435 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6439 except KeyboardInterrupt: