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, pickle, random, copy, gettext, getpass
15 import getopt, socket, locale
17 # This import only works on Unixes. The intention is to enable
18 # Ctrl-P, Ctrl-N, and friends in Cmd.
24 # Prevent lossage under Python 3
33 docpath = (".", "doc/", "/usr/share/doc/sst/")
36 return gettext.gettext(st)
38 GALSIZE = 8 # Galaxy size in quadrants
39 NINHAB = (GALSIZE * GALSIZE // 2) # Number of inhabited worlds
40 MAXUNINHAB = 10 # Maximum uninhabited worlds
41 QUADSIZE = 10 # Quadrant size in sectors
42 BASEMIN = 2 # Minimum starbases
43 BASEMAX = (GALSIZE * GALSIZE // 12) # Maximum starbases
44 MAXKLGAME = 127 # Maximum Klingons per game
45 MAXKLQUAD = 9 # Maximum Klingons per quadrant
46 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
47 FOREVER = 1e30 # Time for the indefinite future
48 MAXBURST = 3 # Max # of torps you can launch in one turn
49 MINCMDR = 10 # Minimum number of Klingon commanders
50 DOCKFAC = 0.25 # Repair faster when docked
51 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
53 ALGERON = 2311 # Date of the Treaty of Algeron
74 class TrekError(Exception):
77 class JumpOut(Exception):
81 def __init__(self, x=None, y=None):
84 def valid_quadrant(self):
85 return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
86 def valid_sector(self):
87 return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
89 self.i = self.j = None
91 return self.i != None and self.j != None
92 def __eq__(self, other):
93 return other != None and self.i == other.i and self.j == other.j
94 def __ne__(self, other):
95 return other is None or self.i != other.i or self.j != other.j
96 def __add__(self, other):
97 return Coord(self.i+other.i, self.j+other.j)
98 def __sub__(self, other):
99 return Coord(self.i-other.i, self.j-other.j)
100 def __mul__(self, other):
101 return Coord(self.i*other, self.j*other)
102 def __rmul__(self, other):
103 return Coord(self.i*other, self.j*other)
104 def __div__(self, other):
105 return Coord(self.i/other, self.j/other)
106 def __mod__(self, other):
107 return Coord(self.i % other, self.j % other)
108 def __rdiv__(self, other):
109 return Coord(self.i/other, self.j/other)
110 def roundtogrid(self):
111 return Coord(int(round(self.i)), int(round(self.j)))
112 def distance(self, other=None):
115 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
117 return 1.90985*math.atan2(self.j, self.i)
123 s.i = self.i / abs(self.i)
127 s.j = self.j / abs(self.j)
130 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
131 return self.roundtogrid() / QUADSIZE
133 return self.roundtogrid() % QUADSIZE
136 s.i = self.i + randrange(-1, 2)
137 s.j = self.j + randrange(-1, 2)
140 if self.i is None or self.j is None:
142 return "%s - %s" % (self.i+1, self.j+1)
146 "Do not anger the Space Thingy!"
153 return (q.i, q.j) == (self.i, self.j)
157 self.name = None # string-valued if inhabited
158 self.quadrant = Coord() # quadrant located
159 self.pclass = None # could be ""M", "N", "O", or "destroyed"
160 self.crystals = "absent"# could be "mined", "present", "absent"
161 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
162 self.inhabited = False # is it inhabited?
170 self.starbase = False
173 self.supernova = False
175 self.status = "secure" # Could be "secure", "distressed", "enslaved"
177 return "<Quadrant: %(klingons)d>" % self.__dict__
183 self.starbase = False
186 return "<%s,%s,%s>" % (self.klingons, self.starbase, self.stars)
188 def fill2d(size, fillfun):
189 "Fill an empty list in 2D."
191 for i in range(size):
193 for j in range(size):
194 lst[i].append(fillfun(i, j))
199 self.snap = False # snapshot taken
200 self.crew = 0 # crew complement
201 self.nscrem = 0 # remaining super commanders
202 self.starkl = 0 # destroyed stars
203 self.basekl = 0 # destroyed bases
204 self.nromrem = 0 # Romulans remaining
205 self.nplankl = 0 # destroyed uninhabited planets
206 self.nworldkl = 0 # destroyed inhabited planets
207 self.planets = [] # Planet information
208 self.date = 0.0 # stardate
209 self.remres = 0 # remaining resources
210 self.remtime = 0 # remaining time
211 self.baseq = [] # Base quadrant coordinates
212 self.kcmdr = [] # Commander quadrant coordinates
213 self.kscmdr = Coord() # Supercommander quadrant coordinates
215 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
217 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
219 for i in range(GALSIZE):
220 for j in range(GALSIZE):
221 yield (i, j, self.galaxy[i][j])
225 self.date = None # A real number
226 self.quadrant = None # A coord structure
229 OPTION_ALL = 0xffffffff
230 OPTION_TTY = 0x00000001 # old interface
231 OPTION_CURSES = 0x00000002 # new interface
232 OPTION_IOMODES = 0x00000003 # cover both interfaces
233 OPTION_PLANETS = 0x00000004 # planets and mining
234 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
235 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
236 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
237 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
238 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
239 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
240 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
241 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
242 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
243 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
244 OPTION_CAPTURE = 0x00002000 # Enable BSD-Trek capture (Almy, 2013).
245 OPTION_CLOAK = 0x80004000 # Enable BSD-Trek capture (Almy, 2013).
246 OPTION_PLAIN = 0x01000000 # user chose plain game
247 OPTION_ALMY = 0x02000000 # user chose Almy variant
248 OPTION_COLOR = 0x04000000 # enable color display (ESR, 2010)
268 NDEVICES = 17 # Number of devices
278 return (game.damage[dev] != 0.0)
280 return not damaged(DRADIO) or game.condition=="docked"
282 # Define future events
283 FSPY = 0 # Spy event happens always (no future[] entry)
284 # can cause SC to tractor beam Enterprise
285 FSNOVA = 1 # Supernova
286 FTBEAM = 2 # Commander tractor beams Enterprise
287 FSNAP = 3 # Snapshot for time warp
288 FBATTAK = 4 # Commander attacks base
289 FCDBAS = 5 # Commander destroys base
290 FSCMOVE = 6 # Supercommander moves (might attack base)
291 FSCDBAS = 7 # Supercommander destroys base
292 FDSPROB = 8 # Move deep space probe
293 FDISTR = 9 # Emit distress call from an inhabited world
294 FENSLV = 10 # Inhabited word is enslaved */
295 FREPRO = 11 # Klingons build a ship in an enslaved system
298 # Abstract out the event handling -- underlying data structures will change
299 # when we implement stateful events
300 def findevent(evtype):
301 return game.future[evtype]
304 def __init__(self, etype=None, loc=None, power=None):
306 self.location = Coord()
311 self.power = power # enemy energy level
312 game.enemies.append(self)
314 motion = (loc != self.location)
315 if self.location.i is not None and self.location.j is not None:
318 game.quad[self.location.i][self.location.j] = '#'
320 game.quad[self.location.i][self.location.j] = '.'
322 self.location = copy.copy(loc)
323 game.quad[self.location.i][self.location.j] = self.type
324 self.kdist = self.kavgd = (game.sector - loc).distance()
326 self.location = Coord()
327 self.kdist = self.kavgd = None
328 # Guard prevents failure on Tholian or thingy
329 if self in game.enemies:
330 game.enemies.remove(self)
333 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
337 self.options = None # Game options
338 self.state = Snapshot() # A snapshot structure
339 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
340 self.quad = None # contents of our quadrant
341 self.damage = [0.0] * NDEVICES # damage encountered
342 self.future = [] # future events
346 self.future.append(Event())
347 self.passwd = None # Self Destruct password
349 self.quadrant = None # where we are in the large
350 self.sector = None # where we are in the small
351 self.tholian = None # Tholian enemy object
352 self.base = None # position of base in current quadrant
353 self.battle = None # base coordinates being attacked
354 self.plnet = None # location of planet in quadrant
355 self.gamewon = False # Finished!
356 self.ididit = False # action taken -- allows enemy to attack
357 self.alive = False # we are alive (not killed)
358 self.justin = False # just entered quadrant
359 self.shldup = False # shields are up
360 self.shldchg = False # shield is changing (affects efficiency)
361 self.iscate = False # super commander is here
362 self.ientesc = False # attempted escape from supercommander
363 self.resting = False # rest time
364 self.icraft = False # Kirk in Galileo
365 self.landed = False # party on planet (true), on ship (false)
366 self.alldone = False # game is now finished
367 self.neutz = False # Romulan Neutral Zone
368 self.isarmed = False # probe is armed
369 self.inorbit = False # orbiting a planet
370 self.imine = False # mining
371 self.icrystl = False # dilithium crystals aboard
372 self.iseenit = False # seen base attack report
373 self.thawed = False # thawed game
374 self.condition = None # "green", "yellow", "red", "docked", "dead"
375 self.iscraft = None # "onship", "offship", "removed"
376 self.skill = None # Player skill level
377 self.inkling = 0 # initial number of klingons
378 self.inbase = 0 # initial number of bases
379 self.incom = 0 # initial number of commanders
380 self.inscom = 0 # initial number of commanders
381 self.inrom = 0 # initial number of commanders
382 self.instar = 0 # initial stars
383 self.intorps = 0 # initial/max torpedoes
384 self.torps = 0 # number of torpedoes
385 self.ship = 0 # ship type -- 'E' is Enterprise
386 self.abandoned = 0 # count of crew abandoned in space
387 self.length = 0 # length of game
388 self.klhere = 0 # klingons here
389 self.casual = 0 # causalties
390 self.nhelp = 0 # calls for help
391 self.nkinks = 0 # count of energy-barrier crossings
392 self.iplnet = None # planet # in quadrant
393 self.inplan = 0 # initial planets
394 self.irhere = 0 # Romulans in quadrant
395 self.isatb = 0 # =2 if super commander is attacking base
396 self.tourn = None # tournament number
397 self.nprobes = 0 # number of probes available
398 self.inresor = 0.0 # initial resources
399 self.intime = 0.0 # initial time
400 self.inenrg = 0.0 # initial/max energy
401 self.inshld = 0.0 # initial/max shield
402 self.inlsr = 0.0 # initial life support resources
403 self.indate = 0.0 # initial date
404 self.energy = 0.0 # energy level
405 self.shield = 0.0 # shield level
406 self.warpfac = 0.0 # warp speed
407 self.lsupres = 0.0 # life support reserves
408 self.optime = 0.0 # time taken by current operation
409 self.damfac = 0.0 # damage factor
410 self.lastchart = 0.0 # time star chart was last updated
411 self.cryprob = 0.0 # probability that crystal will work
412 self.probe = None # object holding probe course info
413 self.height = 0.0 # height of orbit around planet
414 self.score = 0.0 # overall score
415 self.perdate = 0.0 # rate of kills
416 self.idebug = False # Debugging instrumentation enabled?
417 self.statekscmdr = None # No SuperCommander coordinates yet.
418 self.brigcapacity = 400 # Enterprise brig capacity
419 self.brigfree = 400 # How many klingons can we put in the brig?
420 self.kcaptured = 0 # Total Klingons captured, for scoring.
421 self.iscloaked = False # Cloaking device on?
422 self.ncviol = 0 # Algreon treaty violations
423 self.isviolreported = False # We have been warned
425 return sum([q.klingons for (_i, _j, q) in list(self.state.traverse())])
427 # Stas thinks this should be (C expression):
428 # game.remkl() + len(game.state.kcmdr) > 0 ?
429 # game.state.remres/(game.remkl() + 4*len(game.state.kcmdr)) : 99
430 # He says the existing expression is prone to divide-by-zero errors
431 # after killing the last klingon when score is shown -- perhaps also
432 # if the only remaining klingon is SCOM.
433 self.state.remtime = self.state.remres/(self.remkl() + 4*len(self.state.kcmdr))
435 "Are there Klingons remaining?"
436 return self.remkl() + len(self.state.kcmdr) + self.state.nscrem
463 return random.random() < p
465 def randrange(*args):
466 return random.randrange(*args)
471 v *= args[0] # from [0, args[0])
473 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
476 # Code from ai.c begins here
479 "Would this quadrant welcome another Klingon?"
480 return iq.valid_quadrant() and \
481 not game.state.galaxy[iq.i][iq.j].supernova and \
482 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
484 def tryexit(enemy, look, irun):
485 "A bad guy attempts to bug out."
487 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
488 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
489 if not welcoming(iq):
491 if enemy.type == 'R':
492 return False # Romulans cannot escape!
494 # avoid intruding on another commander's territory
495 if enemy.type == 'C':
496 if iq in game.state.kcmdr:
498 # refuse to leave if currently attacking starbase
499 if game.battle == game.quadrant:
501 # don't leave if over 1000 units of energy
502 if enemy.power > 1000.0:
504 oldloc = copy.copy(enemy.location)
505 # handle local matters related to escape
508 if game.condition != "docked":
510 # Handle global matters related to escape
511 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
512 game.state.galaxy[iq.i][iq.j].klingons += 1
513 if enemy.type == 'S':
517 schedule(FSCMOVE, 0.2777)
519 game.state.kscmdr = iq
521 for cmdr in game.state.kcmdr:
522 if cmdr == game.quadrant:
523 game.state.kcmdr.append(iq)
525 # report move out of quadrant.
526 return [(True, enemy, oldloc, iq)]
528 # The bad-guy movement algorithm:
530 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
531 # If both are operating full strength, force is 1000. If both are damaged,
532 # force is -1000. Having shields down subtracts an additional 1000.
534 # 2. Enemy has forces equal to the energy of the attacker plus
535 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
536 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
538 # Attacker Initial energy levels (nominal):
539 # Klingon Romulan Commander Super-Commander
540 # Novice 400 700 1200
542 # Good 450 800 1300 1750
543 # Expert 475 850 1350 1875
544 # Emeritus 500 900 1400 2000
545 # VARIANCE 75 200 200 200
547 # Enemy vessels only move prior to their attack. In Novice - Good games
548 # only commanders move. In Expert games, all enemy vessels move if there
549 # is a commander present. In Emeritus games all enemy vessels move.
551 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
552 # forces are 1000 greater than Enterprise.
554 # Agressive action on average cuts the distance between the ship and
555 # the enemy to 1/4 the original.
557 # 4. At lower energy advantage, movement units are proportional to the
558 # advantage with a 650 advantage being to hold ground, 800 to move forward
559 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
561 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
562 # retreat, especially at high skill levels.
564 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
566 def movebaddy(enemy):
567 "Tactical movement for the bad guys."
571 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
572 if game.skill >= SKILL_EXPERT:
573 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
575 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
576 old_dist = enemy.kdist
577 mdist = int(old_dist + 0.5) # Nearest integer distance
578 # If SC, check with spy to see if should hi-tail it
579 if enemy.type == 'S' and \
580 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
584 # decide whether to advance, retreat, or hold position
585 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
587 forces += 1000 # Good for enemy if shield is down!
588 if not damaged(DPHASER) or not damaged(DPHOTON):
589 if damaged(DPHASER): # phasers damaged
592 forces -= 0.2*(game.energy - 2500.0)
593 if damaged(DPHOTON): # photon torpedoes damaged
596 forces -= 50.0*game.torps
598 # phasers and photon tubes both out!
601 if forces <= 1000.0 and game.condition != "docked": # Typical situation
602 motion = ((forces + randreal(200))/150.0) - 5.0
604 if forces > 1000.0: # Very strong -- move in for kill
605 motion = (1.0 - randreal())**2 * old_dist + 1.0
606 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
607 motion -= game.skill*(2.0-randreal()**2)
609 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
610 # don't move if no motion
613 # Limit motion according to skill
614 if abs(motion) > game.skill:
619 # calculate preferred number of steps
620 nsteps = abs(int(motion))
621 if motion > 0 and nsteps > mdist:
622 nsteps = mdist # don't overshoot
623 if nsteps > QUADSIZE:
624 nsteps = QUADSIZE # This shouldn't be necessary
626 nsteps = 1 # This shouldn't be necessary
628 proutn("NSTEPS = %d:" % nsteps)
629 # Compute preferred values of delta X and Y
630 m = game.sector - enemy.location
631 if 2.0 * abs(m.i) < abs(m.j):
633 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
635 m = (motion * m).sgn()
636 goto = enemy.location
638 for ll in range(nsteps):
640 proutn(" %d" % (ll+1))
641 # Check if preferred position available
652 attempts = 0 # Settle mysterious hang problem
653 while attempts < 20 and not success:
655 if look.i < 0 or look.i >= QUADSIZE:
657 return tryexit(enemy, look, irun)
658 if krawli == m.i or m.j == 0:
660 look.i = goto.i + krawli
662 elif look.j < 0 or look.j >= QUADSIZE:
664 return tryexit(enemy, look, irun)
665 if krawlj == m.j or m.i == 0:
667 look.j = goto.j + krawlj
669 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
670 # See if enemy should ram ship
671 if game.quad[look.i][look.j] == game.ship and \
672 (enemy.type == 'C' or enemy.type == 'S'):
673 collision(rammed=True, enemy=enemy)
675 if krawli != m.i and m.j != 0:
676 look.i = goto.i + krawli
678 elif krawlj != m.j and m.i != 0:
679 look.j = goto.j + krawlj
682 break # we have failed
693 # Enemy moved, but is still in sector
694 return [(False, enemy, old_dist, goto)]
697 "Sequence Klingon tactical movement."
700 # Figure out which Klingon is the commander (or Supercommander)
703 if game.quadrant in game.state.kcmdr:
704 for enemy in game.enemies:
705 if enemy.type == 'C':
706 tacmoves += movebaddy(enemy)
707 if game.state.kscmdr == game.quadrant:
708 for enemy in game.enemies:
709 if enemy.type == 'S':
710 tacmoves += movebaddy(enemy)
712 # If skill level is high, move other Klingons and Romulans too!
713 # Move these last so they can base their actions on what the
715 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
716 for enemy in game.enemies:
717 if enemy.type in ('K', 'R'):
718 tacmoves += movebaddy(enemy)
721 def movescom(iq, avoid):
722 "Supercommander movement helper."
723 # Avoid quadrants with bases if we want to avoid Enterprise
724 if not welcoming(iq) or (avoid and iq in game.state.baseq):
726 if game.justin and not game.iscate:
729 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
730 game.state.kscmdr = iq
731 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
732 if game.state.kscmdr == game.quadrant:
733 # SC has scooted, remove him from current quadrant
738 for enemy in game.enemies:
739 if enemy.type == 'S':
742 if game.condition != "docked":
745 # check for a helpful planet
746 for i in range(game.inplan):
747 if game.state.planets[i].quadrant == game.state.kscmdr and \
748 game.state.planets[i].crystals == "present":
750 game.state.planets[i].pclass = "destroyed"
751 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
754 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
755 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
756 prout(_(" by the Super-commander.\""))
758 return True # looks good!
760 def supercommander():
761 "Move the Super Commander."
768 prout("== SUPERCOMMANDER")
769 # Decide on being active or passive
770 avoid = ((game.incom - len(game.state.kcmdr) + game.inkling - game.remkl())/(game.state.date+0.01-game.indate) < 0.1*game.skill*(game.skill+1.0) or \
771 (game.state.date-game.indate) < 3.0)
772 if not game.iscate and avoid:
773 # compute move away from Enterprise
774 idelta = game.state.kscmdr-game.quadrant
775 if idelta.distance() > 2.0:
777 idelta.i = game.state.kscmdr.j-game.quadrant.j
778 idelta.j = game.quadrant.i-game.state.kscmdr.i
780 # compute distances to starbases
781 if not game.state.baseq:
785 sc = game.state.kscmdr
786 for (i, base) in enumerate(game.state.baseq):
787 basetbl.append((i, (base - sc).distance()))
788 if game.state.baseq > 1:
789 basetbl.sort(key=lambda x: x[1])
790 # look for nearest base without a commander, no Enterprise, and
791 # without too many Klingons, and not already under attack.
792 ifindit = iwhichb = 0
793 for (i2, base) in enumerate(game.state.baseq):
794 i = basetbl[i2][0] # bug in original had it not finding nearest
795 if base == game.quadrant or base == game.battle or not welcoming(base):
797 # if there is a commander, and no other base is appropriate,
798 # we will take the one with the commander
799 for cmdr in game.state.kcmdr:
800 if base == cmdr and ifindit != 2:
804 else: # no commander -- use this one
809 return # Nothing suitable -- wait until next time
810 ibq = game.state.baseq[iwhichb]
811 # decide how to move toward base
812 idelta = ibq - game.state.kscmdr
813 # Maximum movement is 1 quadrant in either or both axes
814 idelta = idelta.sgn()
815 # try moving in both x and y directions
816 # there was what looked like a bug in the Almy C code here,
817 # but it might be this translation is just wrong.
818 iq = game.state.kscmdr + idelta
819 if not movescom(iq, avoid):
820 # failed -- try some other maneuvers
821 if idelta.i == 0 or idelta.j == 0:
824 iq.j = game.state.kscmdr.j + 1
825 if not movescom(iq, avoid):
826 iq.j = game.state.kscmdr.j - 1
829 iq.i = game.state.kscmdr.i + 1
830 if not movescom(iq, avoid):
831 iq.i = game.state.kscmdr.i - 1
834 # try moving just in x or y
835 iq.j = game.state.kscmdr.j
836 if not movescom(iq, avoid):
837 iq.j = game.state.kscmdr.j + idelta.j
838 iq.i = game.state.kscmdr.i
841 if len(game.state.baseq) == 0:
844 for ibq in game.state.baseq:
845 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
848 return # no, don't attack base!
851 schedule(FSCDBAS, randreal(1.0, 3.0))
852 if is_scheduled(FCDBAS):
853 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
854 if not communicating():
858 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
860 prout(_(" reports that it is under attack from the Klingon Super-commander."))
861 proutn(_(" It can survive until stardate %d.\"") \
862 % int(scheduled(FSCDBAS)))
865 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
869 game.optime = 0.0 # actually finished
871 # Check for intelligence report
872 if not game.idebug and \
874 (not communicating()) or \
875 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
878 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
879 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
884 if not game.tholian or game.justin:
887 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
890 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
893 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
896 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
900 # something is wrong!
901 game.tholian.move(None)
902 prout("***Internal error: Tholian in a bad spot.")
904 # do nothing if we are blocked
905 if game.quad[tid.i][tid.j] not in ('.', '#'):
907 here = copy.copy(game.tholian.location)
908 delta = (tid - game.tholian.location).sgn()
910 while here.i != tid.i:
912 if game.quad[here.i][here.j] == '.':
913 game.tholian.move(here)
915 while here.j != tid.j:
917 if game.quad[here.i][here.j] == '.':
918 game.tholian.move(here)
919 # check to see if all holes plugged
920 for i in range(QUADSIZE):
921 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
923 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
925 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
927 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
929 # All plugged up -- Tholian splits
930 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
932 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
933 game.tholian.move(None)
936 # Code from battle.c begins here
939 "Change cloaking-device status."
941 prout(_("Ye Faerie Queene hath no cloaking device."));
944 key = scanner.nexttok()
952 if scanner.sees("on"):
954 prout(_("The cloaking device has already been switched on."))
957 elif scanner.sees("off"):
958 if not game.iscloaked:
959 prout(_("The cloaking device has already been switched off."))
966 if not game.iscloaked:
967 proutn(_("Switch cloaking device on? "))
972 proutn(_("Switch cloaking device off? "))
979 if action == "CLOFF":
980 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
981 prout(_("Spock- \"Captain, the Treaty of Algeron is in effect.\n Are you sure this is wise?\""))
984 prout("Engineer Scott- \"Aye, Sir.\"");
985 game.iscloaked = False;
986 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
987 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
989 game.isviolreported = True
991 #if (neutz and game.state.date >= ALGERON) finish(FCLOAK);
996 prout(_("Engineer Scott- \"The cloaking device is damaged, Sir.\""))
999 if game.condition == "docked":
1000 prout(_("You cannot cloak while docked."))
1002 if game.state.date >= ALGERON and not game.isviolreported:
1003 prout(_("Spock- \"Captain, using the cloaking device is a violation"))
1004 prout(_(" of the Treaty of Algeron. Considering the alternatives,"))
1005 proutn(_(" are you sure this is wise? "))
1008 prout(_("Engineer Scott- \"Cloaking device has engaging, Sir...\""))
1010 prout(_("Engineer Scott- \"Cloaking device has engaged, Sir.\""))
1011 game.iscloaked = True
1013 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
1014 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
1016 game.isviolreported = True
1018 def doshield(shraise):
1019 "Change shield status."
1025 key = scanner.nexttok()
1026 if key == "IHALPHA":
1027 if scanner.sees("transfer"):
1030 if damaged(DSHIELD):
1031 prout(_("Shields damaged and down."))
1033 if scanner.sees("up"):
1035 elif scanner.sees("down"):
1037 if action == "NONE":
1038 proutn(_("Do you wish to change shield energy? "))
1041 elif damaged(DSHIELD):
1042 prout(_("Shields damaged and down."))
1045 proutn(_("Shields are up. Do you want them down? "))
1052 proutn(_("Shields are down. Do you want them up? "))
1058 if action == "SHUP": # raise shields
1060 prout(_("Shields already up."))
1064 if game.condition != "docked":
1066 prout(_("Shields raised."))
1067 if game.energy <= 0:
1069 prout(_("Shields raising uses up last of energy."))
1074 elif action == "SHDN":
1076 prout(_("Shields already down."))
1080 prout(_("Shields lowered."))
1083 elif action == "NRG":
1084 while scanner.nexttok() != "IHREAL":
1086 proutn(_("Energy to transfer to shields- "))
1091 if nrg > game.energy:
1092 prout(_("Insufficient ship energy."))
1095 if game.shield+nrg >= game.inshld:
1096 prout(_("Shield energy maximized."))
1097 if game.shield+nrg > game.inshld:
1098 prout(_("Excess energy requested returned to ship energy"))
1099 game.energy -= game.inshld-game.shield
1100 game.shield = game.inshld
1102 if nrg < 0.0 and game.energy-nrg > game.inenrg:
1103 # Prevent shield drain loophole
1105 prout(_("Engineering to bridge--"))
1106 prout(_(" Scott here. Power circuit problem, Captain."))
1107 prout(_(" I can't drain the shields."))
1110 if game.shield+nrg < 0:
1111 prout(_("All shield energy transferred to ship."))
1112 game.energy += game.shield
1115 proutn(_("Scotty- \""))
1117 prout(_("Transferring energy to shields.\""))
1119 prout(_("Draining energy from shields.\""))
1125 "Choose a device to damage, at random."
1127 105, # DSRSENS: short range scanners 10.5%
1128 105, # DLRSENS: long range scanners 10.5%
1129 120, # DPHASER: phasers 12.0%
1130 120, # DPHOTON: photon torpedoes 12.0%
1131 25, # DLIFSUP: life support 2.5%
1132 65, # DWARPEN: warp drive 6.5%
1133 70, # DIMPULS: impulse engines 6.5%
1134 135, # DSHIELD: deflector shields 13.5%
1135 30, # DRADIO: subspace radio 3.0%
1136 45, # DSHUTTL: shuttle 4.5%
1137 15, # DCOMPTR: computer 1.5%
1138 20, # NAVCOMP: navigation system 2.0%
1139 75, # DTRANSP: transporter 7.5%
1140 20, # DSHCTRL: high-speed shield controller 2.0%
1141 10, # DDRAY: death ray 1.0%
1142 30, # DDSP: deep-space probes 3.0%
1143 10, # DCLOAK: the cloaking device 1.0
1145 assert(sum(weights) == 1000)
1146 idx = randrange(1000)
1148 for (i, w) in enumerate(weights):
1152 return None # we should never get here
1154 def collision(rammed, enemy):
1155 "Collision handling for rammong events."
1156 prouts(_("***RED ALERT! RED ALERT!"))
1158 prout(_("***COLLISION IMMINENT."))
1162 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1164 proutn(_(" rammed by "))
1167 proutn(crmena(False, enemy.type, "sector", enemy.location))
1169 proutn(_(" (original position)"))
1171 deadkl(enemy.location, enemy.type, game.sector)
1172 proutn("***" + crmshp() + " heavily damaged.")
1173 icas = randrange(10, 30)
1174 prout(_("***Sickbay reports %d casualties") % icas)
1176 game.state.crew -= icas
1177 # In the pre-SST2K version, all devices got equiprobably damaged,
1178 # which was silly. Instead, pick up to half the devices at
1179 # random according to our weighting table,
1180 ncrits = randrange(NDEVICES/2)
1184 if game.damage[dev] < 0:
1186 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1187 # Damage for at least time of travel!
1188 game.damage[dev] += game.optime + extradm
1190 prout(_("***Shields are down."))
1198 def torpedo(origin, bearing, dispersion, number, nburst):
1199 "Let a photon torpedo fly"
1200 if not damaged(DSRSENS) or game.condition == "docked":
1201 setwnd(srscan_window)
1203 setwnd(message_window)
1204 ac = bearing + 0.25*dispersion # dispersion is a random variable
1205 bullseye = (15.0 - bearing)*0.5235988
1206 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1207 bumpto = Coord(0, 0)
1208 # Loop to move a single torpedo
1209 setwnd(message_window)
1210 for step in range(1, QUADSIZE*2):
1211 if not track.nexttok():
1214 if not w.valid_sector():
1216 iquad = game.quad[w.i][w.j]
1217 tracktorpedo(w, step, number, nburst, iquad)
1221 setwnd(message_window)
1222 if not damaged(DSRSENS) or game.condition == "docked":
1223 skip(1) # start new line after text track
1224 if iquad in ('E', 'F'): # Hit our ship
1226 prout(_("Torpedo hits %s.") % crmshp())
1227 hit = 700.0 + randreal(100) - \
1228 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1229 newcnd() # we're blown out of dock
1230 if game.landed or game.condition == "docked":
1231 return hit # Cheat if on a planet
1232 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1233 # is 143 degrees, which is almost exactly 4.8 clockface units
1234 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1235 displacement.nexttok()
1236 bumpto = displacement.sector()
1237 if not bumpto.valid_sector():
1239 if game.quad[bumpto.i][bumpto.j] == ' ':
1242 if game.quad[bumpto.i][bumpto.j] != '.':
1243 # can't move into object
1245 game.sector = bumpto
1247 game.quad[w.i][w.j] = '.'
1248 game.quad[bumpto.i][bumpto.j] = iquad
1249 prout(_(" displaced by blast to Sector %s ") % bumpto)
1250 for enemy in game.enemies:
1251 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1254 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1256 if iquad in ('C', 'S') and withprob(0.05):
1257 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1258 prout(_(" torpedo neutralized."))
1260 for enemy in game.enemies:
1261 if w == enemy.location:
1262 kp = math.fabs(enemy.power)
1263 h1 = 700.0 + randrange(100) - \
1264 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1272 if enemy.power == 0:
1275 proutn(crmena(True, iquad, "sector", w))
1276 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1277 displacement.nexttok()
1278 bumpto = displacement.sector()
1279 if not bumpto.valid_sector():
1280 prout(_(" damaged but not destroyed."))
1282 if game.quad[bumpto.i][bumpto.j] == ' ':
1283 prout(_(" buffeted into black hole."))
1284 deadkl(w, iquad, bumpto)
1285 if game.quad[bumpto.i][bumpto.j] != '.':
1286 prout(_(" damaged but not destroyed."))
1288 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1289 enemy.location = bumpto
1290 game.quad[w.i][w.j] = '.'
1291 game.quad[bumpto.i][bumpto.j] = iquad
1292 for enemy in game.enemies:
1293 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1297 prout("Internal error, no enemy where expected!")
1300 elif iquad == 'B': # Hit a base
1302 prout(_("***STARBASE DESTROYED.."))
1303 game.state.baseq = [x for x in game.state.baseq if x != game.quadrant]
1304 game.quad[w.i][w.j] = '.'
1305 game.base.invalidate()
1306 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
1307 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = False
1308 game.state.basekl += 1
1311 elif iquad == 'P': # Hit a planet
1312 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1313 game.state.nplankl += 1
1314 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1315 game.iplnet.pclass = "destroyed"
1317 game.plnet.invalidate()
1318 game.quad[w.i][w.j] = '.'
1320 # captain perishes on planet
1323 elif iquad == '@': # Hit an inhabited world -- very bad!
1324 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1325 game.state.nworldkl += 1
1326 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1327 game.iplnet.pclass = "destroyed"
1329 game.plnet.invalidate()
1330 game.quad[w.i][w.j] = '.'
1332 # captain perishes on planet
1334 prout(_("The torpedo destroyed an inhabited planet."))
1336 elif iquad == '*': # Hit a star
1340 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1342 elif iquad == '?': # Hit a thingy
1343 if not (game.options & OPTION_THINGY) or withprob(0.3):
1345 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1347 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1349 proutn(_("Mr. Spock-"))
1350 prouts(_(" \"Fascinating!\""))
1354 # Stas Sergeev added the possibility that
1355 # you can shove the Thingy and piss it off.
1356 # It then becomes an enemy and may fire at you.
1359 elif iquad == ' ': # Black hole
1361 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1363 elif iquad == '#': # hit the web
1365 prout(_("***Torpedo absorbed by Tholian web."))
1367 elif iquad == 'T': # Hit a Tholian
1368 h1 = 700.0 + randrange(100) - \
1369 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1372 game.quad[w.i][w.j] = '.'
1377 proutn(crmena(True, 'T', "sector", w))
1379 prout(_(" survives photon blast."))
1381 prout(_(" disappears."))
1382 game.tholian.move(None)
1383 game.quad[w.i][w.j] = '#'
1388 proutn("Don't know how to handle torpedo collision with ")
1389 proutn(crmena(True, iquad, "sector", w))
1394 setwnd(message_window)
1395 prout(_("Torpedo missed."))
1399 "Critical-hit resolution."
1400 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1402 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1403 proutn(_("***CRITICAL HIT--"))
1404 # Select devices and cause damage
1409 # Cheat to prevent shuttle damage unless on ship
1410 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship") or (j == DCLOAK and game.ship != 'E' or j == DDRAY)):
1413 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1414 game.damage[j] += extradm
1417 for (i, j) in enumerate(cdam):
1419 if skipcount % 3 == 2 and i < len(cdam)-1:
1424 prout(_(" damaged."))
1425 if damaged(DSHIELD) and game.shldup:
1426 prout(_("***Shields knocked down."))
1428 if damaged(DCLOAK) and game.iscloaked:
1429 prout(_("***Cloaking device rendered inoperative."))
1430 game.iscloaked = False
1432 def attack(torps_ok):
1433 # bad guy attacks us
1434 # torps_ok == False forces use of phasers in an attack
1437 # game could be over at this point, check
1447 prout("=== ATTACK!")
1448 # Tholian gets to move before attacking
1451 # if you have just entered the RNZ, you'll get a warning
1452 if game.neutz: # The one chance not to be attacked
1455 # commanders get a chance to tac-move towards you
1456 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:
1457 for (bugout, enemy, old, goto) in moveklings():
1459 # we know about this if either short or long range
1460 # sensors are working
1461 if damaged(DSRSENS) and damaged(DLRSENS) \
1462 and game.condition != "docked":
1463 prout(crmena(True, enemy.type, "sector", old) + \
1464 (_(" escapes to Quadrant %s (and regains strength).") % goto))
1465 else: # Enemy still in-sector
1466 if enemy.move(goto):
1467 if not damaged(DSRSENS) or game.condition == "docked":
1468 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
1469 if enemy.kdist < old:
1470 proutn(_(" advances to "))
1472 proutn(_(" retreats to "))
1473 prout("Sector %s." % goto)
1475 # if no enemies remain after movement, we're done
1476 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered):
1478 # set up partial hits if attack happens during shield status change
1479 pfac = 1.0/game.inshld
1481 chgfac = 0.25 + randreal(0.5)
1483 # message verbosity control
1484 if game.skill <= SKILL_FAIR:
1486 for enemy in game.enemies:
1488 continue # too weak to attack
1489 # compute hit strength and diminish shield power
1491 # Increase chance of photon torpedos if docked or enemy energy is low
1492 if game.condition == "docked":
1494 if enemy.power < 500:
1496 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1498 # different enemies have different probabilities of throwing a torp
1499 usephasers = not torps_ok or \
1500 (enemy.type == 'K' and r > 0.0005) or \
1501 (enemy.type == 'C' and r > 0.015) or \
1502 (enemy.type == 'R' and r > 0.3) or \
1503 (enemy.type == 'S' and r > 0.07) or \
1504 (enemy.type == '?' and r > 0.05)
1505 if usephasers: # Enemy uses phasers
1506 if game.condition == "docked":
1507 continue # Don't waste the effort!
1508 attempt = True # Attempt to attack
1509 dustfac = randreal(0.8, 0.85)
1510 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1512 else: # Enemy uses photon torpedo
1513 # We should be able to make the bearing() method work here
1514 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1516 proutn(_("***TORPEDO INCOMING"))
1517 if not damaged(DSRSENS):
1518 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1521 dispersion = (randreal()+randreal())*0.5 - 0.5
1522 dispersion += 0.002*enemy.power*dispersion
1523 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1524 if game.unwon() == 0:
1525 finish(FWON) # Klingons did themselves in!
1526 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1527 return # Supernova or finished
1530 # incoming phaser or torpedo, shields may dissipate it
1531 if game.shldup or game.shldchg or game.condition == "docked":
1532 # shields will take hits
1533 propor = pfac * game.shield
1534 if game.condition == "docked":
1538 hitsh = propor*chgfac*hit+1.0
1540 if absorb > game.shield:
1541 absorb = game.shield
1542 game.shield -= absorb
1544 # taking a hit blasts us out of a starbase dock
1545 if game.condition == "docked":
1547 # but the shields may take care of it
1548 if propor > 0.1 and hit < 0.005*game.energy:
1550 # hit from this opponent got through shields, so take damage
1552 proutn(_("%d unit hit") % int(hit))
1553 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1554 proutn(_(" on the ") + crmshp())
1555 if not damaged(DSRSENS) and usephasers:
1556 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1558 # Decide if hit is critical
1564 if game.energy <= 0:
1565 # Returning home upon your shield, not with it...
1568 if not attempt and game.condition == "docked":
1569 prout(_("***Enemies decide against attacking your ship."))
1570 percent = 100.0*pfac*game.shield+0.5
1572 # Shields fully protect ship
1573 proutn(_("Enemy attack reduces shield strength to "))
1575 # Emit message if starship suffered hit(s)
1577 proutn(_("Energy left %2d shields ") % int(game.energy))
1580 elif not damaged(DSHIELD):
1583 proutn(_("damaged, "))
1584 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1585 # Check if anyone was hurt
1586 if hitmax >= 200 or hittot >= 500:
1587 icas = randrange(int(hittot * 0.015))
1590 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1591 prout(_(" in that last attack.\""))
1593 game.state.crew -= icas
1594 # After attack, reset average distance to enemies
1595 for enemy in game.enemies:
1596 enemy.kavgd = enemy.kdist
1600 def deadkl(w, etype, mv):
1601 "Kill a Klingon, Tholian, Romulan, or Thingy."
1602 # Added mv to allow enemy to "move" before dying
1603 proutn(crmena(True, etype, "sector", mv))
1604 # Decide what kind of enemy it is and update appropriately
1606 # Chalk up a Romulan
1607 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1609 game.state.nromrem -= 1
1618 # Killed some type of Klingon
1619 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1622 game.state.kcmdr.remove(game.quadrant)
1624 if game.state.kcmdr:
1625 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1626 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1631 game.state.nscrem -= 1
1632 game.state.kscmdr.invalidate()
1637 # For each kind of enemy, finish message to player
1638 prout(_(" destroyed."))
1639 if game.unwon() == 0:
1642 # Remove enemy ship from arrays describing local conditions
1643 for e in game.enemies:
1650 "Return None if target is invalid, otherwise return a course angle."
1651 if not w.valid_sector():
1655 # C code this was translated from is wacky -- why the sign reversal?
1656 delta.j = (w.j - game.sector.j)
1657 delta.i = (game.sector.i - w.i)
1658 if delta == Coord(0, 0):
1660 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1661 prout(_(" I recommend an immediate review of"))
1662 prout(_(" the Captain's psychological profile.\""))
1665 return delta.bearing()
1668 "Launch photon torpedo salvo."
1671 if damaged(DPHOTON):
1672 prout(_("Photon tubes damaged."))
1676 prout(_("No torpedoes left."))
1679 # First, get torpedo count
1682 if scanner.token == "IHALPHA":
1685 elif scanner.token == "IHEOL" or not scanner.waiting():
1686 prout(_("%d torpedoes left.") % game.torps)
1688 proutn(_("Number of torpedoes to fire- "))
1689 continue # Go back around to get a number
1690 else: # key == "IHREAL"
1692 if n <= 0: # abort command
1697 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1700 scanner.chew() # User requested more torps than available
1701 continue # Go back around
1702 break # All is good, go to next stage
1706 key = scanner.nexttok()
1707 if i == 0 and key == "IHEOL":
1708 break # no coordinate waiting, we will try prompting
1709 if i == 1 and key == "IHEOL":
1710 # direct all torpedoes at one target
1712 target.append(target[0])
1713 tcourse.append(tcourse[0])
1716 scanner.push(scanner.token)
1717 target.append(scanner.getcoord())
1718 if target[-1] is None:
1720 tcourse.append(targetcheck(target[-1]))
1721 if tcourse[-1] is None:
1724 if len(target) == 0:
1725 # prompt for each one
1727 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1729 target.append(scanner.getcoord())
1730 if target[-1] is None:
1732 tcourse.append(targetcheck(target[-1]))
1733 if tcourse[-1] is None:
1736 # Loop for moving <n> torpedoes
1738 if game.condition != "docked":
1740 dispersion = (randreal()+randreal())*0.5 -0.5
1741 if math.fabs(dispersion) >= 0.47:
1743 dispersion *= randreal(1.2, 2.2)
1745 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1747 prouts(_("***TORPEDO MISFIRES."))
1750 prout(_(" Remainder of burst aborted."))
1752 prout(_("***Photon tubes damaged by misfire."))
1753 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1757 elif game.shldup or game.condition == "docked":
1758 dispersion *= 1.0 + 0.0001*game.shield
1759 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1760 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1766 "Check for phasers overheating."
1768 checkburn = (rpow-1500.0)*0.00038
1769 if withprob(checkburn):
1770 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1771 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1773 def checkshctrl(rpow):
1774 "Check shield control."
1777 prout(_("Shields lowered."))
1779 # Something bad has happened
1780 prouts(_("***RED ALERT! RED ALERT!"))
1782 hit = rpow*game.shield/game.inshld
1783 game.energy -= rpow+hit*0.8
1784 game.shield -= hit*0.2
1785 if game.energy <= 0.0:
1786 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1791 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1793 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1794 icas = randrange(int(hit*0.012))
1799 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1800 prout(_(" %d casualties so far.\"") % icas)
1802 game.state.crew -= icas
1804 prout(_("Phaser energy dispersed by shields."))
1805 prout(_("Enemy unaffected."))
1810 "Register a phaser hit on Klingons and Romulans."
1817 dustfac = randreal(0.9, 1.0)
1818 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1819 kpini = game.enemies[kk].power
1820 kp = math.fabs(kpini)
1821 if PHASEFAC*hit < kp:
1823 if game.enemies[kk].power < 0:
1824 game.enemies[kk].power -= -kp
1826 game.enemies[kk].power -= kp
1827 kpow = game.enemies[kk].power
1828 w = game.enemies[kk].location
1830 if not damaged(DSRSENS):
1832 proutn(_("%d unit hit on ") % int(hit))
1834 proutn(_("Very small hit on "))
1835 ienm = game.quad[w.i][w.j]
1838 proutn(crmena(False, ienm, "sector", w))
1847 else: # decide whether or not to emasculate klingon
1848 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1849 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1850 prout(_(" has just lost its firepower.\""))
1851 game.enemies[kk].power = -kpow
1856 "Fire phasers at bad guys."
1860 irec = 0 # Cheating inhibitor
1869 # SR sensors and Computer are needed for automode
1870 if damaged(DSRSENS) or damaged(DCOMPTR):
1872 if game.condition == "docked":
1873 prout(_("Phasers can't be fired through base shields."))
1876 if damaged(DPHASER):
1877 prout(_("Phaser control damaged."))
1881 if damaged(DSHCTRL):
1882 prout(_("High speed shield control damaged."))
1885 if game.energy <= 200.0:
1886 prout(_("Insufficient energy to activate high-speed shield control."))
1889 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1891 # Original code so convoluted, I re-did it all
1892 # (That was Tom Almy talking about the C code, I think -- ESR)
1893 while automode == "NOTSET":
1894 key = scanner.nexttok()
1895 if key == "IHALPHA":
1896 if scanner.sees("manual"):
1897 if len(game.enemies)==0:
1898 prout(_("There is no enemy present to select."))
1901 automode = "AUTOMATIC"
1904 key = scanner.nexttok()
1905 elif scanner.sees("automatic"):
1906 if (not itarg) and len(game.enemies) != 0:
1907 automode = "FORCEMAN"
1909 if len(game.enemies)==0:
1910 prout(_("Energy will be expended into space."))
1911 automode = "AUTOMATIC"
1912 key = scanner.nexttok()
1913 elif scanner.sees("no"):
1918 elif key == "IHREAL":
1919 if len(game.enemies)==0:
1920 prout(_("Energy will be expended into space."))
1921 automode = "AUTOMATIC"
1923 automode = "FORCEMAN"
1925 automode = "AUTOMATIC"
1928 if len(game.enemies)==0:
1929 prout(_("Energy will be expended into space."))
1930 automode = "AUTOMATIC"
1932 automode = "FORCEMAN"
1934 proutn(_("Manual or automatic? "))
1939 if automode == "AUTOMATIC":
1940 if key == "IHALPHA" and scanner.sees("no"):
1942 key = scanner.nexttok()
1943 if key != "IHREAL" and len(game.enemies) != 0:
1944 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1949 for i in range(len(game.enemies)):
1950 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1952 proutn(_("%d units required. ") % irec)
1954 proutn(_("Units to fire= "))
1955 key = scanner.nexttok()
1960 proutn(_("Energy available= %.2f") % avail)
1963 if not rpow > avail:
1969 key = scanner.nexttok()
1970 if key == "IHALPHA" and scanner.sees("no"):
1973 game.energy -= 200 # Go and do it!
1974 if checkshctrl(rpow):
1979 if len(game.enemies):
1982 for i in range(len(game.enemies)):
1986 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1987 over = randreal(1.01, 1.06) * hits[i]
1989 powrem -= hits[i] + over
1990 if powrem <= 0 and temp < hits[i]:
1999 if extra > 0 and not game.alldone:
2001 proutn(_("*** Tholian web absorbs "))
2002 if len(game.enemies)>0:
2003 proutn(_("excess "))
2004 prout(_("phaser energy."))
2006 prout(_("%d expended on empty space.") % int(extra))
2007 elif automode == "FORCEMAN":
2010 if damaged(DCOMPTR):
2011 prout(_("Battle computer damaged, manual fire only."))
2014 prouts(_("---WORKING---"))
2016 prout(_("Short-range-sensors-damaged"))
2017 prout(_("Insufficient-data-for-automatic-phaser-fire"))
2018 prout(_("Manual-fire-must-be-used"))
2020 elif automode == "MANUAL":
2022 for k in range(len(game.enemies)):
2023 aim = game.enemies[k].location
2024 ienm = game.quad[aim.i][aim.j]
2026 proutn(_("Energy available= %.2f") % (avail-0.006))
2030 if damaged(DSRSENS) and \
2031 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
2032 prout(cramen(ienm) + _(" can't be located without short range scan."))
2035 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
2040 if itarg and k > kz:
2041 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
2044 if not damaged(DCOMPTR):
2049 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
2050 key = scanner.nexttok()
2051 if key == "IHALPHA" and scanner.sees("no"):
2053 key = scanner.nexttok()
2055 if key == "IHALPHA":
2059 if k == 1: # Let me say I'm baffled by this
2062 if scanner.real < 0:
2066 hits[k] = scanner.real
2067 rpow += scanner.real
2068 # If total requested is too much, inform and start over
2070 prout(_("Available energy exceeded -- try again."))
2073 key = scanner.nexttok() # scan for next value
2076 # zero energy -- abort
2079 if key == "IHALPHA" and scanner.sees("no"):
2084 game.energy -= 200.0
2085 if checkshctrl(rpow):
2089 # Say shield raised or malfunction, if necessary
2096 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
2097 prouts(_(" CLICK CLICK POP . . ."))
2098 prout(_(" No response, sir!"))
2101 prout(_("Shields raised."))
2108 game.ididit = False # Nothing if we fail
2111 # Make sure there is room in the brig */
2112 if game.brigfree == 0:
2113 prout(_("Security reports the brig is already full."))
2117 prout(_("Uhura- \"We have no subspace radio communication, sir.\""))
2120 if damaged(DTRANSP):
2121 prout(_("Scotty- \"Transporter damaged, sir.\""))
2124 # find out if there are any at all
2126 prout(_("Uhura- \"Getting no response, sir.\""))
2129 # if there is more than one Klingon, find out which one */
2130 # Cruddy, just takes one at random. Should ask the captain.
2131 # Nah, just select the weakest one since it is most likely to
2132 # surrender (Tom Almy mod)
2133 klingons = [e for e in game.enemies if e.type == 'K']
2134 weakest = sorted(klingons, key=lambda e: e.power)[0]
2135 game.optime = 0.05 # This action will take some time
2136 game.ididit = True # So any others can strike back
2138 # check out that Klingon
2139 # The algorithm isn't that great and could use some more
2140 # intelligent design
2141 # x = 300 + 25*skill;
2142 x = game.energy / (weakest.power * len(klingons))
2143 #prout(_("Stats: energy = %s, kpower = %s, klingons = %s")
2144 # % (game.energy, weakest.power, len(klingons)))
2145 x *= 2.5 # would originally have been equivalent of 1.4,
2146 # but we want command to work more often, more humanely */
2147 #prout(_("Prob = %.4f" % x))
2148 # x = 100; // For testing, of course!
2149 if x < randreal(100):
2150 # guess what, he surrendered!!! */
2151 prout(_("Klingon captain at %s surrenders.") % weakest.location)
2154 prout(_("%d Klingons commit suicide rather than be taken captive.") % (200 - i))
2155 if i > game.brigfree:
2156 prout(_("%d Klingons die because there is no room for them in the brig.") % (i-brigfree))
2159 prout(_("%d captives taken") % i)
2160 deadkl(weakest.location, weakest.type, game.sector)
2165 # big surprise, he refuses to surrender */
2166 prout(_("Fat chance, captain!"))
2168 # Code from events.c begins here.
2170 # This isn't a real event queue a la BSD Trek yet -- you can only have one
2171 # event of each type active at any given time. Mostly these means we can
2172 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
2173 # BSD Trek, from which we swiped the idea, can have up to 5.
2175 def unschedule(evtype):
2176 "Remove an event from the schedule."
2177 game.future[evtype].date = FOREVER
2178 return game.future[evtype]
2180 def is_scheduled(evtype):
2181 "Is an event of specified type scheduled."
2182 return game.future[evtype].date != FOREVER
2184 def scheduled(evtype):
2185 "When will this event happen?"
2186 return game.future[evtype].date
2188 def schedule(evtype, offset):
2189 "Schedule an event of specified type."
2190 game.future[evtype].date = game.state.date + offset
2191 return game.future[evtype]
2193 def postpone(evtype, offset):
2194 "Postpone a scheduled event."
2195 game.future[evtype].date += offset
2198 "Rest period is interrupted by event."
2201 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2203 game.resting = False
2209 "Run through the event queue looking for things to do."
2211 fintim = game.state.date + game.optime
2220 def tractorbeam(yank):
2221 "Tractor-beaming cases merge here."
2223 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2225 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2226 # If Kirk & Co. screwing around on planet, handle
2227 atover(True) # atover(true) is Grab
2230 if game.icraft: # Caught in Galileo?
2233 # Check to see if shuttle is aboard
2234 if game.iscraft == "offship":
2237 prout(_("Galileo, left on the planet surface, is captured"))
2238 prout(_("by aliens and made into a flying McDonald's."))
2239 game.damage[DSHUTTL] = -10
2240 game.iscraft = "removed"
2242 prout(_("Galileo, left on the planet surface, is well hidden."))
2244 game.quadrant = game.state.kscmdr
2246 game.quadrant = game.state.kcmdr[i]
2247 game.sector = randplace(QUADSIZE)
2248 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2249 % (game.quadrant, game.sector))
2251 prout(_("(Remainder of rest/repair period cancelled.)"))
2252 game.resting = False
2254 if not damaged(DSHIELD) and game.shield > 0:
2255 doshield(shraise=True) # raise shields
2256 game.shldchg = False
2258 prout(_("(Shields not currently useable.)"))
2260 # Adjust finish time to time of tractor beaming?
2261 # fintim = game.state.date+game.optime
2262 attack(torps_ok=False)
2263 if not game.state.kcmdr:
2266 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2269 "Code merges here for any commander destroying a starbase."
2270 # Not perfect, but will have to do
2271 # Handle case where base is in same quadrant as starship
2272 if game.battle == game.quadrant:
2273 game.state.chart[game.battle.i][game.battle.j].starbase = False
2274 game.quad[game.base.i][game.base.j] = '.'
2275 game.base.invalidate()
2278 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2279 elif game.state.baseq and communicating():
2280 # Get word via subspace radio
2283 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2284 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2286 prout(_("the Klingon Super-Commander"))
2288 prout(_("a Klingon Commander"))
2289 game.state.chart[game.battle.i][game.battle.j].starbase = False
2290 # Remove Starbase from galaxy
2291 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2292 game.state.baseq = [x for x in game.state.baseq if x != game.battle]
2294 # reinstate a commander's base attack
2298 game.battle.invalidate()
2300 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2301 for i in range(1, NEVENTS):
2302 if i == FSNOVA: proutn("=== Supernova ")
2303 elif i == FTBEAM: proutn("=== T Beam ")
2304 elif i == FSNAP: proutn("=== Snapshot ")
2305 elif i == FBATTAK: proutn("=== Base Attack ")
2306 elif i == FCDBAS: proutn("=== Base Destroy ")
2307 elif i == FSCMOVE: proutn("=== SC Move ")
2308 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2309 elif i == FDSPROB: proutn("=== Probe Move ")
2310 elif i == FDISTR: proutn("=== Distress Call ")
2311 elif i == FENSLV: proutn("=== Enslavement ")
2312 elif i == FREPRO: proutn("=== Klingon Build ")
2314 prout("%.2f" % (scheduled(i)))
2317 radio_was_broken = damaged(DRADIO)
2320 # Select earliest extraneous event, evcode==0 if no events
2325 for l in range(1, NEVENTS):
2326 if game.future[l].date < datemin:
2329 prout("== Event %d fires" % evcode)
2330 datemin = game.future[l].date
2331 xtime = datemin-game.state.date
2333 game.energy -= xtime*500.0
2334 if game.energy <= 0:
2337 game.state.date = datemin
2338 # Decrement Federation resources and recompute remaining time
2339 game.state.remres -= (game.remkl()+4*len(game.state.kcmdr))*xtime
2341 if game.state.remtime <= 0:
2344 # Any crew left alive?
2345 if game.state.crew <= 0:
2348 # Is life support adequate?
2349 if damaged(DLIFSUP) and game.condition != "docked":
2350 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2353 game.lsupres -= xtime
2354 if game.damage[DLIFSUP] <= xtime:
2355 game.lsupres = game.inlsr
2358 if game.condition == "docked":
2360 # Don't fix Deathray here
2361 for l in range(NDEVICES):
2362 if game.damage[l] > 0.0 and l != DDRAY:
2363 if game.damage[l]-repair > 0.0:
2364 game.damage[l] -= repair
2366 game.damage[l] = 0.0
2367 # If radio repaired, update star chart and attack reports
2368 if radio_was_broken and not damaged(DRADIO):
2369 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2370 prout(_(" surveillance reports are coming in."))
2372 if not game.iseenit:
2376 prout(_(" The star chart is now up to date.\""))
2378 # Cause extraneous event EVCODE to occur
2379 game.optime -= xtime
2380 if evcode == FSNOVA: # Supernova
2383 schedule(FSNOVA, expran(0.5*game.intime))
2384 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2386 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2387 if game.state.nscrem == 0 or game.iscloaked or \
2388 ictbeam or istract or \
2389 game.condition == "docked" or game.isatb == 1 or game.iscate:
2391 if game.ientesc or \
2392 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2393 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2394 (damaged(DSHIELD) and \
2395 (game.energy < 2500 or damaged(DPHASER)) and \
2396 (game.torps < 5 or damaged(DPHOTON))):
2398 istract = ictbeam = True
2399 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2402 elif evcode == FTBEAM: # Tractor beam
2403 if not game.state.kcmdr:
2406 i = randrange(len(game.state.kcmdr))
2407 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2408 if istract or game.condition == "docked" or game.iscloaked or yank == 0:
2409 # Drats! Have to reschedule
2411 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2415 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2416 game.snapsht = copy.deepcopy(game.state)
2417 game.state.snap = True
2418 schedule(FSNAP, expran(0.5 * game.intime))
2419 elif evcode == FBATTAK: # Commander attacks starbase
2420 if not game.state.kcmdr or not game.state.baseq:
2425 ibq = None # Force battle location to persist past loop
2427 for ibq in game.state.baseq:
2428 for cmdr in game.state.kcmdr:
2429 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2431 # no match found -- try later
2432 schedule(FBATTAK, expran(0.3*game.intime))
2437 # commander + starbase combination found -- launch attack
2439 schedule(FCDBAS, randreal(1.0, 4.0))
2440 if game.isatb: # extra time if SC already attacking
2441 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2442 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2443 game.iseenit = False
2444 if not communicating():
2445 continue # No warning :-(
2449 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2450 prout(_(" reports that it is under attack and that it can"))
2451 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2454 elif evcode == FSCDBAS: # Supercommander destroys base
2457 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2458 continue # WAS RETURN!
2460 game.battle = game.state.kscmdr
2462 elif evcode == FCDBAS: # Commander succeeds in destroying base
2463 if evcode == FCDBAS:
2465 if not game.state.baseq() \
2466 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2467 game.battle.invalidate()
2469 # find the lucky pair
2470 for cmdr in game.state.kcmdr:
2471 if cmdr == game.battle:
2474 # No action to take after all
2477 elif evcode == FSCMOVE: # Supercommander moves
2478 schedule(FSCMOVE, 0.2777)
2479 if not game.ientesc and not istract and game.isatb != 1 and \
2480 (not game.iscate or not game.justin):
2482 elif evcode == FDSPROB: # Move deep space probe
2483 schedule(FDSPROB, 0.01)
2484 if not game.probe.nexttok():
2485 if not game.probe.quadrant().valid_quadrant() or \
2486 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2487 # Left galaxy or ran into supernova
2491 proutn(_("Lt. Uhura- \"The deep space probe "))
2492 if not game.probe.quadrant().valid_quadrant():
2493 prout(_("has left the galaxy.\""))
2495 prout(_("is no longer transmitting.\""))
2501 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2502 pquad = game.probe.quadrant()
2503 pdest = game.state.galaxy[pquad.i][pquad.j]
2505 game.state.chart[pquad.i][pquad.j].klingons = pdest.klingons
2506 game.state.chart[pquad.i][pquad.j].starbase = pdest.starbase
2507 game.state.chart[pquad.i][pquad.j].stars = pdest.stars
2508 pdest.charted = True
2509 game.probe.moves -= 1 # One less to travel
2510 if game.probe.arrived() and game.isarmed and pdest.stars:
2511 supernova(game.probe) # fire in the hole!
2513 if game.state.galaxy[pquad.i][pquad.j].supernova:
2515 elif evcode == FDISTR: # inhabited system issues distress call
2517 # try a whole bunch of times to find something suitable
2518 for i in range(100):
2519 # need a quadrant which is not the current one,
2520 # which has some stars which are inhabited and
2521 # not already under attack, which is not
2522 # supernova'ed, and which has some Klingons in it
2523 w = randplace(GALSIZE)
2524 q = game.state.galaxy[w.i][w.j]
2525 if not (game.quadrant == w or q.planet is None or \
2526 not q.planet.inhabited or \
2527 q.supernova or q.status!="secure" or q.klingons<=0):
2530 # can't seem to find one; ignore this call
2532 prout("=== Couldn't find location for distress event.")
2534 # got one!! Schedule its enslavement
2535 ev = schedule(FENSLV, expran(game.intime))
2537 q.status = "distressed"
2538 # tell the captain about it if we can
2540 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2541 % (q.planet, repr(w)))
2542 prout(_("by a Klingon invasion fleet."))
2545 elif evcode == FENSLV: # starsystem is enslaved
2546 ev = unschedule(FENSLV)
2547 # see if current distress call still active
2548 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2552 q.status = "enslaved"
2554 # play stork and schedule the first baby
2555 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2556 ev2.quadrant = ev.quadrant
2558 # report the disaster if we can
2560 prout(_("Uhura- We've lost contact with starsystem %s") % \
2562 prout(_("in Quadrant %s.\n") % ev.quadrant)
2563 elif evcode == FREPRO: # Klingon reproduces
2564 # If we ever switch to a real event queue, we'll need to
2565 # explicitly retrieve and restore the x and y.
2566 ev = schedule(FREPRO, expran(1.0 * game.intime))
2567 # see if current distress call still active
2568 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2572 if game.remkl() >= MAXKLGAME:
2573 continue # full right now
2574 # reproduce one Klingon
2577 if game.klhere >= MAXKLQUAD:
2579 # this quadrant not ok, pick an adjacent one
2580 for m.i in range(w.i - 1, w.i + 2):
2581 for m.j in range(w.j - 1, w.j + 2):
2582 if not m.valid_quadrant():
2584 q = game.state.galaxy[m.i][m.j]
2585 # check for this quad ok (not full & no snova)
2586 if q.klingons >= MAXKLQUAD or q.supernova:
2589 # search for eligible quadrant failed
2595 if game.quadrant == w:
2597 game.enemies.append(newkling())
2598 # recompute time left
2601 if game.quadrant == w:
2602 prout(_("Spock- sensors indicate the Klingons have"))
2603 prout(_("launched a warship from %s.") % q.planet)
2605 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2606 if q.planet != None:
2607 proutn(_("near %s ") % q.planet)
2608 prout(_("in Quadrant %s.") % w)
2614 key = scanner.nexttok()
2617 proutn(_("How long? "))
2622 origTime = delay = scanner.real
2625 if delay >= game.state.remtime or len(game.enemies) != 0:
2626 proutn(_("Are you sure? "))
2629 # Alternate resting periods (events) with attacks
2633 game.resting = False
2634 if not game.resting:
2635 prout(_("%d stardates left.") % int(game.state.remtime))
2637 temp = game.optime = delay
2638 if len(game.enemies):
2639 rtime = randreal(1.0, 2.0)
2643 if game.optime < delay:
2644 attack(torps_ok=False)
2652 # Repair Deathray if long rest at starbase
2653 if origTime-delay >= 9.99 and game.condition == "docked":
2654 game.damage[DDRAY] = 0.0
2655 # leave if quadrant supernovas
2656 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2658 game.resting = False
2663 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2664 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2666 # Wow! We've supernova'ed
2667 supernova(game.quadrant)
2669 # handle initial nova
2670 game.quad[nov.i][nov.j] = '.'
2671 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2672 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2673 game.state.starkl += 1
2674 # Set up queue to recursively trigger adjacent stars
2680 for offset.i in range(-1, 1+1):
2681 for offset.j in range(-1, 1+1):
2682 if offset.j == 0 and offset.i == 0:
2684 neighbor = start + offset
2685 if not neighbor.valid_sector():
2687 iquad = game.quad[neighbor.i][neighbor.j]
2688 # Empty space ends reaction
2689 if iquad in ('.', '?', ' ', 'T', '#'):
2691 elif iquad == '*': # Affect another star
2693 # This star supernovas
2694 supernova(game.quadrant)
2697 hits.append(neighbor)
2698 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2699 game.state.starkl += 1
2700 proutn(crmena(True, '*', "sector", neighbor))
2702 game.quad[neighbor.i][neighbor.j] = '.'
2704 elif iquad in ('P', '@'): # Destroy planet
2705 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2707 game.state.nplankl += 1
2709 game.state.nworldkl += 1
2710 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2711 game.iplnet.pclass = "destroyed"
2713 game.plnet.invalidate()
2717 game.quad[neighbor.i][neighbor.j] = '.'
2718 elif iquad == 'B': # Destroy base
2719 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2720 game.state.baseq = [x for x in game.state.baseq if x!= game.quadrant]
2721 game.base.invalidate()
2722 game.state.basekl += 1
2724 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2725 game.quad[neighbor.i][neighbor.j] = '.'
2726 elif iquad in ('E', 'F'): # Buffet ship
2727 prout(_("***Starship buffeted by nova."))
2729 if game.shield >= 2000.0:
2730 game.shield -= 2000.0
2732 diff = 2000.0 - game.shield
2736 prout(_("***Shields knocked out."))
2737 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2739 game.energy -= 2000.0
2740 if game.energy <= 0:
2743 # add in course nova contributes to kicking starship
2744 bump += (game.sector-hits[-1]).sgn()
2745 elif iquad == 'K': # kill klingon
2746 deadkl(neighbor, iquad, neighbor)
2747 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2749 for ll in range(len(game.enemies)):
2750 if game.enemies[ll].location == neighbor:
2751 target = game.enemies[ll]
2753 if target is not None:
2754 target.power -= 800.0 # If firepower is lost, die
2755 if target.power <= 0.0:
2756 deadkl(neighbor, iquad, neighbor)
2757 continue # neighbor loop
2758 # Else enemy gets flung by the blast wave
2759 newc = neighbor + neighbor - start
2760 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2761 if not newc.valid_sector():
2762 # can't leave quadrant
2765 iquad1 = game.quad[newc.i][newc.j]
2767 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2769 deadkl(neighbor, iquad, newc)
2772 # can't move into something else
2775 proutn(_(", buffeted to Sector %s") % newc)
2776 game.quad[neighbor.i][neighbor.j] = '.'
2777 game.quad[newc.i][newc.j] = iquad
2779 # Starship affected by nova -- kick it away.
2781 direc = ncourse[3*(bump.i+1)+bump.j+2]
2786 scourse = course(bearing=direc, distance=dist)
2787 game.optime = scourse.time(w=4)
2789 prout(_("Force of nova displaces starship."))
2790 imove(scourse, noattack=True)
2791 game.optime = scourse.time(w=4)
2795 "Star goes supernova."
2800 # Scheduled supernova -- select star at random.
2803 for nq.i in range(GALSIZE):
2804 for nq.j in range(GALSIZE):
2805 nstars += game.state.galaxy[nq.i][nq.j].stars
2807 return # nothing to supernova exists
2808 num = randrange(nstars) + 1
2809 for nq.i in range(GALSIZE):
2810 for nq.j in range(GALSIZE):
2811 num -= game.state.galaxy[nq.i][nq.j].stars
2817 proutn("=== Super nova here?")
2820 if not nq == game.quadrant or game.justin:
2821 # it isn't here, or we just entered (treat as enroute)
2824 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2825 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2828 # we are in the quadrant!
2829 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2830 for ns.i in range(QUADSIZE):
2831 for ns.j in range(QUADSIZE):
2832 if game.quad[ns.i][ns.j]=='*':
2839 prouts(_("***RED ALERT! RED ALERT!"))
2841 prout(_("***Incipient supernova detected at Sector %s") % ns)
2842 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2843 proutn(_("Emergency override attempts t"))
2844 prouts("***************")
2848 # destroy any Klingons in supernovaed quadrant
2849 game.state.galaxy[nq.i][nq.j].klingons = 0
2850 if nq == game.state.kscmdr:
2851 # did in the Supercommander!
2852 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2856 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2857 comkills = len(game.state.kcmdr) - len(survivors)
2858 game.state.kcmdr = survivors
2859 if not game.state.kcmdr:
2861 # destroy Romulans and planets in supernovaed quadrant
2862 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2863 game.state.galaxy[nq.i][nq.j].romulans = 0
2864 game.state.nromrem -= nrmdead
2866 for loop in range(game.inplan):
2867 if game.state.planets[loop].quadrant == nq:
2868 game.state.planets[loop].pclass = "destroyed"
2870 # Destroy any base in supernovaed quadrant
2871 game.state.baseq = [x for x in game.state.baseq if x != nq]
2872 # If starship caused supernova, tally up destruction
2874 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2875 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2876 game.state.nplankl += npdead
2877 # mark supernova in galaxy and in star chart
2878 if game.quadrant == nq or communicating():
2879 game.state.galaxy[nq.i][nq.j].supernova = True
2880 # If supernova destroys last Klingons give special message
2881 if game.unwon()==0 and not nq == game.quadrant:
2884 prout(_("Lucky you!"))
2885 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2888 # if some Klingons remain, continue or die in supernova
2893 # Code from finish.c ends here.
2896 "Self-destruct maneuver. Finish with a BANG!"
2898 if damaged(DCOMPTR):
2899 prout(_("Computer damaged; cannot execute destruct sequence."))
2901 prouts(_("---WORKING---")); skip(1)
2902 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2903 prouts(" 10"); skip(1)
2904 prouts(" 9"); skip(1)
2905 prouts(" 8"); skip(1)
2906 prouts(" 7"); skip(1)
2907 prouts(" 6"); skip(1)
2909 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2911 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2913 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2916 if game.passwd != scanner.token:
2917 prouts(_("PASSWORD-REJECTED;"))
2919 prouts(_("CONTINUITY-EFFECTED"))
2922 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2923 prouts(" 5"); skip(1)
2924 prouts(" 4"); skip(1)
2925 prouts(" 3"); skip(1)
2926 prouts(" 2"); skip(1)
2927 prouts(" 1"); skip(1)
2929 prouts(_("GOODBYE-CRUEL-WORLD"))
2937 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2941 if len(game.enemies) != 0:
2942 whammo = 25.0 * game.energy
2943 for l in range(len(game.enemies)):
2944 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2945 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2949 "Compute our rate of kils over time."
2950 elapsed = game.state.date - game.indate
2951 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2954 starting = (game.inkling + game.incom + game.inscom)
2955 remaining = game.unwon()
2956 return (starting - remaining)/elapsed
2960 badpt = 5.0*game.state.starkl + \
2962 10.0*game.state.nplankl + \
2963 300*game.state.nworldkl + \
2965 100.0*game.state.basekl +\
2966 3.0*game.abandoned +\
2968 if game.ship == 'F':
2970 elif game.ship is None:
2975 # end the game, with appropriate notifications
2979 prout(_("It is stardate %.1f.") % game.state.date)
2981 if ifin == FWON: # Game has been won
2982 if game.state.nromrem != 0:
2983 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2986 prout(_("You have smashed the Klingon invasion fleet and saved"))
2987 prout(_("the Federation."))
2988 if game.alive and game.brigcapacity-game.brigfree > 0:
2989 game.kcaptured += game.brigcapacity-game.brigfree
2990 prout(_("The %d captured Klingons are transferred to Star Fleet Command.") % (game.brigcapacity-game.brigfree))
2995 badpt = 0.0 # Close enough!
2996 # killsPerDate >= RateMax
2997 if game.state.date-game.indate < 5.0 or \
2998 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
3000 prout(_("In fact, you have done so well that Starfleet Command"))
3001 if game.skill == SKILL_NOVICE:
3002 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
3003 elif game.skill == SKILL_FAIR:
3004 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
3005 elif game.skill == SKILL_GOOD:
3006 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
3007 elif game.skill == SKILL_EXPERT:
3008 prout(_("promotes you to Commodore Emeritus."))
3010 prout(_("Now that you think you're really good, try playing"))
3011 prout(_("the \"Emeritus\" game. It will splatter your ego."))
3012 elif game.skill == SKILL_EMERITUS:
3014 proutn(_("Computer- "))
3015 prouts(_("ERROR-ERROR-ERROR-ERROR"))
3017 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
3019 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3021 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3023 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3025 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
3027 prout(_("Now you can retire and write your own Star Trek game!"))
3029 elif game.skill >= SKILL_EXPERT:
3030 if game.thawed and not game.idebug:
3031 prout(_("You cannot get a citation, so..."))
3033 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
3037 # Only grant long life if alive (original didn't!)
3039 prout(_("LIVE LONG AND PROSPER."))
3044 elif ifin == FDEPLETE: # Federation Resources Depleted
3045 prout(_("Your time has run out and the Federation has been"))
3046 prout(_("conquered. Your starship is now Klingon property,"))
3047 prout(_("and you are put on trial as a war criminal. On the"))
3048 proutn(_("basis of your record, you are "))
3049 if game.unwon()*3.0 > (game.inkling + game.incom + game.inscom):
3050 prout(_("acquitted."))
3052 prout(_("LIVE LONG AND PROSPER."))
3054 prout(_("found guilty and"))
3055 prout(_("sentenced to death by slow torture."))
3059 elif ifin == FLIFESUP:
3060 prout(_("Your life support reserves have run out, and"))
3061 prout(_("you die of thirst, starvation, and asphyxiation."))
3062 prout(_("Your starship is a derelict in space."))
3064 prout(_("Your energy supply is exhausted."))
3066 prout(_("Your starship is a derelict in space."))
3067 elif ifin == FBATTLE:
3068 prout(_("The %s has been destroyed in battle.") % crmshp())
3070 prout(_("Dulce et decorum est pro patria mori."))
3072 prout(_("You have made three attempts to cross the negative energy"))
3073 prout(_("barrier which surrounds the galaxy."))
3075 prout(_("Your navigation is abominable."))
3078 prout(_("Your starship has been destroyed by a nova."))
3079 prout(_("That was a great shot."))
3081 elif ifin == FSNOVAED:
3082 prout(_("The %s has been fried by a supernova.") % crmshp())
3083 prout(_("...Not even cinders remain..."))
3084 elif ifin == FABANDN:
3085 prout(_("You have been captured by the Klingons. If you still"))
3086 prout(_("had a starbase to be returned to, you would have been"))
3087 prout(_("repatriated and given another chance. Since you have"))
3088 prout(_("no starbases, you will be mercilessly tortured to death."))
3089 elif ifin == FDILITHIUM:
3090 prout(_("Your starship is now an expanding cloud of subatomic particles"))
3091 elif ifin == FMATERIALIZE:
3092 prout(_("Starbase was unable to re-materialize your starship."))
3093 prout(_("Sic transit gloria mundi"))
3094 elif ifin == FPHASER:
3095 prout(_("The %s has been cremated by its own phasers.") % crmshp())
3097 prout(_("You and your landing party have been"))
3098 prout(_("converted to energy, dissipating through space."))
3099 elif ifin == FMINING:
3100 prout(_("You are left with your landing party on"))
3101 prout(_("a wild jungle planet inhabited by primitive cannibals."))
3103 prout(_("They are very fond of \"Captain Kirk\" soup."))
3105 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3106 elif ifin == FDPLANET:
3107 prout(_("You and your mining party perish."))
3109 prout(_("That was a great shot."))
3112 prout(_("The Galileo is instantly annihilated by the supernova."))
3113 prout(_("You and your mining party are atomized."))
3115 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3116 prout(_("joins the Romulans, wreaking terror on the Federation."))
3117 elif ifin == FPNOVA:
3118 prout(_("You and your mining party are atomized."))
3120 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3121 prout(_("joins the Romulans, wreaking terror on the Federation."))
3122 elif ifin == FSTRACTOR:
3123 prout(_("The shuttle craft Galileo is also caught,"))
3124 prout(_("and breaks up under the strain."))
3126 prout(_("Your debris is scattered for millions of miles."))
3127 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3129 prout(_("The mutants attack and kill Spock."))
3130 prout(_("Your ship is captured by Klingons, and"))
3131 prout(_("your crew is put on display in a Klingon zoo."))
3132 elif ifin == FTRIBBLE:
3133 prout(_("Tribbles consume all remaining water,"))
3134 prout(_("food, and oxygen on your ship."))
3136 prout(_("You die of thirst, starvation, and asphyxiation."))
3137 prout(_("Your starship is a derelict in space."))
3139 prout(_("Your ship is drawn to the center of the black hole."))
3140 prout(_("You are crushed into extremely dense matter."))
3141 elif ifin == FCLOAK:
3143 prout(_("You have violated the Treaty of Algeron."))
3144 prout(_("The Romulan Empire can never trust you again."))
3146 prout(_("Your last crew member has died."))
3147 if ifin != FWON and ifin != FCLOAK and game.iscloaked:
3148 prout(_("Your ship was cloaked so your subspace radio did not receive anything."))
3149 prout(_("You may have missed some warning messages."))
3151 if game.ship == 'F':
3153 elif game.ship == 'E':
3156 if game.unwon() != 0:
3157 goodies = game.state.remres/game.inresor
3158 baddies = (game.remkl() + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
3159 if goodies/baddies >= randreal(1.0, 1.5):
3160 prout(_("As a result of your actions, a treaty with the Klingon"))
3161 prout(_("Empire has been signed. The terms of the treaty are"))
3162 if goodies/baddies >= randreal(3.0):
3163 prout(_("favorable to the Federation."))
3165 prout(_("Congratulations!"))
3167 prout(_("highly unfavorable to the Federation."))
3169 prout(_("The Federation will be destroyed."))
3171 prout(_("Since you took the last Klingon with you, you are a"))
3172 prout(_("martyr and a hero. Someday maybe they'll erect a"))
3173 prout(_("statue in your memory. Rest in peace, and try not"))
3174 prout(_("to think about pigeons."))
3177 scanner.chew() # Clean up leftovers
3180 "Compute player's score."
3181 timused = game.state.date - game.indate
3182 if (timused == 0 or game.unwon() != 0) and timused < 5.0:
3184 game.perdate = killrate()
3185 ithperd = 500*game.perdate + 0.5
3188 iwon = 100*game.skill
3189 if game.ship == 'E':
3191 elif game.ship == 'F':
3195 game.score = 10*(game.inkling - game.remkl()) \
3196 + 50*(game.incom - len(game.state.kcmdr)) \
3198 + 20*(game.inrom - game.state.nromrem) \
3199 + 200*(game.inscom - game.state.nscrem) \
3200 - game.state.nromrem \
3201 + 3 * game.kcaptured \
3206 prout(_("Your score --"))
3207 if game.inrom - game.state.nromrem:
3208 prout(_("%6d Romulans destroyed %5d") %
3209 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
3210 if game.state.nromrem and game.gamewon:
3211 prout(_("%6d Romulans captured %5d") %
3212 (game.state.nromrem, game.state.nromrem))
3213 if game.inkling - game.remkl():
3214 prout(_("%6d ordinary Klingons destroyed %5d") %
3215 (game.inkling - game.remkl(), 10*(game.inkling - game.remkl())))
3216 if game.incom - len(game.state.kcmdr):
3217 prout(_("%6d Klingon commanders destroyed %5d") %
3218 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3220 prout(_("%d Klingons captured %5d") %
3221 (game.kcaptured, 3 * game.kcaptured))
3222 if game.inscom - game.state.nscrem:
3223 prout(_("%6d Super-Commander destroyed %5d") %
3224 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3226 prout(_("%6.2f Klingons per stardate %5d") %
3227 (game.perdate, ithperd))
3228 if game.state.starkl:
3229 prout(_("%6d stars destroyed by your action %5d") %
3230 (game.state.starkl, -5*game.state.starkl))
3231 if game.state.nplankl:
3232 prout(_("%6d planets destroyed by your action %5d") %
3233 (game.state.nplankl, -10*game.state.nplankl))
3234 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3235 prout(_("%6d inhabited planets destroyed by your action %5d") %
3236 (game.state.nworldkl, -300*game.state.nworldkl))
3237 if game.state.basekl:
3238 prout(_("%6d bases destroyed by your action %5d") %
3239 (game.state.basekl, -100*game.state.basekl))
3241 prout(_("%6d calls for help from starbase %5d") %
3242 (game.nhelp, -45*game.nhelp))
3244 prout(_("%6d casualties incurred %5d") %
3245 (game.casual, -game.casual))
3247 prout(_("%6d crew abandoned in space %5d") %
3248 (game.abandoned, -3*game.abandoned))
3250 prout(_("%6d ship(s) lost or destroyed %5d") %
3251 (klship, -100*klship))
3254 prout(_("1 Treaty of Algeron violation -100"))
3256 prout(_("%6d Treaty of Algeron violations %5d\n") %
3257 (ncviol, -100*ncviol))
3259 prout(_("Penalty for getting yourself killed -200"))
3261 proutn(_("Bonus for winning "))
3262 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3263 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3264 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3265 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3266 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3267 prout(" %5d" % iwon)
3269 prout(_("TOTAL SCORE %5d") % game.score)
3272 "Emit winner's commemmorative plaque."
3275 proutn(_("File or device name for your plaque: "))
3278 fp = open(winner, "w")
3281 prout(_("Invalid name."))
3283 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3285 # The 38 below must be 64 for 132-column paper
3286 nskip = 38 - len(winner)/2
3287 # This is where the ASCII art picture was emitted.
3288 # It got garbled somewhere in the chain of transmission to the Almy version.
3289 # We should restore it if we can find old enough FORTRAN sources.
3291 fp.write(_(" U. S. S. ENTERPRISE\n"))
3292 fp.write("\n\n\n\n")
3293 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3295 fp.write(_(" Starfleet Command bestows to you\n"))
3297 fp.write("%*s%s\n\n" % (nskip, "", winner))
3298 fp.write(_(" the rank of\n\n"))
3299 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3301 if game.skill == SKILL_EXPERT:
3302 fp.write(_(" Expert level\n\n"))
3303 elif game.skill == SKILL_EMERITUS:
3304 fp.write(_("Emeritus level\n\n"))
3306 fp.write(_(" Cheat level\n\n"))
3307 timestring = time.ctime()
3308 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3309 (timestring+4, timestring+20, timestring+11))
3310 fp.write(_(" Your score: %d\n\n") % game.score)
3311 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3314 # Code from io.c begins here
3316 rows = linecount = 0 # for paging
3319 fullscreen_window = None
3320 srscan_window = None # Short range scan
3321 report_window = None # Report legends for status window
3322 status_window = None # The status window itself
3323 lrscan_window = None # Long range scan
3324 message_window = None # Main window for scrolling text
3325 prompt_window = None # Prompt window at bottom of display
3330 # for some recent versions of python2, the following enables UTF8
3331 # for the older ones we probably need to set C locale, and python3
3332 # has no problems at all
3333 if sys.version_info[0] < 3:
3334 locale.setlocale(locale.LC_ALL, "")
3335 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3336 gettext.textdomain("sst")
3337 if not (game.options & OPTION_CURSES):
3338 ln_env = os.getenv("LINES")
3344 stdscr = curses.initscr()
3348 if game.options & OPTION_COLOR:
3349 curses.start_color()
3350 curses.use_default_colors()
3351 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3352 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3353 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3354 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3355 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3356 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3357 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3358 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3359 global fullscreen_window, srscan_window, report_window, status_window
3360 global lrscan_window, message_window, prompt_window
3361 (rows, _columns) = stdscr.getmaxyx()
3362 fullscreen_window = stdscr
3363 srscan_window = curses.newwin(12, 25, 0, 0)
3364 report_window = curses.newwin(11, 0, 1, 25)
3365 status_window = curses.newwin(10, 0, 1, 39)
3366 lrscan_window = curses.newwin(5, 0, 0, 64)
3367 message_window = curses.newwin(0, 0, 12, 0)
3368 prompt_window = curses.newwin(1, 0, rows-2, 0)
3369 message_window.scrollok(True)
3370 setwnd(fullscreen_window)
3374 if game.options & OPTION_CURSES:
3375 stdscr.keypad(False)
3381 "Wait for user action -- OK to do nothing if on a TTY"
3382 if game.options & OPTION_CURSES:
3387 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3391 if game.skill > SKILL_FAIR:
3392 prompt = _("[CONTINUE?]")
3394 prompt = _("[PRESS ENTER TO CONTINUE]")
3396 if game.options & OPTION_CURSES:
3398 setwnd(prompt_window)
3399 prompt_window.clear()
3400 prompt_window.addstr(prompt)
3401 prompt_window.getstr()
3402 prompt_window.clear()
3403 prompt_window.refresh()
3404 setwnd(message_window)
3407 sys.stdout.write('\n')
3411 sys.stdout.write('\n' * rows)
3415 "Skip i lines. Pause game if this would cause a scrolling event."
3416 for _dummy in range(i):
3417 if game.options & OPTION_CURSES:
3418 (y, _x) = curwnd.getyx()
3421 except curses.error:
3426 if rows and linecount >= rows:
3429 sys.stdout.write('\n')
3431 def proutn(proutntline):
3432 "Utter a line with no following line feed."
3433 if game.options & OPTION_CURSES:
3434 (y, x) = curwnd.getyx()
3435 (my, _mx) = curwnd.getmaxyx()
3436 if curwnd == message_window and y >= my - 2:
3439 # Uncomment this to debug curses problems
3441 # logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(proutntline)))
3442 curwnd.addstr(proutntline)
3445 sys.stdout.write(proutntline)
3448 def prout(proutline):
3452 def prouts(proutsline):
3454 for c in proutsline:
3455 if not replayfp or replayfp.closed: # Don't slow down replays
3458 if game.options & OPTION_CURSES:
3462 if not replayfp or replayfp.closed:
3466 "Get a line of input."
3467 if game.options & OPTION_CURSES:
3468 linein = curwnd.getstr() + "\n"
3471 if replayfp and not replayfp.closed:
3473 linein = replayfp.readline()
3476 prout("*** Replay finished")
3479 elif linein[0] != "#":
3483 linein = my_input() + "\n"
3492 "Change windows -- OK for this to be a no-op in tty mode."
3494 if game.options & OPTION_CURSES:
3495 # Uncomment this to debug curses problems
3497 if wnd == fullscreen_window:
3498 legend = "fullscreen"
3499 elif wnd == srscan_window:
3501 elif wnd == report_window:
3503 elif wnd == status_window:
3505 elif wnd == lrscan_window:
3507 elif wnd == message_window:
3509 elif wnd == prompt_window:
3513 #logfp.write("#curses: setwnd(%s)\n" % legend)
3515 # Some curses implementations get confused when you try this.
3517 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3518 except curses.error:
3522 "Clear to end of line -- can be a no-op in tty mode"
3523 if game.options & OPTION_CURSES:
3528 "Clear screen -- can be a no-op in tty mode."
3530 if game.options & OPTION_CURSES:
3536 def textcolor(color=DEFAULT):
3537 if (game.options & OPTION_COLOR) and (game.options & OPTION_CURSES):
3538 if color == DEFAULT:
3540 elif color == BLACK:
3541 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3543 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3544 elif color == GREEN:
3545 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3547 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3549 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3550 elif color == MAGENTA:
3551 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3552 elif color == BROWN:
3553 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3554 elif color == LIGHTGRAY:
3555 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3556 elif color == DARKGRAY:
3557 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3558 elif color == LIGHTBLUE:
3559 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3560 elif color == LIGHTGREEN:
3561 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3562 elif color == LIGHTCYAN:
3563 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3564 elif color == LIGHTRED:
3565 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3566 elif color == LIGHTMAGENTA:
3567 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3568 elif color == YELLOW:
3569 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3570 elif color == WHITE:
3571 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3574 if (game.options & OPTION_COLOR) and (game.options & OPTION_CURSES):
3575 curwnd.attron(curses.A_REVERSE)
3578 # Things past this point have policy implications.
3582 "Hook to be called after moving to redraw maps."
3583 if game.options & OPTION_CURSES:
3586 setwnd(srscan_window)
3590 setwnd(status_window)
3591 status_window.clear()
3592 status_window.move(0, 0)
3593 setwnd(report_window)
3594 report_window.clear()
3595 report_window.move(0, 0)
3597 setwnd(lrscan_window)
3598 lrscan_window.clear()
3599 lrscan_window.move(0, 0)
3600 lrscan(silent=False)
3602 def put_srscan_sym(w, sym):
3603 "Emit symbol for short-range scan."
3604 srscan_window.move(w.i+1, w.j*2+2)
3605 srscan_window.addch(sym)
3606 srscan_window.refresh()
3609 "Enemy fall down, go boom."
3610 if game.options & OPTION_CURSES:
3612 setwnd(srscan_window)
3613 srscan_window.attron(curses.A_REVERSE)
3614 put_srscan_sym(w, game.quad[w.i][w.j])
3618 srscan_window.attroff(curses.A_REVERSE)
3619 put_srscan_sym(w, game.quad[w.i][w.j])
3620 curses.delay_output(500)
3621 setwnd(message_window)
3624 "Sound and visual effects for teleportation."
3625 if game.options & OPTION_CURSES:
3627 setwnd(message_window)
3629 prouts(" . . . . . ")
3630 if game.options & OPTION_CURSES:
3631 #curses.delay_output(1000)
3635 def tracktorpedo(w, step, i, n, iquad):
3636 "Torpedo-track animation."
3637 if not game.options & OPTION_CURSES:
3641 proutn(_("Track for torpedo number %d- ") % (i+1))
3644 proutn(_("Torpedo track- "))
3645 elif step==4 or step==9:
3649 if not damaged(DSRSENS) or game.condition=="docked":
3650 if i != 0 and step == 1:
3653 if (iquad=='.') or (iquad==' '):
3654 put_srscan_sym(w, '+')
3658 put_srscan_sym(w, iquad)
3660 curwnd.attron(curses.A_REVERSE)
3661 put_srscan_sym(w, iquad)
3665 curwnd.attroff(curses.A_REVERSE)
3666 put_srscan_sym(w, iquad)
3671 "Display the current galaxy chart."
3672 if game.options & OPTION_CURSES:
3673 setwnd(message_window)
3674 message_window.clear()
3676 if game.options & OPTION_TTY:
3681 def prstat(txt, data):
3683 if game.options & OPTION_CURSES:
3685 setwnd(status_window)
3687 proutn(" " * (NSYM - len(txt)))
3690 if game.options & OPTION_CURSES:
3691 setwnd(report_window)
3693 # Code from moving.c begins here
3695 def imove(icourse=None, noattack=False):
3696 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3699 def newquadrant(noattack):
3700 # Leaving quadrant -- allow final enemy attack
3701 # Don't set up attack if being pushed by nova or cloaked
3702 if len(game.enemies) != 0 and not noattack and not game.iscloaked:
3704 for enemy in game.enemies:
3705 finald = (w - enemy.location).distance()
3706 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3707 # Stas Sergeev added the condition
3708 # that attacks only happen if Klingons
3709 # are present and your skill is good.
3710 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3711 attack(torps_ok=False)
3714 # check for edge of galaxy
3718 if icourse.final.i < 0:
3719 icourse.final.i = -icourse.final.i
3721 if icourse.final.j < 0:
3722 icourse.final.j = -icourse.final.j
3724 if icourse.final.i >= GALSIZE*QUADSIZE:
3725 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3727 if icourse.final.j >= GALSIZE*QUADSIZE:
3728 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3736 if game.nkinks == 3:
3737 # Three strikes -- you're out!
3741 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3742 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3743 prout(_("YOU WILL BE DESTROYED."))
3744 # Compute final position in new quadrant
3745 if trbeam: # Don't bother if we are to be beamed
3747 game.quadrant = icourse.final.quadrant()
3748 game.sector = icourse.final.sector()
3750 prout(_("Entering Quadrant %s.") % game.quadrant)
3751 game.quad[game.sector.i][game.sector.j] = game.ship
3753 if game.skill>SKILL_NOVICE:
3754 attack(torps_ok=False)
3756 def check_collision(h):
3757 iquad = game.quad[h.i][h.j]
3759 # object encountered in flight path
3760 stopegy = 50.0*icourse.distance/game.optime
3761 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3762 for enemy in game.enemies:
3763 if enemy.location == game.sector:
3764 collision(rammed=False, enemy=enemy)
3766 # This should not happen
3767 prout(_("Which way did he go?"))
3771 prouts(_("***RED ALERT! RED ALERT!"))
3773 proutn("***" + crmshp())
3774 proutn(_(" pulled into black hole at Sector %s") % h)
3775 # Getting pulled into a black hole was certain
3776 # death in Almy's original. Stas Sergeev added a
3777 # possibility that you'll get timewarped instead.
3779 for m in range(NDEVICES):
3780 if game.damage[m]>0:
3782 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3783 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3793 prout(_(" encounters Tholian web at %s;") % h)
3795 prout(_(" blocked by object at %s;") % h)
3796 proutn(_("Emergency stop required "))
3797 prout(_("%2d units of energy.") % int(stopegy))
3798 game.energy -= stopegy
3799 if game.energy <= 0:
3806 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3807 game.inorbit = False
3808 # If tractor beam is to occur, don't move full distance
3809 if game.state.date+game.optime >= scheduled(FTBEAM):
3811 # We can't be tractor beamed if cloaked,
3812 # so move the event into the future
3813 postpone(FTBEAM, game.optime + expran(1.5*game.intime/len(game.kcmdr)))
3817 game.condition = "red"
3818 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3819 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3821 game.quad[game.sector.i][game.sector.j] = '.'
3822 for _m in range(icourse.moves):
3824 w = icourse.sector()
3825 if icourse.origin.quadrant() != icourse.location.quadrant():
3826 newquadrant(noattack)
3828 elif check_collision(w):
3829 print("Collision detected")
3833 # We're in destination quadrant -- compute new average enemy distances
3834 game.quad[game.sector.i][game.sector.j] = game.ship
3836 for enemy in game.enemies:
3837 finald = (w-enemy.location).distance()
3838 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3839 enemy.kdist = finald
3841 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3842 attack(torps_ok=False)
3843 for enemy in game.enemies:
3844 enemy.kavgd = enemy.kdist
3847 setwnd(message_window)
3851 "Dock our ship at a starbase."
3853 if game.condition == "docked" and verbose:
3854 prout(_("Already docked."))
3857 prout(_("You must first leave standard orbit."))
3859 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3860 prout(crmshp() + _(" not adjacent to base."))
3863 prout(_("You cannot dock while cloaked."))
3865 game.condition = "docked"
3869 if game.energy < game.inenrg:
3870 game.energy = game.inenrg
3871 game.shield = game.inshld
3872 game.torps = game.intorps
3873 game.lsupres = game.inlsr
3874 game.state.crew = FULLCREW
3875 if game.brigcapacity-game.brigfree > 0:
3876 prout(_("%d captured Klingons transferred to base") % (game.brigcapacity-game.brigfree))
3877 game.kcaptured += game.brigcapacity-game.brigfree
3878 game.brigfree = game.brigcapacity
3879 if communicating() and \
3880 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3881 # get attack report from base
3882 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3886 def cartesian(loc1=None, loc2=None):
3888 return game.quadrant * QUADSIZE + game.sector
3890 return game.quadrant * QUADSIZE + loc1
3892 return loc1 * QUADSIZE + loc2
3894 def getcourse(isprobe):
3895 "Get a course and distance from the user."
3897 dquad = copy.copy(game.quadrant)
3898 navmode = "unspecified"
3902 if game.landed and not isprobe:
3903 prout(_("Dummy! You can't leave standard orbit until you"))
3904 proutn(_("are back aboard the ship."))
3907 while navmode == "unspecified":
3908 if damaged(DNAVSYS):
3910 prout(_("Computer damaged; manual navigation only"))
3912 prout(_("Computer damaged; manual movement only"))
3917 key = scanner.nexttok()
3919 proutn(_("Manual or automatic- "))
3922 elif key == "IHALPHA":
3923 if scanner.sees("manual"):
3925 key = scanner.nexttok()
3927 elif scanner.sees("automatic"):
3928 navmode = "automatic"
3929 key = scanner.nexttok()
3937 prout(_("(Manual navigation assumed.)"))
3939 prout(_("(Manual movement assumed.)"))
3943 if navmode == "automatic":
3944 while key == "IHEOL":
3946 proutn(_("Target quadrant or quadrant§or- "))
3948 proutn(_("Destination sector or quadrant§or- "))
3951 key = scanner.nexttok()
3955 xi = int(round(scanner.real))-1
3956 key = scanner.nexttok()
3960 xj = int(round(scanner.real))-1
3961 key = scanner.nexttok()
3963 # both quadrant and sector specified
3964 xk = int(round(scanner.real))-1
3965 key = scanner.nexttok()
3969 xl = int(round(scanner.real))-1
3975 # only one pair of numbers was specified
3977 # only quadrant specified -- go to center of dest quad
3980 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3982 # only sector specified
3986 if not dquad.valid_quadrant() or not dsect.valid_sector():
3993 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3995 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3996 # the actual deltas get computed here
3997 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3998 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
4000 while key == "IHEOL":
4001 proutn(_("X and Y displacements- "))
4004 key = scanner.nexttok()
4007 delta.j = scanner.real
4011 key = scanner.nexttok()
4013 delta.i = scanner.real
4014 elif key == "IHEOL":
4020 # Check for zero movement
4021 if delta.i == 0 and delta.j == 0:
4024 if itemp == "verbose" and not isprobe:
4026 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
4028 return course(bearing=delta.bearing(), distance=delta.distance())
4031 def __init__(self, bearing, distance, origin=None):
4032 self.distance = distance
4033 self.bearing = bearing
4035 self.origin = cartesian(game.quadrant, game.sector)
4037 self.origin = origin
4038 # The bearing() code we inherited from FORTRAN is actually computing
4039 # clockface directions!
4040 if self.bearing < 0.0:
4041 self.bearing += 12.0
4042 self.angle = ((15.0 - self.bearing) * 0.5235988)
4043 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
4044 bigger = max(abs(self.increment.i), abs(self.increment.j))
4045 self.increment /= bigger
4046 self.moves = int(round(10*self.distance*bigger))
4048 self.final = (self.location + self.moves*self.increment).roundtogrid()
4049 self.location = self.origin
4050 self.nextlocation = None
4052 self.location = self.origin
4055 return self.location.roundtogrid() == self.final
4057 "Next step on course."
4059 self.nextlocation = self.location + self.increment
4060 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
4061 self.location = self.nextlocation
4064 return self.location.quadrant()
4066 return self.location.sector()
4068 return self.distance*(w**3)*(game.shldup+1)
4070 return 10.0*self.distance/w**2
4073 "Move under impulse power."
4075 if damaged(DIMPULS):
4078 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4080 if game.energy > 30.0:
4082 icourse = getcourse(isprobe=False)
4085 power = 20.0 + 100.0*icourse.distance
4088 if power >= game.energy:
4089 # Insufficient power for trip
4091 prout(_("First Officer Spock- \"Captain, the impulse engines"))
4092 prout(_("require 20.0 units to engage, plus 100.0 units per"))
4093 if game.energy > 30:
4094 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
4095 int(0.01 * (game.energy-20.0)-0.05))
4096 prout(_(" quadrants.\""))
4098 prout(_("quadrant. They are, therefore, useless.\""))
4101 # Make sure enough time is left for the trip
4102 game.optime = icourse.distance/0.095
4103 if game.optime >= game.state.remtime:
4104 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
4105 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
4106 proutn(_("we dare spend the time?\" "))
4109 # Activate impulse engines and pay the cost
4110 imove(icourse, noattack=False)
4114 power = 20.0 + 100.0*icourse.distance
4115 game.energy -= power
4116 game.optime = icourse.distance/0.095
4117 if game.energy <= 0:
4121 def warp(wcourse, involuntary):
4122 "ove under warp drive."
4123 blooey = False; twarp = False
4124 if not involuntary: # Not WARPX entry
4129 prout(_("Engineer Scott- \"The warp engines can not be used while cloaked, Sir.\""))
4131 if game.damage[DWARPEN] > 10.0:
4134 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
4136 if damaged(DWARPEN) and game.warpfac > 4.0:
4139 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4140 prout(_(" is repaired, I can only give you warp 4.\""))
4142 # Read in course and distance
4145 wcourse = getcourse(isprobe=False)
4148 # Make sure starship has enough energy for the trip
4149 # Note: this formula is slightly different from the C version,
4150 # and lets you skate a bit closer to the edge.
4151 if wcourse.power(game.warpfac) >= game.energy:
4152 # Insufficient power for trip
4155 prout(_("Engineering to bridge--"))
4156 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
4157 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
4159 prout(_("We can't do it, Captain. We don't have enough energy."))
4161 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4164 prout(_("if you'll lower the shields."))
4168 prout(_("We haven't the energy to go that far with the shields up."))
4170 # Make sure enough time is left for the trip
4171 game.optime = wcourse.time(game.warpfac)
4172 if game.optime >= 0.8*game.state.remtime:
4174 prout(_("First Officer Spock- \"Captain, I compute that such"))
4175 proutn(_(" a trip would require approximately %2.0f") %
4176 (100.0*game.optime/game.state.remtime))
4177 prout(_(" percent of our"))
4178 proutn(_(" remaining time. Are you sure this is wise?\" "))
4184 if game.warpfac > 6.0:
4185 # Decide if engine damage will occur
4186 # ESR: Seems wrong. Probability of damage goes *down* with distance?
4187 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
4188 if prob > randreal():
4190 wcourse.distance = randreal(wcourse.distance)
4191 # Decide if time warp will occur
4192 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
4194 if game.idebug and game.warpfac==10 and not twarp:
4196 proutn("=== Force time warp? ")
4200 # If time warp or engine damage, check path
4201 # If it is obstructed, don't do warp or damage
4202 look = wcourse.moves
4206 w = wcourse.sector()
4207 if not w.valid_sector():
4209 if game.quad[w.i][w.j] != '.':
4213 # Activate Warp Engines and pay the cost
4214 imove(wcourse, noattack=False)
4217 game.energy -= wcourse.power(game.warpfac)
4218 if game.energy <= 0:
4220 game.optime = wcourse.time(game.warpfac)
4224 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4226 prout(_("Engineering to bridge--"))
4227 prout(_(" Scott here. The warp engines are damaged."))
4228 prout(_(" We'll have to reduce speed to warp 4."))
4233 "Change the warp factor."
4235 key=scanner.nexttok()
4239 proutn(_("Warp factor- "))
4243 if game.damage[DWARPEN] > 10.0:
4244 prout(_("Warp engines inoperative."))
4246 if damaged(DWARPEN) and scanner.real > 4.0:
4247 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4248 prout(_(" but right now we can only go warp 4.\""))
4250 if scanner.real > 10.0:
4251 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4253 if scanner.real < 1.0:
4254 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4256 oldfac = game.warpfac
4257 game.warpfac = scanner.real
4258 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4259 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4262 if game.warpfac < 8.00:
4263 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4265 if game.warpfac == 10.0:
4266 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4268 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4272 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4274 # is captain on planet?
4276 if damaged(DTRANSP):
4279 prout(_("Scotty rushes to the transporter controls."))
4281 prout(_("But with the shields up it's hopeless."))
4283 prouts(_("His desperate attempt to rescue you . . ."))
4288 prout(_("SUCCEEDS!"))
4291 proutn(_("The crystals mined were "))
4299 # Check to see if captain in shuttle craft
4304 # Inform captain of attempt to reach safety
4308 prouts(_("***RED ALERT! RED ALERT!"))
4310 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4311 prouts(_(" a supernova."))
4313 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4314 prout(_("safely out of quadrant."))
4315 if not damaged(DRADIO):
4316 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4317 # Try to use warp engines
4318 if damaged(DWARPEN):
4320 prout(_("Warp engines damaged."))
4323 game.warpfac = randreal(6.0, 8.0)
4324 prout(_("Warp factor set to %d") % int(game.warpfac))
4325 power = 0.75*game.energy
4326 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4327 dist = max(dist, randreal(math.sqrt(2)))
4328 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4329 game.optime = bugout.time(game.warpfac)
4331 game.inorbit = False
4332 warp(bugout, involuntary=True)
4334 # This is bad news, we didn't leave quadrant.
4338 prout(_("Insufficient energy to leave quadrant."))
4341 # Repeat if another snova
4342 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4345 finish(FWON) # Snova killed remaining enemy.
4348 "Let's do the time warp again."
4349 prout(_("***TIME WARP ENTERED."))
4350 if game.state.snap and withprob(0.5):
4352 prout(_("You are traveling backwards in time %d stardates.") %
4353 int(game.state.date-game.snapsht.date))
4354 game.state = game.snapsht
4355 game.state.snap = False
4356 if len(game.state.kcmdr):
4357 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4358 schedule(FBATTAK, expran(0.3*game.intime))
4359 schedule(FSNOVA, expran(0.5*game.intime))
4360 # next snapshot will be sooner
4361 schedule(FSNAP, expran(0.25*game.state.remtime))
4363 if game.state.nscrem:
4364 schedule(FSCMOVE, 0.2777)
4368 game.battle.invalidate()
4369 # Make sure Galileo is consistant -- Snapshot may have been taken
4370 # when on planet, which would give us two Galileos!
4372 for l in range(game.inplan):
4373 if game.state.planets[l].known == "shuttle_down":
4375 if game.iscraft == "onship" and game.ship=='E':
4376 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4377 game.iscraft = "offship"
4378 # Likewise, if in the original time the Galileo was abandoned, but
4379 # was on ship earlier, it would have vanished -- let's restore it.
4380 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4381 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4382 game.iscraft = "onship"
4383 # There used to be code to do the actual reconstrction here,
4384 # but the starchart is now part of the snapshotted galaxy state.
4385 prout(_("Spock has reconstructed a correct star chart from memory"))
4387 # Go forward in time
4388 game.optime = expran(0.5*game.intime)
4389 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4390 # cheat to make sure no tractor beams occur during time warp
4391 postpone(FTBEAM, game.optime)
4392 game.damage[DRADIO] += game.optime
4394 events() # Stas Sergeev added this -- do pending events
4397 "Launch deep-space probe."
4398 # New code to launch a deep space probe
4399 if game.nprobes == 0:
4402 if game.ship == 'E':
4403 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4405 prout(_("Ye Faerie Queene has no deep space probes."))
4410 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4412 if is_scheduled(FDSPROB):
4415 if damaged(DRADIO) and game.condition != "docked":
4416 prout(_("Spock- \"Records show the previous probe has not yet"))
4417 prout(_(" reached its destination.\""))
4419 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4421 key = scanner.nexttok()
4423 if game.nprobes == 1:
4424 prout(_("1 probe left."))
4426 prout(_("%d probes left") % game.nprobes)
4427 proutn(_("Are you sure you want to fire a probe? "))
4430 game.isarmed = False
4431 if key == "IHALPHA" and scanner.token == "armed":
4433 key = scanner.nexttok()
4434 elif key == "IHEOL":
4435 proutn(_("Arm NOVAMAX warhead? "))
4437 elif key == "IHREAL": # first element of course
4438 scanner.push(scanner.token)
4440 game.probe = getcourse(isprobe=True)
4444 schedule(FDSPROB, 0.01) # Time to move one sector
4445 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4450 "Yell for help from nearest starbase."
4451 # There's more than one way to move in this game!
4453 # Test for conditions which prevent calling for help
4454 if game.condition == "docked":
4455 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4458 prout(_("Subspace radio damaged."))
4460 if not game.state.baseq:
4461 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4464 prout(_("You must be aboard the %s.") % crmshp())
4466 # OK -- call for help from nearest starbase
4469 # There's one in this quadrant
4470 ddist = (game.base - game.sector).distance()
4472 ibq = None # Force base-quadrant game to persist past loop
4474 for ibq in game.state.baseq:
4475 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4479 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4481 # Since starbase not in quadrant, set up new quadrant
4484 # dematerialize starship
4485 game.quad[game.sector.i][game.sector.j]='.'
4486 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4487 % (game.quadrant, crmshp()))
4488 game.sector.invalidate()
4489 for m in range(1, 5+1):
4490 w = game.base.scatter()
4491 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4492 # found one -- finish up
4495 if not game.sector.is_valid():
4496 prout(_("You have been lost in space..."))
4497 finish(FMATERIALIZE)
4499 # Give starbase three chances to rematerialize starship
4500 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4501 for m in range(1, 3+1):
4502 if m == 1: proutn(_("1st"))
4503 elif m == 2: proutn(_("2nd"))
4504 elif m == 3: proutn(_("3rd"))
4505 proutn(_(" attempt to re-materialize ") + crmshp())
4506 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4509 if randreal() > probf:
4513 curses.delay_output(500)
4515 game.quad[game.sector.i][game.sector.j]='?'
4518 setwnd(message_window)
4519 finish(FMATERIALIZE)
4521 game.quad[game.sector.i][game.sector.j]=game.ship
4523 prout(_("succeeds."))
4527 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4532 if game.condition=="docked":
4534 prout(_("You cannot abandon Ye Faerie Queene."))
4537 # Must take shuttle craft to exit
4538 if game.damage[DSHUTTL]==-1:
4539 prout(_("Ye Faerie Queene has no shuttle craft."))
4541 if game.damage[DSHUTTL]<0:
4542 prout(_("Shuttle craft now serving Big Macs."))
4544 if game.damage[DSHUTTL]>0:
4545 prout(_("Shuttle craft damaged."))
4548 prout(_("You must be aboard the ship."))
4550 if game.iscraft != "onship":
4551 prout(_("Shuttle craft not currently available."))
4553 # Emit abandon ship messages
4555 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4557 prouts(_("***ALL HANDS ABANDON SHIP!"))
4559 prout(_("Captain and crew escape in shuttle craft."))
4560 if not game.state.baseq:
4561 # Oops! no place to go...
4564 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4566 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4567 prout(_("Remainder of ship's complement beam down"))
4568 prout(_("to nearest habitable planet."))
4569 elif q.planet != None and not damaged(DTRANSP):
4570 prout(_("Remainder of ship's complement beam down to %s.") %
4573 prout(_("Entire crew of %d left to die in outer space.") %
4575 game.casual += game.state.crew
4576 game.abandoned += game.state.crew
4577 # If at least one base left, give 'em the Faerie Queene
4579 game.icrystl = False # crystals are lost
4580 game.nprobes = 0 # No probes
4581 prout(_("You are captured by Klingons and released to"))
4582 prout(_("the Federation in a prisoner-of-war exchange."))
4583 nb = randrange(len(game.state.baseq))
4584 # Set up quadrant and position FQ adjacient to base
4585 if not game.quadrant == game.state.baseq[nb]:
4586 game.quadrant = game.state.baseq[nb]
4587 game.sector.i = game.sector.j = 5
4590 # position next to base by trial and error
4591 game.quad[game.sector.i][game.sector.j] = '.'
4593 for l in range(QUADSIZE):
4594 game.sector = game.base.scatter()
4595 if game.sector.valid_sector() and \
4596 game.quad[game.sector.i][game.sector.j] == '.':
4599 break # found a spot
4600 game.sector.i=QUADSIZE/2
4601 game.sector.j=QUADSIZE/2
4603 # Get new commission
4604 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4605 game.state.crew = FULLCREW
4606 prout(_("Starfleet puts you in command of another ship,"))
4607 prout(_("the Faerie Queene, which is antiquated but,"))
4608 prout(_("still useable."))
4610 prout(_("The dilithium crystals have been moved."))
4612 game.iscraft = "offship" # Galileo disappears
4614 game.condition="docked"
4615 for l in range(NDEVICES):
4616 game.damage[l] = 0.0
4617 game.damage[DSHUTTL] = -1
4618 game.energy = game.inenrg = 3000.0
4619 game.shield = game.inshld = 1250.0
4620 game.torps = game.intorps = 6
4621 game.lsupres=game.inlsr=3.0
4624 game.brigfree = game.brigcapacity = 300
4627 # Code from planets.c begins here.
4630 "Abort a lengthy operation if an event interrupts it."
4633 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4638 "Report on (uninhabited) planets in the galaxy."
4642 prout(_("Spock- \"Planet report follows, Captain.\""))
4644 for i in range(game.inplan):
4645 if game.state.planets[i].pclass == "destroyed":
4647 if (game.state.planets[i].known != "unknown" \
4648 and not game.state.planets[i].inhabited) \
4651 if game.idebug and game.state.planets[i].known=="unknown":
4652 proutn("(Unknown) ")
4653 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4654 proutn(_(" class "))
4655 proutn(game.state.planets[i].pclass)
4657 if game.state.planets[i].crystals != "present":
4659 prout(_("dilithium crystals present."))
4660 if game.state.planets[i].known=="shuttle_down":
4661 prout(_(" Shuttle Craft Galileo on surface."))
4663 prout(_("No information available."))
4666 "Enter standard orbit."
4670 prout(_("Already in standard orbit."))
4672 if damaged(DWARPEN) and damaged(DIMPULS):
4673 prout(_("Both warp and impulse engines damaged."))
4675 if not game.plnet.is_valid():
4676 prout("There is no planet in this sector.")
4678 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4679 prout(crmshp() + _(" not adjacent to planet."))
4682 game.optime = randreal(0.02, 0.05)
4683 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4687 game.height = randreal(1400, 8600)
4688 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4693 "Examine planets in this quadrant."
4694 if damaged(DSRSENS):
4695 if game.options & OPTION_TTY:
4696 prout(_("Short range sensors damaged."))
4698 if game.iplnet is None:
4699 if game.options & OPTION_TTY:
4700 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4702 if game.iplnet.known == "unknown":
4703 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4705 prout(_(" Planet at Sector %s is of class %s.") %
4706 (game.plnet, game.iplnet.pclass))
4707 if game.iplnet.known=="shuttle_down":
4708 prout(_(" Sensors show Galileo still on surface."))
4709 proutn(_(" Readings indicate"))
4710 if game.iplnet.crystals != "present":
4712 prout(_(" dilithium crystals present.\""))
4713 if game.iplnet.known == "unknown":
4714 game.iplnet.known = "known"
4715 elif game.iplnet.inhabited:
4716 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4717 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4720 "Use the transporter."
4724 if damaged(DTRANSP):
4725 prout(_("Transporter damaged."))
4726 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4728 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4732 if not game.inorbit:
4733 prout(crmshp() + _(" not in standard orbit."))
4736 prout(_("Impossible to transport through shields."))
4738 if game.iplnet.known=="unknown":
4739 prout(_("Spock- \"Captain, we have no information on this planet"))
4740 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4741 prout(_(" you may not go down.\""))
4743 if not game.landed and game.iplnet.crystals=="absent":
4744 prout(_("Spock- \"Captain, I fail to see the logic in"))
4745 prout(_(" exploring a planet with no dilithium crystals."))
4746 proutn(_(" Are you sure this is wise?\" "))
4750 if not (game.options & OPTION_PLAIN):
4751 nrgneed = 50 * game.skill + game.height / 100.0
4752 if nrgneed > game.energy:
4753 prout(_("Engineering to bridge--"))
4754 prout(_(" Captain, we don't have enough energy for transportation."))
4756 if not game.landed and nrgneed * 2 > game.energy:
4757 prout(_("Engineering to bridge--"))
4758 prout(_(" Captain, we have enough energy only to transport you down to"))
4759 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4760 if game.iplnet.known == "shuttle_down":
4761 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4762 proutn(_(" Are you sure this is wise?\" "))
4767 # Coming from planet
4768 if game.iplnet.known=="shuttle_down":
4769 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4773 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4774 prout(_("Landing party assembled, ready to beam up."))
4776 prout(_("Kirk whips out communicator..."))
4777 prouts(_("BEEP BEEP BEEP"))
4779 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4782 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4784 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4786 prout(_("Kirk- \"Energize.\""))
4789 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4791 if not withprob(0.98):
4792 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4794 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4797 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4798 game.landed = not game.landed
4799 game.energy -= nrgneed
4801 prout(_("Transport complete."))
4802 if game.landed and game.iplnet.known=="shuttle_down":
4803 prout(_("The shuttle craft Galileo is here!"))
4804 if not game.landed and game.imine:
4811 "Strip-mine a world for dilithium."
4815 prout(_("Mining party not on planet."))
4817 if game.iplnet.crystals == "mined":
4818 prout(_("This planet has already been strip-mined for dilithium."))
4820 elif game.iplnet.crystals == "absent":
4821 prout(_("No dilithium crystals on this planet."))
4824 prout(_("You've already mined enough crystals for this trip."))
4826 if game.icrystl and game.cryprob == 0.05:
4827 prout(_("With all those fresh crystals aboard the ") + crmshp())
4828 prout(_("there's no reason to mine more at this time."))
4830 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4833 prout(_("Mining operation complete."))
4834 game.iplnet.crystals = "mined"
4835 game.imine = game.ididit = True
4838 "Use dilithium crystals."
4842 if not game.icrystl:
4843 prout(_("No dilithium crystals available."))
4845 if game.energy >= 1000:
4846 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4847 prout(_(" except when Condition Yellow exists."))
4849 prout(_("Spock- \"Captain, I must warn you that loading"))
4850 prout(_(" raw dilithium crystals into the ship's power"))
4851 prout(_(" system may risk a severe explosion."))
4852 proutn(_(" Are you sure this is wise?\" "))
4857 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4858 prout(_(" Mr. Spock and I will try it.\""))
4860 prout(_("Spock- \"Crystals in place, Sir."))
4861 prout(_(" Ready to activate circuit.\""))
4863 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4865 if withprob(game.cryprob):
4866 prouts(_(" \"Activating now! - - No good! It's***"))
4868 prouts(_("***RED ALERT! RED A*L********************************"))
4871 prouts(_("****************** KA-BOOM!!!! *******************"))
4875 game.energy += randreal(5000.0, 5500.0)
4876 prouts(_(" \"Activating now! - - "))
4877 prout(_("The instruments"))
4878 prout(_(" are going crazy, but I think it's"))
4879 prout(_(" going to work!! Congratulations, Sir!\""))
4884 "Use shuttlecraft for planetary jaunt."
4887 if damaged(DSHUTTL):
4888 if game.damage[DSHUTTL] == -1.0:
4889 if game.inorbit and game.iplnet.known == "shuttle_down":
4890 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4892 prout(_("Ye Faerie Queene had no shuttle craft."))
4893 elif game.damage[DSHUTTL] > 0:
4894 prout(_("The Galileo is damaged."))
4895 else: # game.damage[DSHUTTL] < 0
4896 prout(_("Shuttle craft is now serving Big Macs."))
4898 if not game.inorbit:
4899 prout(crmshp() + _(" not in standard orbit."))
4901 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4902 prout(_("Shuttle craft not currently available."))
4904 if not game.landed and game.iplnet.known=="shuttle_down":
4905 prout(_("You will have to beam down to retrieve the shuttle craft."))
4907 if game.shldup or game.condition == "docked":
4908 prout(_("Shuttle craft cannot pass through shields."))
4910 if game.iplnet.known=="unknown":
4911 prout(_("Spock- \"Captain, we have no information on this planet"))
4912 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4913 prout(_(" you may not fly down.\""))
4915 game.optime = 3.0e-5*game.height
4916 if game.optime >= 0.8*game.state.remtime:
4917 prout(_("First Officer Spock- \"Captain, I compute that such"))
4918 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4919 int(100*game.optime/game.state.remtime))
4920 prout(_("remaining time."))
4921 proutn(_("Are you sure this is wise?\" "))
4927 if game.iscraft == "onship":
4929 if not damaged(DTRANSP):
4930 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4934 proutn(_("Shuttle crew"))
4936 proutn(_("Rescue party"))
4937 prout(_(" boards Galileo and swoops toward planet surface."))
4938 game.iscraft = "offship"
4942 game.iplnet.known="shuttle_down"
4943 prout(_("Trip complete."))
4946 # Ready to go back to ship
4947 prout(_("You and your mining party board the"))
4948 prout(_("shuttle craft for the trip back to the Enterprise."))
4950 prouts(_("The short hop begins . . ."))
4952 game.iplnet.known="known"
4958 game.iscraft = "onship"
4964 prout(_("Trip complete."))
4967 # Kirk on ship and so is Galileo
4968 prout(_("Mining party assembles in the hangar deck,"))
4969 prout(_("ready to board the shuttle craft \"Galileo\"."))
4971 prouts(_("The hangar doors open; the trip begins."))
4974 game.iscraft = "offship"
4977 game.iplnet.known = "shuttle_down"
4980 prout(_("Trip complete."))
4984 "Use the big zapper."
4988 if game.ship != 'E':
4989 prout(_("Ye Faerie Queene has no death ray."))
4991 if len(game.enemies)==0:
4992 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4995 prout(_("Death Ray is damaged."))
4997 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4998 prout(_(" is highly unpredictible. Considering the alternatives,"))
4999 proutn(_(" are you sure this is wise?\" "))
5002 prout(_("Spock- \"Acknowledged.\""))
5005 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
5007 prout(_("Crew scrambles in emergency preparation."))
5008 prout(_("Spock and Scotty ready the death ray and"))
5009 prout(_("prepare to channel all ship's power to the device."))
5011 prout(_("Spock- \"Preparations complete, sir.\""))
5012 prout(_("Kirk- \"Engage!\""))
5014 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
5017 if game.options & OPTION_PLAIN:
5021 prouts(_("Sulu- \"Captain! It's working!\""))
5023 while len(game.enemies) > 0:
5024 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
5025 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
5026 if game.unwon() == 0:
5028 if (game.options & OPTION_PLAIN) == 0:
5029 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
5031 prout(_(" is still operational.\""))
5033 prout(_(" has been rendered nonfunctional.\""))
5034 game.damage[DDRAY] = 39.95
5036 r = randreal() # Pick failure method
5038 prouts(_("Sulu- \"Captain! It's working!\""))
5040 prouts(_("***RED ALERT! RED ALERT!"))
5042 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
5044 prouts(_("***RED ALERT! RED A*L********************************"))
5047 prouts(_("****************** KA-BOOM!!!! *******************"))
5052 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
5054 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
5056 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
5057 prout(_(" have apparently been transformed into strange mutations."))
5058 prout(_(" Vulcans do not seem to be affected."))
5060 prout(_("Kirk- \"Raauch! Raauch!\""))
5064 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
5066 proutn(_("Spock- \"I believe the word is"))
5067 prouts(_(" *ASTONISHING*"))
5068 prout(_(" Mr. Sulu."))
5069 for i in range(QUADSIZE):
5070 for j in range(QUADSIZE):
5071 if game.quad[i][j] == '.':
5072 game.quad[i][j] = '?'
5073 prout(_(" Captain, our quadrant is now infested with"))
5074 prouts(_(" - - - - - - *THINGS*."))
5076 prout(_(" I have no logical explanation.\""))
5078 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
5080 prout(_("Scotty- \"There are so many tribbles down here"))
5081 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
5085 # Code from reports.c begins here
5087 def attackreport(curt):
5088 "eport status of bases under attack."
5090 if is_scheduled(FCDBAS):
5091 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
5092 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
5093 elif game.isatb == 1:
5094 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
5095 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
5097 prout(_("No Starbase is currently under attack."))
5099 if is_scheduled(FCDBAS):
5100 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
5102 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
5106 # report on general game status
5108 s1 = (game.thawed and _("thawed ")) or ""
5109 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
5110 s3 = (None, _("novice"), _("fair"),
5111 _("good"), _("expert"), _("emeritus"))[game.skill]
5112 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
5113 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
5114 prout(_("No plaque is allowed."))
5116 prout(_("This is tournament game %d.") % game.tourn)
5117 prout(_("Your secret password is \"%s\"") % game.passwd)
5118 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - game.unwon()),
5119 (game.inkling + game.incom + game.inscom)))
5120 if game.incom - len(game.state.kcmdr):
5121 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
5122 elif game.inkling - game.remkl() + (game.inscom - game.state.nscrem) > 0:
5123 prout(_(", but no Commanders."))
5126 if game.skill > SKILL_FAIR:
5127 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
5128 if len(game.state.baseq) != game.inbase:
5130 if game.inbase-len(game.state.baseq)==1:
5131 proutn(_("has been 1 base"))
5133 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
5134 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
5136 prout(_("There are %d bases.") % game.inbase)
5137 if communicating() or game.iseenit:
5138 # Don't report this if not seen and
5139 # either the radio is dead or not at base!
5143 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
5144 if game.brigcapacity != game.brigfree:
5145 embriggened = brigcapacity-brigfree
5146 if embriggened == 1:
5147 prout(_("1 Klingon in brig"))
5149 prout(_("%d Klingons in brig.") % embriggened)
5150 if game.kcaptured == 0:
5152 elif game.kcaptured == 1:
5153 prout(_("1 captured Klingon turned in to Starfleet."))
5155 prout(_("%d captured Klingons turned in to Star Fleet.") % game.kcaptured)
5157 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
5158 if game.ship == 'E':
5159 proutn(_("You have "))
5161 proutn("%d" % (game.nprobes))
5164 proutn(_(" deep space probe"))
5168 if communicating() and is_scheduled(FDSPROB):
5170 proutn(_("An armed deep space probe is in "))
5172 proutn(_("A deep space probe is in "))
5173 prout("Quadrant %s." % game.probe.quadrant())
5175 if game.cryprob <= .05:
5176 prout(_("Dilithium crystals aboard ship... not yet used."))
5180 while game.cryprob > ai:
5183 prout(_("Dilithium crystals have been used %d time%s.") % \
5184 (i, (_("s"), "")[i==1]))
5188 "Long-range sensor scan."
5189 if damaged(DLRSENS):
5190 # Now allow base's sensors if docked
5191 if game.condition != "docked":
5193 prout(_("LONG-RANGE SENSORS DAMAGED."))
5196 prout(_("Starbase's long-range scan"))
5198 prout(_("Long-range scan"))
5199 for x in range(game.quadrant.i-1, game.quadrant.i+2):
5202 for y in range(game.quadrant.j-1, game.quadrant.j+2):
5203 if not Coord(x, y).valid_quadrant():
5207 if not damaged(DRADIO):
5208 game.state.galaxy[x][y].charted = True
5209 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5210 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5211 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5212 if not silent and game.state.galaxy[x][y].supernova:
5215 cn = " %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars)
5216 proutn(((3 - len(cn)) * '.') + cn)
5224 for i in range(NDEVICES):
5227 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5228 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5230 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5231 game.damage[i]+0.05,
5232 DOCKFAC*game.damage[i]+0.005))
5234 prout(_("All devices functional."))
5237 "Update the chart in the Enterprise's computer from galaxy data."
5238 game.lastchart = game.state.date
5239 for i in range(GALSIZE):
5240 for j in range(GALSIZE):
5241 if game.state.galaxy[i][j].charted:
5242 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5243 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5244 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5247 "Display the star chart."
5249 if (game.options & OPTION_AUTOSCAN):
5253 if game.lastchart < game.state.date and game.condition == "docked":
5254 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5256 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5257 if game.state.date > game.lastchart:
5258 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5259 prout(" 1 2 3 4 5 6 7 8")
5260 for i in range(GALSIZE):
5261 proutn("%d |" % (i+1))
5262 for j in range(GALSIZE):
5263 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5267 if game.state.galaxy[i][j].supernova:
5269 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5271 elif game.state.galaxy[i][j].charted:
5272 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5276 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5284 def sectscan(goodScan, i, j):
5285 "Light up an individual dot in a sector."
5286 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5287 if game.quad[i][j] in ('E', 'F'):
5290 textcolor({"green":GREEN,
5294 "dead":BROWN}[game.condition])
5296 textcolor({'?':LIGHTMAGENTA,
5302 }.get(game.quad[i][j], DEFAULT))
5303 proutn("%c " % game.quad[i][j])
5309 "Emit status report lines"
5310 if not req or req == 1:
5311 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5312 % (game.state.date, game.state.remtime))
5313 if not req or req == 2:
5314 if game.condition != "docked":
5316 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5317 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5319 prout(_(", CLOAKED"))
5320 if not req or req == 3:
5321 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5322 if not req or req == 4:
5323 if damaged(DLIFSUP):
5324 if game.condition == "docked":
5325 s = _("DAMAGED, Base provides")
5327 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5330 prstat(_("Life Support"), s)
5331 if not req or req == 5:
5332 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5333 if not req or req == 6:
5335 if game.icrystl and (game.options & OPTION_SHOWME):
5336 extra = _(" (have crystals)")
5337 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5338 if not req or req == 7:
5339 prstat(_("Torpedoes"), "%d" % (game.torps))
5340 if not req or req == 8:
5341 if damaged(DSHIELD):
5347 data = _(" %d%% %.1f units") \
5348 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5349 prstat(_("Shields"), s+data)
5350 if not req or req == 9:
5351 prstat(_("Klingons Left"), "%d" % game.unwon())
5352 if not req or req == 10:
5353 if game.options & OPTION_WORLDS:
5354 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5355 if plnet and plnet.inhabited:
5356 prstat(_("Major system"), plnet.name)
5358 prout(_("Sector is uninhabited"))
5359 elif not req or req == 11:
5360 attackreport(not req)
5363 "Request specified status data, a historical relic from slow TTYs."
5364 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5365 while scanner.nexttok() == "IHEOL":
5366 proutn(_("Information desired? "))
5368 if scanner.token in requests:
5369 status(requests.index(scanner.token))
5371 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5372 prout((" date, condition, position, lsupport, warpfactor,"))
5373 prout((" energy, torpedoes, shields, klingons, system, time."))
5378 if damaged(DSRSENS):
5379 # Allow base's sensors if docked
5380 if game.condition != "docked":
5381 prout(_(" S.R. SENSORS DAMAGED!"))
5384 prout(_(" [Using Base's sensors]"))
5386 prout(_(" Short-range scan"))
5387 if goodScan and communicating():
5388 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5389 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5390 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5391 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5392 prout(" 1 2 3 4 5 6 7 8 9 10")
5393 if game.condition != "docked":
5395 for i in range(QUADSIZE):
5396 proutn("%2d " % (i+1))
5397 for j in range(QUADSIZE):
5398 sectscan(goodScan, i, j)
5402 "Use computer to get estimated time of arrival for a warp jump."
5403 w1 = Coord(); w2 = Coord()
5405 if damaged(DCOMPTR):
5406 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5409 if scanner.nexttok() != "IHREAL":
5412 proutn(_("Destination quadrant and/or sector? "))
5413 if scanner.nexttok()!="IHREAL":
5416 w1.j = int(scanner.real-0.5)
5417 if scanner.nexttok() != "IHREAL":
5420 w1.i = int(scanner.real-0.5)
5421 if scanner.nexttok() == "IHREAL":
5422 w2.j = int(scanner.real-0.5)
5423 if scanner.nexttok() != "IHREAL":
5426 w2.i = int(scanner.real-0.5)
5428 if game.quadrant.j>w1.i:
5432 if game.quadrant.i>w1.j:
5436 if not w1.valid_quadrant() or not w2.valid_sector():
5439 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5440 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5443 prout(_("Answer \"no\" if you don't know the value:"))
5446 proutn(_("Time or arrival date? "))
5447 if scanner.nexttok()=="IHREAL":
5448 ttime = scanner.real
5449 if ttime > game.state.date:
5450 ttime -= game.state.date # Actually a star date
5451 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5452 if ttime <= 1e-10 or twarp > 10:
5453 prout(_("We'll never make it, sir."))
5460 proutn(_("Warp factor? "))
5461 if scanner.nexttok()== "IHREAL":
5463 twarp = scanner.real
5464 if twarp<1.0 or twarp > 10.0:
5468 prout(_("Captain, certainly you can give me one of these."))
5471 ttime = (10.0*dist)/twarp**2
5472 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5473 if tpower >= game.energy:
5474 prout(_("Insufficient energy, sir."))
5475 if not game.shldup or tpower > game.energy*2.0:
5478 proutn(_("New warp factor to try? "))
5479 if scanner.nexttok() == "IHREAL":
5481 twarp = scanner.real
5482 if twarp<1.0 or twarp > 10.0:
5490 prout(_("But if you lower your shields,"))
5491 proutn(_("remaining"))
5494 proutn(_("Remaining"))
5495 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5497 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5499 prout(_("Any warp speed is adequate."))
5501 prout(_("Minimum warp needed is %.2f,") % (twarp))
5502 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5503 if game.state.remtime < ttime:
5504 prout(_("Unfortunately, the Federation will be destroyed by then."))
5506 prout(_("You'll be taking risks at that speed, Captain"))
5507 if (game.isatb==1 and game.state.kscmdr == w1 and \
5508 scheduled(FSCDBAS)< ttime+game.state.date) or \
5509 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5510 prout(_("The starbase there will be destroyed by then."))
5511 proutn(_("New warp factor to try? "))
5512 if scanner.nexttok() == "IHREAL":
5514 twarp = scanner.real
5515 if twarp<1.0 or twarp > 10.0:
5523 # Code from setup.c begins here
5526 "Issue a historically correct banner."
5528 prout(_("-SUPER- STAR TREK"))
5530 # From the FORTRAN original
5531 # prout(_("Latest update-21 Sept 78"))
5537 scanner.push("emsave.trk")
5538 key = scanner.nexttok()
5540 proutn(_("File name: "))
5541 key = scanner.nexttok()
5542 if key != "IHALPHA":
5545 if '.' not in scanner.token:
5546 scanner.token += ".trk"
5548 fp = open(scanner.token, "wb")
5550 prout(_("Can't freeze game as file %s") % scanner.token)
5552 pickle.dump(game, fp)
5557 "Retrieve saved game."
5560 key = scanner.nexttok()
5562 proutn(_("File name: "))
5563 key = scanner.nexttok()
5564 if key != "IHALPHA":
5567 if '.' not in scanner.token:
5568 scanner.token += ".trk"
5570 fp = open(scanner.token, "rb")
5572 prout(_("Can't thaw game in %s") % scanner.token)
5574 game = pickle.load(fp)
5579 # I used <http://www.memory-alpha.org> to find planets
5580 # with references in ST:TOS. Earth and the Alpha Centauri
5581 # Colony have been omitted.
5583 # Some planets marked Class G and P here will be displayed as class M
5584 # because of the way planets are generated. This is a known bug.
5587 _("Andoria (Fesoan)"), # several episodes
5588 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5589 _("Vulcan (T'Khasi)"), # many episodes
5590 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5591 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5592 _("Ardana"), # TOS: "The Cloud Minders"
5593 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5594 _("Gideon"), # TOS: "The Mark of Gideon"
5595 _("Aldebaran III"), # TOS: "The Deadly Years"
5596 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5597 _("Altair IV"), # TOS: "Amok Time
5598 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5599 _("Benecia"), # TOS: "The Conscience of the King"
5600 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5601 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5602 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5603 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5604 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5605 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5606 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5607 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5608 _("Ingraham B"), # TOS: "Operation: Annihilate"
5609 _("Janus IV"), # TOS: "The Devil in the Dark"
5610 _("Makus III"), # TOS: "The Galileo Seven"
5611 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5612 _("Omega IV"), # TOS: "The Omega Glory"
5613 _("Regulus V"), # TOS: "Amok Time
5614 _("Deneva"), # TOS: "Operation -- Annihilate!"
5615 # Worlds from BSD Trek
5616 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5617 _("Beta III"), # TOS: "The Return of the Archons"
5618 _("Triacus"), # TOS: "And the Children Shall Lead",
5619 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5621 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5622 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5623 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5624 # _("Izar"), # TOS: "Whom Gods Destroy"
5625 # _("Tiburon"), # TOS: "The Way to Eden"
5626 # _("Merak II"), # TOS: "The Cloud Minders"
5627 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5628 # _("Iotia"), # TOS: "A Piece of the Action"
5632 _("S. R. Sensors"), \
5633 _("L. R. Sensors"), \
5635 _("Photon Tubes"), \
5636 _("Life Support"), \
5637 _("Warp Engines"), \
5638 _("Impulse Engines"), \
5640 _("Subspace Radio"), \
5641 _("Shuttle Craft"), \
5643 _("Navigation System"), \
5645 _("Shield Control"), \
5648 _("Cloaking Device"), \
5652 "Prepare to play, set up cosmos."
5654 # Decide how many of everything
5656 return # frozen game
5657 # Prepare the Enterprise
5658 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5660 game.state.crew = FULLCREW
5661 game.energy = game.inenrg = 5000.0
5662 game.shield = game.inshld = 2500.0
5665 game.quadrant = randplace(GALSIZE)
5666 game.sector = randplace(QUADSIZE)
5667 game.torps = game.intorps = 10
5668 game.nprobes = randrange(2, 5)
5670 for i in range(NDEVICES):
5671 game.damage[i] = 0.0
5672 # Set up assorted game parameters
5673 game.battle = Coord()
5674 game.state.date = game.indate = 100.0 * randreal(20, 51)
5675 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5676 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5677 game.isatb = game.state.nplankl = 0
5678 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5679 game.iscraft = "onship"
5684 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5686 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5688 game.state.planets = [] # Planet information
5689 game.state.baseq = [] # Base quadrant coordinates
5690 game.state.kcmdr = [] # Commander quadrant coordinates
5691 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5693 # Starchart is functional but we've never seen it
5694 game.lastchart = FOREVER
5695 # Put stars in the galaxy
5697 for i in range(GALSIZE):
5698 for j in range(GALSIZE):
5699 # Can't have more stars per quadrant than fit in one decimal digit,
5700 # if we do the chart representation will break.
5701 k = randrange(1, min(10, QUADSIZE**2/10))
5703 game.state.galaxy[i][j].stars = k
5704 # Locate star bases in galaxy
5706 prout("=== Allocating %d bases" % game.inbase)
5707 for i in range(game.inbase):
5710 w = randplace(GALSIZE)
5711 if not game.state.galaxy[w.i][w.j].starbase:
5714 # C version: for (j = i-1; j > 0; j--)
5715 # so it did them in the opposite order.
5716 for j in range(1, i):
5717 # Improved placement algorithm to spread out bases
5718 distq = (w - game.state.baseq[j]).distance()
5719 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5722 prout("=== Abandoning base #%d at %s" % (i, w))
5724 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5726 prout("=== Saving base #%d, close to #%d" % (i, j))
5730 prout("=== Placing base #%d in quadrant %s" % (i, w))
5731 game.state.baseq.append(w)
5732 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5733 # Position ordinary Klingon Battle Cruisers
5735 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5736 if klumper > MAXKLQUAD:
5740 klump = int((1.0 - r*r)*klumper)
5745 w = randplace(GALSIZE)
5746 if not game.state.galaxy[w.i][w.j].supernova and \
5747 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5749 game.state.galaxy[w.i][w.j].klingons += klump
5752 # Position Klingon Commander Ships
5753 for i in range(game.incom):
5755 w = randplace(GALSIZE)
5756 if not welcoming(w) or w in game.state.kcmdr:
5758 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5760 game.state.galaxy[w.i][w.j].klingons += 1
5761 game.state.kcmdr.append(w)
5762 # Locate planets in galaxy
5763 for i in range(game.inplan):
5765 w = randplace(GALSIZE)
5766 if game.state.galaxy[w.i][w.j].planet is None:
5770 new.crystals = "absent"
5771 if (game.options & OPTION_WORLDS) and i < NINHAB:
5772 new.pclass = "M" # All inhabited planets are class M
5773 new.crystals = "absent"
5775 new.name = systnames[i]
5776 new.inhabited = True
5778 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5780 new.crystals = "present"
5781 new.known = "unknown"
5782 new.inhabited = False
5783 game.state.galaxy[w.i][w.j].planet = new
5784 game.state.planets.append(new)
5786 for i in range(game.state.nromrem):
5787 w = randplace(GALSIZE)
5788 game.state.galaxy[w.i][w.j].romulans += 1
5789 # Place the Super-Commander if needed
5790 if game.state.nscrem > 0:
5792 w = randplace(GALSIZE)
5795 game.state.kscmdr = w
5796 game.state.galaxy[w.i][w.j].klingons += 1
5797 # Initialize times for extraneous events
5798 schedule(FSNOVA, expran(0.5 * game.intime))
5799 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5800 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5801 schedule(FBATTAK, expran(0.3*game.intime))
5803 if game.state.nscrem:
5804 schedule(FSCMOVE, 0.2777)
5809 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5810 schedule(FDISTR, expran(1.0 + game.intime))
5815 # Place thing (in tournament game, we don't want one!)
5816 # New in SST2K: never place the Thing near a starbase.
5817 # This makes sense and avoids a special case in the old code.
5819 if game.tourn is None:
5821 thing = randplace(GALSIZE)
5822 if thing not in game.state.baseq:
5825 game.state.snap = False
5826 if game.skill == SKILL_NOVICE:
5827 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5828 prout(_("a deadly Klingon invasion force. As captain of the United"))
5829 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5830 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5831 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5832 prout(_("your mission. As you proceed you may be given more time."))
5834 prout(_("You will have %d supporting starbases.") % (game.inbase))
5835 proutn(_("Starbase locations- "))
5837 prout(_("Stardate %d.") % int(game.state.date))
5839 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5840 prout(_("An unknown number of Romulans."))
5841 if game.state.nscrem:
5842 prout(_("And one (GULP) Super-Commander."))
5843 prout(_("%d stardates.") % int(game.intime))
5844 proutn(_("%d starbases in ") % game.inbase)
5845 for i in range(game.inbase):
5846 proutn(repr(game.state.baseq[i]))
5849 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5850 proutn(_(" Sector %s") % game.sector)
5852 prout(_("Good Luck!"))
5853 if game.state.nscrem:
5854 prout(_(" YOU'LL NEED IT."))
5857 setwnd(message_window)
5859 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5861 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5862 attack(torps_ok=False)
5865 "Choose your game type."
5867 game.tourn = game.length = 0
5869 game.skill = SKILL_NONE
5870 # Do not chew here, we want to use command-line tokens
5871 if not scanner.inqueue: # Can start with command line options
5872 proutn(_("Would you like a regular, tournament, or saved game? "))
5874 if scanner.sees("tournament"):
5875 while scanner.nexttok() == "IHEOL":
5876 proutn(_("Type in tournament number-"))
5877 if scanner.real == 0:
5879 continue # We don't want a blank entry
5880 game.tourn = int(round(scanner.real))
5881 random.seed(scanner.real)
5883 logfp.write("# random.seed(%d)\n" % scanner.real)
5885 if scanner.sees("saved") or scanner.sees("frozen"):
5889 if game.passwd is None:
5891 if not game.alldone:
5892 game.thawed = True # No plaque if not finished
5896 if scanner.sees("regular"):
5898 proutn(_("What is \"%s\"? ") % scanner.token)
5900 while game.length==0 or game.skill==SKILL_NONE:
5901 if scanner.nexttok() == "IHALPHA":
5902 if scanner.sees("short"):
5904 elif scanner.sees("medium"):
5906 elif scanner.sees("long"):
5908 elif scanner.sees("novice"):
5909 game.skill = SKILL_NOVICE
5910 elif scanner.sees("fair"):
5911 game.skill = SKILL_FAIR
5912 elif scanner.sees("good"):
5913 game.skill = SKILL_GOOD
5914 elif scanner.sees("expert"):
5915 game.skill = SKILL_EXPERT
5916 elif scanner.sees("emeritus"):
5917 game.skill = SKILL_EMERITUS
5919 proutn(_("What is \""))
5920 proutn(scanner.token)
5925 proutn(_("Would you like a Short, Medium, or Long game? "))
5926 elif game.skill == SKILL_NONE:
5927 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5928 # Choose game options -- added by ESR for SST2K
5929 if scanner.nexttok() != "IHALPHA":
5931 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5933 if scanner.sees("plain"):
5934 # Approximates the UT FORTRAN version.
5935 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR | OPTION_CAPTURE | OPTION_CLOAK)
5936 game.options |= OPTION_PLAIN
5937 elif scanner.sees("almy"):
5938 # Approximates Tom Almy's version.
5939 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
5940 game.options |= OPTION_ALMY
5941 elif scanner.sees("fancy") or scanner.sees("\n"):
5943 elif len(scanner.token):
5944 proutn(_("What is \"%s\"?") % scanner.token)
5946 if game.passwd == "debug":
5948 prout("=== Debug mode enabled.")
5949 # Use parameters to generate initial values of things
5950 game.damfac = 0.5 * game.skill
5951 game.inbase = randrange(BASEMIN, BASEMAX+1)
5953 if game.options & OPTION_PLANETS:
5954 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5955 if game.options & OPTION_WORLDS:
5956 game.inplan += int(NINHAB)
5957 game.state.nromrem = game.inrom = randrange(2 * game.skill)
5958 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5959 game.state.remtime = 7.0 * game.length
5960 game.intime = game.state.remtime
5961 game.inkling = int(2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15))
5962 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5963 game.state.remres = (game.inkling+4*game.incom)*game.intime
5964 game.inresor = game.state.remres
5965 if game.inkling > 50:
5969 def dropin(iquad=None):
5970 "Drop a feature on a random dot in the current quadrant."
5972 w = randplace(QUADSIZE)
5973 if game.quad[w.i][w.j] == '.':
5975 if iquad is not None:
5976 game.quad[w.i][w.j] = iquad
5980 "Update our alert status."
5981 game.condition = "green"
5982 if game.energy < 1000.0:
5983 game.condition = "yellow"
5984 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5985 game.condition = "red"
5987 game.condition="dead"
5990 "Drop new Klingon into current quadrant."
5991 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5994 "Sort enemies by distance so 'nearest' is meaningful."
5995 game.enemies.sort(key=lambda x: x.kdist)
5998 "Set up a new state of quadrant, for when we enter or re-enter it."
6001 game.neutz = game.inorbit = game.landed = False
6002 game.ientesc = game.iseenit = game.isviolreported = False
6003 # Create a blank quadrant
6004 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
6006 # Attempt to escape Super-commander, so tbeam back!
6009 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
6010 # cope with supernova
6013 game.klhere = q.klingons
6014 game.irhere = q.romulans
6016 game.quad[game.sector.i][game.sector.j] = game.ship
6019 # Position ordinary Klingons
6020 for _i in range(game.klhere):
6022 # If we need a commander, promote a Klingon
6023 for cmdr in game.state.kcmdr:
6024 if cmdr == game.quadrant:
6025 e = game.enemies[game.klhere-1]
6026 game.quad[e.location.i][e.location.j] = 'C'
6027 e.power = randreal(950,1350) + 50.0*game.skill
6029 # If we need a super-commander, promote a Klingon
6030 if game.quadrant == game.state.kscmdr:
6032 game.quad[e.location.i][e.location.j] = 'S'
6033 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
6034 game.iscate = (game.remkl() > 1)
6035 # Put in Romulans if needed
6036 for _i in range(q.romulans):
6037 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
6038 # If quadrant needs a starbase, put it in
6040 game.base = dropin('B')
6041 # If quadrant needs a planet, put it in
6043 game.iplnet = q.planet
6044 if not q.planet.inhabited:
6045 game.plnet = dropin('P')
6047 game.plnet = dropin('@')
6048 # Check for condition
6051 if game.irhere > 0 and game.klhere == 0:
6053 if not damaged(DRADIO):
6055 prout(_("LT. Uhura- \"Captain, an urgent message."))
6056 prout(_(" I'll put it on audio.\" CLICK"))
6058 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
6059 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
6060 # Put in THING if needed
6061 if thing == game.quadrant:
6062 Enemy(etype='?', loc=dropin(),
6063 power=randreal(6000,6500.0)+250.0*game.skill)
6064 if not damaged(DSRSENS):
6066 prout(_("Mr. Spock- \"Captain, this is most unusual."))
6067 prout(_(" Please examine your short-range scan.\""))
6068 # Decide if quadrant needs a Tholian; lighten up if skill is low
6069 if game.options & OPTION_THOLIAN:
6070 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
6071 (game.skill == SKILL_GOOD and withprob(0.05)) or \
6072 (game.skill > SKILL_GOOD and withprob(0.08)):
6075 w.i = withprob(0.5) * (QUADSIZE-1)
6076 w.j = withprob(0.5) * (QUADSIZE-1)
6077 if game.quad[w.i][w.j] == '.':
6079 game.tholian = Enemy(etype='T', loc=w,
6080 power=randrange(100, 500) + 25.0*game.skill)
6081 # Reserve unoccupied corners
6082 if game.quad[0][0]=='.':
6083 game.quad[0][0] = 'X'
6084 if game.quad[0][QUADSIZE-1]=='.':
6085 game.quad[0][QUADSIZE-1] = 'X'
6086 if game.quad[QUADSIZE-1][0]=='.':
6087 game.quad[QUADSIZE-1][0] = 'X'
6088 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
6089 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
6091 # And finally the stars
6092 for _i in range(q.stars):
6094 # Put in a few black holes
6095 for _i in range(1, 3+1):
6098 # Take out X's in corners if Tholian present
6100 if game.quad[0][0]=='X':
6101 game.quad[0][0] = '.'
6102 if game.quad[0][QUADSIZE-1]=='X':
6103 game.quad[0][QUADSIZE-1] = '.'
6104 if game.quad[QUADSIZE-1][0]=='X':
6105 game.quad[QUADSIZE-1][0] = '.'
6106 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
6107 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
6108 # This should guarantee that replay games don't lose info about the chart
6109 if (game.options & OPTION_AUTOSCAN) or replayfp:
6113 "Set the self-destruct password."
6114 if game.options & OPTION_PLAIN:
6117 proutn(_("Please type in a secret password- "))
6119 game.passwd = scanner.token
6120 if game.passwd != None:
6124 game.passwd += chr(ord('a')+randrange(26))
6125 game.passwd += chr(ord('a')+randrange(26))
6126 game.passwd += chr(ord('a')+randrange(26))
6128 # Code from sst.c begins here
6131 ("SRSCAN", OPTION_TTY),
6132 ("STATUS", OPTION_TTY),
6133 ("REQUEST", OPTION_TTY),
6134 ("LRSCAN", OPTION_TTY),
6146 ("SENSORS", OPTION_PLANETS),
6147 ("ORBIT", OPTION_PLANETS),
6148 ("TRANSPORT", OPTION_PLANETS),
6149 ("MINE", OPTION_PLANETS),
6150 ("CRYSTALS", OPTION_PLANETS),
6151 ("SHUTTLE", OPTION_PLANETS),
6152 ("PLANETS", OPTION_PLANETS),
6157 ("PROBE", OPTION_PROBE),
6159 ("FREEZE", 0), # Synonym for SAVE
6163 ("CAPTURE", OPTION_CAPTURE),
6164 ("CLOAK", OPTION_CLOAK),
6167 ("SOS", 0), # Synonym for MAYDAY
6168 ("CALL", 0), # Synonym for MAYDAY
6177 "Generate a list of legal commands."
6178 prout(_("LEGAL COMMANDS ARE:"))
6180 for (key, opt) in commands:
6181 if not opt or (opt & game.options):
6182 proutn("%-12s " % key)
6184 if emitted % 5 == 4:
6189 "Browse on-line help."
6190 key = scanner.nexttok()
6193 setwnd(prompt_window)
6194 proutn(_("Help on what command? "))
6195 key = scanner.nexttok()
6196 setwnd(message_window)
6199 cmds = [x[0] for x in commands]
6200 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
6207 cmd = scanner.token.upper()
6208 for directory in docpath:
6210 fp = open(os.path.join(directory, "sst.doc"), "r")
6215 prout(_("Spock- \"Captain, that information is missing from the"))
6216 prout(_(" computer. You need to find sst.doc and put it somewhere"))
6217 proutn(_(" in these directories: %s") % ":".join(docpath))
6219 # This used to continue: "You need to find SST.DOC and put
6220 # it in the current directory."
6223 linebuf = fp.readline()
6225 prout(_("Spock- \"Captain, there is no information on that command.\""))
6228 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
6229 linebuf = linebuf[3:].strip()
6230 if cmd.upper() == linebuf:
6233 prout(_("Spock- \"Captain, I've found the following information:\""))
6236 linebuf = fp.readline()
6237 if "******" in linebuf:
6243 "Command-interpretation loop."
6245 if game.irhere and game.state.date >= ALGERON and not game.isviolreported and game.iscloaked:
6246 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
6248 game.isviolreported = True
6249 while True: # command loop
6251 while True: # get a command
6253 game.optime = game.justin = False
6255 setwnd(prompt_window)
6258 if scanner.nexttok() == "IHEOL":
6259 if game.options & OPTION_CURSES:
6262 elif scanner.token == "":
6266 setwnd(message_window)
6268 abandon_passed = False
6269 cmd = "" # Force cmd to persist after loop
6270 opt = 0 # Force opt to persist after loop
6271 for (cmd, opt) in commands:
6272 # commands after ABANDON cannot be abbreviated
6273 if cmd == "ABANDON":
6274 abandon_passed = True
6275 if cmd == scanner.token.upper() or (not abandon_passed \
6276 and cmd.startswith(scanner.token.upper())):
6281 elif opt and not (opt & game.options):
6285 if game.options & OPTION_CURSES:
6286 prout("COMMAND> %s" % cmd)
6287 if cmd == "SRSCAN": # srscan
6289 elif cmd == "STATUS": # status
6291 elif cmd == "REQUEST": # status request
6293 elif cmd == "LRSCAN": # long range scan
6294 lrscan(silent=False)
6295 elif cmd == "PHASERS": # phasers
6300 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6305 elif cmd == "MOVE": # move under warp
6306 warp(wcourse=None, involuntary=False)
6307 elif cmd == "SHIELDS": # shields
6308 doshield(shraise=False)
6311 game.shldchg = False
6312 elif cmd == "DOCK": # dock at starbase
6315 attack(torps_ok=False)
6316 elif cmd == "DAMAGES": # damage reports
6318 elif cmd == "CHART": # chart
6320 elif cmd == "IMPULSE": # impulse
6322 elif cmd == "REST": # rest
6326 elif cmd == "WARP": # warp
6328 elif cmd == "SENSORS": # sensors
6330 elif cmd == "ORBIT": # orbit
6334 elif cmd == "TRANSPORT": # transport "beam"
6336 elif cmd == "MINE": # mine
6340 elif cmd == "CRYSTALS": # crystals
6344 elif cmd == "SHUTTLE": # shuttle
6348 elif cmd == "PLANETS": # Planet list
6350 elif cmd == "REPORT": # Game Report
6352 elif cmd == "COMPUTER": # use COMPUTER!
6354 elif cmd == "COMMANDS":
6356 elif cmd == "EMEXIT": # Emergency exit
6357 clrscr() # Hide screen
6358 freeze(True) # forced save
6359 raise SystemExit(1) # And quick exit
6360 elif cmd == "PROBE":
6361 probe() # Launch probe
6364 elif cmd == "ABANDON": # Abandon Ship
6366 elif cmd == "DESTRUCT": # Self Destruct
6368 elif cmd == "SAVE": # Save Game
6371 if game.skill > SKILL_GOOD:
6372 prout(_("WARNING--Saved games produce no plaques!"))
6373 elif cmd == "DEATHRAY": # Try a desparation measure
6377 elif cmd == "CAPTURE":
6379 elif cmd == "CLOAK":
6381 elif cmd == "DEBUGCMD": # What do we want for debug???
6383 elif cmd == "MAYDAY": # Call for help
6388 game.alldone = True # quit the game
6391 elif cmd == "SCORE":
6392 score() # see current score
6393 elif cmd == "CURSES":
6394 game.options |= (OPTION_CURSES | OPTION_COLOR)
6398 break # Game has ended
6399 if game.optime != 0.0:
6402 break # Events did us in
6403 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6406 if hitme and not game.justin:
6407 attack(torps_ok=True)
6410 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6421 "Emit the name of an enemy or feature."
6422 if ch == 'R': s = _("Romulan")
6423 elif ch == 'K': s = _("Klingon")
6424 elif ch == 'C': s = _("Commander")
6425 elif ch == 'S': s = _("Super-commander")
6426 elif ch == '*': s = _("Star")
6427 elif ch == 'P': s = _("Planet")
6428 elif ch == 'B': s = _("Starbase")
6429 elif ch == ' ': s = _("Black hole")
6430 elif ch == 'T': s = _("Tholian")
6431 elif ch == '#': s = _("Tholian web")
6432 elif ch == '?': s = _("Stranger")
6433 elif ch == '@': s = _("Inhabited World")
6434 else: s = "Unknown??"
6437 def crmena(loud, enemy, loctype, w):
6438 "Emit the name of an enemy and his location."
6442 buf += cramen(enemy) + _(" at ")
6443 if loctype == "quadrant":
6444 buf += _("Quadrant ")
6445 elif loctype == "sector":
6447 return buf + repr(w)
6450 "Emit our ship name."
6451 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6454 "Emit a line of stars"
6455 prouts("******************************************************")
6459 return -avrage*math.log(1e-7 + randreal())
6461 def randplace(size):
6462 "Choose a random location."
6464 w.i = randrange(size)
6465 w.j = randrange(size)
6475 # Get a token from the user
6478 # Fill the token quue if nothing here
6479 while not self.inqueue:
6481 if curwnd==prompt_window:
6483 setwnd(message_window)
6490 self.inqueue = sline.lstrip().split() + ["\n"]
6491 # From here on in it's all looking at the queue
6492 self.token = self.inqueue.pop(0)
6493 if self.token == "\n":
6497 self.real = float(self.token)
6498 self.type = "IHREAL"
6503 self.token = self.token.lower()
6504 self.type = "IHALPHA"
6507 def append(self, tok):
6508 self.inqueue.append(tok)
6509 def push(self, tok):
6510 self.inqueue.insert(0, tok)
6514 # Demand input for next scan
6516 self.real = self.token = None
6518 # compares s to item and returns true if it matches to the length of s
6519 return s.startswith(self.token)
6521 # Round token value to nearest integer
6522 return int(round(self.real))
6526 if self.type != "IHREAL":
6531 if self.type != "IHREAL":
6537 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6540 "Yes-or-no confirmation."
6544 if scanner.token == 'y':
6546 if scanner.token == 'n':
6549 proutn(_("Please answer with \"y\" or \"n\": "))
6552 "Complain about unparseable input."
6555 prout(_("Beg your pardon, Captain?"))
6558 "Access to the internals for debugging."
6559 proutn("Reset levels? ")
6561 if game.energy < game.inenrg:
6562 game.energy = game.inenrg
6563 game.shield = game.inshld
6564 game.torps = game.intorps
6565 game.lsupres = game.inlsr
6566 proutn("Reset damage? ")
6568 for i in range(NDEVICES):
6569 if game.damage[i] > 0.0:
6570 game.damage[i] = 0.0
6571 proutn("Toggle debug flag? ")
6573 game.idebug = not game.idebug
6575 prout("Debug output ON")
6577 prout("Debug output OFF")
6578 proutn("Cause selective damage? ")
6580 for i in range(NDEVICES):
6581 proutn("Kill %s?" % device[i])
6583 key = scanner.nexttok()
6584 if key == "IHALPHA" and scanner.sees("y"):
6585 game.damage[i] = 10.0
6586 proutn("Examine/change events? ")
6591 FSNOVA: "Supernova ",
6594 FBATTAK: "Base Attack ",
6595 FCDBAS: "Base Destroy ",
6596 FSCMOVE: "SC Move ",
6597 FSCDBAS: "SC Base Destroy ",
6598 FDSPROB: "Probe Move ",
6599 FDISTR: "Distress Call ",
6600 FENSLV: "Enslavement ",
6601 FREPRO: "Klingon Build ",
6603 for i in range(1, NEVENTS):
6606 proutn("%.2f" % (scheduled(i)-game.state.date))
6607 if i == FENSLV or i == FREPRO:
6609 proutn(" in %s" % ev.quadrant)
6614 key = scanner.nexttok()
6618 elif key == "IHREAL":
6619 ev = schedule(i, scanner.real)
6620 if i == FENSLV or i == FREPRO:
6622 proutn("In quadrant- ")
6623 key = scanner.nexttok()
6624 # "IHEOL" says to leave coordinates as they are
6627 prout("Event %d canceled, no x coordinate." % (i))
6630 w.i = int(round(scanner.real))
6631 key = scanner.nexttok()
6633 prout("Event %d canceled, no y coordinate." % (i))
6636 w.j = int(round(scanner.real))
6639 proutn("Induce supernova here? ")
6641 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6644 if __name__ == '__main__':
6646 #global line, thing, game
6650 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6651 if os.getenv("TERM"):
6652 game.options |= OPTION_CURSES
6654 game.options |= OPTION_TTY
6655 seed = int(time.time())
6656 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6658 for (switch, val) in options:
6661 replayfp = open(val, "r")
6663 sys.stderr.write("sst: can't open replay file %s\n" % val)
6666 line = replayfp.readline().strip()
6667 (leader, __, seed) = line.split()
6669 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6670 line = replayfp.readline().strip()
6671 arguments += line.split()[2:]
6674 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6676 game.options |= OPTION_TTY
6677 game.options &=~ OPTION_CURSES
6678 elif switch == '-s':
6680 elif switch == '-t':
6681 game.options |= OPTION_TTY
6682 game.options &=~ OPTION_CURSES
6683 elif switch == '-x':
6685 elif switch == '-V':
6686 print("SST2K", version)
6689 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6691 # where to save the input in case of bugs
6692 if "TMPDIR" in os.environ:
6693 tmpdir = os.environ['TMPDIR']
6697 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6699 sys.stderr.write("sst: warning, can't open logfile\n")
6702 logfp.write("# seed %s\n" % seed)
6703 logfp.write("# options %s\n" % " ".join(arguments))
6704 logfp.write("# SST2K version %s\n" % version)
6705 logfp.write("# recorded by %s@%s on %s\n" % \
6706 (getpass.getuser(),socket.gethostname(),time.ctime()))
6708 scanner = sstscanner()
6709 for arg in arguments:
6713 while True: # Play a game
6714 setwnd(fullscreen_window)
6720 game.alldone = False
6728 if game.tourn and game.alldone:
6729 proutn(_("Do you want your score recorded?"))
6735 proutn(_("Do you want to play again? "))
6739 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6743 except KeyboardInterrupt: