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)
535 old_dist = enemy.kdist
536 mdist = int(old_dist + 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 * old_dist + 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
652 return (enemy, old_dist, goto)
655 "Sequence Klingon tactical movement."
658 # Figure out which Klingon is the commander (or Supercommander)
661 if game.quadrant in game.state.kcmdr:
662 for enemy in game.enemies:
663 if enemy.type == 'C':
664 tacmoves.append(movebaddy(enemy))
665 if game.state.kscmdr == game.quadrant:
666 for enemy in game.enemies:
667 if enemy.type == 'S':
668 tacmoves.append(movebaddy(enemy))
670 # If skill level is high, move other Klingons and Romulans too!
671 # Move these last so they can base their actions on what the
673 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
674 for enemy in game.enemies:
675 if enemy.type in ('K', 'R'):
676 tacmoves.append(movebaddy(enemy))
679 def movescom(iq, avoid):
680 "Commander movement helper."
681 # Avoid quadrants with bases if we want to avoid Enterprise
682 if not welcoming(iq) or (avoid and iq in game.state.baseq):
684 if game.justin and not game.iscate:
687 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
688 game.state.kscmdr = iq
689 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
690 if game.state.kscmdr == game.quadrant:
691 # SC has scooted, remove him from current quadrant
696 for enemy in game.enemies:
697 if enemy.type == 'S':
700 if game.condition != "docked":
703 # check for a helpful planet
704 for i in range(game.inplan):
705 if game.state.planets[i].quadrant == game.state.kscmdr and \
706 game.state.planets[i].crystals == "present":
708 game.state.planets[i].pclass = "destroyed"
709 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
712 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
713 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
714 prout(_(" by the Super-commander.\""))
716 return True # looks good!
718 def supercommander():
719 "Move the Super Commander."
726 prout("== SUPERCOMMANDER")
727 # Decide on being active or passive
728 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 \
729 (game.state.date-game.indate) < 3.0)
730 if not game.iscate and avoid:
731 # compute move away from Enterprise
732 idelta = game.state.kscmdr-game.quadrant
733 if idelta.distance() > 2.0:
735 idelta.i = game.state.kscmdr.j-game.quadrant.j
736 idelta.j = game.quadrant.i-game.state.kscmdr.i
738 # compute distances to starbases
739 if not game.state.baseq:
743 sc = game.state.kscmdr
744 for (i, base) in enumerate(game.state.baseq):
745 basetbl.append((i, (base - sc).distance()))
746 if game.state.baseq > 1:
747 basetbl.sort(lambda x, y: cmp(x[1], y[1]))
748 # look for nearest base without a commander, no Enterprise, and
749 # without too many Klingons, and not already under attack.
750 ifindit = iwhichb = 0
751 for (i2, base) in enumerate(game.state.baseq):
752 i = basetbl[i2][0] # bug in original had it not finding nearest
753 if base == game.quadrant or base == game.battle or not welcoming(base):
755 # if there is a commander, and no other base is appropriate,
756 # we will take the one with the commander
757 for cmdr in game.state.kcmdr:
758 if base == cmdr and ifindit != 2:
762 else: # no commander -- use this one
767 return # Nothing suitable -- wait until next time
768 ibq = game.state.baseq[iwhichb]
769 # decide how to move toward base
770 idelta = ibq - game.state.kscmdr
771 # Maximum movement is 1 quadrant in either or both axes
772 idelta = idelta.sgn()
773 # try moving in both x and y directions
774 # there was what looked like a bug in the Almy C code here,
775 # but it might be this translation is just wrong.
776 iq = game.state.kscmdr + idelta
777 if not movescom(iq, avoid):
778 # failed -- try some other maneuvers
779 if idelta.i == 0 or idelta.j == 0:
782 iq.j = game.state.kscmdr.j + 1
783 if not movescom(iq, avoid):
784 iq.j = game.state.kscmdr.j - 1
787 iq.i = game.state.kscmdr.i + 1
788 if not movescom(iq, avoid):
789 iq.i = game.state.kscmdr.i - 1
792 # try moving just in x or y
793 iq.j = game.state.kscmdr.j
794 if not movescom(iq, avoid):
795 iq.j = game.state.kscmdr.j + idelta.j
796 iq.i = game.state.kscmdr.i
799 if len(game.state.baseq) == 0:
802 for ibq in game.state.baseq:
803 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
806 return # no, don't attack base!
809 schedule(FSCDBAS, randreal(1.0, 3.0))
810 if is_scheduled(FCDBAS):
811 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
812 if not communicating():
816 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
818 prout(_(" reports that it is under attack from the Klingon Super-commander."))
819 proutn(_(" It can survive until stardate %d.\"") \
820 % int(scheduled(FSCDBAS)))
823 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
827 game.optime = 0.0 # actually finished
829 # Check for intelligence report
830 if not game.idebug and \
832 (not communicating()) or \
833 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
836 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
837 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
842 if not game.tholian or game.justin:
845 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
848 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
851 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
854 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
858 # something is wrong!
859 game.tholian.move(None)
860 prout("***Internal error: Tholian in a bad spot.")
862 # do nothing if we are blocked
863 if game.quad[tid.i][tid.j] not in ('.', '#'):
865 here = copy.copy(game.tholian.location)
866 delta = (tid - game.tholian.location).sgn()
868 while here.i != tid.i:
870 if game.quad[here.i][here.j] == '.':
871 game.tholian.move(here)
873 while here.j != tid.j:
875 if game.quad[here.i][here.j] == '.':
876 game.tholian.move(here)
877 # check to see if all holes plugged
878 for i in range(QUADSIZE):
879 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
881 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
883 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
885 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
887 # All plugged up -- Tholian splits
888 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
890 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
891 game.tholian.move(None)
894 # Code from battle.c begins here
896 def doshield(shraise):
897 "Change shield status."
905 if scanner.sees("transfer"):
909 prout(_("Shields damaged and down."))
911 if scanner.sees("up"):
913 elif scanner.sees("down"):
916 proutn(_("Do you wish to change shield energy? "))
919 elif damaged(DSHIELD):
920 prout(_("Shields damaged and down."))
923 proutn(_("Shields are up. Do you want them down? "))
930 proutn(_("Shields are down. Do you want them up? "))
936 if action == "SHUP": # raise shields
938 prout(_("Shields already up."))
942 if game.condition != "docked":
944 prout(_("Shields raised."))
947 prout(_("Shields raising uses up last of energy."))
952 elif action == "SHDN":
954 prout(_("Shields already down."))
958 prout(_("Shields lowered."))
961 elif action == "NRG":
962 while scanner.next() != "IHREAL":
964 proutn(_("Energy to transfer to shields- "))
969 if nrg > game.energy:
970 prout(_("Insufficient ship energy."))
973 if game.shield+nrg >= game.inshld:
974 prout(_("Shield energy maximized."))
975 if game.shield+nrg > game.inshld:
976 prout(_("Excess energy requested returned to ship energy"))
977 game.energy -= game.inshld-game.shield
978 game.shield = game.inshld
980 if nrg < 0.0 and game.energy-nrg > game.inenrg:
981 # Prevent shield drain loophole
983 prout(_("Engineering to bridge--"))
984 prout(_(" Scott here. Power circuit problem, Captain."))
985 prout(_(" I can't drain the shields."))
988 if game.shield+nrg < 0:
989 prout(_("All shield energy transferred to ship."))
990 game.energy += game.shield
993 proutn(_("Scotty- \""))
995 prout(_("Transferring energy to shields.\""))
997 prout(_("Draining energy from shields.\""))
1003 "Choose a device to damage, at random."
1005 105, # DSRSENS: short range scanners 10.5%
1006 105, # DLRSENS: long range scanners 10.5%
1007 120, # DPHASER: phasers 12.0%
1008 120, # DPHOTON: photon torpedoes 12.0%
1009 25, # DLIFSUP: life support 2.5%
1010 65, # DWARPEN: warp drive 6.5%
1011 70, # DIMPULS: impulse engines 6.5%
1012 145, # DSHIELD: deflector shields 14.5%
1013 30, # DRADIO: subspace radio 3.0%
1014 45, # DSHUTTL: shuttle 4.5%
1015 15, # DCOMPTR: computer 1.5%
1016 20, # NAVCOMP: navigation system 2.0%
1017 75, # DTRANSP: transporter 7.5%
1018 20, # DSHCTRL: high-speed shield controller 2.0%
1019 10, # DDRAY: death ray 1.0%
1020 30, # DDSP: deep-space probes 3.0%
1022 assert(sum(weights) == 1000)
1023 idx = randrange(1000)
1025 for (i, w) in enumerate(weights):
1029 return None # we should never get here
1031 def collision(rammed, enemy):
1032 "Collision handling fot rammong events."
1033 prouts(_("***RED ALERT! RED ALERT!"))
1035 prout(_("***COLLISION IMMINENT."))
1039 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1041 proutn(_(" rammed by "))
1044 proutn(crmena(False, enemy.type, "sector", enemy.location))
1046 proutn(_(" (original position)"))
1048 deadkl(enemy.location, enemy.type, game.sector)
1049 proutn("***" + crmshp() + " heavily damaged.")
1050 icas = randrange(10, 30)
1051 prout(_("***Sickbay reports %d casualties") % icas)
1053 game.state.crew -= icas
1054 # In the pre-SST2K version, all devices got equiprobably damaged,
1055 # which was silly. Instead, pick up to half the devices at
1056 # random according to our weighting table,
1057 ncrits = randrange(NDEVICES/2)
1061 if game.damage[dev] < 0:
1063 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1064 # Damage for at least time of travel!
1065 game.damage[dev] += game.optime + extradm
1067 prout(_("***Shields are down."))
1068 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1075 def torpedo(origin, bearing, dispersion, number, nburst):
1076 "Let a photon torpedo fly"
1077 if not damaged(DSRSENS) or game.condition == "docked":
1078 setwnd(srscan_window)
1080 setwnd(message_window)
1081 ac = bearing + 0.25*dispersion # dispersion is a random variable
1082 bullseye = (15.0 - bearing)*0.5235988
1083 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1084 bumpto = Coord(0, 0)
1085 # Loop to move a single torpedo
1086 setwnd(message_window)
1087 for step in range(1, QUADSIZE*2):
1088 if not track.next():
1091 if not w.valid_sector():
1093 iquad = game.quad[w.i][w.j]
1094 tracktorpedo(w, step, number, nburst, iquad)
1098 setwnd(message_window)
1099 if not damaged(DSRSENS) or game.condition == "docked":
1100 skip(1) # start new line after text track
1101 if iquad in ('E', 'F'): # Hit our ship
1103 prout(_("Torpedo hits %s.") % crmshp())
1104 hit = 700.0 + randreal(100) - \
1105 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1106 newcnd() # we're blown out of dock
1107 if game.landed or game.condition == "docked":
1108 return hit # Cheat if on a planet
1109 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1110 # is 143 degrees, which is almost exactly 4.8 clockface units
1111 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1113 bumpto = displacement.sector()
1114 if not bumpto.valid_sector():
1116 if game.quad[bumpto.i][bumpto.j] == ' ':
1119 if game.quad[bumpto.i][bumpto.j] != '.':
1120 # can't move into object
1122 game.sector = bumpto
1124 game.quad[w.i][w.j] = '.'
1125 game.quad[bumpto.i][bumpto.j] = iquad
1126 prout(_(" displaced by blast to Sector %s ") % bumpto)
1127 for enemy in game.enemies:
1128 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1131 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1133 if iquad in ('C', 'S') and withprob(0.05):
1134 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1135 prout(_(" torpedo neutralized."))
1137 for enemy in game.enemies:
1138 if w == enemy.location:
1139 kp = math.fabs(enemy.power)
1140 h1 = 700.0 + randrange(100) - \
1141 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1149 if enemy.power == 0:
1152 proutn(crmena(True, iquad, "sector", w))
1153 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1155 bumpto = displacement.sector()
1156 if not bumpto.valid_sector():
1157 prout(_(" damaged but not destroyed."))
1159 if game.quad[bumpto.i][bumpto.j] == ' ':
1160 prout(_(" buffeted into black hole."))
1161 deadkl(w, iquad, bumpto)
1162 if game.quad[bumpto.i][bumpto.j] != '.':
1163 prout(_(" damaged but not destroyed."))
1165 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1166 enemy.location = bumpto
1167 game.quad[w.i][w.j] = '.'
1168 game.quad[bumpto.i][bumpto.j] = iquad
1169 for enemy in game.enemies:
1170 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1174 prout("Internal error, no enemy where expected!")
1177 elif iquad == 'B': # Hit a base
1179 prout(_("***STARBASE DESTROYED.."))
1180 game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
1181 game.quad[w.i][w.j] = '.'
1182 game.base.invalidate()
1183 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1
1184 game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1
1185 game.state.basekl += 1
1188 elif iquad == 'P': # Hit a planet
1189 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1190 game.state.nplankl += 1
1191 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1192 game.iplnet.pclass = "destroyed"
1194 game.plnet.invalidate()
1195 game.quad[w.i][w.j] = '.'
1197 # captain perishes on planet
1200 elif iquad == '@': # Hit an inhabited world -- very bad!
1201 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1202 game.state.nworldkl += 1
1203 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1204 game.iplnet.pclass = "destroyed"
1206 game.plnet.invalidate()
1207 game.quad[w.i][w.j] = '.'
1209 # captain perishes on planet
1211 prout(_("The torpedo destroyed an inhabited planet."))
1213 elif iquad == '*': # Hit a star
1217 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1219 elif iquad == '?': # Hit a thingy
1220 if not (game.options & OPTION_THINGY) or withprob(0.3):
1222 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1224 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1226 proutn(_("Mr. Spock-"))
1227 prouts(_(" \"Fascinating!\""))
1231 # Stas Sergeev added the possibility that
1232 # you can shove the Thingy and piss it off.
1233 # It then becomes an enemy and may fire at you.
1236 elif iquad == ' ': # Black hole
1238 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1240 elif iquad == '#': # hit the web
1242 prout(_("***Torpedo absorbed by Tholian web."))
1244 elif iquad == 'T': # Hit a Tholian
1245 h1 = 700.0 + randrange(100) - \
1246 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1249 game.quad[w.i][w.j] = '.'
1254 proutn(crmena(True, 'T', "sector", w))
1256 prout(_(" survives photon blast."))
1258 prout(_(" disappears."))
1259 game.tholian.move(None)
1260 game.quad[w.i][w.j] = '#'
1265 proutn("Don't know how to handle torpedo collision with ")
1266 proutn(crmena(True, iquad, "sector", w))
1271 setwnd(message_window)
1272 prout(_("Torpedo missed."))
1276 "Critical-hit resolution."
1277 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1279 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1280 proutn(_("***CRITICAL HIT--"))
1281 # Select devices and cause damage
1286 # Cheat to prevent shuttle damage unless on ship
1287 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship")):
1290 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1291 game.damage[j] += extradm
1294 for (i, j) in enumerate(cdam):
1296 if skipcount % 3 == 2 and i < len(cdam)-1:
1301 prout(_(" damaged."))
1302 if damaged(DSHIELD) and game.shldup:
1303 prout(_("***Shields knocked down."))
1306 def attack(torps_ok):
1307 # bad guy attacks us
1308 # torps_ok == False forces use of phasers in an attack
1309 # game could be over at this point, check
1319 prout("=== ATTACK!")
1320 # Tholian gets to move before attacking
1323 # if you have just entered the RNZ, you'll get a warning
1324 if game.neutz: # The one chance not to be attacked
1327 # commanders get a chance to tac-move towards you
1328 if (((game.quadrant in game.state.kcmdr or game.state.kscmdr == game.quadrant) and not game.justin) or game.skill == SKILL_EMERITUS) and torps_ok:
1329 for (enemy, old_dist, goto) in moveklings():
1330 if enemy.move(goto):
1331 if not damaged(DSRSENS) or game.condition == "docked":
1332 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
1333 if enemy.kdist < old_dist:
1334 proutn(_(" advances to "))
1336 proutn(_(" retreats to "))
1337 prout("Sector %s." % goto)
1339 # if no enemies remain after movement, we're done
1340 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing == game.quadrant and not thing.angered):
1342 # set up partial hits if attack happens during shield status change
1343 pfac = 1.0/game.inshld
1345 chgfac = 0.25 + randreal(0.5)
1347 # message verbosity control
1348 if game.skill <= SKILL_FAIR:
1350 for enemy in game.enemies:
1352 continue # too weak to attack
1353 # compute hit strength and diminish shield power
1355 # Increase chance of photon torpedos if docked or enemy energy is low
1356 if game.condition == "docked":
1358 if enemy.power < 500:
1360 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1362 # different enemies have different probabilities of throwing a torp
1363 usephasers = not torps_ok or \
1364 (enemy.type == 'K' and r > 0.0005) or \
1365 (enemy.type == 'C' and r > 0.015) or \
1366 (enemy.type == 'R' and r > 0.3) or \
1367 (enemy.type == 'S' and r > 0.07) or \
1368 (enemy.type == '?' and r > 0.05)
1369 if usephasers: # Enemy uses phasers
1370 if game.condition == "docked":
1371 continue # Don't waste the effort!
1372 attempt = True # Attempt to attack
1373 dustfac = randreal(0.8, 0.85)
1374 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1376 else: # Enemy uses photon torpedo
1377 # We should be able to make the bearing() method work here
1378 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1380 proutn(_("***TORPEDO INCOMING"))
1381 if not damaged(DSRSENS):
1382 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1385 dispersion = (randreal()+randreal())*0.5 - 0.5
1386 dispersion += 0.002*enemy.power*dispersion
1387 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1388 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1389 finish(FWON) # Klingons did themselves in!
1390 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1391 return # Supernova or finished
1394 # incoming phaser or torpedo, shields may dissipate it
1395 if game.shldup or game.shldchg or game.condition == "docked":
1396 # shields will take hits
1397 propor = pfac * game.shield
1398 if game.condition == "docked":
1402 hitsh = propor*chgfac*hit+1.0
1404 if absorb > game.shield:
1405 absorb = game.shield
1406 game.shield -= absorb
1408 # taking a hit blasts us out of a starbase dock
1409 if game.condition == "docked":
1411 # but the shields may take care of it
1412 if propor > 0.1 and hit < 0.005*game.energy:
1414 # hit from this opponent got through shields, so take damage
1416 proutn(_("%d unit hit") % int(hit))
1417 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1418 proutn(_(" on the ") + crmshp())
1419 if not damaged(DSRSENS) and usephasers:
1420 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1422 # Decide if hit is critical
1428 if game.energy <= 0:
1429 # Returning home upon your shield, not with it...
1432 if not attempt and game.condition == "docked":
1433 prout(_("***Enemies decide against attacking your ship."))
1434 percent = 100.0*pfac*game.shield+0.5
1436 # Shields fully protect ship
1437 proutn(_("Enemy attack reduces shield strength to "))
1439 # Emit message if starship suffered hit(s)
1441 proutn(_("Energy left %2d shields ") % int(game.energy))
1444 elif not damaged(DSHIELD):
1447 proutn(_("damaged, "))
1448 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1449 # Check if anyone was hurt
1450 if hitmax >= 200 or hittot >= 500:
1451 icas = randrange(int(hittot * 0.015))
1454 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1455 prout(_(" in that last attack.\""))
1457 game.state.crew -= icas
1458 # After attack, reset average distance to enemies
1459 for enemy in game.enemies:
1460 enemy.kavgd = enemy.kdist
1464 def deadkl(w, etype, mv):
1465 "Kill a Klingon, Tholian, Romulan, or Thingy."
1466 # Added mv to allow enemy to "move" before dying
1467 proutn(crmena(True, etype, "sector", mv))
1468 # Decide what kind of enemy it is and update appropriately
1470 # Chalk up a Romulan
1471 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1473 game.state.nromrem -= 1
1482 # Killed some type of Klingon
1483 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1486 game.state.kcmdr.remove(game.quadrant)
1488 if game.state.kcmdr:
1489 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1490 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1493 game.state.remkl -= 1
1495 game.state.nscrem -= 1
1496 game.state.kscmdr.invalidate()
1501 # For each kind of enemy, finish message to player
1502 prout(_(" destroyed."))
1503 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1506 # Remove enemy ship from arrays describing local conditions
1507 for e in game.enemies:
1514 "Return None if target is invalid, otherwise return a course angle."
1515 if not w.valid_sector():
1519 # C code this was translated from is wacky -- why the sign reversal?
1520 delta.j = (w.j - game.sector.j)
1521 delta.i = (game.sector.i - w.i)
1522 if delta == Coord(0, 0):
1524 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1525 prout(_(" I recommend an immediate review of"))
1526 prout(_(" the Captain's psychological profile.\""))
1529 return delta.bearing()
1532 "Launch photon torpedo salvo."
1535 if damaged(DPHOTON):
1536 prout(_("Photon tubes damaged."))
1540 prout(_("No torpedoes left."))
1543 # First, get torpedo count
1546 if scanner.token == "IHALPHA":
1549 elif scanner.token == "IHEOL" or not scanner.waiting():
1550 prout(_("%d torpedoes left.") % game.torps)
1552 proutn(_("Number of torpedoes to fire- "))
1553 continue # Go back around to get a number
1554 else: # key == "IHREAL"
1556 if n <= 0: # abort command
1561 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1564 scanner.chew() # User requested more torps than available
1565 continue # Go back around
1566 break # All is good, go to next stage
1570 key = scanner.next()
1571 if i == 0 and key == "IHEOL":
1572 break # no coordinate waiting, we will try prompting
1573 if i == 1 and key == "IHEOL":
1574 # direct all torpedoes at one target
1576 target.append(target[0])
1577 tcourse.append(tcourse[0])
1580 scanner.push(scanner.token)
1581 target.append(scanner.getcoord())
1582 if target[-1] == None:
1584 tcourse.append(targetcheck(target[-1]))
1585 if tcourse[-1] == None:
1588 if len(target) == 0:
1589 # prompt for each one
1591 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1593 target.append(scanner.getcoord())
1594 if target[-1] == None:
1596 tcourse.append(targetcheck(target[-1]))
1597 if tcourse[-1] == None:
1600 # Loop for moving <n> torpedoes
1602 if game.condition != "docked":
1604 dispersion = (randreal()+randreal())*0.5 -0.5
1605 if math.fabs(dispersion) >= 0.47:
1607 dispersion *= randreal(1.2, 2.2)
1609 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1611 prouts(_("***TORPEDO MISFIRES."))
1614 prout(_(" Remainder of burst aborted."))
1616 prout(_("***Photon tubes damaged by misfire."))
1617 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1619 if game.shldup or game.condition == "docked":
1620 dispersion *= 1.0 + 0.0001*game.shield
1621 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1622 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1624 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1628 "Check for phasers overheating."
1630 checkburn = (rpow-1500.0)*0.00038
1631 if withprob(checkburn):
1632 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1633 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1635 def checkshctrl(rpow):
1636 "Check shield control."
1639 prout(_("Shields lowered."))
1641 # Something bad has happened
1642 prouts(_("***RED ALERT! RED ALERT!"))
1644 hit = rpow*game.shield/game.inshld
1645 game.energy -= rpow+hit*0.8
1646 game.shield -= hit*0.2
1647 if game.energy <= 0.0:
1648 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1653 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1655 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1656 icas = randrange(int(hit*0.012))
1661 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1662 prout(_(" %d casualties so far.\"") % icas)
1664 game.state.crew -= icas
1666 prout(_("Phaser energy dispersed by shields."))
1667 prout(_("Enemy unaffected."))
1672 "Register a phaser hit on Klingons and Romulans."
1679 dustfac = randreal(0.9, 1.0)
1680 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1681 kpini = game.enemies[kk].power
1682 kp = math.fabs(kpini)
1683 if PHASEFAC*hit < kp:
1685 if game.enemies[kk].power < 0:
1686 game.enemies[kk].power -= -kp
1688 game.enemies[kk].power -= kp
1689 kpow = game.enemies[kk].power
1690 w = game.enemies[kk].location
1692 if not damaged(DSRSENS):
1694 proutn(_("%d unit hit on ") % int(hit))
1696 proutn(_("Very small hit on "))
1697 ienm = game.quad[w.i][w.j]
1700 proutn(crmena(False, ienm, "sector", w))
1704 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1708 kk -= 1 # don't do the increment
1710 else: # decide whether or not to emasculate klingon
1711 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1712 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1713 prout(_(" has just lost its firepower.\""))
1714 game.enemies[kk].power = -kpow
1719 "Fire phasers at bad guys."
1723 irec = 0 # Cheating inhibitor
1732 # SR sensors and Computer are needed for automode
1733 if damaged(DSRSENS) or damaged(DCOMPTR):
1735 if game.condition == "docked":
1736 prout(_("Phasers can't be fired through base shields."))
1739 if damaged(DPHASER):
1740 prout(_("Phaser control damaged."))
1744 if damaged(DSHCTRL):
1745 prout(_("High speed shield control damaged."))
1748 if game.energy <= 200.0:
1749 prout(_("Insufficient energy to activate high-speed shield control."))
1752 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1754 # Original code so convoluted, I re-did it all
1755 # (That was Tom Almy talking about the C code, I think -- ESR)
1756 while automode == "NOTSET":
1757 key = scanner.next()
1758 if key == "IHALPHA":
1759 if scanner.sees("manual"):
1760 if len(game.enemies)==0:
1761 prout(_("There is no enemy present to select."))
1764 automode = "AUTOMATIC"
1767 key = scanner.next()
1768 elif scanner.sees("automatic"):
1769 if (not itarg) and len(game.enemies) != 0:
1770 automode = "FORCEMAN"
1772 if len(game.enemies)==0:
1773 prout(_("Energy will be expended into space."))
1774 automode = "AUTOMATIC"
1775 key = scanner.next()
1776 elif scanner.sees("no"):
1781 elif key == "IHREAL":
1782 if len(game.enemies)==0:
1783 prout(_("Energy will be expended into space."))
1784 automode = "AUTOMATIC"
1786 automode = "FORCEMAN"
1788 automode = "AUTOMATIC"
1791 if len(game.enemies)==0:
1792 prout(_("Energy will be expended into space."))
1793 automode = "AUTOMATIC"
1795 automode = "FORCEMAN"
1797 proutn(_("Manual or automatic? "))
1802 if automode == "AUTOMATIC":
1803 if key == "IHALPHA" and scanner.sees("no"):
1805 key = scanner.next()
1806 if key != "IHREAL" and len(game.enemies) != 0:
1807 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1812 for i in range(len(game.enemies)):
1813 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1815 proutn(_("%d units required. ") % irec)
1817 proutn(_("Units to fire= "))
1818 key = scanner.next()
1823 proutn(_("Energy available= %.2f") % avail)
1826 if not rpow > avail:
1832 key = scanner.next()
1833 if key == "IHALPHA" and scanner.sees("no"):
1836 game.energy -= 200 # Go and do it!
1837 if checkshctrl(rpow):
1842 if len(game.enemies):
1845 for i in range(len(game.enemies)):
1849 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1850 over = randreal(1.01, 1.06) * hits[i]
1852 powrem -= hits[i] + over
1853 if powrem <= 0 and temp < hits[i]:
1862 if extra > 0 and not game.alldone:
1864 proutn(_("*** Tholian web absorbs "))
1865 if len(game.enemies)>0:
1866 proutn(_("excess "))
1867 prout(_("phaser energy."))
1869 prout(_("%d expended on empty space.") % int(extra))
1870 elif automode == "FORCEMAN":
1873 if damaged(DCOMPTR):
1874 prout(_("Battle computer damaged, manual fire only."))
1877 prouts(_("---WORKING---"))
1879 prout(_("Short-range-sensors-damaged"))
1880 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1881 prout(_("Manual-fire-must-be-used"))
1883 elif automode == "MANUAL":
1885 for k in range(len(game.enemies)):
1886 aim = game.enemies[k].location
1887 ienm = game.quad[aim.i][aim.j]
1889 proutn(_("Energy available= %.2f") % (avail-0.006))
1893 if damaged(DSRSENS) and \
1894 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1895 prout(cramen(ienm) + _(" can't be located without short range scan."))
1898 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
1903 if itarg and k > kz:
1904 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1907 if not damaged(DCOMPTR):
1912 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1913 key = scanner.next()
1914 if key == "IHALPHA" and scanner.sees("no"):
1916 key = scanner.next()
1918 if key == "IHALPHA":
1922 if k == 1: # Let me say I'm baffled by this
1925 if scanner.real < 0:
1929 hits[k] = scanner.real
1930 rpow += scanner.real
1931 # If total requested is too much, inform and start over
1933 prout(_("Available energy exceeded -- try again."))
1936 key = scanner.next() # scan for next value
1939 # zero energy -- abort
1942 if key == "IHALPHA" and scanner.sees("no"):
1947 game.energy -= 200.0
1948 if checkshctrl(rpow):
1952 # Say shield raised or malfunction, if necessary
1959 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1960 prouts(_(" CLICK CLICK POP . . ."))
1961 prout(_(" No response, sir!"))
1964 prout(_("Shields raised."))
1969 # Code from events,c begins here.
1971 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1972 # event of each type active at any given time. Mostly these means we can
1973 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1974 # BSD Trek, from which we swiped the idea, can have up to 5.
1976 def unschedule(evtype):
1977 "Remove an event from the schedule."
1978 game.future[evtype].date = FOREVER
1979 return game.future[evtype]
1981 def is_scheduled(evtype):
1982 "Is an event of specified type scheduled."
1983 return game.future[evtype].date != FOREVER
1985 def scheduled(evtype):
1986 "When will this event happen?"
1987 return game.future[evtype].date
1989 def schedule(evtype, offset):
1990 "Schedule an event of specified type."
1991 game.future[evtype].date = game.state.date + offset
1992 return game.future[evtype]
1994 def postpone(evtype, offset):
1995 "Postpone a scheduled event."
1996 game.future[evtype].date += offset
1999 "Rest period is interrupted by event."
2002 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2004 game.resting = False
2010 "Run through the event queue looking for things to do."
2012 fintim = game.state.date + game.optime
2021 def tractorbeam(yank):
2022 "Tractor-beaming cases merge here."
2024 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2026 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2027 # If Kirk & Co. screwing around on planet, handle
2028 atover(True) # atover(true) is Grab
2031 if game.icraft: # Caught in Galileo?
2034 # Check to see if shuttle is aboard
2035 if game.iscraft == "offship":
2038 prout(_("Galileo, left on the planet surface, is captured"))
2039 prout(_("by aliens and made into a flying McDonald's."))
2040 game.damage[DSHUTTL] = -10
2041 game.iscraft = "removed"
2043 prout(_("Galileo, left on the planet surface, is well hidden."))
2045 game.quadrant = game.state.kscmdr
2047 game.quadrant = game.state.kcmdr[i]
2048 game.sector = randplace(QUADSIZE)
2049 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2050 % (game.quadrant, game.sector))
2052 prout(_("(Remainder of rest/repair period cancelled.)"))
2053 game.resting = False
2055 if not damaged(DSHIELD) and game.shield > 0:
2056 doshield(shraise=True) # raise shields
2057 game.shldchg = False
2059 prout(_("(Shields not currently useable.)"))
2061 # Adjust finish time to time of tractor beaming?
2062 # fintim = game.state.date+game.optime
2063 attack(torps_ok=False)
2064 if not game.state.kcmdr:
2067 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2070 "Code merges here for any commander destroying a starbase."
2071 # Not perfect, but will have to do
2072 # Handle case where base is in same quadrant as starship
2073 if game.battle == game.quadrant:
2074 game.state.chart[game.battle.i][game.battle.j].starbase = False
2075 game.quad[game.base.i][game.base.j] = '.'
2076 game.base.invalidate()
2079 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2080 elif game.state.baseq and communicating():
2081 # Get word via subspace radio
2084 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2085 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2087 prout(_("the Klingon Super-Commander"))
2089 prout(_("a Klingon Commander"))
2090 game.state.chart[game.battle.i][game.battle.j].starbase = False
2091 # Remove Starbase from galaxy
2092 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2093 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2095 # reinstate a commander's base attack
2099 game.battle.invalidate()
2101 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2102 for i in range(1, NEVENTS):
2103 if i == FSNOVA: proutn("=== Supernova ")
2104 elif i == FTBEAM: proutn("=== T Beam ")
2105 elif i == FSNAP: proutn("=== Snapshot ")
2106 elif i == FBATTAK: proutn("=== Base Attack ")
2107 elif i == FCDBAS: proutn("=== Base Destroy ")
2108 elif i == FSCMOVE: proutn("=== SC Move ")
2109 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2110 elif i == FDSPROB: proutn("=== Probe Move ")
2111 elif i == FDISTR: proutn("=== Distress Call ")
2112 elif i == FENSLV: proutn("=== Enslavement ")
2113 elif i == FREPRO: proutn("=== Klingon Build ")
2115 prout("%.2f" % (scheduled(i)))
2118 radio_was_broken = damaged(DRADIO)
2121 # Select earliest extraneous event, evcode==0 if no events
2126 for l in range(1, NEVENTS):
2127 if game.future[l].date < datemin:
2130 prout("== Event %d fires" % evcode)
2131 datemin = game.future[l].date
2132 xtime = datemin-game.state.date
2133 game.state.date = datemin
2134 # Decrement Federation resources and recompute remaining time
2135 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2137 if game.state.remtime <= 0:
2140 # Any crew left alive?
2141 if game.state.crew <= 0:
2144 # Is life support adequate?
2145 if damaged(DLIFSUP) and game.condition != "docked":
2146 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2149 game.lsupres -= xtime
2150 if game.damage[DLIFSUP] <= xtime:
2151 game.lsupres = game.inlsr
2154 if game.condition == "docked":
2156 # Don't fix Deathray here
2157 for l in range(NDEVICES):
2158 if game.damage[l] > 0.0 and l != DDRAY:
2159 if game.damage[l]-repair > 0.0:
2160 game.damage[l] -= repair
2162 game.damage[l] = 0.0
2163 # If radio repaired, update star chart and attack reports
2164 if radio_was_broken and not damaged(DRADIO):
2165 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2166 prout(_(" surveillance reports are coming in."))
2168 if not game.iseenit:
2172 prout(_(" The star chart is now up to date.\""))
2174 # Cause extraneous event EVCODE to occur
2175 game.optime -= xtime
2176 if evcode == FSNOVA: # Supernova
2179 schedule(FSNOVA, expran(0.5*game.intime))
2180 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2182 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2183 if game.state.nscrem == 0 or \
2184 ictbeam or istract or \
2185 game.condition == "docked" or game.isatb == 1 or game.iscate:
2187 if game.ientesc or \
2188 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2189 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2190 (damaged(DSHIELD) and \
2191 (game.energy < 2500 or damaged(DPHASER)) and \
2192 (game.torps < 5 or damaged(DPHOTON))):
2194 istract = ictbeam = True
2195 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2198 elif evcode == FTBEAM: # Tractor beam
2199 if not game.state.kcmdr:
2202 i = randrange(len(game.state.kcmdr))
2203 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2204 if istract or game.condition == "docked" or yank == 0:
2205 # Drats! Have to reschedule
2207 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2211 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2212 game.snapsht = copy.deepcopy(game.state)
2213 game.state.snap = True
2214 schedule(FSNAP, expran(0.5 * game.intime))
2215 elif evcode == FBATTAK: # Commander attacks starbase
2216 if not game.state.kcmdr or not game.state.baseq:
2222 for ibq in game.state.baseq:
2223 for cmdr in game.state.kcmdr:
2224 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2227 # no match found -- try later
2228 schedule(FBATTAK, expran(0.3*game.intime))
2233 # commander + starbase combination found -- launch attack
2235 schedule(FCDBAS, randreal(1.0, 4.0))
2236 if game.isatb: # extra time if SC already attacking
2237 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2238 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2239 game.iseenit = False
2240 if not communicating():
2241 continue # No warning :-(
2245 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2246 prout(_(" reports that it is under attack and that it can"))
2247 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2250 elif evcode == FSCDBAS: # Supercommander destroys base
2253 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2254 continue # WAS RETURN!
2256 game.battle = game.state.kscmdr
2258 elif evcode == FCDBAS: # Commander succeeds in destroying base
2259 if evcode == FCDBAS:
2261 if not game.state.baseq() \
2262 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2263 game.battle.invalidate()
2265 # find the lucky pair
2266 for cmdr in game.state.kcmdr:
2267 if cmdr == game.battle:
2270 # No action to take after all
2273 elif evcode == FSCMOVE: # Supercommander moves
2274 schedule(FSCMOVE, 0.2777)
2275 if not game.ientesc and not istract and game.isatb != 1 and \
2276 (not game.iscate or not game.justin):
2278 elif evcode == FDSPROB: # Move deep space probe
2279 schedule(FDSPROB, 0.01)
2280 if not game.probe.next():
2281 if not game.probe.quadrant().valid_quadrant() or \
2282 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2283 # Left galaxy or ran into supernova
2287 proutn(_("Lt. Uhura- \"The deep space probe "))
2288 if not game.probe.quadrant().valid_quadrant():
2289 prout(_("has left the galaxy.\""))
2291 prout(_("is no longer transmitting.\""))
2297 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2298 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2300 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2301 chp.klingons = pdest.klingons
2302 chp.starbase = pdest.starbase
2303 chp.stars = pdest.stars
2304 pdest.charted = True
2305 game.probe.moves -= 1 # One less to travel
2306 if game.probe.arrived() and game.isarmed and pdest.stars:
2307 supernova(game.probe) # fire in the hole!
2309 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2311 elif evcode == FDISTR: # inhabited system issues distress call
2313 # try a whole bunch of times to find something suitable
2314 for i in range(100):
2315 # need a quadrant which is not the current one,
2316 # which has some stars which are inhabited and
2317 # not already under attack, which is not
2318 # supernova'ed, and which has some Klingons in it
2319 w = randplace(GALSIZE)
2320 q = game.state.galaxy[w.i][w.j]
2321 if not (game.quadrant == w or q.planet == None or \
2322 not q.planet.inhabited or \
2323 q.supernova or q.status!="secure" or q.klingons<=0):
2326 # can't seem to find one; ignore this call
2328 prout("=== Couldn't find location for distress event.")
2330 # got one!! Schedule its enslavement
2331 ev = schedule(FENSLV, expran(game.intime))
2333 q.status = "distressed"
2334 # tell the captain about it if we can
2336 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2337 % (q.planet, repr(w)))
2338 prout(_("by a Klingon invasion fleet."))
2341 elif evcode == FENSLV: # starsystem is enslaved
2342 ev = unschedule(FENSLV)
2343 # see if current distress call still active
2344 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2348 q.status = "enslaved"
2350 # play stork and schedule the first baby
2351 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2352 ev2.quadrant = ev.quadrant
2354 # report the disaster if we can
2356 prout(_("Uhura- We've lost contact with starsystem %s") % \
2358 prout(_("in Quadrant %s.\n") % ev.quadrant)
2359 elif evcode == FREPRO: # Klingon reproduces
2360 # If we ever switch to a real event queue, we'll need to
2361 # explicitly retrieve and restore the x and y.
2362 ev = schedule(FREPRO, expran(1.0 * game.intime))
2363 # see if current distress call still active
2364 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2368 if game.state.remkl >= MAXKLGAME:
2369 continue # full right now
2370 # reproduce one Klingon
2373 if game.klhere >= MAXKLQUAD:
2375 # this quadrant not ok, pick an adjacent one
2376 for m.i in range(w.i - 1, w.i + 2):
2377 for m.j in range(w.j - 1, w.j + 2):
2378 if not m.valid_quadrant():
2380 q = game.state.galaxy[m.i][m.j]
2381 # check for this quad ok (not full & no snova)
2382 if q.klingons >= MAXKLQUAD or q.supernova:
2386 continue # search for eligible quadrant failed
2390 game.state.remkl += 1
2392 if game.quadrant == w:
2394 game.enemies.append(newkling())
2395 # recompute time left
2398 if game.quadrant == w:
2399 prout(_("Spock- sensors indicate the Klingons have"))
2400 prout(_("launched a warship from %s.") % q.planet)
2402 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2403 if q.planet != None:
2404 proutn(_("near %s ") % q.planet)
2405 prout(_("in Quadrant %s.") % w)
2411 key = scanner.next()
2414 proutn(_("How long? "))
2419 origTime = delay = scanner.real
2422 if delay >= game.state.remtime or len(game.enemies) != 0:
2423 proutn(_("Are you sure? "))
2426 # Alternate resting periods (events) with attacks
2430 game.resting = False
2431 if not game.resting:
2432 prout(_("%d stardates left.") % int(game.state.remtime))
2434 temp = game.optime = delay
2435 if len(game.enemies):
2436 rtime = randreal(1.0, 2.0)
2440 if game.optime < delay:
2441 attack(torps_ok=False)
2449 # Repair Deathray if long rest at starbase
2450 if origTime-delay >= 9.99 and game.condition == "docked":
2451 game.damage[DDRAY] = 0.0
2452 # leave if quadrant supernovas
2453 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2455 game.resting = False
2460 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2461 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2463 # Wow! We've supernova'ed
2464 supernova(game.quadrant)
2466 # handle initial nova
2467 game.quad[nov.i][nov.j] = '.'
2468 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2469 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2470 game.state.starkl += 1
2471 # Set up queue to recursively trigger adjacent stars
2477 for offset.i in range(-1, 1+1):
2478 for offset.j in range(-1, 1+1):
2479 if offset.j == 0 and offset.i == 0:
2481 neighbor = start + offset
2482 if not neighbor.valid_sector():
2484 iquad = game.quad[neighbor.i][neighbor.j]
2485 # Empty space ends reaction
2486 if iquad in ('.', '?', ' ', 'T', '#'):
2488 elif iquad == '*': # Affect another star
2490 # This star supernovas
2491 supernova(game.quadrant)
2494 hits.append(neighbor)
2495 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2496 game.state.starkl += 1
2497 proutn(crmena(True, '*', "sector", neighbor))
2499 game.quad[neighbor.i][neighbor.j] = '.'
2501 elif iquad in ('P', '@'): # Destroy planet
2502 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2504 game.state.nplankl += 1
2506 game.state.nworldkl += 1
2507 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2508 game.iplnet.pclass = "destroyed"
2510 game.plnet.invalidate()
2514 game.quad[neighbor.i][neighbor.j] = '.'
2515 elif iquad == 'B': # Destroy base
2516 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2517 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2518 game.base.invalidate()
2519 game.state.basekl += 1
2521 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2522 game.quad[neighbor.i][neighbor.j] = '.'
2523 elif iquad in ('E', 'F'): # Buffet ship
2524 prout(_("***Starship buffeted by nova."))
2526 if game.shield >= 2000.0:
2527 game.shield -= 2000.0
2529 diff = 2000.0 - game.shield
2533 prout(_("***Shields knocked out."))
2534 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2536 game.energy -= 2000.0
2537 if game.energy <= 0:
2540 # add in course nova contributes to kicking starship
2541 bump += (game.sector-hits[-1]).sgn()
2542 elif iquad == 'K': # kill klingon
2543 deadkl(neighbor, iquad, neighbor)
2544 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2545 for ll in range(len(game.enemies)):
2546 if game.enemies[ll].location == neighbor:
2548 game.enemies[ll].power -= 800.0 # If firepower is lost, die
2549 if game.enemies[ll].power <= 0.0:
2550 deadkl(neighbor, iquad, neighbor)
2552 newc = neighbor + neighbor - hits[-1]
2553 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2554 if not newc.valid_sector():
2555 # can't leave quadrant
2558 iquad1 = game.quad[newc.i][newc.j]
2560 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2562 deadkl(neighbor, iquad, newc)
2565 # can't move into something else
2568 proutn(_(", buffeted to Sector %s") % newc)
2569 game.quad[neighbor.i][neighbor.j] = '.'
2570 game.quad[newc.i][newc.j] = iquad
2571 game.enemies[ll].move(newc)
2572 # Starship affected by nova -- kick it away.
2574 direc = ncourse[3*(bump.i+1)+bump.j+2]
2579 scourse = course(bearing=direc, distance=dist)
2580 game.optime = scourse.time(warp=4)
2582 prout(_("Force of nova displaces starship."))
2583 imove(scourse, noattack=True)
2584 game.optime = scourse.time(warp=4)
2588 "Star goes supernova."
2593 # Scheduled supernova -- select star at random.
2596 for nq.i in range(GALSIZE):
2597 for nq.j in range(GALSIZE):
2598 stars += game.state.galaxy[nq.i][nq.j].stars
2600 return # nothing to supernova exists
2601 num = randrange(stars) + 1
2602 for nq.i in range(GALSIZE):
2603 for nq.j in range(GALSIZE):
2604 num -= game.state.galaxy[nq.i][nq.j].stars
2610 proutn("=== Super nova here?")
2613 if not nq == game.quadrant or game.justin:
2614 # it isn't here, or we just entered (treat as enroute)
2617 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2618 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2621 # we are in the quadrant!
2622 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2623 for ns.i in range(QUADSIZE):
2624 for ns.j in range(QUADSIZE):
2625 if game.quad[ns.i][ns.j]=='*':
2632 prouts(_("***RED ALERT! RED ALERT!"))
2634 prout(_("***Incipient supernova detected at Sector %s") % ns)
2635 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2636 proutn(_("Emergency override attempts t"))
2637 prouts("***************")
2641 # destroy any Klingons in supernovaed quadrant
2642 kldead = game.state.galaxy[nq.i][nq.j].klingons
2643 game.state.galaxy[nq.i][nq.j].klingons = 0
2644 if nq == game.state.kscmdr:
2645 # did in the Supercommander!
2646 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2650 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2651 comkills = len(game.state.kcmdr) - len(survivors)
2652 game.state.kcmdr = survivors
2654 if not game.state.kcmdr:
2656 game.state.remkl -= kldead
2657 # destroy Romulans and planets in supernovaed quadrant
2658 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2659 game.state.galaxy[nq.i][nq.j].romulans = 0
2660 game.state.nromrem -= nrmdead
2662 for loop in range(game.inplan):
2663 if game.state.planets[loop].quadrant == nq:
2664 game.state.planets[loop].pclass = "destroyed"
2666 # Destroy any base in supernovaed quadrant
2667 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2668 # If starship caused supernova, tally up destruction
2670 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2671 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2672 game.state.nplankl += npdead
2673 # mark supernova in galaxy and in star chart
2674 if game.quadrant == nq or communicating():
2675 game.state.galaxy[nq.i][nq.j].supernova = True
2676 # If supernova destroys last Klingons give special message
2677 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2680 prout(_("Lucky you!"))
2681 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2684 # if some Klingons remain, continue or die in supernova
2689 # Code from finish.c ends here.
2692 "Self-destruct maneuver. Finish with a BANG!"
2694 if damaged(DCOMPTR):
2695 prout(_("Computer damaged; cannot execute destruct sequence."))
2697 prouts(_("---WORKING---")); skip(1)
2698 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2699 prouts(" 10"); skip(1)
2700 prouts(" 9"); skip(1)
2701 prouts(" 8"); skip(1)
2702 prouts(" 7"); skip(1)
2703 prouts(" 6"); skip(1)
2705 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2707 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2709 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2712 if game.passwd != scanner.token:
2713 prouts(_("PASSWORD-REJECTED;"))
2715 prouts(_("CONTINUITY-EFFECTED"))
2718 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2719 prouts(" 5"); skip(1)
2720 prouts(" 4"); skip(1)
2721 prouts(" 3"); skip(1)
2722 prouts(" 2"); skip(1)
2723 prouts(" 1"); skip(1)
2725 prouts(_("GOODBYE-CRUEL-WORLD"))
2733 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2737 if len(game.enemies) != 0:
2738 whammo = 25.0 * game.energy
2739 for l in range(len(game.enemies)):
2740 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2741 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2745 "Compute our rate of kils over time."
2746 elapsed = game.state.date - game.indate
2747 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2750 starting = (game.inkling + game.incom + game.inscom)
2751 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2752 return (starting - remaining)/elapsed
2756 badpt = 5.0*game.state.starkl + \
2758 10.0*game.state.nplankl + \
2759 300*game.state.nworldkl + \
2761 100.0*game.state.basekl +\
2763 if game.ship == 'F':
2765 elif game.ship == None:
2770 # end the game, with appropriate notfications
2774 prout(_("It is stardate %.1f.") % game.state.date)
2776 if ifin == FWON: # Game has been won
2777 if game.state.nromrem != 0:
2778 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2781 prout(_("You have smashed the Klingon invasion fleet and saved"))
2782 prout(_("the Federation."))
2787 badpt = 0.0 # Close enough!
2788 # killsPerDate >= RateMax
2789 if game.state.date-game.indate < 5.0 or \
2790 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2792 prout(_("In fact, you have done so well that Starfleet Command"))
2793 if game.skill == SKILL_NOVICE:
2794 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2795 elif game.skill == SKILL_FAIR:
2796 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2797 elif game.skill == SKILL_GOOD:
2798 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2799 elif game.skill == SKILL_EXPERT:
2800 prout(_("promotes you to Commodore Emeritus."))
2802 prout(_("Now that you think you're really good, try playing"))
2803 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2804 elif game.skill == SKILL_EMERITUS:
2806 proutn(_("Computer- "))
2807 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2809 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2811 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2813 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2815 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2817 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2819 prout(_("Now you can retire and write your own Star Trek game!"))
2821 elif game.skill >= SKILL_EXPERT:
2822 if game.thawed and not game.idebug:
2823 prout(_("You cannot get a citation, so..."))
2825 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2829 # Only grant long life if alive (original didn't!)
2831 prout(_("LIVE LONG AND PROSPER."))
2836 elif ifin == FDEPLETE: # Federation Resources Depleted
2837 prout(_("Your time has run out and the Federation has been"))
2838 prout(_("conquered. Your starship is now Klingon property,"))
2839 prout(_("and you are put on trial as a war criminal. On the"))
2840 proutn(_("basis of your record, you are "))
2841 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2842 prout(_("acquitted."))
2844 prout(_("LIVE LONG AND PROSPER."))
2846 prout(_("found guilty and"))
2847 prout(_("sentenced to death by slow torture."))
2851 elif ifin == FLIFESUP:
2852 prout(_("Your life support reserves have run out, and"))
2853 prout(_("you die of thirst, starvation, and asphyxiation."))
2854 prout(_("Your starship is a derelict in space."))
2856 prout(_("Your energy supply is exhausted."))
2858 prout(_("Your starship is a derelict in space."))
2859 elif ifin == FBATTLE:
2860 prout(_("The %s has been destroyed in battle.") % crmshp())
2862 prout(_("Dulce et decorum est pro patria mori."))
2864 prout(_("You have made three attempts to cross the negative energy"))
2865 prout(_("barrier which surrounds the galaxy."))
2867 prout(_("Your navigation is abominable."))
2870 prout(_("Your starship has been destroyed by a nova."))
2871 prout(_("That was a great shot."))
2873 elif ifin == FSNOVAED:
2874 prout(_("The %s has been fried by a supernova.") % crmshp())
2875 prout(_("...Not even cinders remain..."))
2876 elif ifin == FABANDN:
2877 prout(_("You have been captured by the Klingons. If you still"))
2878 prout(_("had a starbase to be returned to, you would have been"))
2879 prout(_("repatriated and given another chance. Since you have"))
2880 prout(_("no starbases, you will be mercilessly tortured to death."))
2881 elif ifin == FDILITHIUM:
2882 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2883 elif ifin == FMATERIALIZE:
2884 prout(_("Starbase was unable to re-materialize your starship."))
2885 prout(_("Sic transit gloria mundi"))
2886 elif ifin == FPHASER:
2887 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2889 prout(_("You and your landing party have been"))
2890 prout(_("converted to energy, disipating through space."))
2891 elif ifin == FMINING:
2892 prout(_("You are left with your landing party on"))
2893 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2895 prout(_("They are very fond of \"Captain Kirk\" soup."))
2897 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2898 elif ifin == FDPLANET:
2899 prout(_("You and your mining party perish."))
2901 prout(_("That was a great shot."))
2904 prout(_("The Galileo is instantly annihilated by the supernova."))
2905 prout(_("You and your mining party are atomized."))
2907 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2908 prout(_("joins the Romulans, wreaking terror on the Federation."))
2909 elif ifin == FPNOVA:
2910 prout(_("You and your mining party are atomized."))
2912 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2913 prout(_("joins the Romulans, wreaking terror on the Federation."))
2914 elif ifin == FSTRACTOR:
2915 prout(_("The shuttle craft Galileo is also caught,"))
2916 prout(_("and breaks up under the strain."))
2918 prout(_("Your debris is scattered for millions of miles."))
2919 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2921 prout(_("The mutants attack and kill Spock."))
2922 prout(_("Your ship is captured by Klingons, and"))
2923 prout(_("your crew is put on display in a Klingon zoo."))
2924 elif ifin == FTRIBBLE:
2925 prout(_("Tribbles consume all remaining water,"))
2926 prout(_("food, and oxygen on your ship."))
2928 prout(_("You die of thirst, starvation, and asphyxiation."))
2929 prout(_("Your starship is a derelict in space."))
2931 prout(_("Your ship is drawn to the center of the black hole."))
2932 prout(_("You are crushed into extremely dense matter."))
2934 prout(_("Your last crew member has died."))
2935 if game.ship == 'F':
2937 elif game.ship == 'E':
2940 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2941 goodies = game.state.remres/game.inresor
2942 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2943 if goodies/baddies >= randreal(1.0, 1.5):
2944 prout(_("As a result of your actions, a treaty with the Klingon"))
2945 prout(_("Empire has been signed. The terms of the treaty are"))
2946 if goodies/baddies >= randreal(3.0):
2947 prout(_("favorable to the Federation."))
2949 prout(_("Congratulations!"))
2951 prout(_("highly unfavorable to the Federation."))
2953 prout(_("The Federation will be destroyed."))
2955 prout(_("Since you took the last Klingon with you, you are a"))
2956 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2957 prout(_("statue in your memory. Rest in peace, and try not"))
2958 prout(_("to think about pigeons."))
2963 "Compute player's score."
2964 timused = game.state.date - game.indate
2965 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2967 game.perdate = killrate()
2968 ithperd = 500*game.perdate + 0.5
2971 iwon = 100*game.skill
2972 if game.ship == 'E':
2974 elif game.ship == 'F':
2978 game.score = 10*(game.inkling - game.state.remkl) \
2979 + 50*(game.incom - len(game.state.kcmdr)) \
2981 + 20*(game.inrom - game.state.nromrem) \
2982 + 200*(game.inscom - game.state.nscrem) \
2983 - game.state.nromrem \
2988 prout(_("Your score --"))
2989 if game.inrom - game.state.nromrem:
2990 prout(_("%6d Romulans destroyed %5d") %
2991 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
2992 if game.state.nromrem and game.gamewon:
2993 prout(_("%6d Romulans captured %5d") %
2994 (game.state.nromrem, game.state.nromrem))
2995 if game.inkling - game.state.remkl:
2996 prout(_("%6d ordinary Klingons destroyed %5d") %
2997 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
2998 if game.incom - len(game.state.kcmdr):
2999 prout(_("%6d Klingon commanders destroyed %5d") %
3000 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3001 if game.inscom - game.state.nscrem:
3002 prout(_("%6d Super-Commander destroyed %5d") %
3003 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3005 prout(_("%6.2f Klingons per stardate %5d") %
3006 (game.perdate, ithperd))
3007 if game.state.starkl:
3008 prout(_("%6d stars destroyed by your action %5d") %
3009 (game.state.starkl, -5*game.state.starkl))
3010 if game.state.nplankl:
3011 prout(_("%6d planets destroyed by your action %5d") %
3012 (game.state.nplankl, -10*game.state.nplankl))
3013 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3014 prout(_("%6d inhabited planets destroyed by your action %5d") %
3015 (game.state.nworldkl, -300*game.state.nworldkl))
3016 if game.state.basekl:
3017 prout(_("%6d bases destroyed by your action %5d") %
3018 (game.state.basekl, -100*game.state.basekl))
3020 prout(_("%6d calls for help from starbase %5d") %
3021 (game.nhelp, -45*game.nhelp))
3023 prout(_("%6d casualties incurred %5d") %
3024 (game.casual, -game.casual))
3026 prout(_("%6d crew abandoned in space %5d") %
3027 (game.abandoned, -3*game.abandoned))
3029 prout(_("%6d ship(s) lost or destroyed %5d") %
3030 (klship, -100*klship))
3032 prout(_("Penalty for getting yourself killed -200"))
3034 proutn(_("Bonus for winning "))
3035 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3036 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3037 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3038 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3039 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3040 prout(" %5d" % iwon)
3042 prout(_("TOTAL SCORE %5d") % game.score)
3045 "Emit winner's commemmorative plaque."
3048 proutn(_("File or device name for your plaque: "))
3051 fp = open(winner, "w")
3054 prout(_("Invalid name."))
3056 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3058 # The 38 below must be 64 for 132-column paper
3059 nskip = 38 - len(winner)/2
3060 fp.write("\n\n\n\n")
3061 # --------DRAW ENTERPRISE PICTURE.
3062 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3063 fp.write(" EEE E : : : E\n" )
3064 fp.write(" EE EEE E : : NCC-1701 : E\n")
3065 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3066 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3067 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3068 fp.write(" EEEEEEE EEEEE E E E E\n")
3069 fp.write(" EEE E E E E\n")
3070 fp.write(" E E E E\n")
3071 fp.write(" EEEEEEEEEEEEE E E\n")
3072 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3073 fp.write(" :E : EEEE E\n")
3074 fp.write(" .-E -:----- E\n")
3075 fp.write(" :E : E\n")
3076 fp.write(" EE : EEEEEEEE\n")
3077 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3079 fp.write(_(" U. S. S. ENTERPRISE\n"))
3080 fp.write("\n\n\n\n")
3081 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3083 fp.write(_(" Starfleet Command bestows to you\n"))
3085 fp.write("%*s%s\n\n" % (nskip, "", winner))
3086 fp.write(_(" the rank of\n\n"))
3087 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3089 if game.skill == SKILL_EXPERT:
3090 fp.write(_(" Expert level\n\n"))
3091 elif game.skill == SKILL_EMERITUS:
3092 fp.write(_("Emeritus level\n\n"))
3094 fp.write(_(" Cheat level\n\n"))
3095 timestring = time.ctime()
3096 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3097 (timestring+4, timestring+20, timestring+11))
3098 fp.write(_(" Your score: %d\n\n") % game.score)
3099 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3102 # Code from io.c begins here
3104 rows = linecount = 0 # for paging
3107 fullscreen_window = None
3108 srscan_window = None
3109 report_window = None
3110 status_window = None
3111 lrscan_window = None
3112 message_window = None
3113 prompt_window = None
3118 "for some recent versions of python2, the following enables UTF8"
3119 "for the older ones we probably need to set C locale, and the python3"
3120 "has no problems at all"
3121 if sys.version_info[0] < 3:
3123 locale.setlocale(locale.LC_ALL, "")
3124 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3125 gettext.textdomain("sst")
3126 if not (game.options & OPTION_CURSES):
3127 ln_env = os.getenv("LINES")
3133 stdscr = curses.initscr()
3137 if game.options & OPTION_COLOR:
3138 curses.start_color()
3139 curses.use_default_colors()
3140 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3141 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3142 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3143 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3144 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3145 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3146 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3147 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3148 global fullscreen_window, srscan_window, report_window, status_window
3149 global lrscan_window, message_window, prompt_window
3150 (rows, columns) = stdscr.getmaxyx()
3151 fullscreen_window = stdscr
3152 srscan_window = curses.newwin(12, 25, 0, 0)
3153 report_window = curses.newwin(11, 0, 1, 25)
3154 status_window = curses.newwin(10, 0, 1, 39)
3155 lrscan_window = curses.newwin(5, 0, 0, 64)
3156 message_window = curses.newwin(0, 0, 12, 0)
3157 prompt_window = curses.newwin(1, 0, rows-2, 0)
3158 message_window.scrollok(True)
3159 setwnd(fullscreen_window)
3163 if game.options & OPTION_CURSES:
3164 stdscr.keypad(False)
3170 "Wait for user action -- OK to do nothing if on a TTY"
3171 if game.options & OPTION_CURSES:
3176 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3180 if game.skill > SKILL_FAIR:
3181 prompt = _("[CONTINUE?]")
3183 prompt = _("[PRESS ENTER TO CONTINUE]")
3185 if game.options & OPTION_CURSES:
3187 setwnd(prompt_window)
3188 prompt_window.clear()
3189 prompt_window.addstr(prompt)
3190 prompt_window.getstr()
3191 prompt_window.clear()
3192 prompt_window.refresh()
3193 setwnd(message_window)
3196 sys.stdout.write('\n')
3200 sys.stdout.write('\n' * rows)
3204 "Skip i lines. Pause game if this would cause a scrolling event."
3205 for dummy in range(i):
3206 if game.options & OPTION_CURSES:
3207 (y, x) = curwnd.getyx()
3210 except curses.error:
3215 if rows and linecount >= rows:
3218 sys.stdout.write('\n')
3221 "Utter a line with no following line feed."
3222 if game.options & OPTION_CURSES:
3223 (y, x) = curwnd.getyx()
3224 (my, mx) = curwnd.getmaxyx()
3225 if curwnd == message_window and y >= my - 2:
3228 # Uncomment this to debug curses problems
3230 logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(line)))
3234 sys.stdout.write(line)
3244 if not replayfp or replayfp.closed: # Don't slow down replays
3247 if game.options & OPTION_CURSES:
3251 if not replayfp or replayfp.closed:
3255 "Get a line of input."
3256 if game.options & OPTION_CURSES:
3257 line = curwnd.getstr() + "\n"
3260 if replayfp and not replayfp.closed:
3262 line = replayfp.readline()
3265 prout("*** Replay finished")
3268 elif line[0] != "#":
3271 line = raw_input() + "\n"
3277 "Change windows -- OK for this to be a no-op in tty mode."
3279 if game.options & OPTION_CURSES:
3280 # Uncomment this to debug curses problems
3282 if wnd == fullscreen_window:
3283 legend = "fullscreen"
3284 elif wnd == srscan_window:
3286 elif wnd == report_window:
3288 elif wnd == status_window:
3290 elif wnd == lrscan_window:
3292 elif wnd == message_window:
3294 elif wnd == prompt_window:
3298 logfp.write("#curses: setwnd(%s)\n" % legend)
3300 # Some curses implementations get confused when you try this.
3302 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3303 except curses.error:
3307 "Clear to end of line -- can be a no-op in tty mode"
3308 if game.options & OPTION_CURSES:
3313 "Clear screen -- can be a no-op in tty mode."
3315 if game.options & OPTION_CURSES:
3321 def textcolor(color=DEFAULT):
3322 if game.options & OPTION_COLOR:
3323 if color == DEFAULT:
3325 elif color == BLACK:
3326 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3328 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3329 elif color == GREEN:
3330 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3332 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3334 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3335 elif color == MAGENTA:
3336 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3337 elif color == BROWN:
3338 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3339 elif color == LIGHTGRAY:
3340 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3341 elif color == DARKGRAY:
3342 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3343 elif color == LIGHTBLUE:
3344 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3345 elif color == LIGHTGREEN:
3346 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3347 elif color == LIGHTCYAN:
3348 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3349 elif color == LIGHTRED:
3350 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3351 elif color == LIGHTMAGENTA:
3352 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3353 elif color == YELLOW:
3354 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3355 elif color == WHITE:
3356 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3359 if game.options & OPTION_COLOR:
3360 curwnd.attron(curses.A_REVERSE)
3363 # Things past this point have policy implications.
3367 "Hook to be called after moving to redraw maps."
3368 if game.options & OPTION_CURSES:
3371 setwnd(srscan_window)
3375 setwnd(status_window)
3376 status_window.clear()
3377 status_window.move(0, 0)
3378 setwnd(report_window)
3379 report_window.clear()
3380 report_window.move(0, 0)
3382 setwnd(lrscan_window)
3383 lrscan_window.clear()
3384 lrscan_window.move(0, 0)
3385 lrscan(silent=False)
3387 def put_srscan_sym(w, sym):
3388 "Emit symbol for short-range scan."
3389 srscan_window.move(w.i+1, w.j*2+2)
3390 srscan_window.addch(sym)
3391 srscan_window.refresh()
3394 "Enemy fall down, go boom."
3395 if game.options & OPTION_CURSES:
3397 setwnd(srscan_window)
3398 srscan_window.attron(curses.A_REVERSE)
3399 put_srscan_sym(w, game.quad[w.i][w.j])
3403 srscan_window.attroff(curses.A_REVERSE)
3404 put_srscan_sym(w, game.quad[w.i][w.j])
3405 curses.delay_output(500)
3406 setwnd(message_window)
3409 "Sound and visual effects for teleportation."
3410 if game.options & OPTION_CURSES:
3412 setwnd(message_window)
3414 prouts(" . . . . . ")
3415 if game.options & OPTION_CURSES:
3416 #curses.delay_output(1000)
3420 def tracktorpedo(w, step, i, n, iquad):
3421 "Torpedo-track animation."
3422 if not game.options & OPTION_CURSES:
3426 proutn(_("Track for torpedo number %d- ") % (i+1))
3429 proutn(_("Torpedo track- "))
3430 elif step==4 or step==9:
3434 if not damaged(DSRSENS) or game.condition=="docked":
3435 if i != 0 and step == 1:
3438 if (iquad=='.') or (iquad==' '):
3439 put_srscan_sym(w, '+')
3443 put_srscan_sym(w, iquad)
3445 curwnd.attron(curses.A_REVERSE)
3446 put_srscan_sym(w, iquad)
3450 curwnd.attroff(curses.A_REVERSE)
3451 put_srscan_sym(w, iquad)
3456 "Display the current galaxy chart."
3457 if game.options & OPTION_CURSES:
3458 setwnd(message_window)
3459 message_window.clear()
3461 if game.options & OPTION_TTY:
3466 def prstat(txt, data):
3468 if game.options & OPTION_CURSES:
3470 setwnd(status_window)
3472 proutn(" " * (NSYM - len(txt)))
3475 if game.options & OPTION_CURSES:
3476 setwnd(report_window)
3478 # Code from moving.c begins here
3480 def imove(icourse=None, noattack=False):
3481 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3484 def newquadrant(noattack):
3485 # Leaving quadrant -- allow final enemy attack
3486 # Don't do it if being pushed by Nova
3487 if len(game.enemies) != 0 and not noattack:
3489 for enemy in game.enemies:
3490 finald = (w - enemy.location).distance()
3491 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3492 # Stas Sergeev added the condition
3493 # that attacks only happen if Klingons
3494 # are present and your skill is good.
3495 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3496 attack(torps_ok=False)
3499 # check for edge of galaxy
3503 if icourse.final.i < 0:
3504 icourse.final.i = -icourse.final.i
3506 if icourse.final.j < 0:
3507 icourse.final.j = -icourse.final.j
3509 if icourse.final.i >= GALSIZE*QUADSIZE:
3510 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3512 if icourse.final.j >= GALSIZE*QUADSIZE:
3513 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3521 if game.nkinks == 3:
3522 # Three strikes -- you're out!
3526 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3527 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3528 prout(_("YOU WILL BE DESTROYED."))
3529 # Compute final position in new quadrant
3530 if trbeam: # Don't bother if we are to be beamed
3532 game.quadrant = icourse.final.quadrant()
3533 game.sector = icourse.final.sector()
3535 prout(_("Entering Quadrant %s.") % game.quadrant)
3536 game.quad[game.sector.i][game.sector.j] = game.ship
3538 if game.skill>SKILL_NOVICE:
3539 attack(torps_ok=False)
3541 def check_collision(h):
3542 iquad = game.quad[h.i][h.j]
3544 # object encountered in flight path
3545 stopegy = 50.0*icourse.distance/game.optime
3546 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3547 for enemy in game.enemies:
3548 if enemy.location == game.sector:
3550 collision(rammed=False, enemy=enemy)
3554 prouts(_("***RED ALERT! RED ALERT!"))
3556 proutn("***" + crmshp())
3557 proutn(_(" pulled into black hole at Sector %s") % h)
3558 # Getting pulled into a black hole was certain
3559 # death in Almy's original. Stas Sergeev added a
3560 # possibility that you'll get timewarped instead.
3562 for m in range(NDEVICES):
3563 if game.damage[m]>0:
3565 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3566 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3576 prout(_(" encounters Tholian web at %s;") % h)
3578 prout(_(" blocked by object at %s;") % h)
3579 proutn(_("Emergency stop required "))
3580 prout(_("%2d units of energy.") % int(stopegy))
3581 game.energy -= stopegy
3582 if game.energy <= 0:
3589 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3590 game.inorbit = False
3591 # If tractor beam is to occur, don't move full distance
3592 if game.state.date+game.optime >= scheduled(FTBEAM):
3594 game.condition = "red"
3595 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3596 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3598 game.quad[game.sector.i][game.sector.j] = '.'
3599 for m in range(icourse.moves):
3601 w = icourse.sector()
3602 if icourse.origin.quadrant() != icourse.location.quadrant():
3603 newquadrant(noattack)
3605 elif check_collision(w):
3606 print "Collision detected"
3610 # We're in destination quadrant -- compute new average enemy distances
3611 game.quad[game.sector.i][game.sector.j] = game.ship
3613 for enemy in game.enemies:
3614 finald = (w-enemy.location).distance()
3615 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3616 enemy.kdist = finald
3618 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3619 attack(torps_ok=False)
3620 for enemy in game.enemies:
3621 enemy.kavgd = enemy.kdist
3624 setwnd(message_window)
3628 "Dock our ship at a starbase."
3630 if game.condition == "docked" and verbose:
3631 prout(_("Already docked."))
3634 prout(_("You must first leave standard orbit."))
3636 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3637 prout(crmshp() + _(" not adjacent to base."))
3639 game.condition = "docked"
3643 if game.energy < game.inenrg:
3644 game.energy = game.inenrg
3645 game.shield = game.inshld
3646 game.torps = game.intorps
3647 game.lsupres = game.inlsr
3648 game.state.crew = FULLCREW
3649 if not damaged(DRADIO) and \
3650 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3651 # get attack report from base
3652 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3656 def cartesian(loc1=None, loc2=None):
3658 return game.quadrant * QUADSIZE + game.sector
3660 return game.quadrant * QUADSIZE + loc1
3662 return loc1 * QUADSIZE + loc2
3664 def getcourse(isprobe):
3665 "Get a course and distance from the user."
3667 dquad = copy.copy(game.quadrant)
3668 navmode = "unspecified"
3672 if game.landed and not isprobe:
3673 prout(_("Dummy! You can't leave standard orbit until you"))
3674 proutn(_("are back aboard the ship."))
3677 while navmode == "unspecified":
3678 if damaged(DNAVSYS):
3680 prout(_("Computer damaged; manual navigation only"))
3682 prout(_("Computer damaged; manual movement only"))
3687 key = scanner.next()
3689 proutn(_("Manual or automatic- "))
3692 elif key == "IHALPHA":
3693 if scanner.sees("manual"):
3695 key = scanner.next()
3697 elif scanner.sees("automatic"):
3698 navmode = "automatic"
3699 key = scanner.next()
3707 prout(_("(Manual navigation assumed.)"))
3709 prout(_("(Manual movement assumed.)"))
3713 if navmode == "automatic":
3714 while key == "IHEOL":
3716 proutn(_("Target quadrant or quadrant§or- "))
3718 proutn(_("Destination sector or quadrant§or- "))
3721 key = scanner.next()
3725 xi = int(round(scanner.real))-1
3726 key = scanner.next()
3730 xj = int(round(scanner.real))-1
3731 key = scanner.next()
3733 # both quadrant and sector specified
3734 xk = int(round(scanner.real))-1
3735 key = scanner.next()
3739 xl = int(round(scanner.real))-1
3745 # only one pair of numbers was specified
3747 # only quadrant specified -- go to center of dest quad
3750 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3752 # only sector specified
3756 if not dquad.valid_quadrant() or not dsect.valid_sector():
3763 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3765 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3766 # the actual deltas get computed here
3767 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3768 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3770 while key == "IHEOL":
3771 proutn(_("X and Y displacements- "))
3774 key = scanner.next()
3779 delta.j = scanner.real
3780 key = scanner.next()
3784 delta.i = scanner.real
3785 # Check for zero movement
3786 if delta.i == 0 and delta.j == 0:
3789 if itemp == "verbose" and not isprobe:
3791 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3793 return course(bearing=delta.bearing(), distance=delta.distance())
3796 def __init__(self, bearing, distance, origin=None):
3797 self.distance = distance
3798 self.bearing = bearing
3800 self.origin = cartesian(game.quadrant, game.sector)
3802 self.origin = origin
3803 # The bearing() code we inherited from FORTRAN is actually computing
3804 # clockface directions!
3805 if self.bearing < 0.0:
3806 self.bearing += 12.0
3807 self.angle = ((15.0 - self.bearing) * 0.5235988)
3809 self.origin = cartesian(game.quadrant, game.sector)
3811 self.origin = cartesian(game.quadrant, origin)
3812 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
3813 bigger = max(abs(self.increment.i), abs(self.increment.j))
3814 self.increment /= bigger
3815 self.moves = int(round(10*self.distance*bigger))
3817 self.final = (self.location + self.moves*self.increment).roundtogrid()
3819 self.location = self.origin
3822 return self.location.roundtogrid() == self.final
3824 "Next step on course."
3826 self.nextlocation = self.location + self.increment
3827 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3828 self.location = self.nextlocation
3831 return self.location.quadrant()
3833 return self.location.sector()
3834 def power(self, warp):
3835 return self.distance*(warp**3)*(game.shldup+1)
3836 def time(self, warp):
3837 return 10.0*self.distance/warp**2
3840 "Move under impulse power."
3842 if damaged(DIMPULS):
3845 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3847 if game.energy > 30.0:
3849 course = getcourse(isprobe=False)
3852 power = 20.0 + 100.0*course.distance
3855 if power >= game.energy:
3856 # Insufficient power for trip
3858 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3859 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3860 if game.energy > 30:
3861 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3862 int(0.01 * (game.energy-20.0)-0.05))
3863 prout(_(" quadrants.\""))
3865 prout(_("quadrant. They are, therefore, useless.\""))
3868 # Make sure enough time is left for the trip
3869 game.optime = course.distance/0.095
3870 if game.optime >= game.state.remtime:
3871 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3872 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3873 proutn(_("we dare spend the time?\" "))
3876 # Activate impulse engines and pay the cost
3877 imove(course, noattack=False)
3881 power = 20.0 + 100.0*course.distance
3882 game.energy -= power
3883 game.optime = course.distance/0.095
3884 if game.energy <= 0:
3888 def warp(wcourse, involuntary):
3889 "ove under warp drive."
3890 blooey = False; twarp = False
3891 if not involuntary: # Not WARPX entry
3893 if game.damage[DWARPEN] > 10.0:
3896 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3898 if damaged(DWARPEN) and game.warpfac > 4.0:
3901 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3902 prout(_(" is repaired, I can only give you warp 4.\""))
3904 # Read in course and distance
3907 wcourse = getcourse(isprobe=False)
3910 # Make sure starship has enough energy for the trip
3911 # Note: this formula is slightly different from the C version,
3912 # and lets you skate a bit closer to the edge.
3913 if wcourse.power(game.warpfac) >= game.energy:
3914 # Insufficient power for trip
3917 prout(_("Engineering to bridge--"))
3918 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
3919 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
3921 prout(_("We can't do it, Captain. We don't have enough energy."))
3923 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3926 prout(_("if you'll lower the shields."))
3930 prout(_("We haven't the energy to go that far with the shields up."))
3932 # Make sure enough time is left for the trip
3933 game.optime = wcourse.time(game.warpfac)
3934 if game.optime >= 0.8*game.state.remtime:
3936 prout(_("First Officer Spock- \"Captain, I compute that such"))
3937 proutn(_(" a trip would require approximately %2.0f") %
3938 (100.0*game.optime/game.state.remtime))
3939 prout(_(" percent of our"))
3940 proutn(_(" remaining time. Are you sure this is wise?\" "))
3946 if game.warpfac > 6.0:
3947 # Decide if engine damage will occur
3948 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3949 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
3950 if prob > randreal():
3952 wcourse.distance = randreal(wcourse.distance)
3953 # Decide if time warp will occur
3954 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3956 if game.idebug and game.warpfac==10 and not twarp:
3958 proutn("=== Force time warp? ")
3962 # If time warp or engine damage, check path
3963 # If it is obstructed, don't do warp or damage
3964 look = wcourse.moves
3968 w = wcourse.sector()
3969 if not w.valid_sector():
3971 if game.quad[w.i][w.j] != '.':
3975 # Activate Warp Engines and pay the cost
3976 imove(wcourse, noattack=False)
3979 game.energy -= wcourse.power(game.warpfac)
3980 if game.energy <= 0:
3982 game.optime = wcourse.time(game.warpfac)
3986 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
3988 prout(_("Engineering to bridge--"))
3989 prout(_(" Scott here. The warp engines are damaged."))
3990 prout(_(" We'll have to reduce speed to warp 4."))
3995 "Change the warp factor."
4001 proutn(_("Warp factor- "))
4005 if game.damage[DWARPEN] > 10.0:
4006 prout(_("Warp engines inoperative."))
4008 if damaged(DWARPEN) and scanner.real > 4.0:
4009 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4010 prout(_(" but right now we can only go warp 4.\""))
4012 if scanner.real > 10.0:
4013 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4015 if scanner.real < 1.0:
4016 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4018 oldfac = game.warpfac
4019 game.warpfac = scanner.real
4020 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4021 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4024 if game.warpfac < 8.00:
4025 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4027 if game.warpfac == 10.0:
4028 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4030 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4034 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4036 # is captain on planet?
4038 if damaged(DTRANSP):
4041 prout(_("Scotty rushes to the transporter controls."))
4043 prout(_("But with the shields up it's hopeless."))
4045 prouts(_("His desperate attempt to rescue you . . ."))
4050 prout(_("SUCCEEDS!"))
4053 proutn(_("The crystals mined were "))
4061 # Check to see if captain in shuttle craft
4066 # Inform captain of attempt to reach safety
4070 prouts(_("***RED ALERT! RED ALERT!"))
4072 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4073 prouts(_(" a supernova."))
4075 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4076 prout(_("safely out of quadrant."))
4077 if not damaged(DRADIO):
4078 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4079 # Try to use warp engines
4080 if damaged(DWARPEN):
4082 prout(_("Warp engines damaged."))
4085 game.warpfac = randreal(6.0, 8.0)
4086 prout(_("Warp factor set to %d") % int(game.warpfac))
4087 power = 0.75*game.energy
4088 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4089 dist = max(dist, randreal(math.sqrt(2)))
4090 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4091 game.optime = bugout.time(game.warpfac)
4093 game.inorbit = False
4094 warp(bugout, involuntary=True)
4096 # This is bad news, we didn't leave quadrant.
4100 prout(_("Insufficient energy to leave quadrant."))
4103 # Repeat if another snova
4104 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4106 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4107 finish(FWON) # Snova killed remaining enemy.
4110 "Let's do the time warp again."
4111 prout(_("***TIME WARP ENTERED."))
4112 if game.state.snap and withprob(0.5):
4114 prout(_("You are traveling backwards in time %d stardates.") %
4115 int(game.state.date-game.snapsht.date))
4116 game.state = game.snapsht
4117 game.state.snap = False
4118 if len(game.state.kcmdr):
4119 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4120 schedule(FBATTAK, expran(0.3*game.intime))
4121 schedule(FSNOVA, expran(0.5*game.intime))
4122 # next snapshot will be sooner
4123 schedule(FSNAP, expran(0.25*game.state.remtime))
4125 if game.state.nscrem:
4126 schedule(FSCMOVE, 0.2777)
4130 game.battle.invalidate()
4131 # Make sure Galileo is consistant -- Snapshot may have been taken
4132 # when on planet, which would give us two Galileos!
4134 for l in range(game.inplan):
4135 if game.state.planets[l].known == "shuttle_down":
4137 if game.iscraft == "onship" and game.ship=='E':
4138 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4139 game.iscraft = "offship"
4140 # Likewise, if in the original time the Galileo was abandoned, but
4141 # was on ship earlier, it would have vanished -- let's restore it.
4142 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4143 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4144 game.iscraft = "onship"
4145 # There used to be code to do the actual reconstrction here,
4146 # but the starchart is now part of the snapshotted galaxy state.
4147 prout(_("Spock has reconstructed a correct star chart from memory"))
4149 # Go forward in time
4150 game.optime = expran(0.5*game.intime)
4151 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4152 # cheat to make sure no tractor beams occur during time warp
4153 postpone(FTBEAM, game.optime)
4154 game.damage[DRADIO] += game.optime
4156 events() # Stas Sergeev added this -- do pending events
4159 "Launch deep-space probe."
4160 # New code to launch a deep space probe
4161 if game.nprobes == 0:
4164 if game.ship == 'E':
4165 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4167 prout(_("Ye Faerie Queene has no deep space probes."))
4172 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4174 if is_scheduled(FDSPROB):
4177 if damaged(DRADIO) and game.condition != "docked":
4178 prout(_("Spock- \"Records show the previous probe has not yet"))
4179 prout(_(" reached its destination.\""))
4181 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4183 key = scanner.next()
4185 if game.nprobes == 1:
4186 prout(_("1 probe left."))
4188 prout(_("%d probes left") % game.nprobes)
4189 proutn(_("Are you sure you want to fire a probe? "))
4192 game.isarmed = False
4193 if key == "IHALPHA" and scanner.token == "armed":
4195 key = scanner.next()
4196 elif key == "IHEOL":
4197 proutn(_("Arm NOVAMAX warhead? "))
4199 elif key == "IHREAL": # first element of course
4200 scanner.push(scanner.token)
4202 game.probe = getcourse(isprobe=True)
4206 schedule(FDSPROB, 0.01) # Time to move one sector
4207 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4212 "Yell for help from nearest starbase."
4213 # There's more than one way to move in this game!
4215 # Test for conditions which prevent calling for help
4216 if game.condition == "docked":
4217 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4220 prout(_("Subspace radio damaged."))
4222 if not game.state.baseq:
4223 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4226 prout(_("You must be aboard the %s.") % crmshp())
4228 # OK -- call for help from nearest starbase
4231 # There's one in this quadrant
4232 ddist = (game.base - game.sector).distance()
4235 for ibq in game.state.baseq:
4236 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4239 # Since starbase not in quadrant, set up new quadrant
4242 # dematerialize starship
4243 game.quad[game.sector.i][game.sector.j]='.'
4244 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4245 % (game.quadrant, crmshp()))
4246 game.sector.invalidate()
4247 for m in range(1, 5+1):
4248 w = game.base.scatter()
4249 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4250 # found one -- finish up
4253 if not game.sector.is_valid():
4254 prout(_("You have been lost in space..."))
4255 finish(FMATERIALIZE)
4257 # Give starbase three chances to rematerialize starship
4258 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4259 for m in range(1, 3+1):
4260 if m == 1: proutn(_("1st"))
4261 elif m == 2: proutn(_("2nd"))
4262 elif m == 3: proutn(_("3rd"))
4263 proutn(_(" attempt to re-materialize ") + crmshp())
4264 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4267 if randreal() > probf:
4271 curses.delay_output(500)
4273 game.quad[game.sector.i][game.sector.j]='?'
4276 setwnd(message_window)
4277 finish(FMATERIALIZE)
4279 game.quad[game.sector.i][game.sector.j]=game.ship
4281 prout(_("succeeds."))
4285 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4290 if game.condition=="docked":
4292 prout(_("You cannot abandon Ye Faerie Queene."))
4295 # Must take shuttle craft to exit
4296 if game.damage[DSHUTTL]==-1:
4297 prout(_("Ye Faerie Queene has no shuttle craft."))
4299 if game.damage[DSHUTTL]<0:
4300 prout(_("Shuttle craft now serving Big Macs."))
4302 if game.damage[DSHUTTL]>0:
4303 prout(_("Shuttle craft damaged."))
4306 prout(_("You must be aboard the ship."))
4308 if game.iscraft != "onship":
4309 prout(_("Shuttle craft not currently available."))
4311 # Emit abandon ship messages
4313 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4315 prouts(_("***ALL HANDS ABANDON SHIP!"))
4317 prout(_("Captain and crew escape in shuttle craft."))
4318 if not game.state.baseq:
4319 # Oops! no place to go...
4322 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4324 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4325 prout(_("Remainder of ship's complement beam down"))
4326 prout(_("to nearest habitable planet."))
4327 elif q.planet != None and not damaged(DTRANSP):
4328 prout(_("Remainder of ship's complement beam down to %s.") %
4331 prout(_("Entire crew of %d left to die in outer space.") %
4333 game.casual += game.state.crew
4334 game.abandoned += game.state.crew
4335 # If at least one base left, give 'em the Faerie Queene
4337 game.icrystl = False # crystals are lost
4338 game.nprobes = 0 # No probes
4339 prout(_("You are captured by Klingons and released to"))
4340 prout(_("the Federation in a prisoner-of-war exchange."))
4341 nb = randrange(len(game.state.baseq))
4342 # Set up quadrant and position FQ adjacient to base
4343 if not game.quadrant == game.state.baseq[nb]:
4344 game.quadrant = game.state.baseq[nb]
4345 game.sector.i = game.sector.j = 5
4348 # position next to base by trial and error
4349 game.quad[game.sector.i][game.sector.j] = '.'
4350 for l in range(QUADSIZE):
4351 game.sector = game.base.scatter()
4352 if game.sector.valid_sector() and \
4353 game.quad[game.sector.i][game.sector.j] == '.':
4356 break # found a spot
4357 game.sector.i=QUADSIZE/2
4358 game.sector.j=QUADSIZE/2
4360 # Get new commission
4361 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4362 game.state.crew = FULLCREW
4363 prout(_("Starfleet puts you in command of another ship,"))
4364 prout(_("the Faerie Queene, which is antiquated but,"))
4365 prout(_("still useable."))
4367 prout(_("The dilithium crystals have been moved."))
4369 game.iscraft = "offship" # Galileo disappears
4371 game.condition="docked"
4372 for l in range(NDEVICES):
4373 game.damage[l] = 0.0
4374 game.damage[DSHUTTL] = -1
4375 game.energy = game.inenrg = 3000.0
4376 game.shield = game.inshld = 1250.0
4377 game.torps = game.intorps = 6
4378 game.lsupres=game.inlsr=3.0
4383 # Code from planets.c begins here.
4386 "Abort a lengthy operation if an event interrupts it."
4389 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4394 "Report on (uninhabited) planets in the galaxy."
4398 prout(_("Spock- \"Planet report follows, Captain.\""))
4400 for i in range(game.inplan):
4401 if game.state.planets[i].pclass == "destroyed":
4403 if (game.state.planets[i].known != "unknown" \
4404 and not game.state.planets[i].inhabited) \
4407 if game.idebug and game.state.planets[i].known=="unknown":
4408 proutn("(Unknown) ")
4409 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4410 proutn(_(" class "))
4411 proutn(game.state.planets[i].pclass)
4413 if game.state.planets[i].crystals != "present":
4415 prout(_("dilithium crystals present."))
4416 if game.state.planets[i].known=="shuttle_down":
4417 prout(_(" Shuttle Craft Galileo on surface."))
4419 prout(_("No information available."))
4422 "Enter standard orbit."
4426 prout(_("Already in standard orbit."))
4428 if damaged(DWARPEN) and damaged(DIMPULS):
4429 prout(_("Both warp and impulse engines damaged."))
4431 if not game.plnet.is_valid():
4432 prout("There is no planet in this sector.")
4434 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4435 prout(crmshp() + _(" not adjacent to planet."))
4438 game.optime = randreal(0.02, 0.05)
4439 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4443 game.height = randreal(1400, 8600)
4444 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4449 "Examine planets in this quadrant."
4450 if damaged(DSRSENS):
4451 if game.options & OPTION_TTY:
4452 prout(_("Short range sensors damaged."))
4454 if game.iplnet == None:
4455 if game.options & OPTION_TTY:
4456 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4458 if game.iplnet.known == "unknown":
4459 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4461 prout(_(" Planet at Sector %s is of class %s.") %
4462 (game.plnet, game.iplnet.pclass))
4463 if game.iplnet.known=="shuttle_down":
4464 prout(_(" Sensors show Galileo still on surface."))
4465 proutn(_(" Readings indicate"))
4466 if game.iplnet.crystals != "present":
4468 prout(_(" dilithium crystals present.\""))
4469 if game.iplnet.known == "unknown":
4470 game.iplnet.known = "known"
4471 elif game.iplnet.inhabited:
4472 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4473 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4476 "Use the transporter."
4480 if damaged(DTRANSP):
4481 prout(_("Transporter damaged."))
4482 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4484 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4488 if not game.inorbit:
4489 prout(crmshp() + _(" not in standard orbit."))
4492 prout(_("Impossible to transport through shields."))
4494 if game.iplnet.known=="unknown":
4495 prout(_("Spock- \"Captain, we have no information on this planet"))
4496 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4497 prout(_(" you may not go down.\""))
4499 if not game.landed and game.iplnet.crystals=="absent":
4500 prout(_("Spock- \"Captain, I fail to see the logic in"))
4501 prout(_(" exploring a planet with no dilithium crystals."))
4502 proutn(_(" Are you sure this is wise?\" "))
4506 if not (game.options & OPTION_PLAIN):
4507 nrgneed = 50 * game.skill + game.height / 100.0
4508 if nrgneed > game.energy:
4509 prout(_("Engineering to bridge--"))
4510 prout(_(" Captain, we don't have enough energy for transportation."))
4512 if not game.landed and nrgneed * 2 > game.energy:
4513 prout(_("Engineering to bridge--"))
4514 prout(_(" Captain, we have enough energy only to transport you down to"))
4515 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4516 if game.iplnet.known == "shuttle_down":
4517 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4518 proutn(_(" Are you sure this is wise?\" "))
4523 # Coming from planet
4524 if game.iplnet.known=="shuttle_down":
4525 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4529 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4530 prout(_("Landing party assembled, ready to beam up."))
4532 prout(_("Kirk whips out communicator..."))
4533 prouts(_("BEEP BEEP BEEP"))
4535 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4538 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4540 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4542 prout(_("Kirk- \"Energize.\""))
4545 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4548 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4550 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4553 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4554 game.landed = not game.landed
4555 game.energy -= nrgneed
4557 prout(_("Transport complete."))
4558 if game.landed and game.iplnet.known=="shuttle_down":
4559 prout(_("The shuttle craft Galileo is here!"))
4560 if not game.landed and game.imine:
4567 "Strip-mine a world for dilithium."
4571 prout(_("Mining party not on planet."))
4573 if game.iplnet.crystals == "mined":
4574 prout(_("This planet has already been strip-mined for dilithium."))
4576 elif game.iplnet.crystals == "absent":
4577 prout(_("No dilithium crystals on this planet."))
4580 prout(_("You've already mined enough crystals for this trip."))
4582 if game.icrystl and game.cryprob == 0.05:
4583 prout(_("With all those fresh crystals aboard the ") + crmshp())
4584 prout(_("there's no reason to mine more at this time."))
4586 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4589 prout(_("Mining operation complete."))
4590 game.iplnet.crystals = "mined"
4591 game.imine = game.ididit = True
4594 "Use dilithium crystals."
4598 if not game.icrystl:
4599 prout(_("No dilithium crystals available."))
4601 if game.energy >= 1000:
4602 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4603 prout(_(" except when Condition Yellow exists."))
4605 prout(_("Spock- \"Captain, I must warn you that loading"))
4606 prout(_(" raw dilithium crystals into the ship's power"))
4607 prout(_(" system may risk a severe explosion."))
4608 proutn(_(" Are you sure this is wise?\" "))
4613 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4614 prout(_(" Mr. Spock and I will try it.\""))
4616 prout(_("Spock- \"Crystals in place, Sir."))
4617 prout(_(" Ready to activate circuit.\""))
4619 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4621 if withprob(game.cryprob):
4622 prouts(_(" \"Activating now! - - No good! It's***"))
4624 prouts(_("***RED ALERT! RED A*L********************************"))
4627 prouts(_("****************** KA-BOOM!!!! *******************"))
4631 game.energy += randreal(5000.0, 5500.0)
4632 prouts(_(" \"Activating now! - - "))
4633 prout(_("The instruments"))
4634 prout(_(" are going crazy, but I think it's"))
4635 prout(_(" going to work!! Congratulations, Sir!\""))
4640 "Use shuttlecraft for planetary jaunt."
4643 if damaged(DSHUTTL):
4644 if game.damage[DSHUTTL] == -1.0:
4645 if game.inorbit and game.iplnet.known == "shuttle_down":
4646 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4648 prout(_("Ye Faerie Queene had no shuttle craft."))
4649 elif game.damage[DSHUTTL] > 0:
4650 prout(_("The Galileo is damaged."))
4651 else: # game.damage[DSHUTTL] < 0
4652 prout(_("Shuttle craft is now serving Big Macs."))
4654 if not game.inorbit:
4655 prout(crmshp() + _(" not in standard orbit."))
4657 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4658 prout(_("Shuttle craft not currently available."))
4660 if not game.landed and game.iplnet.known=="shuttle_down":
4661 prout(_("You will have to beam down to retrieve the shuttle craft."))
4663 if game.shldup or game.condition == "docked":
4664 prout(_("Shuttle craft cannot pass through shields."))
4666 if game.iplnet.known=="unknown":
4667 prout(_("Spock- \"Captain, we have no information on this planet"))
4668 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4669 prout(_(" you may not fly down.\""))
4671 game.optime = 3.0e-5*game.height
4672 if game.optime >= 0.8*game.state.remtime:
4673 prout(_("First Officer Spock- \"Captain, I compute that such"))
4674 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4675 int(100*game.optime/game.state.remtime))
4676 prout(_("remaining time."))
4677 proutn(_("Are you sure this is wise?\" "))
4683 if game.iscraft == "onship":
4685 if not damaged(DTRANSP):
4686 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4690 proutn(_("Shuttle crew"))
4692 proutn(_("Rescue party"))
4693 prout(_(" boards Galileo and swoops toward planet surface."))
4694 game.iscraft = "offship"
4698 game.iplnet.known="shuttle_down"
4699 prout(_("Trip complete."))
4702 # Ready to go back to ship
4703 prout(_("You and your mining party board the"))
4704 prout(_("shuttle craft for the trip back to the Enterprise."))
4706 prouts(_("The short hop begins . . ."))
4708 game.iplnet.known="known"
4714 game.iscraft = "onship"
4720 prout(_("Trip complete."))
4723 # Kirk on ship and so is Galileo
4724 prout(_("Mining party assembles in the hangar deck,"))
4725 prout(_("ready to board the shuttle craft \"Galileo\"."))
4727 prouts(_("The hangar doors open; the trip begins."))
4730 game.iscraft = "offship"
4733 game.iplnet.known = "shuttle_down"
4736 prout(_("Trip complete."))
4740 "Use the big zapper."
4744 if game.ship != 'E':
4745 prout(_("Ye Faerie Queene has no death ray."))
4747 if len(game.enemies)==0:
4748 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4751 prout(_("Death Ray is damaged."))
4753 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4754 prout(_(" is highly unpredictible. Considering the alternatives,"))
4755 proutn(_(" are you sure this is wise?\" "))
4758 prout(_("Spock- \"Acknowledged.\""))
4761 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4763 prout(_("Crew scrambles in emergency preparation."))
4764 prout(_("Spock and Scotty ready the death ray and"))
4765 prout(_("prepare to channel all ship's power to the device."))
4767 prout(_("Spock- \"Preparations complete, sir.\""))
4768 prout(_("Kirk- \"Engage!\""))
4770 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4773 if game.options & OPTION_PLAIN:
4777 prouts(_("Sulu- \"Captain! It's working!\""))
4779 while len(game.enemies) > 0:
4780 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4781 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4782 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4784 if (game.options & OPTION_PLAIN) == 0:
4785 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4787 prout(_(" is still operational.\""))
4789 prout(_(" has been rendered nonfunctional.\""))
4790 game.damage[DDRAY] = 39.95
4792 r = randreal() # Pick failure method
4794 prouts(_("Sulu- \"Captain! It's working!\""))
4796 prouts(_("***RED ALERT! RED ALERT!"))
4798 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4800 prouts(_("***RED ALERT! RED A*L********************************"))
4803 prouts(_("****************** KA-BOOM!!!! *******************"))
4808 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4810 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4812 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4813 prout(_(" have apparently been transformed into strange mutations."))
4814 prout(_(" Vulcans do not seem to be affected."))
4816 prout(_("Kirk- \"Raauch! Raauch!\""))
4820 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4822 proutn(_("Spock- \"I believe the word is"))
4823 prouts(_(" *ASTONISHING*"))
4824 prout(_(" Mr. Sulu."))
4825 for i in range(QUADSIZE):
4826 for j in range(QUADSIZE):
4827 if game.quad[i][j] == '.':
4828 game.quad[i][j] = '?'
4829 prout(_(" Captain, our quadrant is now infested with"))
4830 prouts(_(" - - - - - - *THINGS*."))
4832 prout(_(" I have no logical explanation.\""))
4834 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4836 prout(_("Scotty- \"There are so many tribbles down here"))
4837 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4841 # Code from reports.c begins here
4843 def attackreport(curt):
4844 "eport status of bases under attack."
4846 if is_scheduled(FCDBAS):
4847 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4848 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4849 elif game.isatb == 1:
4850 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4851 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4853 prout(_("No Starbase is currently under attack."))
4855 if is_scheduled(FCDBAS):
4856 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4858 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4862 # report on general game status
4864 s1 = (game.thawed and _("thawed ")) or ""
4865 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4866 s3 = (None, _("novice"), _("fair"),
4867 _("good"), _("expert"), _("emeritus"))[game.skill]
4868 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4869 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4870 prout(_("No plaque is allowed."))
4872 prout(_("This is tournament game %d.") % game.tourn)
4873 prout(_("Your secret password is \"%s\"") % game.passwd)
4874 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4875 (game.inkling + game.incom + game.inscom)))
4876 if game.incom - len(game.state.kcmdr):
4877 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4878 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4879 prout(_(", but no Commanders."))
4882 if game.skill > SKILL_FAIR:
4883 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4884 if len(game.state.baseq) != game.inbase:
4886 if game.inbase-len(game.state.baseq)==1:
4887 proutn(_("has been 1 base"))
4889 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4890 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4892 prout(_("There are %d bases.") % game.inbase)
4893 if communicating() or game.iseenit:
4894 # Don't report this if not seen and
4895 # either the radio is dead or not at base!
4899 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4901 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4902 if game.ship == 'E':
4903 proutn(_("You have "))
4905 proutn("%d" % (game.nprobes))
4908 proutn(_(" deep space probe"))
4912 if communicating() and is_scheduled(FDSPROB):
4914 proutn(_("An armed deep space probe is in "))
4916 proutn(_("A deep space probe is in "))
4917 prout("Quadrant %s." % game.probec)
4919 if game.cryprob <= .05:
4920 prout(_("Dilithium crystals aboard ship... not yet used."))
4924 while game.cryprob > ai:
4927 prout(_("Dilithium crystals have been used %d time%s.") % \
4928 (i, (_("s"), "")[i==1]))
4932 "Long-range sensor scan."
4933 if damaged(DLRSENS):
4934 # Now allow base's sensors if docked
4935 if game.condition != "docked":
4937 prout(_("LONG-RANGE SENSORS DAMAGED."))
4940 prout(_("Starbase's long-range scan"))
4942 prout(_("Long-range scan"))
4943 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4946 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4947 if not Coord(x, y).valid_quadrant():
4951 if not damaged(DRADIO):
4952 game.state.galaxy[x][y].charted = True
4953 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4954 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4955 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4956 if not silent and game.state.galaxy[x][y].supernova:
4959 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4967 for i in range(NDEVICES):
4970 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4971 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4973 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4974 game.damage[i]+0.05,
4975 DOCKFAC*game.damage[i]+0.005))
4977 prout(_("All devices functional."))
4980 "Update the chart in the Enterprise's computer from galaxy data."
4981 game.lastchart = game.state.date
4982 for i in range(GALSIZE):
4983 for j in range(GALSIZE):
4984 if game.state.galaxy[i][j].charted:
4985 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
4986 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
4987 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
4990 "Display the star chart."
4992 if (game.options & OPTION_AUTOSCAN):
4994 if not damaged(DRADIO):
4996 if game.lastchart < game.state.date and game.condition == "docked":
4997 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
4999 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5000 if game.state.date > game.lastchart:
5001 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5002 prout(" 1 2 3 4 5 6 7 8")
5003 for i in range(GALSIZE):
5004 proutn("%d |" % (i+1))
5005 for j in range(GALSIZE):
5006 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5010 if game.state.galaxy[i][j].supernova:
5012 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5014 elif game.state.galaxy[i][j].charted:
5015 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5019 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5027 def sectscan(goodScan, i, j):
5028 "Light up an individual dot in a sector."
5029 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5030 textcolor({"green":GREEN,
5034 "dead":BROWN}[game.condition])
5035 if game.quad[i][j] != game.ship:
5037 proutn("%c " % game.quad[i][j])
5043 "Emit status report lines"
5044 if not req or req == 1:
5045 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5046 % (game.state.date, game.state.remtime))
5047 if not req or req == 2:
5048 if game.condition != "docked":
5050 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5051 (game.condition.upper(), sum(map(lambda x: x > 0, game.damage))))
5052 if not req or req == 3:
5053 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5054 if not req or req == 4:
5055 if damaged(DLIFSUP):
5056 if game.condition == "docked":
5057 s = _("DAMAGED, Base provides")
5059 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5062 prstat(_("Life Support"), s)
5063 if not req or req == 5:
5064 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5065 if not req or req == 6:
5067 if game.icrystl and (game.options & OPTION_SHOWME):
5068 extra = _(" (have crystals)")
5069 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5070 if not req or req == 7:
5071 prstat(_("Torpedoes"), "%d" % (game.torps))
5072 if not req or req == 8:
5073 if damaged(DSHIELD):
5079 data = _(" %d%% %.1f units") \
5080 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5081 prstat(_("Shields"), s+data)
5082 if not req or req == 9:
5083 prstat(_("Klingons Left"), "%d" \
5084 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5085 if not req or req == 10:
5086 if game.options & OPTION_WORLDS:
5087 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5088 if plnet and plnet.inhabited:
5089 prstat(_("Major system"), plnet.name)
5091 prout(_("Sector is uninhabited"))
5092 elif not req or req == 11:
5093 attackreport(not req)
5096 "Request specified status data, a historical relic from slow TTYs."
5097 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5098 while scanner.next() == "IHEOL":
5099 proutn(_("Information desired? "))
5101 if scanner.token in requests:
5102 status(requests.index(scanner.token))
5104 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5105 prout((" date, condition, position, lsupport, warpfactor,"))
5106 prout((" energy, torpedoes, shields, klingons, system, time."))
5111 if damaged(DSRSENS):
5112 # Allow base's sensors if docked
5113 if game.condition != "docked":
5114 prout(_(" S.R. SENSORS DAMAGED!"))
5117 prout(_(" [Using Base's sensors]"))
5119 prout(_(" Short-range scan"))
5120 if goodScan and not damaged(DRADIO):
5121 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5122 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5123 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5124 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5125 prout(" 1 2 3 4 5 6 7 8 9 10")
5126 if game.condition != "docked":
5128 for i in range(QUADSIZE):
5129 proutn("%2d " % (i+1))
5130 for j in range(QUADSIZE):
5131 sectscan(goodScan, i, j)
5135 "Use computer to get estimated time of arrival for a warp jump."
5136 w1 = Coord(); w2 = Coord()
5138 if damaged(DCOMPTR):
5139 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5142 if scanner.next() != "IHREAL":
5145 proutn(_("Destination quadrant and/or sector? "))
5146 if scanner.next()!="IHREAL":
5149 w1.j = int(scanner.real-0.5)
5150 if scanner.next() != "IHREAL":
5153 w1.i = int(scanner.real-0.5)
5154 if scanner.next() == "IHREAL":
5155 w2.j = int(scanner.real-0.5)
5156 if scanner.next() != "IHREAL":
5159 w2.i = int(scanner.real-0.5)
5161 if game.quadrant.j>w1.i:
5165 if game.quadrant.i>w1.j:
5169 if not w1.valid_quadrant() or not w2.valid_sector():
5172 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5173 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5176 prout(_("Answer \"no\" if you don't know the value:"))
5179 proutn(_("Time or arrival date? "))
5180 if scanner.next()=="IHREAL":
5181 ttime = scanner.real
5182 if ttime > game.state.date:
5183 ttime -= game.state.date # Actually a star date
5184 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5185 if ttime <= 1e-10 or twarp > 10:
5186 prout(_("We'll never make it, sir."))
5193 proutn(_("Warp factor? "))
5194 if scanner.next()== "IHREAL":
5196 twarp = scanner.real
5197 if twarp<1.0 or twarp > 10.0:
5201 prout(_("Captain, certainly you can give me one of these."))
5204 ttime = (10.0*dist)/twarp**2
5205 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5206 if tpower >= game.energy:
5207 prout(_("Insufficient energy, sir."))
5208 if not game.shldup or tpower > game.energy*2.0:
5211 proutn(_("New warp factor to try? "))
5212 if scanner.next() == "IHREAL":
5214 twarp = scanner.real
5215 if twarp<1.0 or twarp > 10.0:
5223 prout(_("But if you lower your shields,"))
5224 proutn(_("remaining"))
5227 proutn(_("Remaining"))
5228 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5230 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5232 prout(_("Any warp speed is adequate."))
5234 prout(_("Minimum warp needed is %.2f,") % (twarp))
5235 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5236 if game.state.remtime < ttime:
5237 prout(_("Unfortunately, the Federation will be destroyed by then."))
5239 prout(_("You'll be taking risks at that speed, Captain"))
5240 if (game.isatb==1 and game.state.kscmdr == w1 and \
5241 scheduled(FSCDBAS)< ttime+game.state.date) or \
5242 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5243 prout(_("The starbase there will be destroyed by then."))
5244 proutn(_("New warp factor to try? "))
5245 if scanner.next() == "IHREAL":
5247 twarp = scanner.real
5248 if twarp<1.0 or twarp > 10.0:
5256 # Code from setup.c begins here
5259 "Issue a historically correct banner."
5261 prout(_("-SUPER- STAR TREK"))
5263 # From the FORTRAN original
5264 # prout(_("Latest update-21 Sept 78"))
5270 scanner.push("emsave.trk")
5271 key = scanner.next()
5273 proutn(_("File name: "))
5274 key = scanner.next()
5275 if key != "IHALPHA":
5278 if '.' not in scanner.token:
5279 scanner.token += ".trk"
5281 fp = open(scanner.token, "wb")
5283 prout(_("Can't freeze game as file %s") % scanner.token)
5285 cPickle.dump(game, fp)
5290 "Retrieve saved game."
5293 key = scanner.next()
5295 proutn(_("File name: "))
5296 key = scanner.next()
5297 if key != "IHALPHA":
5300 if '.' not in scanner.token:
5301 scanner.token += ".trk"
5303 fp = open(scanner.token, "rb")
5305 prout(_("Can't thaw game in %s") % scanner.token)
5307 game = cPickle.load(fp)
5312 # I used <http://www.memory-alpha.org> to find planets
5313 # with references in ST:TOS. Earth and the Alpha Centauri
5314 # Colony have been omitted.
5316 # Some planets marked Class G and P here will be displayed as class M
5317 # because of the way planets are generated. This is a known bug.
5320 _("Andoria (Fesoan)"), # several episodes
5321 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5322 _("Vulcan (T'Khasi)"), # many episodes
5323 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5324 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5325 _("Ardana"), # TOS: "The Cloud Minders"
5326 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5327 _("Gideon"), # TOS: "The Mark of Gideon"
5328 _("Aldebaran III"), # TOS: "The Deadly Years"
5329 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5330 _("Altair IV"), # TOS: "Amok Time
5331 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5332 _("Benecia"), # TOS: "The Conscience of the King"
5333 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5334 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5335 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5336 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5337 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5338 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5339 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5340 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5341 _("Ingraham B"), # TOS: "Operation: Annihilate"
5342 _("Janus IV"), # TOS: "The Devil in the Dark"
5343 _("Makus III"), # TOS: "The Galileo Seven"
5344 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5345 _("Omega IV"), # TOS: "The Omega Glory"
5346 _("Regulus V"), # TOS: "Amok Time
5347 _("Deneva"), # TOS: "Operation -- Annihilate!"
5348 # Worlds from BSD Trek
5349 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5350 _("Beta III"), # TOS: "The Return of the Archons"
5351 _("Triacus"), # TOS: "And the Children Shall Lead",
5352 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5354 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5355 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5356 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5357 # _("Izar"), # TOS: "Whom Gods Destroy"
5358 # _("Tiburon"), # TOS: "The Way to Eden"
5359 # _("Merak II"), # TOS: "The Cloud Minders"
5360 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5361 # _("Iotia"), # TOS: "A Piece of the Action"
5365 _("S. R. Sensors"), \
5366 _("L. R. Sensors"), \
5368 _("Photon Tubes"), \
5369 _("Life Support"), \
5370 _("Warp Engines"), \
5371 _("Impulse Engines"), \
5373 _("Subspace Radio"), \
5374 _("Shuttle Craft"), \
5376 _("Navigation System"), \
5378 _("Shield Control"), \
5384 "Prepare to play, set up cosmos."
5386 # Decide how many of everything
5388 return # frozen game
5389 # Prepare the Enterprise
5390 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5392 game.state.crew = FULLCREW
5393 game.energy = game.inenrg = 5000.0
5394 game.shield = game.inshld = 2500.0
5397 game.quadrant = randplace(GALSIZE)
5398 game.sector = randplace(QUADSIZE)
5399 game.torps = game.intorps = 10
5400 game.nprobes = randrange(2, 5)
5402 for i in range(NDEVICES):
5403 game.damage[i] = 0.0
5404 # Set up assorted game parameters
5405 game.battle = Coord()
5406 game.state.date = game.indate = 100.0 * randreal(20, 51)
5407 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5408 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5409 game.isatb = game.state.nplankl = 0
5410 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5411 game.iscraft = "onship"
5416 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5418 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5420 game.state.planets = [] # Planet information
5421 game.state.baseq = [] # Base quadrant coordinates
5422 game.state.kcmdr = [] # Commander quadrant coordinates
5423 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5425 # Starchart is functional but we've never seen it
5426 game.lastchart = FOREVER
5427 # Put stars in the galaxy
5429 for i in range(GALSIZE):
5430 for j in range(GALSIZE):
5431 k = randrange(1, QUADSIZE**2/10+1)
5433 game.state.galaxy[i][j].stars = k
5434 # Locate star bases in galaxy
5435 for i in range(game.inbase):
5438 w = randplace(GALSIZE)
5439 if not game.state.galaxy[w.i][w.j].starbase:
5442 # C version: for (j = i-1; j > 0; j--)
5443 # so it did them in the opposite order.
5444 for j in range(1, i):
5445 # Improved placement algorithm to spread out bases
5446 distq = (w - game.state.baseq[j]).distance()
5447 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5450 prout("=== Abandoning base #%d at %s" % (i, w))
5452 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5454 prout("=== Saving base #%d, close to #%d" % (i, j))
5457 game.state.baseq.append(w)
5458 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5459 # Position ordinary Klingon Battle Cruisers
5461 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5462 if klumper > MAXKLQUAD:
5466 klump = (1.0 - r*r)*klumper
5471 w = randplace(GALSIZE)
5472 if not game.state.galaxy[w.i][w.j].supernova and \
5473 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5475 game.state.galaxy[w.i][w.j].klingons += int(klump)
5478 # Position Klingon Commander Ships
5479 for i in range(game.incom):
5481 w = randplace(GALSIZE)
5482 if not welcoming(w) or w in game.state.kcmdr:
5484 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5486 game.state.galaxy[w.i][w.j].klingons += 1
5487 game.state.kcmdr.append(w)
5488 # Locate planets in galaxy
5489 for i in range(game.inplan):
5491 w = randplace(GALSIZE)
5492 if game.state.galaxy[w.i][w.j].planet == None:
5496 new.crystals = "absent"
5497 if (game.options & OPTION_WORLDS) and i < NINHAB:
5498 new.pclass = "M" # All inhabited planets are class M
5499 new.crystals = "absent"
5501 new.name = systnames[i]
5502 new.inhabited = True
5504 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5506 new.crystals = "present"
5507 new.known = "unknown"
5508 new.inhabited = False
5509 game.state.galaxy[w.i][w.j].planet = new
5510 game.state.planets.append(new)
5512 for i in range(game.state.nromrem):
5513 w = randplace(GALSIZE)
5514 game.state.galaxy[w.i][w.j].romulans += 1
5515 # Place the Super-Commander if needed
5516 if game.state.nscrem > 0:
5518 w = randplace(GALSIZE)
5521 game.state.kscmdr = w
5522 game.state.galaxy[w.i][w.j].klingons += 1
5523 # Initialize times for extraneous events
5524 schedule(FSNOVA, expran(0.5 * game.intime))
5525 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5526 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5527 schedule(FBATTAK, expran(0.3*game.intime))
5529 if game.state.nscrem:
5530 schedule(FSCMOVE, 0.2777)
5535 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5536 schedule(FDISTR, expran(1.0 + game.intime))
5541 # Place thing (in tournament game, we don't want one!)
5542 # New in SST2K: never place the Thing near a starbase.
5543 # This makes sense and avoids a special case in the old code.
5545 if game.tourn is None:
5547 thing = randplace(GALSIZE)
5548 if thing not in game.state.baseq:
5551 game.state.snap = False
5552 if game.skill == SKILL_NOVICE:
5553 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5554 prout(_("a deadly Klingon invasion force. As captain of the United"))
5555 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5556 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5557 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5558 prout(_("your mission. As you proceed you may be given more time."))
5560 prout(_("You will have %d supporting starbases.") % (game.inbase))
5561 proutn(_("Starbase locations- "))
5563 prout(_("Stardate %d.") % int(game.state.date))
5565 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5566 prout(_("An unknown number of Romulans."))
5567 if game.state.nscrem:
5568 prout(_("And one (GULP) Super-Commander."))
5569 prout(_("%d stardates.") % int(game.intime))
5570 proutn(_("%d starbases in ") % game.inbase)
5571 for i in range(game.inbase):
5572 proutn(`game.state.baseq[i]`)
5575 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5576 proutn(_(" Sector %s") % game.sector)
5578 prout(_("Good Luck!"))
5579 if game.state.nscrem:
5580 prout(_(" YOU'LL NEED IT."))
5583 setwnd(message_window)
5585 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5587 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5588 attack(torps_ok=False)
5591 "Choose your game type."
5593 game.tourn = game.length = 0
5595 game.skill = SKILL_NONE
5597 # if not scanner.inqueue: # Can start with command line options
5598 proutn(_("Would you like a regular, tournament, or saved game? "))
5600 if scanner.sees("tournament"):
5601 while scanner.next() == "IHEOL":
5602 proutn(_("Type in tournament number-"))
5603 if scanner.real == 0:
5605 continue # We don't want a blank entry
5606 game.tourn = int(round(scanner.real))
5607 random.seed(scanner.real)
5609 logfp.write("# random.seed(%d)\n" % scanner.real)
5611 if scanner.sees("saved") or scanner.sees("frozen"):
5615 if game.passwd == None:
5617 if not game.alldone:
5618 game.thawed = True # No plaque if not finished
5622 if scanner.sees("regular"):
5624 proutn(_("What is \"%s\"? ") % scanner.token)
5626 while game.length==0 or game.skill==SKILL_NONE:
5627 if scanner.next() == "IHALPHA":
5628 if scanner.sees("short"):
5630 elif scanner.sees("medium"):
5632 elif scanner.sees("long"):
5634 elif scanner.sees("novice"):
5635 game.skill = SKILL_NOVICE
5636 elif scanner.sees("fair"):
5637 game.skill = SKILL_FAIR
5638 elif scanner.sees("good"):
5639 game.skill = SKILL_GOOD
5640 elif scanner.sees("expert"):
5641 game.skill = SKILL_EXPERT
5642 elif scanner.sees("emeritus"):
5643 game.skill = SKILL_EMERITUS
5645 proutn(_("What is \""))
5646 proutn(scanner.token)
5651 proutn(_("Would you like a Short, Medium, or Long game? "))
5652 elif game.skill == SKILL_NONE:
5653 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5654 # Choose game options -- added by ESR for SST2K
5655 if scanner.next() != "IHALPHA":
5657 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5659 if scanner.sees("plain"):
5660 # Approximates the UT FORTRAN version.
5661 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5662 game.options |= OPTION_PLAIN
5663 elif scanner.sees("almy"):
5664 # Approximates Tom Almy's version.
5665 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5666 game.options |= OPTION_ALMY
5667 elif scanner.sees("fancy") or scanner.sees("\n"):
5669 elif len(scanner.token):
5670 proutn(_("What is \"%s\"?") % scanner.token)
5671 game.options &=~ OPTION_COLOR
5673 if game.passwd == "debug":
5675 prout("=== Debug mode enabled.")
5676 # Use parameters to generate initial values of things
5677 game.damfac = 0.5 * game.skill
5678 game.inbase = randrange(BASEMIN, BASEMAX+1)
5680 if game.options & OPTION_PLANETS:
5681 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5682 if game.options & OPTION_WORLDS:
5683 game.inplan += int(NINHAB)
5684 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5685 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5686 game.state.remtime = 7.0 * game.length
5687 game.intime = game.state.remtime
5688 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5689 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5690 game.state.remres = (game.inkling+4*game.incom)*game.intime
5691 game.inresor = game.state.remres
5692 if game.inkling > 50:
5693 game.state.inbase += 1
5696 def dropin(iquad=None):
5697 "Drop a feature on a random dot in the current quadrant."
5699 w = randplace(QUADSIZE)
5700 if game.quad[w.i][w.j] == '.':
5702 if iquad is not None:
5703 game.quad[w.i][w.j] = iquad
5707 "Update our alert status."
5708 game.condition = "green"
5709 if game.energy < 1000.0:
5710 game.condition = "yellow"
5711 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5712 game.condition = "red"
5714 game.condition="dead"
5717 "Drop new Klingon into current quadrant."
5718 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5721 "Sort enemies by distance so 'nearest' is meaningful."
5722 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
5725 "Set up a new state of quadrant, for when we enter or re-enter it."
5728 game.neutz = game.inorbit = game.landed = False
5729 game.ientesc = game.iseenit = False
5730 # Create a blank quadrant
5731 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5733 # Attempt to escape Super-commander, so tbeam back!
5736 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5737 # cope with supernova
5740 game.klhere = q.klingons
5741 game.irhere = q.romulans
5743 game.quad[game.sector.i][game.sector.j] = game.ship
5746 # Position ordinary Klingons
5747 for i in range(game.klhere):
5749 # If we need a commander, promote a Klingon
5750 for cmdr in game.state.kcmdr:
5751 if cmdr == game.quadrant:
5752 e = game.enemies[game.klhere-1]
5753 game.quad[e.location.i][e.location.j] = 'C'
5754 e.power = randreal(950,1350) + 50.0*game.skill
5756 # If we need a super-commander, promote a Klingon
5757 if game.quadrant == game.state.kscmdr:
5759 game.quad[e.location.i][e.location.j] = 'S'
5760 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5761 game.iscate = (game.state.remkl > 1)
5762 # Put in Romulans if needed
5763 for i in range(q.romulans):
5764 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5765 # If quadrant needs a starbase, put it in
5767 game.base = dropin('B')
5768 # If quadrant needs a planet, put it in
5770 game.iplnet = q.planet
5771 if not q.planet.inhabited:
5772 game.plnet = dropin('P')
5774 game.plnet = dropin('@')
5775 # Check for condition
5778 if game.irhere > 0 and game.klhere == 0:
5780 if not damaged(DRADIO):
5782 prout(_("LT. Uhura- \"Captain, an urgent message."))
5783 prout(_(" I'll put it on audio.\" CLICK"))
5785 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5786 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5787 # Put in THING if needed
5788 if thing == game.quadrant:
5789 Enemy(etype='?', loc=dropin(),
5790 power=randreal(6000,6500.0)+250.0*game.skill)
5791 if not damaged(DSRSENS):
5793 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5794 prout(_(" Please examine your short-range scan.\""))
5795 # Decide if quadrant needs a Tholian; lighten up if skill is low
5796 if game.options & OPTION_THOLIAN:
5797 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5798 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5799 (game.skill > SKILL_GOOD and withprob(0.08)):
5802 w.i = withprob(0.5) * (QUADSIZE-1)
5803 w.j = withprob(0.5) * (QUADSIZE-1)
5804 if game.quad[w.i][w.j] == '.':
5806 game.tholian = Enemy(etype='T', loc=w,
5807 power=randrange(100, 500) + 25.0*game.skill)
5808 # Reserve unoccupied corners
5809 if game.quad[0][0]=='.':
5810 game.quad[0][0] = 'X'
5811 if game.quad[0][QUADSIZE-1]=='.':
5812 game.quad[0][QUADSIZE-1] = 'X'
5813 if game.quad[QUADSIZE-1][0]=='.':
5814 game.quad[QUADSIZE-1][0] = 'X'
5815 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5816 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5818 # And finally the stars
5819 for i in range(q.stars):
5821 # Put in a few black holes
5822 for i in range(1, 3+1):
5825 # Take out X's in corners if Tholian present
5827 if game.quad[0][0]=='X':
5828 game.quad[0][0] = '.'
5829 if game.quad[0][QUADSIZE-1]=='X':
5830 game.quad[0][QUADSIZE-1] = '.'
5831 if game.quad[QUADSIZE-1][0]=='X':
5832 game.quad[QUADSIZE-1][0] = '.'
5833 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5834 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5837 "Set the self-destruct password."
5838 if game.options & OPTION_PLAIN:
5841 proutn(_("Please type in a secret password- "))
5843 game.passwd = scanner.token
5844 if game.passwd != None:
5848 game.passwd += chr(ord('a')+randrange(26))
5849 game.passwd += chr(ord('a')+randrange(26))
5850 game.passwd += chr(ord('a')+randrange(26))
5852 # Code from sst.c begins here
5855 ("SRSCAN", OPTION_TTY),
5856 ("STATUS", OPTION_TTY),
5857 ("REQUEST", OPTION_TTY),
5858 ("LRSCAN", OPTION_TTY),
5871 ("SENSORS", OPTION_PLANETS),
5872 ("ORBIT", OPTION_PLANETS),
5873 ("TRANSPORT", OPTION_PLANETS),
5874 ("MINE", OPTION_PLANETS),
5875 ("CRYSTALS", OPTION_PLANETS),
5876 ("SHUTTLE", OPTION_PLANETS),
5877 ("PLANETS", OPTION_PLANETS),
5882 ("PROBE", OPTION_PROBE),
5884 ("FREEZE", 0), # Synonym for SAVE
5890 ("SOS", 0), # Synonym for MAYDAY
5891 ("CALL", 0), # Synonym for MAYDAY
5898 "Generate a list of legal commands."
5899 prout(_("LEGAL COMMANDS ARE:"))
5901 for (key, opt) in commands:
5902 if not opt or (opt & game.options):
5903 proutn("%-12s " % key)
5905 if emitted % 5 == 4:
5910 "Browse on-line help."
5911 key = scanner.next()
5914 setwnd(prompt_window)
5915 proutn(_("Help on what command? "))
5916 key = scanner.next()
5917 setwnd(message_window)
5920 cmds = map(lambda x: x[0], commands)
5921 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
5928 cmd = scanner.token.upper()
5929 for directory in docpath:
5931 fp = open(os.path.join(directory, "sst.doc"), "r")
5936 prout(_("Spock- \"Captain, that information is missing from the"))
5937 prout(_(" computer. You need to find sst.doc and put it somewhere"))
5938 proutn(_(" in these directories: %s") % ":".join(docpath))
5940 # This used to continue: "You need to find SST.DOC and put
5941 # it in the current directory."
5944 linebuf = fp.readline()
5946 prout(_("Spock- \"Captain, there is no information on that command.\""))
5949 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5950 linebuf = linebuf[3:].strip()
5951 if cmd.upper() == linebuf:
5954 prout(_("Spock- \"Captain, I've found the following information:\""))
5957 linebuf = fp.readline()
5958 if "******" in linebuf:
5964 "Command-interpretation loop."
5965 while True: # command loop
5967 while True: # get a command
5969 game.optime = game.justin = False
5971 setwnd(prompt_window)
5974 if scanner.next() == "IHEOL":
5975 if game.options & OPTION_CURSES:
5978 elif scanner.token == "":
5982 setwnd(message_window)
5984 abandon_passed = False
5985 for (cmd, opt) in commands:
5986 # commands after ABANDON cannot be abbreviated
5987 if cmd == "ABANDON":
5988 abandon_passed = True
5989 if cmd == scanner.token.upper() or (not abandon_passed \
5990 and cmd.startswith(scanner.token.upper())):
5997 if cmd == "SRSCAN": # srscan
5999 elif cmd == "STATUS": # status
6001 elif cmd == "REQUEST": # status request
6003 elif cmd == "LRSCAN": # long range scan
6004 lrscan(silent=False)
6005 elif cmd == "PHASERS": # phasers
6009 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6013 elif cmd == "MOVE": # move under warp
6014 warp(wcourse=None, involuntary=False)
6015 elif cmd == "SHIELDS": # shields
6016 doshield(shraise=False)
6019 game.shldchg = False
6020 elif cmd == "DOCK": # dock at starbase
6023 attack(torps_ok=False)
6024 elif cmd == "DAMAGES": # damage reports
6026 elif cmd == "CHART": # chart
6028 elif cmd == "IMPULSE": # impulse
6030 elif cmd == "REST": # rest
6034 elif cmd == "WARP": # warp
6036 elif cmd == "SCORE": # score
6038 elif cmd == "SENSORS": # sensors
6040 elif cmd == "ORBIT": # orbit
6044 elif cmd == "TRANSPORT": # transport "beam"
6046 elif cmd == "MINE": # mine
6050 elif cmd == "CRYSTALS": # crystals
6054 elif cmd == "SHUTTLE": # shuttle
6058 elif cmd == "PLANETS": # Planet list
6060 elif cmd == "REPORT": # Game Report
6062 elif cmd == "COMPUTER": # use COMPUTER!
6064 elif cmd == "COMMANDS":
6066 elif cmd == "EMEXIT": # Emergency exit
6067 clrscr() # Hide screen
6068 freeze(True) # forced save
6069 raise SystemExit,1 # And quick exit
6070 elif cmd == "PROBE":
6071 probe() # Launch probe
6074 elif cmd == "ABANDON": # Abandon Ship
6076 elif cmd == "DESTRUCT": # Self Destruct
6078 elif cmd == "SAVE": # Save Game
6081 if game.skill > SKILL_GOOD:
6082 prout(_("WARNING--Saved games produce no plaques!"))
6083 elif cmd == "DEATHRAY": # Try a desparation measure
6087 elif cmd == "DEBUGCMD": # What do we want for debug???
6089 elif cmd == "MAYDAY": # Call for help
6094 game.alldone = True # quit the game
6099 break # Game has ended
6100 if game.optime != 0.0:
6103 break # Events did us in
6104 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6107 if hitme and not game.justin:
6108 attack(torps_ok=True)
6111 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6122 "Emit the name of an enemy or feature."
6123 if type == 'R': s = _("Romulan")
6124 elif type == 'K': s = _("Klingon")
6125 elif type == 'C': s = _("Commander")
6126 elif type == 'S': s = _("Super-commander")
6127 elif type == '*': s = _("Star")
6128 elif type == 'P': s = _("Planet")
6129 elif type == 'B': s = _("Starbase")
6130 elif type == ' ': s = _("Black hole")
6131 elif type == 'T': s = _("Tholian")
6132 elif type == '#': s = _("Tholian web")
6133 elif type == '?': s = _("Stranger")
6134 elif type == '@': s = _("Inhabited World")
6135 else: s = "Unknown??"
6138 def crmena(stars, enemy, loctype, w):
6139 "Emit the name of an enemy and his location."
6143 buf += cramen(enemy) + _(" at ")
6144 if loctype == "quadrant":
6145 buf += _("Quadrant ")
6146 elif loctype == "sector":
6151 "Emit our ship name."
6152 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6155 "Emit a line of stars"
6156 prouts("******************************************************")
6160 return -avrage*math.log(1e-7 + randreal())
6162 def randplace(size):
6163 "Choose a random location."
6165 w.i = randrange(size)
6166 w.j = randrange(size)
6176 # Get a token from the user
6179 # Fill the token quue if nothing here
6180 while not self.inqueue:
6182 if curwnd==prompt_window:
6184 setwnd(message_window)
6191 self.inqueue = line.lstrip().split() + ["\n"]
6192 # From here on in it's all looking at the queue
6193 self.token = self.inqueue.pop(0)
6194 if self.token == "\n":
6198 self.real = float(self.token)
6199 self.type = "IHREAL"
6204 self.token = self.token.lower()
6205 self.type = "IHALPHA"
6208 def append(self, tok):
6209 self.inqueue.append(tok)
6210 def push(self, tok):
6211 self.inqueue.insert(0, tok)
6215 # Demand input for next scan
6217 self.real = self.token = None
6219 # compares s to item and returns true if it matches to the length of s
6220 return s.startswith(self.token)
6222 # Round token value to nearest integer
6223 return int(round(scanner.real))
6227 if scanner.type != "IHREAL":
6230 s.i = scanner.int()-1
6232 if scanner.type != "IHREAL":
6235 s.j = scanner.int()-1
6238 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6241 "Yes-or-no confirmation."
6245 if scanner.token == 'y':
6247 if scanner.token == 'n':
6250 proutn(_("Please answer with \"y\" or \"n\": "))
6253 "Complain about unparseable input."
6256 prout(_("Beg your pardon, Captain?"))
6259 "Access to the internals for debugging."
6260 proutn("Reset levels? ")
6262 if game.energy < game.inenrg:
6263 game.energy = game.inenrg
6264 game.shield = game.inshld
6265 game.torps = game.intorps
6266 game.lsupres = game.inlsr
6267 proutn("Reset damage? ")
6269 for i in range(NDEVICES):
6270 if game.damage[i] > 0.0:
6271 game.damage[i] = 0.0
6272 proutn("Toggle debug flag? ")
6274 game.idebug = not game.idebug
6276 prout("Debug output ON")
6278 prout("Debug output OFF")
6279 proutn("Cause selective damage? ")
6281 for i in range(NDEVICES):
6282 proutn("Kill %s?" % device[i])
6284 key = scanner.next()
6285 if key == "IHALPHA" and scanner.sees("y"):
6286 game.damage[i] = 10.0
6287 proutn("Examine/change events? ")
6292 FSNOVA: "Supernova ",
6295 FBATTAK: "Base Attack ",
6296 FCDBAS: "Base Destroy ",
6297 FSCMOVE: "SC Move ",
6298 FSCDBAS: "SC Base Destroy ",
6299 FDSPROB: "Probe Move ",
6300 FDISTR: "Distress Call ",
6301 FENSLV: "Enslavement ",
6302 FREPRO: "Klingon Build ",
6304 for i in range(1, NEVENTS):
6307 proutn("%.2f" % (scheduled(i)-game.state.date))
6308 if i == FENSLV or i == FREPRO:
6310 proutn(" in %s" % ev.quadrant)
6315 key = scanner.next()
6319 elif key == "IHREAL":
6320 ev = schedule(i, scanner.real)
6321 if i == FENSLV or i == FREPRO:
6323 proutn("In quadrant- ")
6324 key = scanner.next()
6325 # "IHEOL" says to leave coordinates as they are
6328 prout("Event %d canceled, no x coordinate." % (i))
6331 w.i = int(round(scanner.real))
6332 key = scanner.next()
6334 prout("Event %d canceled, no y coordinate." % (i))
6337 w.j = int(round(scanner.real))
6340 proutn("Induce supernova here? ")
6342 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6345 if __name__ == '__main__':
6346 import getopt, socket
6348 global line, thing, game
6352 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6353 if os.getenv("TERM"):
6354 game.options |= OPTION_CURSES
6356 game.options |= OPTION_TTY
6357 seed = int(time.time())
6358 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6360 for (switch, val) in options:
6363 replayfp = open(val, "r")
6365 sys.stderr.write("sst: can't open replay file %s\n" % val)
6368 line = replayfp.readline().strip()
6369 (leader, __, seed) = line.split()
6371 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6372 line = replayfp.readline().strip()
6373 arguments += line.split()[2:]
6376 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6378 game.options |= OPTION_TTY
6379 game.options &=~ OPTION_CURSES
6380 elif switch == '-s':
6382 elif switch == '-t':
6383 game.options |= OPTION_TTY
6384 game.options &=~ OPTION_CURSES
6385 elif switch == '-x':
6387 elif switch == '-V':
6388 print "SST2K", version
6391 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6393 # where to save the input in case of bugs
6394 if "TMPDIR" in os.environ:
6395 tmpdir = os.environ['TMPDIR']
6399 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6401 sys.stderr.write("sst: warning, can't open logfile\n")
6404 logfp.write("# seed %s\n" % seed)
6405 logfp.write("# options %s\n" % " ".join(arguments))
6406 logfp.write("# SST2K version %s\n" % version)
6407 logfp.write("# recorded by %s@%s on %s\n" % \
6408 (getpass.getuser(),socket.gethostname(),time.ctime()))
6410 scanner = sstscanner()
6411 map(scanner.append, arguments)
6414 while True: # Play a game
6415 setwnd(fullscreen_window)
6421 game.alldone = False
6429 if game.tourn and game.alldone:
6430 proutn(_("Do you want your score recorded?"))
6436 proutn(_("Do you want to play again? "))
6440 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6444 except KeyboardInterrupt: