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
32 docpath = (".", "doc/", "/usr/share/doc/sst/")
35 return gettext.gettext(st)
37 GALSIZE = 8 # Galaxy size in quadrants
38 NINHAB = (GALSIZE * GALSIZE // 2) # Number of inhabited worlds
39 MAXUNINHAB = 10 # Maximum uninhabited worlds
40 QUADSIZE = 10 # Quadrant size in sectors
41 BASEMIN = 2 # Minimum starbases
42 BASEMAX = (GALSIZE * GALSIZE // 12) # Maximum starbases
43 MAXKLGAME = 127 # Maximum Klingons per game
44 MAXKLQUAD = 9 # Maximum Klingons per quadrant
45 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
46 FOREVER = 1e30 # Time for the indefinite future
47 MAXBURST = 3 # Max # of torps you can launch in one turn
48 MINCMDR = 10 # Minimum number of Klingon commanders
49 DOCKFAC = 0.25 # Repair faster when docked
50 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
52 ALGERON = 2311 # Date of the Treaty of Algeron
73 class TrekError(Exception):
76 class JumpOut(Exception):
80 def __init__(self, x=None, y=None):
83 def valid_quadrant(self):
84 return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
85 def valid_sector(self):
86 return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
88 self.i = self.j = None
89 def __eq__(self, other):
90 return other != None and self.i == other.i and self.j == other.j
91 def __ne__(self, other):
92 return other is None or self.i != other.i or self.j != other.j
93 def __add__(self, other):
94 return Coord(self.i+other.i, self.j+other.j)
95 def __sub__(self, other):
96 return Coord(self.i-other.i, self.j-other.j)
97 def __mul__(self, other):
98 return Coord(self.i*other, self.j*other)
99 def __rmul__(self, other):
100 return Coord(self.i*other, self.j*other)
101 def __div__(self, other):
102 return Coord(self.i/other, self.j/other)
103 def __mod__(self, other):
104 return Coord(self.i % other, self.j % other)
105 def __rdiv__(self, other):
106 return Coord(self.i/other, self.j/other)
107 def roundtogrid(self):
108 return Coord(int(round(self.i)), int(round(self.j)))
109 def distance(self, other=None):
112 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
114 return 1.90985*math.atan2(self.j, self.i)
120 s.i = self.i / abs(self.i)
124 s.j = self.j / abs(self.j)
127 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
128 return self.roundtogrid() / QUADSIZE
130 return self.roundtogrid() % QUADSIZE
133 s.i = self.i + randrange(-1, 2)
134 s.j = self.j + randrange(-1, 2)
137 if self.i is None or self.j is None:
139 return "%s - %s" % (self.i+1, self.j+1)
143 "Do not anger the Space Thingy!"
150 return (q.i, q.j) == (self.i, self.j)
154 self.name = None # string-valued if inhabited
155 self.quadrant = Coord() # quadrant located
156 self.pclass = None # could be ""M", "N", "O", or "destroyed"
157 self.crystals = "absent"# could be "mined", "present", "absent"
158 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
159 self.inhabited = False # is it inhabited?
167 self.starbase = False
170 self.supernova = False
172 self.status = "secure" # Could be "secure", "distressed", "enslaved"
174 return "<Quadrant: %(klingons)d>" % self.__dict__
180 self.starbase = False
183 return "<%s,%s,%s>" % (self.klingons, self.starbase, self.stars)
185 def fill2d(size, fillfun):
186 "Fill an empty list in 2D."
188 for i in range(size):
190 for j in range(size):
191 lst[i].append(fillfun(i, j))
196 self.snap = False # snapshot taken
197 self.crew = 0 # crew complement
198 self.nscrem = 0 # remaining super commanders
199 self.starkl = 0 # destroyed stars
200 self.basekl = 0 # destroyed bases
201 self.nromrem = 0 # Romulans remaining
202 self.nplankl = 0 # destroyed uninhabited planets
203 self.nworldkl = 0 # destroyed inhabited planets
204 self.planets = [] # Planet information
205 self.date = 0.0 # stardate
206 self.remres = 0 # remaining resources
207 self.remtime = 0 # remaining time
208 self.baseq = [] # Base quadrant coordinates
209 self.kcmdr = [] # Commander quadrant coordinates
210 self.kscmdr = Coord() # Supercommander quadrant coordinates
212 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
214 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
216 for i in range(GALSIZE):
217 for j in range(GALSIZE):
218 yield (i, j, self.galaxy[i][j])
222 self.date = None # A real number
223 self.quadrant = None # A coord structure
226 OPTION_ALL = 0xffffffff
227 OPTION_TTY = 0x00000001 # old interface
228 OPTION_CURSES = 0x00000002 # new interface
229 OPTION_IOMODES = 0x00000003 # cover both interfaces
230 OPTION_PLANETS = 0x00000004 # planets and mining
231 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
232 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
233 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
234 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
235 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
236 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
237 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
238 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
239 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
240 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
241 OPTION_CAPTURE = 0x00002000 # Enable BSD-Trek capture (Almy, 2013).
242 OPTION_CLOAK = 0x80004000 # Enable BSD-Trek capture (Almy, 2013).
243 OPTION_PLAIN = 0x01000000 # user chose plain game
244 OPTION_ALMY = 0x02000000 # user chose Almy variant
245 OPTION_COLOR = 0x04000000 # enable color display (ESR, 2010)
265 NDEVICES = 17 # Number of devices
275 return (game.damage[dev] != 0.0)
277 return not damaged(DRADIO) or game.condition=="docked"
279 # Define future events
280 FSPY = 0 # Spy event happens always (no future[] entry)
281 # can cause SC to tractor beam Enterprise
282 FSNOVA = 1 # Supernova
283 FTBEAM = 2 # Commander tractor beams Enterprise
284 FSNAP = 3 # Snapshot for time warp
285 FBATTAK = 4 # Commander attacks base
286 FCDBAS = 5 # Commander destroys base
287 FSCMOVE = 6 # Supercommander moves (might attack base)
288 FSCDBAS = 7 # Supercommander destroys base
289 FDSPROB = 8 # Move deep space probe
290 FDISTR = 9 # Emit distress call from an inhabited world
291 FENSLV = 10 # Inhabited word is enslaved */
292 FREPRO = 11 # Klingons build a ship in an enslaved system
295 # Abstract out the event handling -- underlying data structures will change
296 # when we implement stateful events
297 def findevent(evtype):
298 return game.future[evtype]
301 def __init__(self, etype=None, loc=None, power=None):
303 self.location = Coord()
308 self.power = power # enemy energy level
309 game.enemies.append(self)
311 motion = (loc != self.location)
312 if self.location.i is not None and self.location.j is not None:
315 game.quad[self.location.i][self.location.j] = '#'
317 game.quad[self.location.i][self.location.j] = '.'
319 self.location = copy.copy(loc)
320 game.quad[self.location.i][self.location.j] = self.type
321 self.kdist = self.kavgd = (game.sector - loc).distance()
323 self.location = Coord()
324 self.kdist = self.kavgd = None
325 # Guard prevents failure on Tholian or thingy
326 if self in game.enemies:
327 game.enemies.remove(self)
330 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
334 self.options = None # Game options
335 self.state = Snapshot() # A snapshot structure
336 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
337 self.quad = None # contents of our quadrant
338 self.damage = [0.0] * NDEVICES # damage encountered
339 self.future = [] # future events
343 self.future.append(Event())
344 self.passwd = None # Self Destruct password
346 self.quadrant = None # where we are in the large
347 self.sector = None # where we are in the small
348 self.tholian = None # Tholian enemy object
349 self.base = None # position of base in current quadrant
350 self.battle = None # base coordinates being attacked
351 self.plnet = None # location of planet in quadrant
352 self.gamewon = False # Finished!
353 self.ididit = False # action taken -- allows enemy to attack
354 self.alive = False # we are alive (not killed)
355 self.justin = False # just entered quadrant
356 self.shldup = False # shields are up
357 self.shldchg = False # shield is changing (affects efficiency)
358 self.iscate = False # super commander is here
359 self.ientesc = False # attempted escape from supercommander
360 self.resting = False # rest time
361 self.icraft = False # Kirk in Galileo
362 self.landed = False # party on planet (true), on ship (false)
363 self.alldone = False # game is now finished
364 self.neutz = False # Romulan Neutral Zone
365 self.isarmed = False # probe is armed
366 self.inorbit = False # orbiting a planet
367 self.imine = False # mining
368 self.icrystl = False # dilithium crystals aboard
369 self.iseenit = False # seen base attack report
370 self.thawed = False # thawed game
371 self.condition = None # "green", "yellow", "red", "docked", "dead"
372 self.iscraft = None # "onship", "offship", "removed"
373 self.skill = None # Player skill level
374 self.inkling = 0 # initial number of klingons
375 self.inbase = 0 # initial number of bases
376 self.incom = 0 # initial number of commanders
377 self.inscom = 0 # initial number of commanders
378 self.inrom = 0 # initial number of commanders
379 self.instar = 0 # initial stars
380 self.intorps = 0 # initial/max torpedoes
381 self.torps = 0 # number of torpedoes
382 self.ship = 0 # ship type -- 'E' is Enterprise
383 self.abandoned = 0 # count of crew abandoned in space
384 self.length = 0 # length of game
385 self.klhere = 0 # klingons here
386 self.casual = 0 # causalties
387 self.nhelp = 0 # calls for help
388 self.nkinks = 0 # count of energy-barrier crossings
389 self.iplnet = None # planet # in quadrant
390 self.inplan = 0 # initial planets
391 self.irhere = 0 # Romulans in quadrant
392 self.isatb = 0 # =2 if super commander is attacking base
393 self.tourn = None # tournament number
394 self.nprobes = 0 # number of probes available
395 self.inresor = 0.0 # initial resources
396 self.intime = 0.0 # initial time
397 self.inenrg = 0.0 # initial/max energy
398 self.inshld = 0.0 # initial/max shield
399 self.inlsr = 0.0 # initial life support resources
400 self.indate = 0.0 # initial date
401 self.energy = 0.0 # energy level
402 self.shield = 0.0 # shield level
403 self.warpfac = 0.0 # warp speed
404 self.lsupres = 0.0 # life support reserves
405 self.optime = 0.0 # time taken by current operation
406 self.damfac = 0.0 # damage factor
407 self.lastchart = 0.0 # time star chart was last updated
408 self.cryprob = 0.0 # probability that crystal will work
409 self.probe = None # object holding probe course info
410 self.height = 0.0 # height of orbit around planet
411 self.score = 0.0 # overall score
412 self.perdate = 0.0 # rate of kills
413 self.idebug = False # Debugging instrumentation enabled?
414 self.statekscmdr = None # No SuperCommander coordinates yet.
415 self.brigcapacity = 400 # Enterprise brig capacity
416 self.brigfree = 400 # How many klingons can we put in the brig?
417 self.kcaptured = 0 # Total Klingons captured, for scoring.
418 self.iscloaked = False # Cloaking device on?
419 self.ncviol = 0 # Algreon treaty violations
420 self.isviolreported = False # We have been warned
422 return sum([q.klingons for (_i, _j, q) in list(self.state.traverse())])
424 # Stas thinks this should be (C expression):
425 # game.remkl() + len(game.state.kcmdr) > 0 ?
426 # game.state.remres/(game.remkl() + 4*len(game.state.kcmdr)) : 99
427 # He says the existing expression is prone to divide-by-zero errors
428 # after killing the last klingon when score is shown -- perhaps also
429 # if the only remaining klingon is SCOM.
430 self.state.remtime = self.state.remres/(self.remkl() + 4*len(self.state.kcmdr))
432 "Are there Klingons remaining?"
460 return random.random() < p
462 def randrange(*args):
463 return random.randrange(*args)
468 v *= args[0] # from [0, args[0])
470 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
473 # Code from ai.c begins here
476 "Would this quadrant welcome another Klingon?"
477 return iq.valid_quadrant() and \
478 not game.state.galaxy[iq.i][iq.j].supernova and \
479 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
481 def tryexit(enemy, look, irun):
482 "A bad guy attempts to bug out."
484 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
485 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
486 if not welcoming(iq):
488 if enemy.type == 'R':
489 return False # Romulans cannot escape!
491 # avoid intruding on another commander's territory
492 if enemy.type == 'C':
493 if iq in game.state.kcmdr:
495 # refuse to leave if currently attacking starbase
496 if game.battle == game.quadrant:
498 # don't leave if over 1000 units of energy
499 if enemy.power > 1000.0:
501 oldloc = copy.copy(enemy.location)
502 # handle local matters related to escape
505 if game.condition != "docked":
507 # Handle global matters related to escape
508 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
509 game.state.galaxy[iq.i][iq.j].klingons += 1
510 if enemy.type == 'S':
514 schedule(FSCMOVE, 0.2777)
516 game.state.kscmdr = iq
518 for cmdr in game.state.kcmdr:
519 if cmdr == game.quadrant:
520 game.state.kcmdr.append(iq)
522 # report move out of quadrant.
523 return [(True, enemy, oldloc, iq)]
525 # The bad-guy movement algorithm:
527 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
528 # If both are operating full strength, force is 1000. If both are damaged,
529 # force is -1000. Having shields down subtracts an additional 1000.
531 # 2. Enemy has forces equal to the energy of the attacker plus
532 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
533 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
535 # Attacker Initial energy levels (nominal):
536 # Klingon Romulan Commander Super-Commander
537 # Novice 400 700 1200
539 # Good 450 800 1300 1750
540 # Expert 475 850 1350 1875
541 # Emeritus 500 900 1400 2000
542 # VARIANCE 75 200 200 200
544 # Enemy vessels only move prior to their attack. In Novice - Good games
545 # only commanders move. In Expert games, all enemy vessels move if there
546 # is a commander present. In Emeritus games all enemy vessels move.
548 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
549 # forces are 1000 greater than Enterprise.
551 # Agressive action on average cuts the distance between the ship and
552 # the enemy to 1/4 the original.
554 # 4. At lower energy advantage, movement units are proportional to the
555 # advantage with a 650 advantage being to hold ground, 800 to move forward
556 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
558 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
559 # retreat, especially at high skill levels.
561 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
563 def movebaddy(enemy):
564 "Tactical movement for the bad guys."
568 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
569 if game.skill >= SKILL_EXPERT:
570 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
572 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
573 old_dist = enemy.kdist
574 mdist = int(old_dist + 0.5) # Nearest integer distance
575 # If SC, check with spy to see if should hi-tail it
576 if enemy.type == 'S' and \
577 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
581 # decide whether to advance, retreat, or hold position
582 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
584 forces += 1000 # Good for enemy if shield is down!
585 if not damaged(DPHASER) or not damaged(DPHOTON):
586 if damaged(DPHASER): # phasers damaged
589 forces -= 0.2*(game.energy - 2500.0)
590 if damaged(DPHOTON): # photon torpedoes damaged
593 forces -= 50.0*game.torps
595 # phasers and photon tubes both out!
598 if forces <= 1000.0 and game.condition != "docked": # Typical situation
599 motion = ((forces + randreal(200))/150.0) - 5.0
601 if forces > 1000.0: # Very strong -- move in for kill
602 motion = (1.0 - randreal())**2 * old_dist + 1.0
603 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
604 motion -= game.skill*(2.0-randreal()**2)
606 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
607 # don't move if no motion
610 # Limit motion according to skill
611 if abs(motion) > game.skill:
616 # calculate preferred number of steps
617 nsteps = abs(int(motion))
618 if motion > 0 and nsteps > mdist:
619 nsteps = mdist # don't overshoot
620 if nsteps > QUADSIZE:
621 nsteps = QUADSIZE # This shouldn't be necessary
623 nsteps = 1 # This shouldn't be necessary
625 proutn("NSTEPS = %d:" % nsteps)
626 # Compute preferred values of delta X and Y
627 m = game.sector - enemy.location
628 if 2.0 * abs(m.i) < abs(m.j):
630 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
632 m = (motion * m).sgn()
633 goto = enemy.location
635 for ll in range(nsteps):
637 proutn(" %d" % (ll+1))
638 # Check if preferred position available
649 attempts = 0 # Settle mysterious hang problem
650 while attempts < 20 and not success:
652 if look.i < 0 or look.i >= QUADSIZE:
654 return tryexit(enemy, look, irun)
655 if krawli == m.i or m.j == 0:
657 look.i = goto.i + krawli
659 elif look.j < 0 or look.j >= QUADSIZE:
661 return tryexit(enemy, look, irun)
662 if krawlj == m.j or m.i == 0:
664 look.j = goto.j + krawlj
666 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
667 # See if enemy should ram ship
668 if game.quad[look.i][look.j] == game.ship and \
669 (enemy.type == 'C' or enemy.type == 'S'):
670 collision(rammed=True, enemy=enemy)
672 if krawli != m.i and m.j != 0:
673 look.i = goto.i + krawli
675 elif krawlj != m.j and m.i != 0:
676 look.j = goto.j + krawlj
679 break # we have failed
690 # Enemy moved, but is still in sector
691 return [(False, enemy, old_dist, goto)]
694 "Sequence Klingon tactical movement."
697 # Figure out which Klingon is the commander (or Supercommander)
700 if game.quadrant in game.state.kcmdr:
701 for enemy in game.enemies:
702 if enemy.type == 'C':
703 tacmoves += movebaddy(enemy)
704 if game.state.kscmdr == game.quadrant:
705 for enemy in game.enemies:
706 if enemy.type == 'S':
707 tacmoves += movebaddy(enemy)
709 # If skill level is high, move other Klingons and Romulans too!
710 # Move these last so they can base their actions on what the
712 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
713 for enemy in game.enemies:
714 if enemy.type in ('K', 'R'):
715 tacmoves += movebaddy(enemy)
718 def movescom(iq, avoid):
719 "Supercommander movement helper."
720 # Avoid quadrants with bases if we want to avoid Enterprise
721 if not welcoming(iq) or (avoid and iq in game.state.baseq):
723 if game.justin and not game.iscate:
726 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
727 game.state.kscmdr = iq
728 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
729 if game.state.kscmdr == game.quadrant:
730 # SC has scooted, remove him from current quadrant
735 for enemy in game.enemies:
736 if enemy.type == 'S':
739 if game.condition != "docked":
742 # check for a helpful planet
743 for i in range(game.inplan):
744 if game.state.planets[i].quadrant == game.state.kscmdr and \
745 game.state.planets[i].crystals == "present":
747 game.state.planets[i].pclass = "destroyed"
748 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
751 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
752 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
753 prout(_(" by the Super-commander.\""))
755 return True # looks good!
757 def supercommander():
758 "Move the Super Commander."
765 prout("== SUPERCOMMANDER")
766 # Decide on being active or passive
767 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 \
768 (game.state.date-game.indate) < 3.0)
769 if not game.iscate and avoid:
770 # compute move away from Enterprise
771 idelta = game.state.kscmdr-game.quadrant
772 if idelta.distance() > 2.0:
774 idelta.i = game.state.kscmdr.j-game.quadrant.j
775 idelta.j = game.quadrant.i-game.state.kscmdr.i
777 # compute distances to starbases
778 if not game.state.baseq:
782 sc = game.state.kscmdr
783 for (i, base) in enumerate(game.state.baseq):
784 basetbl.append((i, (base - sc).distance()))
785 if game.state.baseq > 1:
786 basetbl.sort(key=lambda x: x[1])
787 # look for nearest base without a commander, no Enterprise, and
788 # without too many Klingons, and not already under attack.
789 ifindit = iwhichb = 0
790 for (i2, base) in enumerate(game.state.baseq):
791 i = basetbl[i2][0] # bug in original had it not finding nearest
792 if base == game.quadrant or base == game.battle or not welcoming(base):
794 # if there is a commander, and no other base is appropriate,
795 # we will take the one with the commander
796 for cmdr in game.state.kcmdr:
797 if base == cmdr and ifindit != 2:
801 else: # no commander -- use this one
806 return # Nothing suitable -- wait until next time
807 ibq = game.state.baseq[iwhichb]
808 # decide how to move toward base
809 idelta = ibq - game.state.kscmdr
810 # Maximum movement is 1 quadrant in either or both axes
811 idelta = idelta.sgn()
812 # try moving in both x and y directions
813 # there was what looked like a bug in the Almy C code here,
814 # but it might be this translation is just wrong.
815 iq = game.state.kscmdr + idelta
816 if not movescom(iq, avoid):
817 # failed -- try some other maneuvers
818 if idelta.i == 0 or idelta.j == 0:
821 iq.j = game.state.kscmdr.j + 1
822 if not movescom(iq, avoid):
823 iq.j = game.state.kscmdr.j - 1
826 iq.i = game.state.kscmdr.i + 1
827 if not movescom(iq, avoid):
828 iq.i = game.state.kscmdr.i - 1
831 # try moving just in x or y
832 iq.j = game.state.kscmdr.j
833 if not movescom(iq, avoid):
834 iq.j = game.state.kscmdr.j + idelta.j
835 iq.i = game.state.kscmdr.i
838 if len(game.state.baseq) == 0:
841 for ibq in game.state.baseq:
842 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
845 return # no, don't attack base!
848 schedule(FSCDBAS, randreal(1.0, 3.0))
849 if is_scheduled(FCDBAS):
850 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
851 if not communicating():
855 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
857 prout(_(" reports that it is under attack from the Klingon Super-commander."))
858 proutn(_(" It can survive until stardate %d.\"") \
859 % int(scheduled(FSCDBAS)))
862 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
866 game.optime = 0.0 # actually finished
868 # Check for intelligence report
869 if not game.idebug and \
871 (not communicating()) or \
872 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
875 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
876 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
881 if not game.tholian or game.justin:
884 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
887 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
890 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
893 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
897 # something is wrong!
898 game.tholian.move(None)
899 prout("***Internal error: Tholian in a bad spot.")
901 # do nothing if we are blocked
902 if game.quad[tid.i][tid.j] not in ('.', '#'):
904 here = copy.copy(game.tholian.location)
905 delta = (tid - game.tholian.location).sgn()
907 while here.i != tid.i:
909 if game.quad[here.i][here.j] == '.':
910 game.tholian.move(here)
912 while here.j != tid.j:
914 if game.quad[here.i][here.j] == '.':
915 game.tholian.move(here)
916 # check to see if all holes plugged
917 for i in range(QUADSIZE):
918 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
920 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
922 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
924 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
926 # All plugged up -- Tholian splits
927 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
929 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
930 game.tholian.move(None)
933 # Code from battle.c begins here
936 "Change cloaking-device status."
938 prout(_("Ye Faerie Queene hath no cloaking device."));
941 key = scanner.nexttok()
949 if scanner.sees("on"):
951 prout(_("The cloaking device has already been switched on."))
954 elif scanner.sees("off"):
955 if not game.iscloaked:
956 prout(_("The cloaking device has already been switched off."))
963 if not game.iscloaked:
964 proutn(_("Switch cloaking device on? "))
969 proutn(_("Switch cloaking device off? "))
976 if action == "CLOFF":
977 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
978 prout(_("Spock- \"Captain, the Treaty of Algeron is in effect.\n Are you sure this is wise?\""))
981 prout("Engineer Scott- \"Aye, Sir.\"");
982 game.iscloaked = False;
983 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
984 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
986 game.isviolreported = True
988 #if (neutz and game.state.date >= ALGERON) finish(FCLOAK);
993 prout(_("Engineer Scott- \"The cloaking device is damaged, Sir.\""))
996 if game.condition == "docked":
997 prout(_("You cannot cloak while docked."))
999 if game.state.date >= ALGERON and not game.isviolreported:
1000 prout(_("Spock- \"Captain, using the cloaking device is a violation"))
1001 prout(_(" of the Treaty of Algeron. Considering the alternatives,"))
1002 proutn(_(" are you sure this is wise? "))
1005 prout(_("Engineer Scott- \"Cloaking device has engaging, Sir...\""))
1007 prout(_("Engineer Scott- \"Cloaking device has engaged, Sir.\""))
1008 game.iscloaked = True
1010 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
1011 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
1013 game.isviolreported = True
1015 def doshield(shraise):
1016 "Change shield status."
1022 key = scanner.nexttok()
1023 if key == "IHALPHA":
1024 if scanner.sees("transfer"):
1027 if damaged(DSHIELD):
1028 prout(_("Shields damaged and down."))
1030 if scanner.sees("up"):
1032 elif scanner.sees("down"):
1034 if action == "NONE":
1035 proutn(_("Do you wish to change shield energy? "))
1038 elif damaged(DSHIELD):
1039 prout(_("Shields damaged and down."))
1042 proutn(_("Shields are up. Do you want them down? "))
1049 proutn(_("Shields are down. Do you want them up? "))
1055 if action == "SHUP": # raise shields
1057 prout(_("Shields already up."))
1061 if game.condition != "docked":
1063 prout(_("Shields raised."))
1064 if game.energy <= 0:
1066 prout(_("Shields raising uses up last of energy."))
1071 elif action == "SHDN":
1073 prout(_("Shields already down."))
1077 prout(_("Shields lowered."))
1080 elif action == "NRG":
1081 while scanner.nexttok() != "IHREAL":
1083 proutn(_("Energy to transfer to shields- "))
1088 if nrg > game.energy:
1089 prout(_("Insufficient ship energy."))
1092 if game.shield+nrg >= game.inshld:
1093 prout(_("Shield energy maximized."))
1094 if game.shield+nrg > game.inshld:
1095 prout(_("Excess energy requested returned to ship energy"))
1096 game.energy -= game.inshld-game.shield
1097 game.shield = game.inshld
1099 if nrg < 0.0 and game.energy-nrg > game.inenrg:
1100 # Prevent shield drain loophole
1102 prout(_("Engineering to bridge--"))
1103 prout(_(" Scott here. Power circuit problem, Captain."))
1104 prout(_(" I can't drain the shields."))
1107 if game.shield+nrg < 0:
1108 prout(_("All shield energy transferred to ship."))
1109 game.energy += game.shield
1112 proutn(_("Scotty- \""))
1114 prout(_("Transferring energy to shields.\""))
1116 prout(_("Draining energy from shields.\""))
1122 "Choose a device to damage, at random."
1124 105, # DSRSENS: short range scanners 10.5%
1125 105, # DLRSENS: long range scanners 10.5%
1126 120, # DPHASER: phasers 12.0%
1127 120, # DPHOTON: photon torpedoes 12.0%
1128 25, # DLIFSUP: life support 2.5%
1129 65, # DWARPEN: warp drive 6.5%
1130 70, # DIMPULS: impulse engines 6.5%
1131 135, # DSHIELD: deflector shields 13.5%
1132 30, # DRADIO: subspace radio 3.0%
1133 45, # DSHUTTL: shuttle 4.5%
1134 15, # DCOMPTR: computer 1.5%
1135 20, # NAVCOMP: navigation system 2.0%
1136 75, # DTRANSP: transporter 7.5%
1137 20, # DSHCTRL: high-speed shield controller 2.0%
1138 10, # DDRAY: death ray 1.0%
1139 30, # DDSP: deep-space probes 3.0%
1140 10, # DCLOAK: the cloaking device 1.0
1142 assert(sum(weights) == 1000)
1143 idx = randrange(1000)
1145 for (i, w) in enumerate(weights):
1149 return None # we should never get here
1151 def collision(rammed, enemy):
1152 "Collision handling for rammong events."
1153 prouts(_("***RED ALERT! RED ALERT!"))
1155 prout(_("***COLLISION IMMINENT."))
1159 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1161 proutn(_(" rammed by "))
1164 proutn(crmena(False, enemy.type, "sector", enemy.location))
1166 proutn(_(" (original position)"))
1168 deadkl(enemy.location, enemy.type, game.sector)
1169 proutn("***" + crmshp() + " heavily damaged.")
1170 icas = randrange(10, 30)
1171 prout(_("***Sickbay reports %d casualties") % icas)
1173 game.state.crew -= icas
1174 # In the pre-SST2K version, all devices got equiprobably damaged,
1175 # which was silly. Instead, pick up to half the devices at
1176 # random according to our weighting table,
1177 ncrits = randrange(NDEVICES/2)
1181 if game.damage[dev] < 0:
1183 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1184 # Damage for at least time of travel!
1185 game.damage[dev] += game.optime + extradm
1187 prout(_("***Shields are down."))
1195 def torpedo(origin, bearing, dispersion, number, nburst):
1196 "Let a photon torpedo fly"
1197 if not damaged(DSRSENS) or game.condition == "docked":
1198 setwnd(srscan_window)
1200 setwnd(message_window)
1201 ac = bearing + 0.25*dispersion # dispersion is a random variable
1202 bullseye = (15.0 - bearing)*0.5235988
1203 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1204 bumpto = Coord(0, 0)
1205 # Loop to move a single torpedo
1206 setwnd(message_window)
1207 for step in range(1, QUADSIZE*2):
1208 if not track.nexttok():
1211 if not w.valid_sector():
1213 iquad = game.quad[w.i][w.j]
1214 tracktorpedo(w, step, number, nburst, iquad)
1218 setwnd(message_window)
1219 if not damaged(DSRSENS) or game.condition == "docked":
1220 skip(1) # start new line after text track
1221 if iquad in ('E', 'F'): # Hit our ship
1223 prout(_("Torpedo hits %s.") % crmshp())
1224 hit = 700.0 + randreal(100) - \
1225 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1226 newcnd() # we're blown out of dock
1227 if game.landed or game.condition == "docked":
1228 return hit # Cheat if on a planet
1229 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1230 # is 143 degrees, which is almost exactly 4.8 clockface units
1231 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1232 displacement.nexttok()
1233 bumpto = displacement.sector()
1234 if not bumpto.valid_sector():
1236 if game.quad[bumpto.i][bumpto.j] == ' ':
1239 if game.quad[bumpto.i][bumpto.j] != '.':
1240 # can't move into object
1242 game.sector = bumpto
1244 game.quad[w.i][w.j] = '.'
1245 game.quad[bumpto.i][bumpto.j] = iquad
1246 prout(_(" displaced by blast to Sector %s ") % bumpto)
1247 for enemy in game.enemies:
1248 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1251 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1253 if iquad in ('C', 'S') and withprob(0.05):
1254 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1255 prout(_(" torpedo neutralized."))
1257 for enemy in game.enemies:
1258 if w == enemy.location:
1259 kp = math.fabs(enemy.power)
1260 h1 = 700.0 + randrange(100) - \
1261 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1269 if enemy.power == 0:
1272 proutn(crmena(True, iquad, "sector", w))
1273 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1274 displacement.nexttok()
1275 bumpto = displacement.sector()
1276 if not bumpto.valid_sector():
1277 prout(_(" damaged but not destroyed."))
1279 if game.quad[bumpto.i][bumpto.j] == ' ':
1280 prout(_(" buffeted into black hole."))
1281 deadkl(w, iquad, bumpto)
1282 if game.quad[bumpto.i][bumpto.j] != '.':
1283 prout(_(" damaged but not destroyed."))
1285 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1286 enemy.location = bumpto
1287 game.quad[w.i][w.j] = '.'
1288 game.quad[bumpto.i][bumpto.j] = iquad
1289 for enemy in game.enemies:
1290 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1294 prout("Internal error, no enemy where expected!")
1297 elif iquad == 'B': # Hit a base
1299 prout(_("***STARBASE DESTROYED.."))
1300 game.state.baseq = [x for x in game.state.baseq if x != game.quadrant]
1301 game.quad[w.i][w.j] = '.'
1302 game.base.invalidate()
1303 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
1304 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = False
1305 game.state.basekl += 1
1308 elif iquad == 'P': # Hit a planet
1309 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1310 game.state.nplankl += 1
1311 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1312 game.iplnet.pclass = "destroyed"
1314 game.plnet.invalidate()
1315 game.quad[w.i][w.j] = '.'
1317 # captain perishes on planet
1320 elif iquad == '@': # Hit an inhabited world -- very bad!
1321 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1322 game.state.nworldkl += 1
1323 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1324 game.iplnet.pclass = "destroyed"
1326 game.plnet.invalidate()
1327 game.quad[w.i][w.j] = '.'
1329 # captain perishes on planet
1331 prout(_("The torpedo destroyed an inhabited planet."))
1333 elif iquad == '*': # Hit a star
1337 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1339 elif iquad == '?': # Hit a thingy
1340 if not (game.options & OPTION_THINGY) or withprob(0.3):
1342 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1344 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1346 proutn(_("Mr. Spock-"))
1347 prouts(_(" \"Fascinating!\""))
1351 # Stas Sergeev added the possibility that
1352 # you can shove the Thingy and piss it off.
1353 # It then becomes an enemy and may fire at you.
1356 elif iquad == ' ': # Black hole
1358 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1360 elif iquad == '#': # hit the web
1362 prout(_("***Torpedo absorbed by Tholian web."))
1364 elif iquad == 'T': # Hit a Tholian
1365 h1 = 700.0 + randrange(100) - \
1366 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1369 game.quad[w.i][w.j] = '.'
1374 proutn(crmena(True, 'T', "sector", w))
1376 prout(_(" survives photon blast."))
1378 prout(_(" disappears."))
1379 game.tholian.move(None)
1380 game.quad[w.i][w.j] = '#'
1385 proutn("Don't know how to handle torpedo collision with ")
1386 proutn(crmena(True, iquad, "sector", w))
1391 setwnd(message_window)
1392 prout(_("Torpedo missed."))
1396 "Critical-hit resolution."
1397 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1399 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1400 proutn(_("***CRITICAL HIT--"))
1401 # Select devices and cause damage
1406 # Cheat to prevent shuttle damage unless on ship
1407 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship") or (j == DCLOAK and game.ship != 'E' or j == DDRAY)):
1410 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1411 game.damage[j] += extradm
1414 for (i, j) in enumerate(cdam):
1416 if skipcount % 3 == 2 and i < len(cdam)-1:
1421 prout(_(" damaged."))
1422 if damaged(DSHIELD) and game.shldup:
1423 prout(_("***Shields knocked down."))
1425 if damaged(DCLOAK) and game.iscloaked:
1426 prout(_("***Cloaking device rendered inoperative."))
1427 game.iscloaked = False
1429 def attack(torps_ok):
1430 # bad guy attacks us
1431 # torps_ok == False forces use of phasers in an attack
1434 # game could be over at this point, check
1444 prout("=== ATTACK!")
1445 # Tholian gets to move before attacking
1448 # if you have just entered the RNZ, you'll get a warning
1449 if game.neutz: # The one chance not to be attacked
1452 # commanders get a chance to tac-move towards you
1453 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:
1454 for (bugout, enemy, old, goto) in moveklings():
1456 # we know about this if either short or long range
1457 # sensors are working
1458 if damaged(DSRSENS) and damaged(DLRSENS) \
1459 and game.condition != "docked":
1460 prout(crmena(True, enemy.type, "sector", old) + \
1461 (_(" escapes to Quadrant %s (and regains strength).") % goto))
1462 else: # Enemy still in-sector
1463 if enemy.move(goto):
1464 if not damaged(DSRSENS) or game.condition == "docked":
1465 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
1466 if enemy.kdist < old:
1467 proutn(_(" advances to "))
1469 proutn(_(" retreats to "))
1470 prout("Sector %s." % goto)
1472 # if no enemies remain after movement, we're done
1473 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered):
1475 # set up partial hits if attack happens during shield status change
1476 pfac = 1.0/game.inshld
1478 chgfac = 0.25 + randreal(0.5)
1480 # message verbosity control
1481 if game.skill <= SKILL_FAIR:
1483 for enemy in game.enemies:
1485 continue # too weak to attack
1486 # compute hit strength and diminish shield power
1488 # Increase chance of photon torpedos if docked or enemy energy is low
1489 if game.condition == "docked":
1491 if enemy.power < 500:
1493 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1495 # different enemies have different probabilities of throwing a torp
1496 usephasers = not torps_ok or \
1497 (enemy.type == 'K' and r > 0.0005) or \
1498 (enemy.type == 'C' and r > 0.015) or \
1499 (enemy.type == 'R' and r > 0.3) or \
1500 (enemy.type == 'S' and r > 0.07) or \
1501 (enemy.type == '?' and r > 0.05)
1502 if usephasers: # Enemy uses phasers
1503 if game.condition == "docked":
1504 continue # Don't waste the effort!
1505 attempt = True # Attempt to attack
1506 dustfac = randreal(0.8, 0.85)
1507 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1509 else: # Enemy uses photon torpedo
1510 # We should be able to make the bearing() method work here
1511 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1513 proutn(_("***TORPEDO INCOMING"))
1514 if not damaged(DSRSENS):
1515 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1518 dispersion = (randreal()+randreal())*0.5 - 0.5
1519 dispersion += 0.002*enemy.power*dispersion
1520 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1521 if game.unwon() == 0:
1522 finish(FWON) # Klingons did themselves in!
1523 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1524 return # Supernova or finished
1527 # incoming phaser or torpedo, shields may dissipate it
1528 if game.shldup or game.shldchg or game.condition == "docked":
1529 # shields will take hits
1530 propor = pfac * game.shield
1531 if game.condition == "docked":
1535 hitsh = propor*chgfac*hit+1.0
1537 if absorb > game.shield:
1538 absorb = game.shield
1539 game.shield -= absorb
1541 # taking a hit blasts us out of a starbase dock
1542 if game.condition == "docked":
1544 # but the shields may take care of it
1545 if propor > 0.1 and hit < 0.005*game.energy:
1547 # hit from this opponent got through shields, so take damage
1549 proutn(_("%d unit hit") % int(hit))
1550 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1551 proutn(_(" on the ") + crmshp())
1552 if not damaged(DSRSENS) and usephasers:
1553 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1555 # Decide if hit is critical
1561 if game.energy <= 0:
1562 # Returning home upon your shield, not with it...
1565 if not attempt and game.condition == "docked":
1566 prout(_("***Enemies decide against attacking your ship."))
1567 percent = 100.0*pfac*game.shield+0.5
1569 # Shields fully protect ship
1570 proutn(_("Enemy attack reduces shield strength to "))
1572 # Emit message if starship suffered hit(s)
1574 proutn(_("Energy left %2d shields ") % int(game.energy))
1577 elif not damaged(DSHIELD):
1580 proutn(_("damaged, "))
1581 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1582 # Check if anyone was hurt
1583 if hitmax >= 200 or hittot >= 500:
1584 icas = randrange(int(hittot * 0.015))
1587 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1588 prout(_(" in that last attack.\""))
1590 game.state.crew -= icas
1591 # After attack, reset average distance to enemies
1592 for enemy in game.enemies:
1593 enemy.kavgd = enemy.kdist
1597 def deadkl(w, etype, mv):
1598 "Kill a Klingon, Tholian, Romulan, or Thingy."
1599 # Added mv to allow enemy to "move" before dying
1600 proutn(crmena(True, etype, "sector", mv))
1601 # Decide what kind of enemy it is and update appropriately
1603 # Chalk up a Romulan
1604 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1606 game.state.nromrem -= 1
1615 # Killed some type of Klingon
1616 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1619 game.state.kcmdr.remove(game.quadrant)
1621 if game.state.kcmdr:
1622 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1623 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1628 game.state.nscrem -= 1
1629 game.state.kscmdr.invalidate()
1634 # For each kind of enemy, finish message to player
1635 prout(_(" destroyed."))
1636 if game.unwon() == 0:
1639 # Remove enemy ship from arrays describing local conditions
1640 for e in game.enemies:
1647 "Return None if target is invalid, otherwise return a course angle."
1648 if not w.valid_sector():
1652 # C code this was translated from is wacky -- why the sign reversal?
1653 delta.j = (w.j - game.sector.j)
1654 delta.i = (game.sector.i - w.i)
1655 if delta == Coord(0, 0):
1657 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1658 prout(_(" I recommend an immediate review of"))
1659 prout(_(" the Captain's psychological profile.\""))
1662 return delta.bearing()
1665 "Launch photon torpedo salvo."
1668 if damaged(DPHOTON):
1669 prout(_("Photon tubes damaged."))
1673 prout(_("No torpedoes left."))
1676 # First, get torpedo count
1679 if scanner.token == "IHALPHA":
1682 elif scanner.token == "IHEOL" or not scanner.waiting():
1683 prout(_("%d torpedoes left.") % game.torps)
1685 proutn(_("Number of torpedoes to fire- "))
1686 continue # Go back around to get a number
1687 else: # key == "IHREAL"
1689 if n <= 0: # abort command
1694 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1697 scanner.chew() # User requested more torps than available
1698 continue # Go back around
1699 break # All is good, go to next stage
1703 key = scanner.nexttok()
1704 if i == 0 and key == "IHEOL":
1705 break # no coordinate waiting, we will try prompting
1706 if i == 1 and key == "IHEOL":
1707 # direct all torpedoes at one target
1709 target.append(target[0])
1710 tcourse.append(tcourse[0])
1713 scanner.push(scanner.token)
1714 target.append(scanner.getcoord())
1715 if target[-1] is None:
1717 tcourse.append(targetcheck(target[-1]))
1718 if tcourse[-1] is None:
1721 if len(target) == 0:
1722 # prompt for each one
1724 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1726 target.append(scanner.getcoord())
1727 if target[-1] is None:
1729 tcourse.append(targetcheck(target[-1]))
1730 if tcourse[-1] is None:
1733 # Loop for moving <n> torpedoes
1735 if game.condition != "docked":
1737 dispersion = (randreal()+randreal())*0.5 -0.5
1738 if math.fabs(dispersion) >= 0.47:
1740 dispersion *= randreal(1.2, 2.2)
1742 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1744 prouts(_("***TORPEDO MISFIRES."))
1747 prout(_(" Remainder of burst aborted."))
1749 prout(_("***Photon tubes damaged by misfire."))
1750 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1754 elif game.shldup or game.condition == "docked":
1755 dispersion *= 1.0 + 0.0001*game.shield
1756 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1757 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1763 "Check for phasers overheating."
1765 checkburn = (rpow-1500.0)*0.00038
1766 if withprob(checkburn):
1767 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1768 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1770 def checkshctrl(rpow):
1771 "Check shield control."
1774 prout(_("Shields lowered."))
1776 # Something bad has happened
1777 prouts(_("***RED ALERT! RED ALERT!"))
1779 hit = rpow*game.shield/game.inshld
1780 game.energy -= rpow+hit*0.8
1781 game.shield -= hit*0.2
1782 if game.energy <= 0.0:
1783 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1788 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1790 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1791 icas = randrange(int(hit*0.012))
1796 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1797 prout(_(" %d casualties so far.\"") % icas)
1799 game.state.crew -= icas
1801 prout(_("Phaser energy dispersed by shields."))
1802 prout(_("Enemy unaffected."))
1807 "Register a phaser hit on Klingons and Romulans."
1814 dustfac = randreal(0.9, 1.0)
1815 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1816 kpini = game.enemies[kk].power
1817 kp = math.fabs(kpini)
1818 if PHASEFAC*hit < kp:
1820 if game.enemies[kk].power < 0:
1821 game.enemies[kk].power -= -kp
1823 game.enemies[kk].power -= kp
1824 kpow = game.enemies[kk].power
1825 w = game.enemies[kk].location
1827 if not damaged(DSRSENS):
1829 proutn(_("%d unit hit on ") % int(hit))
1831 proutn(_("Very small hit on "))
1832 ienm = game.quad[w.i][w.j]
1835 proutn(crmena(False, ienm, "sector", w))
1844 else: # decide whether or not to emasculate klingon
1845 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1846 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1847 prout(_(" has just lost its firepower.\""))
1848 game.enemies[kk].power = -kpow
1853 "Fire phasers at bad guys."
1857 irec = 0 # Cheating inhibitor
1866 # SR sensors and Computer are needed for automode
1867 if damaged(DSRSENS) or damaged(DCOMPTR):
1869 if game.condition == "docked":
1870 prout(_("Phasers can't be fired through base shields."))
1873 if damaged(DPHASER):
1874 prout(_("Phaser control damaged."))
1878 if damaged(DSHCTRL):
1879 prout(_("High speed shield control damaged."))
1882 if game.energy <= 200.0:
1883 prout(_("Insufficient energy to activate high-speed shield control."))
1886 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1888 # Original code so convoluted, I re-did it all
1889 # (That was Tom Almy talking about the C code, I think -- ESR)
1890 while automode == "NOTSET":
1891 key = scanner.nexttok()
1892 if key == "IHALPHA":
1893 if scanner.sees("manual"):
1894 if len(game.enemies)==0:
1895 prout(_("There is no enemy present to select."))
1898 automode = "AUTOMATIC"
1901 key = scanner.nexttok()
1902 elif scanner.sees("automatic"):
1903 if (not itarg) and len(game.enemies) != 0:
1904 automode = "FORCEMAN"
1906 if len(game.enemies)==0:
1907 prout(_("Energy will be expended into space."))
1908 automode = "AUTOMATIC"
1909 key = scanner.nexttok()
1910 elif scanner.sees("no"):
1915 elif key == "IHREAL":
1916 if len(game.enemies)==0:
1917 prout(_("Energy will be expended into space."))
1918 automode = "AUTOMATIC"
1920 automode = "FORCEMAN"
1922 automode = "AUTOMATIC"
1925 if len(game.enemies)==0:
1926 prout(_("Energy will be expended into space."))
1927 automode = "AUTOMATIC"
1929 automode = "FORCEMAN"
1931 proutn(_("Manual or automatic? "))
1936 if automode == "AUTOMATIC":
1937 if key == "IHALPHA" and scanner.sees("no"):
1939 key = scanner.nexttok()
1940 if key != "IHREAL" and len(game.enemies) != 0:
1941 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1946 for i in range(len(game.enemies)):
1947 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1949 proutn(_("%d units required. ") % irec)
1951 proutn(_("Units to fire= "))
1952 key = scanner.nexttok()
1957 proutn(_("Energy available= %.2f") % avail)
1960 if not rpow > avail:
1966 key = scanner.nexttok()
1967 if key == "IHALPHA" and scanner.sees("no"):
1970 game.energy -= 200 # Go and do it!
1971 if checkshctrl(rpow):
1976 if len(game.enemies):
1979 for i in range(len(game.enemies)):
1983 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1984 over = randreal(1.01, 1.06) * hits[i]
1986 powrem -= hits[i] + over
1987 if powrem <= 0 and temp < hits[i]:
1996 if extra > 0 and not game.alldone:
1998 proutn(_("*** Tholian web absorbs "))
1999 if len(game.enemies)>0:
2000 proutn(_("excess "))
2001 prout(_("phaser energy."))
2003 prout(_("%d expended on empty space.") % int(extra))
2004 elif automode == "FORCEMAN":
2007 if damaged(DCOMPTR):
2008 prout(_("Battle computer damaged, manual fire only."))
2011 prouts(_("---WORKING---"))
2013 prout(_("Short-range-sensors-damaged"))
2014 prout(_("Insufficient-data-for-automatic-phaser-fire"))
2015 prout(_("Manual-fire-must-be-used"))
2017 elif automode == "MANUAL":
2019 for k in range(len(game.enemies)):
2020 aim = game.enemies[k].location
2021 ienm = game.quad[aim.i][aim.j]
2023 proutn(_("Energy available= %.2f") % (avail-0.006))
2027 if damaged(DSRSENS) and \
2028 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
2029 prout(cramen(ienm) + _(" can't be located without short range scan."))
2032 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
2037 if itarg and k > kz:
2038 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
2041 if not damaged(DCOMPTR):
2046 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
2047 key = scanner.nexttok()
2048 if key == "IHALPHA" and scanner.sees("no"):
2050 key = scanner.nexttok()
2052 if key == "IHALPHA":
2056 if k == 1: # Let me say I'm baffled by this
2059 if scanner.real < 0:
2063 hits[k] = scanner.real
2064 rpow += scanner.real
2065 # If total requested is too much, inform and start over
2067 prout(_("Available energy exceeded -- try again."))
2070 key = scanner.nexttok() # scan for next value
2073 # zero energy -- abort
2076 if key == "IHALPHA" and scanner.sees("no"):
2081 game.energy -= 200.0
2082 if checkshctrl(rpow):
2086 # Say shield raised or malfunction, if necessary
2093 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
2094 prouts(_(" CLICK CLICK POP . . ."))
2095 prout(_(" No response, sir!"))
2098 prout(_("Shields raised."))
2105 game.ididit = False # Nothing if we fail
2108 # Make sure there is room in the brig */
2109 if game.brigfree == 0:
2110 prout(_("Security reports the brig is already full."))
2114 prout(_("Uhura- \"We have no subspace radio communication, sir.\""))
2117 if damaged(DTRANSP):
2118 prout(_("Scotty- \"Transporter damaged, sir.\""))
2121 # find out if there are any at all
2123 prout(_("Uhura- \"Getting no response, sir.\""))
2126 # if there is more than one Klingon, find out which one */
2127 # Cruddy, just takes one at random. Should ask the captain.
2128 # Nah, just select the weakest one since it is most likely to
2129 # surrender (Tom Almy mod)
2130 klingons = [e for e in game.enemies if e.type == 'K']
2131 weakest = sorted(klingons, key=lambda e: e.power)[0]
2132 game.optime = 0.05 # This action will take some time
2133 game.ididit = True # So any others can strike back
2135 # check out that Klingon
2136 # The algorithm isn't that great and could use some more
2137 # intelligent design
2138 # x = 300 + 25*skill;
2139 x = game.energy / (weakest.power * len(klingons))
2140 #prout(_("Stats: energy = %s, kpower = %s, klingons = %s")
2141 # % (game.energy, weakest.power, len(klingons)))
2142 x *= 2.5 # would originally have been equivalent of 1.4,
2143 # but we want command to work more often, more humanely */
2144 #prout(_("Prob = %.4f" % x))
2145 # x = 100; // For testing, of course!
2146 if x < randreal(100):
2147 # guess what, he surrendered!!! */
2148 prout(_("Klingon captain at %s surrenders.") % weakest.location)
2151 prout(_("%d Klingons commit suicide rather than be taken captive.") % (200 - i))
2152 if i > game.brigfree:
2153 prout(_("%d Klingons die because there is no room for them in the brig.") % (i-brigfree))
2156 prout(_("%d captives taken") % i)
2157 deadkl(weakest.location, weakest.type, game.sector)
2162 # big surprise, he refuses to surrender */
2163 prout(_("Fat chance, captain!"))
2165 # Code from events.c begins here.
2167 # This isn't a real event queue a la BSD Trek yet -- you can only have one
2168 # event of each type active at any given time. Mostly these means we can
2169 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
2170 # BSD Trek, from which we swiped the idea, can have up to 5.
2172 def unschedule(evtype):
2173 "Remove an event from the schedule."
2174 game.future[evtype].date = FOREVER
2175 return game.future[evtype]
2177 def is_scheduled(evtype):
2178 "Is an event of specified type scheduled."
2179 return game.future[evtype].date != FOREVER
2181 def scheduled(evtype):
2182 "When will this event happen?"
2183 return game.future[evtype].date
2185 def schedule(evtype, offset):
2186 "Schedule an event of specified type."
2187 game.future[evtype].date = game.state.date + offset
2188 return game.future[evtype]
2190 def postpone(evtype, offset):
2191 "Postpone a scheduled event."
2192 game.future[evtype].date += offset
2195 "Rest period is interrupted by event."
2198 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2200 game.resting = False
2206 "Run through the event queue looking for things to do."
2208 fintim = game.state.date + game.optime
2217 def tractorbeam(yank):
2218 "Tractor-beaming cases merge here."
2220 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2222 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2223 # If Kirk & Co. screwing around on planet, handle
2224 atover(True) # atover(true) is Grab
2227 if game.icraft: # Caught in Galileo?
2230 # Check to see if shuttle is aboard
2231 if game.iscraft == "offship":
2234 prout(_("Galileo, left on the planet surface, is captured"))
2235 prout(_("by aliens and made into a flying McDonald's."))
2236 game.damage[DSHUTTL] = -10
2237 game.iscraft = "removed"
2239 prout(_("Galileo, left on the planet surface, is well hidden."))
2241 game.quadrant = game.state.kscmdr
2243 game.quadrant = game.state.kcmdr[i]
2244 game.sector = randplace(QUADSIZE)
2245 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2246 % (game.quadrant, game.sector))
2248 prout(_("(Remainder of rest/repair period cancelled.)"))
2249 game.resting = False
2251 if not damaged(DSHIELD) and game.shield > 0:
2252 doshield(shraise=True) # raise shields
2253 game.shldchg = False
2255 prout(_("(Shields not currently useable.)"))
2257 # Adjust finish time to time of tractor beaming?
2258 # fintim = game.state.date+game.optime
2259 attack(torps_ok=False)
2260 if not game.state.kcmdr:
2263 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2266 "Code merges here for any commander destroying a starbase."
2267 # Not perfect, but will have to do
2268 # Handle case where base is in same quadrant as starship
2269 if game.battle == game.quadrant:
2270 game.state.chart[game.battle.i][game.battle.j].starbase = False
2271 game.quad[game.base.i][game.base.j] = '.'
2272 game.base.invalidate()
2275 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2276 elif game.state.baseq and communicating():
2277 # Get word via subspace radio
2280 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2281 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2283 prout(_("the Klingon Super-Commander"))
2285 prout(_("a Klingon Commander"))
2286 game.state.chart[game.battle.i][game.battle.j].starbase = False
2287 # Remove Starbase from galaxy
2288 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2289 game.state.baseq = [x for x in game.state.baseq if x != game.battle]
2291 # reinstate a commander's base attack
2295 game.battle.invalidate()
2297 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2298 for i in range(1, NEVENTS):
2299 if i == FSNOVA: proutn("=== Supernova ")
2300 elif i == FTBEAM: proutn("=== T Beam ")
2301 elif i == FSNAP: proutn("=== Snapshot ")
2302 elif i == FBATTAK: proutn("=== Base Attack ")
2303 elif i == FCDBAS: proutn("=== Base Destroy ")
2304 elif i == FSCMOVE: proutn("=== SC Move ")
2305 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2306 elif i == FDSPROB: proutn("=== Probe Move ")
2307 elif i == FDISTR: proutn("=== Distress Call ")
2308 elif i == FENSLV: proutn("=== Enslavement ")
2309 elif i == FREPRO: proutn("=== Klingon Build ")
2311 prout("%.2f" % (scheduled(i)))
2314 radio_was_broken = damaged(DRADIO)
2317 # Select earliest extraneous event, evcode==0 if no events
2322 for l in range(1, NEVENTS):
2323 if game.future[l].date < datemin:
2326 prout("== Event %d fires" % evcode)
2327 datemin = game.future[l].date
2328 xtime = datemin-game.state.date
2330 game.energy -= xtime*500.0
2331 if game.energy <= 0:
2334 game.state.date = datemin
2335 # Decrement Federation resources and recompute remaining time
2336 game.state.remres -= (game.remkl()+4*len(game.state.kcmdr))*xtime
2338 if game.state.remtime <= 0:
2341 # Any crew left alive?
2342 if game.state.crew <= 0:
2345 # Is life support adequate?
2346 if damaged(DLIFSUP) and game.condition != "docked":
2347 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2350 game.lsupres -= xtime
2351 if game.damage[DLIFSUP] <= xtime:
2352 game.lsupres = game.inlsr
2355 if game.condition == "docked":
2357 # Don't fix Deathray here
2358 for l in range(NDEVICES):
2359 if game.damage[l] > 0.0 and l != DDRAY:
2360 if game.damage[l]-repair > 0.0:
2361 game.damage[l] -= repair
2363 game.damage[l] = 0.0
2364 # If radio repaired, update star chart and attack reports
2365 if radio_was_broken and not damaged(DRADIO):
2366 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2367 prout(_(" surveillance reports are coming in."))
2369 if not game.iseenit:
2373 prout(_(" The star chart is now up to date.\""))
2375 # Cause extraneous event EVCODE to occur
2376 game.optime -= xtime
2377 if evcode == FSNOVA: # Supernova
2380 schedule(FSNOVA, expran(0.5*game.intime))
2381 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2383 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2384 if game.state.nscrem == 0 or game.iscloaked or \
2385 ictbeam or istract or \
2386 game.condition == "docked" or game.isatb == 1 or game.iscate:
2388 if game.ientesc or \
2389 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2390 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2391 (damaged(DSHIELD) and \
2392 (game.energy < 2500 or damaged(DPHASER)) and \
2393 (game.torps < 5 or damaged(DPHOTON))):
2395 istract = ictbeam = True
2396 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2399 elif evcode == FTBEAM: # Tractor beam
2400 if not game.state.kcmdr:
2403 i = randrange(len(game.state.kcmdr))
2404 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2405 if istract or game.condition == "docked" or game.iscloaked or yank == 0:
2406 # Drats! Have to reschedule
2408 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2412 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2413 game.snapsht = copy.deepcopy(game.state)
2414 game.state.snap = True
2415 schedule(FSNAP, expran(0.5 * game.intime))
2416 elif evcode == FBATTAK: # Commander attacks starbase
2417 if not game.state.kcmdr or not game.state.baseq:
2422 ibq = None # Force battle location to persist past loop
2424 for ibq in game.state.baseq:
2425 for cmdr in game.state.kcmdr:
2426 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2428 # no match found -- try later
2429 schedule(FBATTAK, expran(0.3*game.intime))
2434 # commander + starbase combination found -- launch attack
2436 schedule(FCDBAS, randreal(1.0, 4.0))
2437 if game.isatb: # extra time if SC already attacking
2438 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2439 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2440 game.iseenit = False
2441 if not communicating():
2442 continue # No warning :-(
2446 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2447 prout(_(" reports that it is under attack and that it can"))
2448 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2451 elif evcode == FSCDBAS: # Supercommander destroys base
2454 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2455 continue # WAS RETURN!
2457 game.battle = game.state.kscmdr
2459 elif evcode == FCDBAS: # Commander succeeds in destroying base
2460 if evcode == FCDBAS:
2462 if not game.state.baseq() \
2463 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2464 game.battle.invalidate()
2466 # find the lucky pair
2467 for cmdr in game.state.kcmdr:
2468 if cmdr == game.battle:
2471 # No action to take after all
2474 elif evcode == FSCMOVE: # Supercommander moves
2475 schedule(FSCMOVE, 0.2777)
2476 if not game.ientesc and not istract and game.isatb != 1 and \
2477 (not game.iscate or not game.justin):
2479 elif evcode == FDSPROB: # Move deep space probe
2480 schedule(FDSPROB, 0.01)
2481 if not game.probe.nexttok():
2482 if not game.probe.quadrant().valid_quadrant() or \
2483 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2484 # Left galaxy or ran into supernova
2488 proutn(_("Lt. Uhura- \"The deep space probe "))
2489 if not game.probe.quadrant().valid_quadrant():
2490 prout(_("has left the galaxy.\""))
2492 prout(_("is no longer transmitting.\""))
2498 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2499 pquad = game.probe.quadrant()
2500 pdest = game.state.galaxy[pquad.i][pquad.j]
2502 game.state.chart[pquad.i][pquad.j].klingons = pdest.klingons
2503 game.state.chart[pquad.i][pquad.j].starbase = pdest.starbase
2504 game.state.chart[pquad.i][pquad.j].stars = pdest.stars
2505 pdest.charted = True
2506 game.probe.moves -= 1 # One less to travel
2507 if game.probe.arrived() and game.isarmed and pdest.stars:
2508 supernova(game.probe) # fire in the hole!
2510 if game.state.galaxy[pquad.i][pquad.j].supernova:
2512 elif evcode == FDISTR: # inhabited system issues distress call
2514 # try a whole bunch of times to find something suitable
2515 for i in range(100):
2516 # need a quadrant which is not the current one,
2517 # which has some stars which are inhabited and
2518 # not already under attack, which is not
2519 # supernova'ed, and which has some Klingons in it
2520 w = randplace(GALSIZE)
2521 q = game.state.galaxy[w.i][w.j]
2522 if not (game.quadrant == w or q.planet is None or \
2523 not q.planet.inhabited or \
2524 q.supernova or q.status!="secure" or q.klingons<=0):
2527 # can't seem to find one; ignore this call
2529 prout("=== Couldn't find location for distress event.")
2531 # got one!! Schedule its enslavement
2532 ev = schedule(FENSLV, expran(game.intime))
2534 q.status = "distressed"
2535 # tell the captain about it if we can
2537 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2538 % (q.planet, repr(w)))
2539 prout(_("by a Klingon invasion fleet."))
2542 elif evcode == FENSLV: # starsystem is enslaved
2543 ev = unschedule(FENSLV)
2544 # see if current distress call still active
2545 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2549 q.status = "enslaved"
2551 # play stork and schedule the first baby
2552 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2553 ev2.quadrant = ev.quadrant
2555 # report the disaster if we can
2557 prout(_("Uhura- We've lost contact with starsystem %s") % \
2559 prout(_("in Quadrant %s.\n") % ev.quadrant)
2560 elif evcode == FREPRO: # Klingon reproduces
2561 # If we ever switch to a real event queue, we'll need to
2562 # explicitly retrieve and restore the x and y.
2563 ev = schedule(FREPRO, expran(1.0 * game.intime))
2564 # see if current distress call still active
2565 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2569 if game.remkl() >= MAXKLGAME:
2570 continue # full right now
2571 # reproduce one Klingon
2574 if game.klhere >= MAXKLQUAD:
2576 # this quadrant not ok, pick an adjacent one
2577 for m.i in range(w.i - 1, w.i + 2):
2578 for m.j in range(w.j - 1, w.j + 2):
2579 if not m.valid_quadrant():
2581 q = game.state.galaxy[m.i][m.j]
2582 # check for this quad ok (not full & no snova)
2583 if q.klingons >= MAXKLQUAD or q.supernova:
2586 # search for eligible quadrant failed
2592 if game.quadrant == w:
2594 newkling() # also adds it to game.enemies
2595 # recompute time left
2598 if game.quadrant == w:
2599 prout(_("Spock- sensors indicate the Klingons have"))
2600 prout(_("launched a warship from %s.") % q.planet)
2602 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2603 if q.planet != None:
2604 proutn(_("near %s ") % q.planet)
2605 prout(_("in Quadrant %s.") % w)
2611 key = scanner.nexttok()
2614 proutn(_("How long? "))
2619 origTime = delay = scanner.real
2622 if delay >= game.state.remtime or len(game.enemies) != 0:
2623 proutn(_("Are you sure? "))
2626 # Alternate resting periods (events) with attacks
2630 game.resting = False
2631 if not game.resting:
2632 prout(_("%d stardates left.") % int(game.state.remtime))
2634 temp = game.optime = delay
2635 if len(game.enemies):
2636 rtime = randreal(1.0, 2.0)
2640 if game.optime < delay:
2641 attack(torps_ok=False)
2649 # Repair Deathray if long rest at starbase
2650 if origTime-delay >= 9.99 and game.condition == "docked":
2651 game.damage[DDRAY] = 0.0
2652 # leave if quadrant supernovas
2653 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2655 game.resting = False
2660 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2661 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2663 # Wow! We've supernova'ed
2664 supernova(game.quadrant)
2666 # handle initial nova
2667 game.quad[nov.i][nov.j] = '.'
2668 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2669 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2670 game.state.starkl += 1
2671 # Set up queue to recursively trigger adjacent stars
2677 for offset.i in range(-1, 1+1):
2678 for offset.j in range(-1, 1+1):
2679 if offset.j == 0 and offset.i == 0:
2681 neighbor = start + offset
2682 if not neighbor.valid_sector():
2684 iquad = game.quad[neighbor.i][neighbor.j]
2685 # Empty space ends reaction
2686 if iquad in ('.', '?', ' ', 'T', '#'):
2688 elif iquad == '*': # Affect another star
2690 # This star supernovas
2691 supernova(game.quadrant)
2694 hits.append(neighbor)
2695 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2696 game.state.starkl += 1
2697 proutn(crmena(True, '*', "sector", neighbor))
2699 game.quad[neighbor.i][neighbor.j] = '.'
2701 elif iquad in ('P', '@'): # Destroy planet
2702 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2704 game.state.nplankl += 1
2706 game.state.nworldkl += 1
2707 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2708 game.iplnet.pclass = "destroyed"
2710 game.plnet.invalidate()
2714 game.quad[neighbor.i][neighbor.j] = '.'
2715 elif iquad == 'B': # Destroy base
2716 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2717 game.state.baseq = [x for x in game.state.baseq if x!= game.quadrant]
2718 game.base.invalidate()
2719 game.state.basekl += 1
2721 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2722 game.quad[neighbor.i][neighbor.j] = '.'
2723 elif iquad in ('E', 'F'): # Buffet ship
2724 prout(_("***Starship buffeted by nova."))
2726 if game.shield >= 2000.0:
2727 game.shield -= 2000.0
2729 diff = 2000.0 - game.shield
2733 prout(_("***Shields knocked out."))
2734 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2736 game.energy -= 2000.0
2737 if game.energy <= 0:
2740 # add in course nova contributes to kicking starship
2741 bump += (game.sector-hits[-1]).sgn()
2742 elif iquad == 'K': # kill klingon
2743 deadkl(neighbor, iquad, neighbor)
2744 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2746 for ll in range(len(game.enemies)):
2747 if game.enemies[ll].location == neighbor:
2748 target = game.enemies[ll]
2750 if target is not None:
2751 target.power -= 800.0 # If firepower is lost, die
2752 if target.power <= 0.0:
2753 deadkl(neighbor, iquad, neighbor)
2754 continue # neighbor loop
2755 # Else enemy gets flung by the blast wave
2756 newc = neighbor + neighbor - start
2757 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2758 if not newc.valid_sector():
2759 # can't leave quadrant
2762 iquad1 = game.quad[newc.i][newc.j]
2764 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2766 deadkl(neighbor, iquad, newc)
2769 # can't move into something else
2772 proutn(_(", buffeted to Sector %s") % newc)
2773 game.quad[neighbor.i][neighbor.j] = '.'
2774 game.quad[newc.i][newc.j] = iquad
2776 # Starship affected by nova -- kick it away.
2778 direc = ncourse[3*(bump.i+1)+bump.j+2]
2783 scourse = course(bearing=direc, distance=dist)
2784 game.optime = scourse.time(w=4)
2786 prout(_("Force of nova displaces starship."))
2787 imove(scourse, noattack=True)
2788 game.optime = scourse.time(w=4)
2792 "Star goes supernova."
2797 # Scheduled supernova -- select star at random.
2800 for nq.i in range(GALSIZE):
2801 for nq.j in range(GALSIZE):
2802 nstars += game.state.galaxy[nq.i][nq.j].stars
2804 return # nothing to supernova exists
2805 num = randrange(nstars) + 1
2806 for nq.i in range(GALSIZE):
2807 for nq.j in range(GALSIZE):
2808 num -= game.state.galaxy[nq.i][nq.j].stars
2814 proutn("=== Super nova here?")
2817 if not nq == game.quadrant or game.justin:
2818 # it isn't here, or we just entered (treat as enroute)
2821 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2822 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2825 # we are in the quadrant!
2826 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2827 for ns.i in range(QUADSIZE):
2828 for ns.j in range(QUADSIZE):
2829 if game.quad[ns.i][ns.j]=='*':
2836 prouts(_("***RED ALERT! RED ALERT!"))
2838 prout(_("***Incipient supernova detected at Sector %s") % ns)
2839 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2840 proutn(_("Emergency override attempts t"))
2841 prouts("***************")
2845 # destroy any Klingons in supernovaed quadrant
2846 game.state.galaxy[nq.i][nq.j].klingons = 0
2847 if nq == game.state.kscmdr:
2848 # did in the Supercommander!
2849 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2853 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2854 comkills = len(game.state.kcmdr) - len(survivors)
2855 game.state.kcmdr = survivors
2856 if not game.state.kcmdr:
2858 # destroy Romulans and planets in supernovaed quadrant
2859 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2860 game.state.galaxy[nq.i][nq.j].romulans = 0
2861 game.state.nromrem -= nrmdead
2863 for loop in range(game.inplan):
2864 if game.state.planets[loop].quadrant == nq:
2865 game.state.planets[loop].pclass = "destroyed"
2867 # Destroy any base in supernovaed quadrant
2868 game.state.baseq = [x for x in game.state.baseq if x != nq]
2869 # If starship caused supernova, tally up destruction
2871 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2872 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2873 game.state.nplankl += npdead
2874 # mark supernova in galaxy and in star chart
2875 if game.quadrant == nq or communicating():
2876 game.state.galaxy[nq.i][nq.j].supernova = True
2877 # If supernova destroys last Klingons give special message
2878 if game.unwon()==0 and not nq == game.quadrant:
2881 prout(_("Lucky you!"))
2882 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2885 # if some Klingons remain, continue or die in supernova
2890 # Code from finish.c ends here.
2893 "Self-destruct maneuver. Finish with a BANG!"
2895 if damaged(DCOMPTR):
2896 prout(_("Computer damaged; cannot execute destruct sequence."))
2898 prouts(_("---WORKING---")); skip(1)
2899 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2900 prouts(" 10"); skip(1)
2901 prouts(" 9"); skip(1)
2902 prouts(" 8"); skip(1)
2903 prouts(" 7"); skip(1)
2904 prouts(" 6"); skip(1)
2906 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2908 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2910 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2913 if game.passwd != scanner.token:
2914 prouts(_("PASSWORD-REJECTED;"))
2916 prouts(_("CONTINUITY-EFFECTED"))
2919 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2920 prouts(" 5"); skip(1)
2921 prouts(" 4"); skip(1)
2922 prouts(" 3"); skip(1)
2923 prouts(" 2"); skip(1)
2924 prouts(" 1"); skip(1)
2926 prouts(_("GOODBYE-CRUEL-WORLD"))
2934 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2938 if len(game.enemies) != 0:
2939 whammo = 25.0 * game.energy
2940 for e in game.enemies[::-1]:
2941 if e.power*e.kdist <= whammo:
2942 deadkl(e.location, game.quad[e.location.i][e.location.j], e.location)
2946 "Compute our rate of kils over time."
2947 elapsed = game.state.date - game.indate
2948 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2951 starting = (game.inkling + game.incom + game.inscom)
2952 remaining = game.unwon()
2953 return (starting - remaining)/elapsed
2957 badpt = 5.0*game.state.starkl + \
2959 10.0*game.state.nplankl + \
2960 300*game.state.nworldkl + \
2962 100.0*game.state.basekl +\
2963 3.0*game.abandoned +\
2965 if game.ship == 'F':
2967 elif game.ship is None:
2972 # end the game, with appropriate notifications
2976 prout(_("It is stardate %.1f.") % game.state.date)
2978 if ifin == FWON: # Game has been won
2979 if game.state.nromrem != 0:
2980 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2983 prout(_("You have smashed the Klingon invasion fleet and saved"))
2984 prout(_("the Federation."))
2985 if game.alive and game.brigcapacity-game.brigfree > 0:
2986 game.kcaptured += game.brigcapacity-game.brigfree
2987 prout(_("The %d captured Klingons are transferred to Star Fleet Command.") % (game.brigcapacity-game.brigfree))
2992 badpt = 0.0 # Close enough!
2993 # killsPerDate >= RateMax
2994 if game.state.date-game.indate < 5.0 or \
2995 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2997 prout(_("In fact, you have done so well that Starfleet Command"))
2998 if game.skill == SKILL_NOVICE:
2999 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
3000 elif game.skill == SKILL_FAIR:
3001 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
3002 elif game.skill == SKILL_GOOD:
3003 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
3004 elif game.skill == SKILL_EXPERT:
3005 prout(_("promotes you to Commodore Emeritus."))
3007 prout(_("Now that you think you're really good, try playing"))
3008 prout(_("the \"Emeritus\" game. It will splatter your ego."))
3009 elif game.skill == SKILL_EMERITUS:
3011 proutn(_("Computer- "))
3012 prouts(_("ERROR-ERROR-ERROR-ERROR"))
3014 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
3016 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3018 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3020 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3022 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
3024 prout(_("Now you can retire and write your own Star Trek game!"))
3026 elif game.skill >= SKILL_EXPERT:
3027 if game.thawed and not game.idebug:
3028 prout(_("You cannot get a citation, so..."))
3030 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
3034 # Only grant long life if alive (original didn't!)
3036 prout(_("LIVE LONG AND PROSPER."))
3041 elif ifin == FDEPLETE: # Federation Resources Depleted
3042 prout(_("Your time has run out and the Federation has been"))
3043 prout(_("conquered. Your starship is now Klingon property,"))
3044 prout(_("and you are put on trial as a war criminal. On the"))
3045 proutn(_("basis of your record, you are "))
3046 if game.unwon()*3.0 > (game.inkling + game.incom + game.inscom):
3047 prout(_("acquitted."))
3049 prout(_("LIVE LONG AND PROSPER."))
3051 prout(_("found guilty and"))
3052 prout(_("sentenced to death by slow torture."))
3056 elif ifin == FLIFESUP:
3057 prout(_("Your life support reserves have run out, and"))
3058 prout(_("you die of thirst, starvation, and asphyxiation."))
3059 prout(_("Your starship is a derelict in space."))
3061 prout(_("Your energy supply is exhausted."))
3063 prout(_("Your starship is a derelict in space."))
3064 elif ifin == FBATTLE:
3065 prout(_("The %s has been destroyed in battle.") % crmshp())
3067 prout(_("Dulce et decorum est pro patria mori."))
3069 prout(_("You have made three attempts to cross the negative energy"))
3070 prout(_("barrier which surrounds the galaxy."))
3072 prout(_("Your navigation is abominable."))
3075 prout(_("Your starship has been destroyed by a nova."))
3076 prout(_("That was a great shot."))
3078 elif ifin == FSNOVAED:
3079 prout(_("The %s has been fried by a supernova.") % crmshp())
3080 prout(_("...Not even cinders remain..."))
3081 elif ifin == FABANDN:
3082 prout(_("You have been captured by the Klingons. If you still"))
3083 prout(_("had a starbase to be returned to, you would have been"))
3084 prout(_("repatriated and given another chance. Since you have"))
3085 prout(_("no starbases, you will be mercilessly tortured to death."))
3086 elif ifin == FDILITHIUM:
3087 prout(_("Your starship is now an expanding cloud of subatomic particles"))
3088 elif ifin == FMATERIALIZE:
3089 prout(_("Starbase was unable to re-materialize your starship."))
3090 prout(_("Sic transit gloria mundi"))
3091 elif ifin == FPHASER:
3092 prout(_("The %s has been cremated by its own phasers.") % crmshp())
3094 prout(_("You and your landing party have been"))
3095 prout(_("converted to energy, dissipating through space."))
3096 elif ifin == FMINING:
3097 prout(_("You are left with your landing party on"))
3098 prout(_("a wild jungle planet inhabited by primitive cannibals."))
3100 prout(_("They are very fond of \"Captain Kirk\" soup."))
3102 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3103 elif ifin == FDPLANET:
3104 prout(_("You and your mining party perish."))
3106 prout(_("That was a great shot."))
3109 prout(_("The Galileo is instantly annihilated by the supernova."))
3110 prout(_("You and your mining party are atomized."))
3112 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3113 prout(_("joins the Romulans, wreaking terror on the Federation."))
3114 elif ifin == FPNOVA:
3115 prout(_("You and your mining party are atomized."))
3117 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3118 prout(_("joins the Romulans, wreaking terror on the Federation."))
3119 elif ifin == FSTRACTOR:
3120 prout(_("The shuttle craft Galileo is also caught,"))
3121 prout(_("and breaks up under the strain."))
3123 prout(_("Your debris is scattered for millions of miles."))
3124 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3126 prout(_("The mutants attack and kill Spock."))
3127 prout(_("Your ship is captured by Klingons, and"))
3128 prout(_("your crew is put on display in a Klingon zoo."))
3129 elif ifin == FTRIBBLE:
3130 prout(_("Tribbles consume all remaining water,"))
3131 prout(_("food, and oxygen on your ship."))
3133 prout(_("You die of thirst, starvation, and asphyxiation."))
3134 prout(_("Your starship is a derelict in space."))
3136 prout(_("Your ship is drawn to the center of the black hole."))
3137 prout(_("You are crushed into extremely dense matter."))
3138 elif ifin == FCLOAK:
3140 prout(_("You have violated the Treaty of Algeron."))
3141 prout(_("The Romulan Empire can never trust you again."))
3143 prout(_("Your last crew member has died."))
3144 if ifin != FWON and ifin != FCLOAK and game.iscloaked:
3145 prout(_("Your ship was cloaked so your subspace radio did not receive anything."))
3146 prout(_("You may have missed some warning messages."))
3148 if game.ship == 'F':
3150 elif game.ship == 'E':
3153 if game.unwon() != 0:
3154 goodies = game.state.remres/game.inresor
3155 baddies = (game.remkl() + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
3156 if goodies/baddies >= randreal(1.0, 1.5):
3157 prout(_("As a result of your actions, a treaty with the Klingon"))
3158 prout(_("Empire has been signed. The terms of the treaty are"))
3159 if goodies/baddies >= randreal(3.0):
3160 prout(_("favorable to the Federation."))
3162 prout(_("Congratulations!"))
3164 prout(_("highly unfavorable to the Federation."))
3166 prout(_("The Federation will be destroyed."))
3168 prout(_("Since you took the last Klingon with you, you are a"))
3169 prout(_("martyr and a hero. Someday maybe they'll erect a"))
3170 prout(_("statue in your memory. Rest in peace, and try not"))
3171 prout(_("to think about pigeons."))
3174 scanner.chew() # Clean up leftovers
3177 "Compute player's score."
3178 timused = game.state.date - game.indate
3179 if (timused == 0 or game.unwon() != 0) and timused < 5.0:
3181 game.perdate = killrate()
3182 ithperd = 500*game.perdate + 0.5
3185 iwon = 100*game.skill
3186 if game.ship == 'E':
3188 elif game.ship == 'F':
3192 dead_ordinaries= game.inkling - game.remkl() + len(game.state.kcmdr) + game.state.nscrem
3193 game.score = 10*(dead_ordinaries)\
3194 + 50*(game.incom - len(game.state.kcmdr)) \
3196 + 20*(game.inrom - game.state.nromrem) \
3197 + 200*(game.inscom - game.state.nscrem) \
3198 - game.state.nromrem \
3199 + 3 * game.kcaptured \
3204 prout(_("Your score --"))
3205 if game.inrom - game.state.nromrem:
3206 prout(_("%6d Romulans destroyed %5d") %
3207 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
3208 if game.state.nromrem and game.gamewon:
3209 prout(_("%6d Romulans captured %5d") %
3210 (game.state.nromrem, game.state.nromrem))
3212 prout(_("%6d ordinary Klingons destroyed %5d") %
3213 (dead_ordinaries, 10*dead_ordinaries))
3214 if game.incom - len(game.state.kcmdr):
3215 prout(_("%6d Klingon commanders destroyed %5d") %
3216 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3218 prout(_("%d Klingons captured %5d") %
3219 (game.kcaptured, 3 * game.kcaptured))
3220 if game.inscom - game.state.nscrem:
3221 prout(_("%6d Super-Commander destroyed %5d") %
3222 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3224 prout(_("%6.2f Klingons per stardate %5d") %
3225 (game.perdate, ithperd))
3226 if game.state.starkl:
3227 prout(_("%6d stars destroyed by your action %5d") %
3228 (game.state.starkl, -5*game.state.starkl))
3229 if game.state.nplankl:
3230 prout(_("%6d planets destroyed by your action %5d") %
3231 (game.state.nplankl, -10*game.state.nplankl))
3232 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3233 prout(_("%6d inhabited planets destroyed by your action %5d") %
3234 (game.state.nworldkl, -300*game.state.nworldkl))
3235 if game.state.basekl:
3236 prout(_("%6d bases destroyed by your action %5d") %
3237 (game.state.basekl, -100*game.state.basekl))
3239 prout(_("%6d calls for help from starbase %5d") %
3240 (game.nhelp, -45*game.nhelp))
3242 prout(_("%6d casualties incurred %5d") %
3243 (game.casual, -game.casual))
3245 prout(_("%6d crew abandoned in space %5d") %
3246 (game.abandoned, -3*game.abandoned))
3248 prout(_("%6d ship(s) lost or destroyed %5d") %
3249 (klship, -100*klship))
3252 prout(_("1 Treaty of Algeron violation -100"))
3254 prout(_("%6d Treaty of Algeron violations %5d\n") %
3255 (ncviol, -100*ncviol))
3257 prout(_("Penalty for getting yourself killed -200"))
3259 proutn(_("Bonus for winning "))
3260 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3261 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3262 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3263 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3264 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3265 prout(" %5d" % iwon)
3267 prout(_("TOTAL SCORE %5d") % game.score)
3270 "Emit winner's commemmorative plaque."
3273 proutn(_("File or device name for your plaque: "))
3276 fp = open(winner, "w")
3279 prout(_("Invalid name."))
3281 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3283 # The 38 below must be 64 for 132-column paper
3284 nskip = 38 - len(winner)/2
3285 # This is where the ASCII art picture was emitted.
3286 # It got garbled somewhere in the chain of transmission to the Almy version.
3287 # We should restore it if we can find old enough FORTRAN sources.
3289 fp.write(_(" U. S. S. ENTERPRISE\n"))
3290 fp.write("\n\n\n\n")
3291 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3293 fp.write(_(" Starfleet Command bestows to you\n"))
3295 fp.write("%*s%s\n\n" % (nskip, "", winner))
3296 fp.write(_(" the rank of\n\n"))
3297 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3299 if game.skill == SKILL_EXPERT:
3300 fp.write(_(" Expert level\n\n"))
3301 elif game.skill == SKILL_EMERITUS:
3302 fp.write(_("Emeritus level\n\n"))
3304 fp.write(_(" Cheat level\n\n"))
3305 timestring = time.ctime()
3306 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3307 (timestring+4, timestring+20, timestring+11))
3308 fp.write(_(" Your score: %d\n\n") % game.score)
3309 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3312 # Code from io.c begins here
3314 rows = linecount = 0 # for paging
3317 fullscreen_window = None
3318 srscan_window = None # Short range scan
3319 report_window = None # Report legends for status window
3320 status_window = None # The status window itself
3321 lrscan_window = None # Long range scan
3322 message_window = None # Main window for scrolling text
3323 prompt_window = None # Prompt window at bottom of display
3328 # for some recent versions of python2, the following enables UTF8
3329 # for the older ones we probably need to set C locale, and python3
3330 # has no problems at all
3331 if sys.version_info[0] < 3:
3332 locale.setlocale(locale.LC_ALL, "")
3333 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3334 gettext.textdomain("sst")
3335 if not (game.options & OPTION_CURSES):
3336 ln_env = os.getenv("LINES")
3342 stdscr = curses.initscr()
3346 if game.options & OPTION_COLOR:
3347 curses.start_color()
3348 curses.use_default_colors()
3349 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3350 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3351 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3352 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3353 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3354 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3355 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3356 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3357 global fullscreen_window, srscan_window, report_window, status_window
3358 global lrscan_window, message_window, prompt_window
3359 (rows, _columns) = stdscr.getmaxyx()
3360 fullscreen_window = stdscr
3361 srscan_window = curses.newwin(12, 25, 0, 0)
3362 report_window = curses.newwin(11, 0, 1, 25)
3363 status_window = curses.newwin(10, 0, 1, 39)
3364 lrscan_window = curses.newwin(5, 0, 0, 64)
3365 message_window = curses.newwin(0, 0, 12, 0)
3366 prompt_window = curses.newwin(1, 0, rows-2, 0)
3367 message_window.scrollok(True)
3368 setwnd(fullscreen_window)
3372 if game.options & OPTION_CURSES:
3373 stdscr.keypad(False)
3379 "Wait for user action -- OK to do nothing if on a TTY"
3380 if game.options & OPTION_CURSES:
3385 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3389 if game.skill > SKILL_FAIR:
3390 prompt = _("[CONTINUE?]")
3392 prompt = _("[PRESS ENTER TO CONTINUE]")
3394 if game.options & OPTION_CURSES:
3396 setwnd(prompt_window)
3397 prompt_window.clear()
3398 prompt_window.addstr(prompt)
3399 prompt_window.getstr()
3400 prompt_window.clear()
3401 prompt_window.refresh()
3402 setwnd(message_window)
3405 sys.stdout.write('\n')
3409 sys.stdout.write('\n' * rows)
3413 "Skip i lines. Pause game if this would cause a scrolling event."
3414 for _dummy in range(i):
3415 if game.options & OPTION_CURSES:
3416 (y, _x) = curwnd.getyx()
3419 except curses.error:
3424 if rows and linecount >= rows:
3427 sys.stdout.write('\n')
3429 def proutn(proutntline):
3430 "Utter a line with no following line feed."
3431 if game.options & OPTION_CURSES:
3432 (y, x) = curwnd.getyx()
3433 (my, _mx) = curwnd.getmaxyx()
3434 if curwnd == message_window and y >= my - 2:
3437 # Uncomment this to debug curses problems
3439 # logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(proutntline)))
3440 curwnd.addstr(proutntline)
3443 sys.stdout.write(proutntline)
3446 def prout(proutline):
3450 def prouts(proutsline):
3452 for c in proutsline:
3453 if not replayfp or replayfp.closed: # Don't slow down replays
3456 if game.options & OPTION_CURSES:
3460 if not replayfp or replayfp.closed:
3464 "Get a line of input."
3465 if game.options & OPTION_CURSES:
3466 linein = curwnd.getstr() + "\n"
3469 if replayfp and not replayfp.closed:
3471 linein = replayfp.readline()
3474 prout("*** Replay finished")
3477 elif linein[0] != "#":
3481 linein = my_input() + "\n"
3490 "Change windows -- OK for this to be a no-op in tty mode."
3492 if game.options & OPTION_CURSES:
3493 # Uncomment this to debug curses problems
3495 if wnd == fullscreen_window:
3496 legend = "fullscreen"
3497 elif wnd == srscan_window:
3499 elif wnd == report_window:
3501 elif wnd == status_window:
3503 elif wnd == lrscan_window:
3505 elif wnd == message_window:
3507 elif wnd == prompt_window:
3511 #logfp.write("#curses: setwnd(%s)\n" % legend)
3513 # Some curses implementations get confused when you try this.
3515 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3516 except curses.error:
3520 "Clear to end of line -- can be a no-op in tty mode"
3521 if game.options & OPTION_CURSES:
3526 "Clear screen -- can be a no-op in tty mode."
3528 if game.options & OPTION_CURSES:
3534 def textcolor(color=DEFAULT):
3535 if (game.options & OPTION_COLOR) and (game.options & OPTION_CURSES):
3536 if color == DEFAULT:
3538 elif color == BLACK:
3539 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3541 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3542 elif color == GREEN:
3543 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3545 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3547 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3548 elif color == MAGENTA:
3549 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3550 elif color == BROWN:
3551 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3552 elif color == LIGHTGRAY:
3553 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3554 elif color == DARKGRAY:
3555 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3556 elif color == LIGHTBLUE:
3557 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3558 elif color == LIGHTGREEN:
3559 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3560 elif color == LIGHTCYAN:
3561 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3562 elif color == LIGHTRED:
3563 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3564 elif color == LIGHTMAGENTA:
3565 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3566 elif color == YELLOW:
3567 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3568 elif color == WHITE:
3569 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3572 if (game.options & OPTION_COLOR) and (game.options & OPTION_CURSES):
3573 curwnd.attron(curses.A_REVERSE)
3576 # Things past this point have policy implications.
3580 "Hook to be called after moving to redraw maps."
3581 if game.options & OPTION_CURSES:
3584 setwnd(srscan_window)
3588 setwnd(status_window)
3589 status_window.clear()
3590 status_window.move(0, 0)
3591 setwnd(report_window)
3592 report_window.clear()
3593 report_window.move(0, 0)
3595 setwnd(lrscan_window)
3596 lrscan_window.clear()
3597 lrscan_window.move(0, 0)
3598 lrscan(silent=False)
3600 def put_srscan_sym(w, sym):
3601 "Emit symbol for short-range scan."
3602 srscan_window.move(w.i+1, w.j*2+2)
3603 srscan_window.addch(sym)
3604 srscan_window.refresh()
3607 "Enemy fall down, go boom."
3608 if game.options & OPTION_CURSES:
3610 setwnd(srscan_window)
3611 srscan_window.attron(curses.A_REVERSE)
3612 put_srscan_sym(w, game.quad[w.i][w.j])
3616 srscan_window.attroff(curses.A_REVERSE)
3617 put_srscan_sym(w, game.quad[w.i][w.j])
3618 curses.delay_output(500)
3619 setwnd(message_window)
3622 "Sound and visual effects for teleportation."
3623 if game.options & OPTION_CURSES:
3625 setwnd(message_window)
3627 prouts(" . . . . . ")
3628 if game.options & OPTION_CURSES:
3629 #curses.delay_output(1000)
3633 def tracktorpedo(w, step, i, n, iquad):
3634 "Torpedo-track animation."
3635 if not game.options & OPTION_CURSES:
3639 proutn(_("Track for torpedo number %d- ") % (i+1))
3642 proutn(_("Torpedo track- "))
3643 elif step==4 or step==9:
3647 if not damaged(DSRSENS) or game.condition=="docked":
3648 if i != 0 and step == 1:
3651 if (iquad=='.') or (iquad==' '):
3652 put_srscan_sym(w, '+')
3656 put_srscan_sym(w, iquad)
3658 curwnd.attron(curses.A_REVERSE)
3659 put_srscan_sym(w, iquad)
3663 curwnd.attroff(curses.A_REVERSE)
3664 put_srscan_sym(w, iquad)
3669 "Display the current galaxy chart."
3670 if game.options & OPTION_CURSES:
3671 setwnd(message_window)
3672 message_window.clear()
3674 if game.options & OPTION_TTY:
3679 def prstat(txt, data):
3681 if game.options & OPTION_CURSES:
3683 setwnd(status_window)
3685 proutn(" " * (NSYM - len(txt)))
3688 if game.options & OPTION_CURSES:
3689 setwnd(report_window)
3691 # Code from moving.c begins here
3693 def imove(icourse=None, noattack=False):
3694 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3697 def newquadrant(noattack):
3698 # Leaving quadrant -- allow final enemy attack
3699 # Don't set up attack if being pushed by nova or cloaked
3700 if len(game.enemies) != 0 and not noattack and not game.iscloaked:
3702 for enemy in game.enemies:
3703 finald = (w - enemy.location).distance()
3704 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3705 # Stas Sergeev added the condition
3706 # that attacks only happen if Klingons
3707 # are present and your skill is good.
3708 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3709 attack(torps_ok=False)
3712 # check for edge of galaxy
3716 if icourse.final.i < 0:
3717 icourse.final.i = -icourse.final.i
3719 if icourse.final.j < 0:
3720 icourse.final.j = -icourse.final.j
3722 if icourse.final.i >= GALSIZE*QUADSIZE:
3723 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3725 if icourse.final.j >= GALSIZE*QUADSIZE:
3726 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3734 if game.nkinks == 3:
3735 # Three strikes -- you're out!
3739 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3740 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3741 prout(_("YOU WILL BE DESTROYED."))
3742 # Compute final position in new quadrant
3743 if trbeam: # Don't bother if we are to be beamed
3745 game.quadrant = icourse.final.quadrant()
3746 game.sector = icourse.final.sector()
3748 prout(_("Entering Quadrant %s.") % game.quadrant)
3749 game.quad[game.sector.i][game.sector.j] = game.ship
3751 if game.skill>SKILL_NOVICE:
3752 attack(torps_ok=False)
3754 def check_collision(h):
3755 iquad = game.quad[h.i][h.j]
3757 # object encountered in flight path
3758 stopegy = 50.0*icourse.distance/game.optime
3759 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3760 for enemy in game.enemies:
3761 if enemy.location == game.sector:
3762 collision(rammed=False, enemy=enemy)
3764 # This should not happen
3765 prout(_("Which way did he go?"))
3769 prouts(_("***RED ALERT! RED ALERT!"))
3771 proutn("***" + crmshp())
3772 proutn(_(" pulled into black hole at Sector %s") % h)
3773 # Getting pulled into a black hole was certain
3774 # death in Almy's original. Stas Sergeev added a
3775 # possibility that you'll get timewarped instead.
3777 for m in range(NDEVICES):
3778 if game.damage[m]>0:
3780 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3781 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3791 prout(_(" encounters Tholian web at %s;") % h)
3793 prout(_(" blocked by object at %s;") % h)
3794 proutn(_("Emergency stop required "))
3795 prout(_("%2d units of energy.") % int(stopegy))
3796 game.energy -= stopegy
3797 if game.energy <= 0:
3804 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3805 game.inorbit = False
3806 # If tractor beam is to occur, don't move full distance
3807 if game.state.date+game.optime >= scheduled(FTBEAM):
3809 # We can't be tractor beamed if cloaked,
3810 # so move the event into the future
3811 postpone(FTBEAM, game.optime + expran(1.5*game.intime/len(game.kcmdr)))
3815 game.condition = "red"
3816 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3817 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3819 game.quad[game.sector.i][game.sector.j] = '.'
3820 for _m in range(icourse.moves):
3822 w = icourse.sector()
3823 if icourse.origin.quadrant() != icourse.location.quadrant():
3824 newquadrant(noattack)
3826 elif check_collision(w):
3827 print("Collision detected")
3831 # We're in destination quadrant -- compute new average enemy distances
3832 game.quad[game.sector.i][game.sector.j] = game.ship
3834 for enemy in game.enemies:
3835 finald = (w-enemy.location).distance()
3836 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3837 enemy.kdist = finald
3839 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3840 attack(torps_ok=False)
3841 for enemy in game.enemies:
3842 enemy.kavgd = enemy.kdist
3845 setwnd(message_window)
3849 "Dock our ship at a starbase."
3851 if game.condition == "docked" and verbose:
3852 prout(_("Already docked."))
3855 prout(_("You must first leave standard orbit."))
3857 if game.base is None or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3858 prout(crmshp() + _(" not adjacent to base."))
3861 prout(_("You cannot dock while cloaked."))
3863 game.condition = "docked"
3867 if game.energy < game.inenrg:
3868 game.energy = game.inenrg
3869 game.shield = game.inshld
3870 game.torps = game.intorps
3871 game.lsupres = game.inlsr
3872 game.state.crew = FULLCREW
3873 if game.brigcapacity-game.brigfree > 0:
3874 prout(_("%d captured Klingons transferred to base") % (game.brigcapacity-game.brigfree))
3875 game.kcaptured += game.brigcapacity-game.brigfree
3876 game.brigfree = game.brigcapacity
3877 if communicating() and \
3878 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3879 # get attack report from base
3880 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3884 def cartesian(loc1=None, loc2=None):
3886 return game.quadrant * QUADSIZE + game.sector
3888 return game.quadrant * QUADSIZE + loc1
3890 return loc1 * QUADSIZE + loc2
3892 def getcourse(isprobe):
3893 "Get a course and distance from the user."
3895 dquad = copy.copy(game.quadrant)
3896 navmode = "unspecified"
3900 if game.landed and not isprobe:
3901 prout(_("Dummy! You can't leave standard orbit until you"))
3902 proutn(_("are back aboard the ship."))
3905 while navmode == "unspecified":
3906 if damaged(DNAVSYS):
3908 prout(_("Computer damaged; manual navigation only"))
3910 prout(_("Computer damaged; manual movement only"))
3915 key = scanner.nexttok()
3917 proutn(_("Manual or automatic- "))
3920 elif key == "IHALPHA":
3921 if scanner.sees("manual"):
3923 key = scanner.nexttok()
3925 elif scanner.sees("automatic"):
3926 navmode = "automatic"
3927 key = scanner.nexttok()
3935 prout(_("(Manual navigation assumed.)"))
3937 prout(_("(Manual movement assumed.)"))
3941 if navmode == "automatic":
3942 while key == "IHEOL":
3944 proutn(_("Target quadrant or quadrant§or- "))
3946 proutn(_("Destination sector or quadrant§or- "))
3949 key = scanner.nexttok()
3953 xi = int(round(scanner.real))-1
3954 key = scanner.nexttok()
3958 xj = int(round(scanner.real))-1
3959 key = scanner.nexttok()
3961 # both quadrant and sector specified
3962 xk = int(round(scanner.real))-1
3963 key = scanner.nexttok()
3967 xl = int(round(scanner.real))-1
3973 # only one pair of numbers was specified
3975 # only quadrant specified -- go to center of dest quad
3978 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3980 # only sector specified
3984 if not dquad.valid_quadrant() or not dsect.valid_sector():
3991 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3993 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3994 # the actual deltas get computed here
3995 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3996 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3998 while key == "IHEOL":
3999 proutn(_("X and Y displacements- "))
4002 key = scanner.nexttok()
4005 delta.j = scanner.real
4009 key = scanner.nexttok()
4011 delta.i = scanner.real
4012 elif key == "IHEOL":
4018 # Check for zero movement
4019 if delta.i == 0 and delta.j == 0:
4022 if itemp == "verbose" and not isprobe:
4024 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
4026 return course(bearing=delta.bearing(), distance=delta.distance())
4029 def __init__(self, bearing, distance, origin=None):
4030 self.distance = distance
4031 self.bearing = bearing
4033 self.origin = cartesian(game.quadrant, game.sector)
4035 self.origin = origin
4036 # The bearing() code we inherited from FORTRAN is actually computing
4037 # clockface directions!
4038 if self.bearing < 0.0:
4039 self.bearing += 12.0
4040 self.angle = ((15.0 - self.bearing) * 0.5235988)
4041 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
4042 bigger = max(abs(self.increment.i), abs(self.increment.j))
4043 self.increment /= bigger
4044 self.moves = int(round(10*self.distance*bigger))
4046 self.final = (self.location + self.moves*self.increment).roundtogrid()
4047 self.location = self.origin
4048 self.nextlocation = None
4050 self.location = self.origin
4053 return self.location.roundtogrid() == self.final
4055 "Next step on course."
4057 self.nextlocation = self.location + self.increment
4058 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
4059 self.location = self.nextlocation
4062 return self.location.quadrant()
4064 return self.location.sector()
4066 return self.distance*(w**3)*(game.shldup+1)
4068 return 10.0*self.distance/w**2
4071 "Move under impulse power."
4073 if damaged(DIMPULS):
4076 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4078 if game.energy > 30.0:
4080 icourse = getcourse(isprobe=False)
4083 power = 20.0 + 100.0*icourse.distance
4086 if power >= game.energy:
4087 # Insufficient power for trip
4089 prout(_("First Officer Spock- \"Captain, the impulse engines"))
4090 prout(_("require 20.0 units to engage, plus 100.0 units per"))
4091 if game.energy > 30:
4092 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
4093 int(0.01 * (game.energy-20.0)-0.05))
4094 prout(_(" quadrants.\""))
4096 prout(_("quadrant. They are, therefore, useless.\""))
4099 # Make sure enough time is left for the trip
4100 game.optime = icourse.distance/0.095
4101 if game.optime >= game.state.remtime:
4102 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
4103 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
4104 proutn(_("we dare spend the time?\" "))
4107 # Activate impulse engines and pay the cost
4108 imove(icourse, noattack=False)
4112 power = 20.0 + 100.0*icourse.distance
4113 game.energy -= power
4114 game.optime = icourse.distance/0.095
4115 if game.energy <= 0:
4119 def warp(wcourse, involuntary):
4120 "ove under warp drive."
4121 blooey = False; twarp = False
4122 if not involuntary: # Not WARPX entry
4127 prout(_("Engineer Scott- \"The warp engines can not be used while cloaked, Sir.\""))
4129 if game.damage[DWARPEN] > 10.0:
4132 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
4134 if damaged(DWARPEN) and game.warpfac > 4.0:
4137 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4138 prout(_(" is repaired, I can only give you warp 4.\""))
4140 # Read in course and distance
4143 wcourse = getcourse(isprobe=False)
4146 # Make sure starship has enough energy for the trip
4147 # Note: this formula is slightly different from the C version,
4148 # and lets you skate a bit closer to the edge.
4149 if wcourse.power(game.warpfac) >= game.energy:
4150 # Insufficient power for trip
4153 prout(_("Engineering to bridge--"))
4154 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
4155 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
4157 prout(_("We can't do it, Captain. We don't have enough energy."))
4159 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4162 prout(_("if you'll lower the shields."))
4166 prout(_("We haven't the energy to go that far with the shields up."))
4168 # Make sure enough time is left for the trip
4169 game.optime = wcourse.time(game.warpfac)
4170 if game.optime >= 0.8*game.state.remtime:
4172 prout(_("First Officer Spock- \"Captain, I compute that such"))
4173 proutn(_(" a trip would require approximately %2.0f") %
4174 (100.0*game.optime/game.state.remtime))
4175 prout(_(" percent of our"))
4176 proutn(_(" remaining time. Are you sure this is wise?\" "))
4182 if game.warpfac > 6.0:
4183 # Decide if engine damage will occur
4184 # ESR: Seems wrong. Probability of damage goes *down* with distance?
4185 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
4186 if prob > randreal():
4188 wcourse.distance = randreal(wcourse.distance)
4189 # Decide if time warp will occur
4190 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
4192 if game.idebug and game.warpfac==10 and not twarp:
4194 proutn("=== Force time warp? ")
4198 # If time warp or engine damage, check path
4199 # If it is obstructed, don't do warp or damage
4200 look = wcourse.moves
4204 w = wcourse.sector()
4205 if not w.valid_sector():
4207 if game.quad[w.i][w.j] != '.':
4211 # Activate Warp Engines and pay the cost
4212 imove(wcourse, noattack=False)
4215 game.energy -= wcourse.power(game.warpfac)
4216 if game.energy <= 0:
4218 game.optime = wcourse.time(game.warpfac)
4222 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4224 prout(_("Engineering to bridge--"))
4225 prout(_(" Scott here. The warp engines are damaged."))
4226 prout(_(" We'll have to reduce speed to warp 4."))
4231 "Change the warp factor."
4233 key=scanner.nexttok()
4237 proutn(_("Warp factor- "))
4241 if game.damage[DWARPEN] > 10.0:
4242 prout(_("Warp engines inoperative."))
4244 if damaged(DWARPEN) and scanner.real > 4.0:
4245 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4246 prout(_(" but right now we can only go warp 4.\""))
4248 if scanner.real > 10.0:
4249 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4251 if scanner.real < 1.0:
4252 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4254 oldfac = game.warpfac
4255 game.warpfac = scanner.real
4256 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4257 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4260 if game.warpfac < 8.00:
4261 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4263 if game.warpfac == 10.0:
4264 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4266 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4270 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4272 # is captain on planet?
4274 if damaged(DTRANSP):
4277 prout(_("Scotty rushes to the transporter controls."))
4279 prout(_("But with the shields up it's hopeless."))
4281 prouts(_("His desperate attempt to rescue you . . ."))
4286 prout(_("SUCCEEDS!"))
4289 proutn(_("The crystals mined were "))
4297 # Check to see if captain in shuttle craft
4302 # Inform captain of attempt to reach safety
4306 prouts(_("***RED ALERT! RED ALERT!"))
4308 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4309 prouts(_(" a supernova."))
4311 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4312 prout(_("safely out of quadrant."))
4313 if not damaged(DRADIO):
4314 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4315 # Try to use warp engines
4316 if damaged(DWARPEN):
4318 prout(_("Warp engines damaged."))
4321 game.warpfac = randreal(6.0, 8.0)
4322 prout(_("Warp factor set to %d") % int(game.warpfac))
4323 power = 0.75*game.energy
4324 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4325 dist = max(dist, randreal(math.sqrt(2)))
4326 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4327 game.optime = bugout.time(game.warpfac)
4329 game.inorbit = False
4330 warp(bugout, involuntary=True)
4332 # This is bad news, we didn't leave quadrant.
4336 prout(_("Insufficient energy to leave quadrant."))
4339 # Repeat if another snova
4340 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4343 finish(FWON) # Snova killed remaining enemy.
4346 "Let's do the time warp again."
4347 prout(_("***TIME WARP ENTERED."))
4348 if game.state.snap and withprob(0.5):
4350 prout(_("You are traveling backwards in time %d stardates.") %
4351 int(game.state.date-game.snapsht.date))
4352 game.state = game.snapsht
4353 game.state.snap = False
4354 if len(game.state.kcmdr):
4355 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4356 schedule(FBATTAK, expran(0.3*game.intime))
4357 schedule(FSNOVA, expran(0.5*game.intime))
4358 # next snapshot will be sooner
4359 schedule(FSNAP, expran(0.25*game.state.remtime))
4361 if game.state.nscrem:
4362 schedule(FSCMOVE, 0.2777)
4366 game.battle.invalidate()
4367 # Make sure Galileo is consistant -- Snapshot may have been taken
4368 # when on planet, which would give us two Galileos!
4370 for l in range(game.inplan):
4371 if game.state.planets[l].known == "shuttle_down":
4373 if game.iscraft == "onship" and game.ship=='E':
4374 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4375 game.iscraft = "offship"
4376 # Likewise, if in the original time the Galileo was abandoned, but
4377 # was on ship earlier, it would have vanished -- let's restore it.
4378 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4379 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4380 game.iscraft = "onship"
4381 # There used to be code to do the actual reconstrction here,
4382 # but the starchart is now part of the snapshotted galaxy state.
4383 prout(_("Spock has reconstructed a correct star chart from memory"))
4385 # Go forward in time
4386 game.optime = expran(0.5*game.intime)
4387 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4388 # cheat to make sure no tractor beams occur during time warp
4389 postpone(FTBEAM, game.optime)
4390 game.damage[DRADIO] += game.optime
4392 events() # Stas Sergeev added this -- do pending events
4395 "Launch deep-space probe."
4396 # New code to launch a deep space probe
4397 if game.nprobes == 0:
4400 if game.ship == 'E':
4401 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4403 prout(_("Ye Faerie Queene has no deep space probes."))
4408 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4410 if is_scheduled(FDSPROB):
4413 if damaged(DRADIO) and game.condition != "docked":
4414 prout(_("Spock- \"Records show the previous probe has not yet"))
4415 prout(_(" reached its destination.\""))
4417 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4419 key = scanner.nexttok()
4421 if game.nprobes == 1:
4422 prout(_("1 probe left."))
4424 prout(_("%d probes left") % game.nprobes)
4425 proutn(_("Are you sure you want to fire a probe? "))
4428 game.isarmed = False
4429 if key == "IHALPHA" and scanner.token == "armed":
4431 key = scanner.nexttok()
4432 elif key == "IHEOL":
4433 proutn(_("Arm NOVAMAX warhead? "))
4435 elif key == "IHREAL": # first element of course
4436 scanner.push(scanner.token)
4438 game.probe = getcourse(isprobe=True)
4442 schedule(FDSPROB, 0.01) # Time to move one sector
4443 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4448 "Yell for help from nearest starbase."
4449 # There's more than one way to move in this game!
4451 # Test for conditions which prevent calling for help
4452 if game.condition == "docked":
4453 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4456 prout(_("Subspace radio damaged."))
4458 if not game.state.baseq:
4459 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4462 prout(_("You must be aboard the %s.") % crmshp())
4464 # OK -- call for help from nearest starbase
4467 # There's one in this quadrant
4468 ddist = (game.base - game.sector).distance()
4470 ibq = None # Force base-quadrant game to persist past loop
4472 for ibq in game.state.baseq:
4473 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4477 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4479 # Since starbase not in quadrant, set up new quadrant
4482 # dematerialize starship
4483 game.quad[game.sector.i][game.sector.j]='.'
4484 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4485 % (game.quadrant, crmshp()))
4486 game.sector.invalidate()
4487 for m in range(1, 5+1):
4488 w = game.base.scatter()
4489 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4490 # found one -- finish up
4493 if game.sector is None:
4494 prout(_("You have been lost in space..."))
4495 finish(FMATERIALIZE)
4497 # Give starbase three chances to rematerialize starship
4498 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4499 for m in range(1, 3+1):
4500 if m == 1: proutn(_("1st"))
4501 elif m == 2: proutn(_("2nd"))
4502 elif m == 3: proutn(_("3rd"))
4503 proutn(_(" attempt to re-materialize ") + crmshp())
4504 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4507 if randreal() > probf:
4511 curses.delay_output(500)
4513 game.quad[game.sector.i][game.sector.j]='?'
4516 setwnd(message_window)
4517 finish(FMATERIALIZE)
4519 game.quad[game.sector.i][game.sector.j]=game.ship
4521 prout(_("succeeds."))
4525 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4530 if game.condition=="docked":
4532 prout(_("You cannot abandon Ye Faerie Queene."))
4535 # Must take shuttle craft to exit
4536 if game.damage[DSHUTTL]==-1:
4537 prout(_("Ye Faerie Queene has no shuttle craft."))
4539 if game.damage[DSHUTTL]<0:
4540 prout(_("Shuttle craft now serving Big Macs."))
4542 if game.damage[DSHUTTL]>0:
4543 prout(_("Shuttle craft damaged."))
4546 prout(_("You must be aboard the ship."))
4548 if game.iscraft != "onship":
4549 prout(_("Shuttle craft not currently available."))
4551 # Emit abandon ship messages
4553 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4555 prouts(_("***ALL HANDS ABANDON SHIP!"))
4557 prout(_("Captain and crew escape in shuttle craft."))
4558 if not game.state.baseq:
4559 # Oops! no place to go...
4562 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4564 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4565 prout(_("Remainder of ship's complement beam down"))
4566 prout(_("to nearest habitable planet."))
4567 elif q.planet != None and not damaged(DTRANSP):
4568 prout(_("Remainder of ship's complement beam down to %s.") %
4571 prout(_("Entire crew of %d left to die in outer space.") %
4573 game.casual += game.state.crew
4574 game.abandoned += game.state.crew
4575 # If at least one base left, give 'em the Faerie Queene
4577 game.icrystl = False # crystals are lost
4578 game.nprobes = 0 # No probes
4579 prout(_("You are captured by Klingons and released to"))
4580 prout(_("the Federation in a prisoner-of-war exchange."))
4581 nb = randrange(len(game.state.baseq))
4582 # Set up quadrant and position FQ adjacient to base
4583 if not game.quadrant == game.state.baseq[nb]:
4584 game.quadrant = game.state.baseq[nb]
4585 game.sector.i = game.sector.j = 5
4588 # position next to base by trial and error
4589 game.quad[game.sector.i][game.sector.j] = '.'
4591 for l in range(QUADSIZE):
4592 game.sector = game.base.scatter()
4593 if game.sector.valid_sector() and \
4594 game.quad[game.sector.i][game.sector.j] == '.':
4597 break # found a spot
4598 game.sector.i=QUADSIZE/2
4599 game.sector.j=QUADSIZE/2
4601 # Get new commission
4602 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4603 game.state.crew = FULLCREW
4604 prout(_("Starfleet puts you in command of another ship,"))
4605 prout(_("the Faerie Queene, which is antiquated but,"))
4606 prout(_("still useable."))
4608 prout(_("The dilithium crystals have been moved."))
4610 game.iscraft = "offship" # Galileo disappears
4612 game.condition="docked"
4613 for l in range(NDEVICES):
4614 game.damage[l] = 0.0
4615 game.damage[DSHUTTL] = -1
4616 game.energy = game.inenrg = 3000.0
4617 game.shield = game.inshld = 1250.0
4618 game.torps = game.intorps = 6
4619 game.lsupres=game.inlsr=3.0
4622 game.brigfree = game.brigcapacity = 300
4625 # Code from planets.c begins here.
4628 "Abort a lengthy operation if an event interrupts it."
4631 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4636 "Report on (uninhabited) planets in the galaxy."
4640 prout(_("Spock- \"Planet report follows, Captain.\""))
4642 for i in range(game.inplan):
4643 if game.state.planets[i].pclass == "destroyed":
4645 if (game.state.planets[i].known != "unknown" \
4646 and not game.state.planets[i].inhabited) \
4649 if game.idebug and game.state.planets[i].known=="unknown":
4650 proutn("(Unknown) ")
4651 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4652 proutn(_(" class "))
4653 proutn(game.state.planets[i].pclass)
4655 if game.state.planets[i].crystals != "present":
4657 prout(_("dilithium crystals present."))
4658 if game.state.planets[i].known=="shuttle_down":
4659 prout(_(" Shuttle Craft Galileo on surface."))
4661 prout(_("No information available."))
4664 "Enter standard orbit."
4668 prout(_("Already in standard orbit."))
4670 if damaged(DWARPEN) and damaged(DIMPULS):
4671 prout(_("Both warp and impulse engines damaged."))
4673 if game.plnet is None:
4674 prout("There is no planet in this sector.")
4676 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4677 prout(crmshp() + _(" not adjacent to planet."))
4680 game.optime = randreal(0.02, 0.05)
4681 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4685 game.height = randreal(1400, 8600)
4686 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4691 "Examine planets in this quadrant."
4692 if damaged(DSRSENS):
4693 if game.options & OPTION_TTY:
4694 prout(_("Short range sensors damaged."))
4696 if game.iplnet is None:
4697 if game.options & OPTION_TTY:
4698 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4700 if game.iplnet.known == "unknown":
4701 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4703 prout(_(" Planet at Sector %s is of class %s.") %
4704 (game.plnet, game.iplnet.pclass))
4705 if game.iplnet.known=="shuttle_down":
4706 prout(_(" Sensors show Galileo still on surface."))
4707 proutn(_(" Readings indicate"))
4708 if game.iplnet.crystals != "present":
4710 prout(_(" dilithium crystals present.\""))
4711 if game.iplnet.known == "unknown":
4712 game.iplnet.known = "known"
4713 elif game.iplnet.inhabited:
4714 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4715 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4718 "Use the transporter."
4722 if damaged(DTRANSP):
4723 prout(_("Transporter damaged."))
4724 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4726 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4730 if not game.inorbit:
4731 prout(crmshp() + _(" not in standard orbit."))
4734 prout(_("Impossible to transport through shields."))
4736 if game.iplnet.known=="unknown":
4737 prout(_("Spock- \"Captain, we have no information on this planet"))
4738 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4739 prout(_(" you may not go down.\""))
4741 if not game.landed and game.iplnet.crystals=="absent":
4742 prout(_("Spock- \"Captain, I fail to see the logic in"))
4743 prout(_(" exploring a planet with no dilithium crystals."))
4744 proutn(_(" Are you sure this is wise?\" "))
4748 if not (game.options & OPTION_PLAIN):
4749 nrgneed = 50 * game.skill + game.height / 100.0
4750 if nrgneed > game.energy:
4751 prout(_("Engineering to bridge--"))
4752 prout(_(" Captain, we don't have enough energy for transportation."))
4754 if not game.landed and nrgneed * 2 > game.energy:
4755 prout(_("Engineering to bridge--"))
4756 prout(_(" Captain, we have enough energy only to transport you down to"))
4757 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4758 if game.iplnet.known == "shuttle_down":
4759 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4760 proutn(_(" Are you sure this is wise?\" "))
4765 # Coming from planet
4766 if game.iplnet.known=="shuttle_down":
4767 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4771 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4772 prout(_("Landing party assembled, ready to beam up."))
4774 prout(_("Kirk whips out communicator..."))
4775 prouts(_("BEEP BEEP BEEP"))
4777 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4780 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4782 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4784 prout(_("Kirk- \"Energize.\""))
4787 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4789 if not withprob(0.98):
4790 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4792 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4795 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4796 game.landed = not game.landed
4797 game.energy -= nrgneed
4799 prout(_("Transport complete."))
4800 if game.landed and game.iplnet.known=="shuttle_down":
4801 prout(_("The shuttle craft Galileo is here!"))
4802 if not game.landed and game.imine:
4809 "Strip-mine a world for dilithium."
4813 prout(_("Mining party not on planet."))
4815 if game.iplnet.crystals == "mined":
4816 prout(_("This planet has already been strip-mined for dilithium."))
4818 elif game.iplnet.crystals == "absent":
4819 prout(_("No dilithium crystals on this planet."))
4822 prout(_("You've already mined enough crystals for this trip."))
4824 if game.icrystl and game.cryprob == 0.05:
4825 prout(_("With all those fresh crystals aboard the ") + crmshp())
4826 prout(_("there's no reason to mine more at this time."))
4828 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4831 prout(_("Mining operation complete."))
4832 game.iplnet.crystals = "mined"
4833 game.imine = game.ididit = True
4836 "Use dilithium crystals."
4840 if not game.icrystl:
4841 prout(_("No dilithium crystals available."))
4843 if game.energy >= 1000:
4844 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4845 prout(_(" except when Condition Yellow exists."))
4847 prout(_("Spock- \"Captain, I must warn you that loading"))
4848 prout(_(" raw dilithium crystals into the ship's power"))
4849 prout(_(" system may risk a severe explosion."))
4850 proutn(_(" Are you sure this is wise?\" "))
4855 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4856 prout(_(" Mr. Spock and I will try it.\""))
4858 prout(_("Spock- \"Crystals in place, Sir."))
4859 prout(_(" Ready to activate circuit.\""))
4861 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4863 if withprob(game.cryprob):
4864 prouts(_(" \"Activating now! - - No good! It's***"))
4866 prouts(_("***RED ALERT! RED A*L********************************"))
4869 prouts(_("****************** KA-BOOM!!!! *******************"))
4873 game.energy += randreal(5000.0, 5500.0)
4874 prouts(_(" \"Activating now! - - "))
4875 prout(_("The instruments"))
4876 prout(_(" are going crazy, but I think it's"))
4877 prout(_(" going to work!! Congratulations, Sir!\""))
4882 "Use shuttlecraft for planetary jaunt."
4885 if damaged(DSHUTTL):
4886 if game.damage[DSHUTTL] == -1.0:
4887 if game.inorbit and game.iplnet.known == "shuttle_down":
4888 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4890 prout(_("Ye Faerie Queene had no shuttle craft."))
4891 elif game.damage[DSHUTTL] > 0:
4892 prout(_("The Galileo is damaged."))
4893 else: # game.damage[DSHUTTL] < 0
4894 prout(_("Shuttle craft is now serving Big Macs."))
4896 if not game.inorbit:
4897 prout(crmshp() + _(" not in standard orbit."))
4899 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4900 prout(_("Shuttle craft not currently available."))
4902 if not game.landed and game.iplnet.known=="shuttle_down":
4903 prout(_("You will have to beam down to retrieve the shuttle craft."))
4905 if game.shldup or game.condition == "docked":
4906 prout(_("Shuttle craft cannot pass through shields."))
4908 if game.iplnet.known=="unknown":
4909 prout(_("Spock- \"Captain, we have no information on this planet"))
4910 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4911 prout(_(" you may not fly down.\""))
4913 game.optime = 3.0e-5*game.height
4914 if game.optime >= 0.8*game.state.remtime:
4915 prout(_("First Officer Spock- \"Captain, I compute that such"))
4916 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4917 int(100*game.optime/game.state.remtime))
4918 prout(_("remaining time."))
4919 proutn(_("Are you sure this is wise?\" "))
4925 if game.iscraft == "onship":
4927 if not damaged(DTRANSP):
4928 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4932 proutn(_("Shuttle crew"))
4934 proutn(_("Rescue party"))
4935 prout(_(" boards Galileo and swoops toward planet surface."))
4936 game.iscraft = "offship"
4940 game.iplnet.known="shuttle_down"
4941 prout(_("Trip complete."))
4944 # Ready to go back to ship
4945 prout(_("You and your mining party board the"))
4946 prout(_("shuttle craft for the trip back to the Enterprise."))
4948 prouts(_("The short hop begins . . ."))
4950 game.iplnet.known="known"
4956 game.iscraft = "onship"
4962 prout(_("Trip complete."))
4965 # Kirk on ship and so is Galileo
4966 prout(_("Mining party assembles in the hangar deck,"))
4967 prout(_("ready to board the shuttle craft \"Galileo\"."))
4969 prouts(_("The hangar doors open; the trip begins."))
4972 game.iscraft = "offship"
4975 game.iplnet.known = "shuttle_down"
4978 prout(_("Trip complete."))
4982 "Use the big zapper."
4986 if game.ship != 'E':
4987 prout(_("Ye Faerie Queene has no death ray."))
4989 if len(game.enemies)==0:
4990 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4993 prout(_("Death Ray is damaged."))
4995 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4996 prout(_(" is highly unpredictible. Considering the alternatives,"))
4997 proutn(_(" are you sure this is wise?\" "))
5000 prout(_("Spock- \"Acknowledged.\""))
5003 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
5005 prout(_("Crew scrambles in emergency preparation."))
5006 prout(_("Spock and Scotty ready the death ray and"))
5007 prout(_("prepare to channel all ship's power to the device."))
5009 prout(_("Spock- \"Preparations complete, sir.\""))
5010 prout(_("Kirk- \"Engage!\""))
5012 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
5015 if game.options & OPTION_PLAIN:
5019 prouts(_("Sulu- \"Captain! It's working!\""))
5021 while len(game.enemies) > 0:
5022 deadkl(game.enemies[-1].location, game.quad[game.enemies[-1].location.i][game.enemies[-1].location.j],game.enemies[-1].location)
5023 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
5024 if game.unwon() == 0:
5026 if (game.options & OPTION_PLAIN) == 0:
5027 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
5029 prout(_(" is still operational.\""))
5031 prout(_(" has been rendered nonfunctional.\""))
5032 game.damage[DDRAY] = 39.95
5034 r = randreal() # Pick failure method
5036 prouts(_("Sulu- \"Captain! It's working!\""))
5038 prouts(_("***RED ALERT! RED ALERT!"))
5040 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
5042 prouts(_("***RED ALERT! RED A*L********************************"))
5045 prouts(_("****************** KA-BOOM!!!! *******************"))
5050 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
5052 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
5054 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
5055 prout(_(" have apparently been transformed into strange mutations."))
5056 prout(_(" Vulcans do not seem to be affected."))
5058 prout(_("Kirk- \"Raauch! Raauch!\""))
5062 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
5064 proutn(_("Spock- \"I believe the word is"))
5065 prouts(_(" *ASTONISHING*"))
5066 prout(_(" Mr. Sulu."))
5067 for i in range(QUADSIZE):
5068 for j in range(QUADSIZE):
5069 if game.quad[i][j] == '.':
5070 game.quad[i][j] = '?'
5071 prout(_(" Captain, our quadrant is now infested with"))
5072 prouts(_(" - - - - - - *THINGS*."))
5074 prout(_(" I have no logical explanation.\""))
5076 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
5078 prout(_("Scotty- \"There are so many tribbles down here"))
5079 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
5083 # Code from reports.c begins here
5085 def attackreport(curt):
5086 "eport status of bases under attack."
5088 if is_scheduled(FCDBAS):
5089 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
5090 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
5091 elif game.isatb == 1:
5092 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
5093 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
5095 prout(_("No Starbase is currently under attack."))
5097 if is_scheduled(FCDBAS):
5098 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
5100 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
5104 # report on general game status
5106 s1 = (game.thawed and _("thawed ")) or ""
5107 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
5108 s3 = (None, _("novice"), _("fair"),
5109 _("good"), _("expert"), _("emeritus"))[game.skill]
5110 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
5111 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
5112 prout(_("No plaque is allowed."))
5114 prout(_("This is tournament game %d.") % game.tourn)
5115 prout(_("Your secret password is \"%s\"") % game.passwd)
5116 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - game.unwon()),
5117 (game.inkling + game.incom + game.inscom)))
5118 if game.incom - len(game.state.kcmdr):
5119 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
5120 elif game.inkling - game.remkl() + (game.inscom - game.state.nscrem) > 0:
5121 prout(_(", but no Commanders."))
5124 if game.skill > SKILL_FAIR:
5125 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
5126 if len(game.state.baseq) != game.inbase:
5128 if game.inbase-len(game.state.baseq)==1:
5129 proutn(_("has been 1 base"))
5131 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
5132 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
5134 prout(_("There are %d bases.") % game.inbase)
5135 if communicating() or game.iseenit:
5136 # Don't report this if not seen and
5137 # either the radio is dead or not at base!
5141 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
5142 if game.brigcapacity != game.brigfree:
5143 embriggened = brigcapacity-brigfree
5144 if embriggened == 1:
5145 prout(_("1 Klingon in brig"))
5147 prout(_("%d Klingons in brig.") % embriggened)
5148 if game.kcaptured == 0:
5150 elif game.kcaptured == 1:
5151 prout(_("1 captured Klingon turned in to Starfleet."))
5153 prout(_("%d captured Klingons turned in to Star Fleet.") % game.kcaptured)
5155 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
5156 if game.ship == 'E':
5157 proutn(_("You have "))
5159 proutn("%d" % (game.nprobes))
5162 proutn(_(" deep space probe"))
5166 if communicating() and is_scheduled(FDSPROB):
5168 proutn(_("An armed deep space probe is in "))
5170 proutn(_("A deep space probe is in "))
5171 prout("Quadrant %s." % game.probe.quadrant())
5173 if game.cryprob <= .05:
5174 prout(_("Dilithium crystals aboard ship... not yet used."))
5178 while game.cryprob > ai:
5181 prout(_("Dilithium crystals have been used %d time%s.") % \
5182 (i, (_("s"), "")[i==1]))
5186 "Long-range sensor scan."
5187 if damaged(DLRSENS):
5188 # Now allow base's sensors if docked
5189 if game.condition != "docked":
5191 prout(_("LONG-RANGE SENSORS DAMAGED."))
5194 prout(_("Starbase's long-range scan"))
5196 prout(_("Long-range scan"))
5197 for x in range(game.quadrant.i-1, game.quadrant.i+2):
5200 for y in range(game.quadrant.j-1, game.quadrant.j+2):
5201 if not Coord(x, y).valid_quadrant():
5205 if not damaged(DRADIO):
5206 game.state.galaxy[x][y].charted = True
5207 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5208 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5209 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5210 if not silent and game.state.galaxy[x][y].supernova:
5213 cn = " %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars)
5214 proutn(((3 - len(cn)) * '.') + cn)
5222 for i in range(NDEVICES):
5225 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5226 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5228 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5229 game.damage[i]+0.05,
5230 DOCKFAC*game.damage[i]+0.005))
5232 prout(_("All devices functional."))
5235 "Update the chart in the Enterprise's computer from galaxy data."
5236 game.lastchart = game.state.date
5237 for i in range(GALSIZE):
5238 for j in range(GALSIZE):
5239 if game.state.galaxy[i][j].charted:
5240 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5241 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5242 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5245 "Display the star chart."
5247 if (game.options & OPTION_AUTOSCAN):
5251 if game.lastchart < game.state.date and game.condition == "docked":
5252 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5254 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5255 if game.state.date > game.lastchart:
5256 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5257 prout(" 1 2 3 4 5 6 7 8")
5258 for i in range(GALSIZE):
5259 proutn("%d |" % (i+1))
5260 for j in range(GALSIZE):
5261 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5265 if game.state.galaxy[i][j].supernova:
5267 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5269 elif game.state.galaxy[i][j].charted:
5270 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5274 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5282 def sectscan(goodScan, i, j):
5283 "Light up an individual dot in a sector."
5284 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5285 if game.quad[i][j] in ('E', 'F'):
5288 textcolor({"green":GREEN,
5292 "dead":BROWN}[game.condition])
5294 textcolor({'?':LIGHTMAGENTA,
5300 }.get(game.quad[i][j], DEFAULT))
5301 proutn("%c " % game.quad[i][j])
5307 "Emit status report lines"
5308 if not req or req == 1:
5309 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5310 % (game.state.date, game.state.remtime))
5311 if not req or req == 2:
5312 if game.condition != "docked":
5314 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5315 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5317 prout(_(", CLOAKED"))
5318 if not req or req == 3:
5319 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5320 if not req or req == 4:
5321 if damaged(DLIFSUP):
5322 if game.condition == "docked":
5323 s = _("DAMAGED, Base provides")
5325 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5328 prstat(_("Life Support"), s)
5329 if not req or req == 5:
5330 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5331 if not req or req == 6:
5333 if game.icrystl and (game.options & OPTION_SHOWME):
5334 extra = _(" (have crystals)")
5335 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5336 if not req or req == 7:
5337 prstat(_("Torpedoes"), "%d" % (game.torps))
5338 if not req or req == 8:
5339 if damaged(DSHIELD):
5345 data = _(" %d%% %.1f units") \
5346 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5347 prstat(_("Shields"), s+data)
5348 if not req or req == 9:
5349 prstat(_("Klingons Left"), "%d" % game.unwon())
5350 if not req or req == 10:
5351 if game.options & OPTION_WORLDS:
5352 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5353 if plnet and plnet.inhabited:
5354 prstat(_("Major system"), plnet.name)
5356 prout(_("Sector is uninhabited"))
5357 elif not req or req == 11:
5358 attackreport(not req)
5361 "Request specified status data, a historical relic from slow TTYs."
5362 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5363 while scanner.nexttok() == "IHEOL":
5364 proutn(_("Information desired? "))
5366 if scanner.token in requests:
5367 status(requests.index(scanner.token))
5369 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5370 prout((" date, condition, position, lsupport, warpfactor,"))
5371 prout((" energy, torpedoes, shields, klingons, system, time."))
5376 if damaged(DSRSENS):
5377 # Allow base's sensors if docked
5378 if game.condition != "docked":
5379 prout(_(" S.R. SENSORS DAMAGED!"))
5382 prout(_(" [Using Base's sensors]"))
5384 prout(_(" Short-range scan"))
5385 if goodScan and communicating():
5386 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5387 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5388 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5389 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5390 prout(" 1 2 3 4 5 6 7 8 9 10")
5391 if game.condition != "docked":
5393 for i in range(QUADSIZE):
5394 proutn("%2d " % (i+1))
5395 for j in range(QUADSIZE):
5396 sectscan(goodScan, i, j)
5400 "Use computer to get estimated time of arrival for a warp jump."
5401 w1 = Coord(); w2 = Coord()
5403 if damaged(DCOMPTR):
5404 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5407 if scanner.nexttok() != "IHREAL":
5410 proutn(_("Destination quadrant and/or sector? "))
5411 if scanner.nexttok()!="IHREAL":
5414 w1.j = int(scanner.real-0.5)
5415 if scanner.nexttok() != "IHREAL":
5418 w1.i = int(scanner.real-0.5)
5419 if scanner.nexttok() == "IHREAL":
5420 w2.j = int(scanner.real-0.5)
5421 if scanner.nexttok() != "IHREAL":
5424 w2.i = int(scanner.real-0.5)
5426 if game.quadrant.j>w1.i:
5430 if game.quadrant.i>w1.j:
5434 if not w1.valid_quadrant() or not w2.valid_sector():
5437 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5438 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5441 prout(_("Answer \"no\" if you don't know the value:"))
5444 proutn(_("Time or arrival date? "))
5445 if scanner.nexttok()=="IHREAL":
5446 ttime = scanner.real
5447 if ttime > game.state.date:
5448 ttime -= game.state.date # Actually a star date
5449 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5450 if ttime <= 1e-10 or twarp > 10:
5451 prout(_("We'll never make it, sir."))
5458 proutn(_("Warp factor? "))
5459 if scanner.nexttok()== "IHREAL":
5461 twarp = scanner.real
5462 if twarp<1.0 or twarp > 10.0:
5466 prout(_("Captain, certainly you can give me one of these."))
5469 ttime = (10.0*dist)/twarp**2
5470 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5471 if tpower >= game.energy:
5472 prout(_("Insufficient energy, sir."))
5473 if not game.shldup or tpower > game.energy*2.0:
5476 proutn(_("New warp factor to try? "))
5477 if scanner.nexttok() == "IHREAL":
5479 twarp = scanner.real
5480 if twarp<1.0 or twarp > 10.0:
5488 prout(_("But if you lower your shields,"))
5489 proutn(_("remaining"))
5492 proutn(_("Remaining"))
5493 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5495 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5497 prout(_("Any warp speed is adequate."))
5499 prout(_("Minimum warp needed is %.2f,") % (twarp))
5500 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5501 if game.state.remtime < ttime:
5502 prout(_("Unfortunately, the Federation will be destroyed by then."))
5504 prout(_("You'll be taking risks at that speed, Captain"))
5505 if (game.isatb==1 and game.state.kscmdr == w1 and \
5506 scheduled(FSCDBAS)< ttime+game.state.date) or \
5507 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5508 prout(_("The starbase there will be destroyed by then."))
5509 proutn(_("New warp factor to try? "))
5510 if scanner.nexttok() == "IHREAL":
5512 twarp = scanner.real
5513 if twarp<1.0 or twarp > 10.0:
5521 # Code from setup.c begins here
5524 "Issue a historically correct banner."
5526 prout(_("-SUPER- STAR TREK"))
5528 # From the FORTRAN original
5529 # prout(_("Latest update-21 Sept 78"))
5535 scanner.push("emsave.trk")
5536 key = scanner.nexttok()
5538 proutn(_("File name: "))
5539 key = scanner.nexttok()
5540 if key != "IHALPHA":
5543 if '.' not in scanner.token:
5544 scanner.token += ".trk"
5546 fp = open(scanner.token, "wb")
5548 prout(_("Can't freeze game as file %s") % scanner.token)
5550 pickle.dump(game, fp)
5555 "Retrieve saved game."
5558 key = scanner.nexttok()
5560 proutn(_("File name: "))
5561 key = scanner.nexttok()
5562 if key != "IHALPHA":
5565 if '.' not in scanner.token:
5566 scanner.token += ".trk"
5568 fp = open(scanner.token, "rb")
5570 prout(_("Can't thaw game in %s") % scanner.token)
5572 game = pickle.load(fp)
5577 # I used <http://www.memory-alpha.org> to find planets
5578 # with references in ST:TOS. Earth and the Alpha Centauri
5579 # Colony have been omitted.
5581 # Some planets marked Class G and P here will be displayed as class M
5582 # because of the way planets are generated. This is a known bug.
5585 _("Andoria (Fesoan)"), # several episodes
5586 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5587 _("Vulcan (T'Khasi)"), # many episodes
5588 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5589 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5590 _("Ardana"), # TOS: "The Cloud Minders"
5591 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5592 _("Gideon"), # TOS: "The Mark of Gideon"
5593 _("Aldebaran III"), # TOS: "The Deadly Years"
5594 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5595 _("Altair IV"), # TOS: "Amok Time
5596 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5597 _("Benecia"), # TOS: "The Conscience of the King"
5598 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5599 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5600 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5601 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5602 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5603 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5604 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5605 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5606 _("Ingraham B"), # TOS: "Operation: Annihilate"
5607 _("Janus IV"), # TOS: "The Devil in the Dark"
5608 _("Makus III"), # TOS: "The Galileo Seven"
5609 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5610 _("Omega IV"), # TOS: "The Omega Glory"
5611 _("Regulus V"), # TOS: "Amok Time
5612 _("Deneva"), # TOS: "Operation -- Annihilate!"
5613 # Worlds from BSD Trek
5614 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5615 _("Beta III"), # TOS: "The Return of the Archons"
5616 _("Triacus"), # TOS: "And the Children Shall Lead",
5617 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5619 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5620 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5621 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5622 # _("Izar"), # TOS: "Whom Gods Destroy"
5623 # _("Tiburon"), # TOS: "The Way to Eden"
5624 # _("Merak II"), # TOS: "The Cloud Minders"
5625 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5626 # _("Iotia"), # TOS: "A Piece of the Action"
5630 _("S. R. Sensors"), \
5631 _("L. R. Sensors"), \
5633 _("Photon Tubes"), \
5634 _("Life Support"), \
5635 _("Warp Engines"), \
5636 _("Impulse Engines"), \
5638 _("Subspace Radio"), \
5639 _("Shuttle Craft"), \
5641 _("Navigation System"), \
5643 _("Shield Control"), \
5646 _("Cloaking Device"), \
5650 "Prepare to play, set up cosmos."
5652 # Decide how many of everything
5654 return # frozen game
5655 # Prepare the Enterprise
5656 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5658 game.state.crew = FULLCREW
5659 game.energy = game.inenrg = 5000.0
5660 game.shield = game.inshld = 2500.0
5663 game.quadrant = randplace(GALSIZE)
5664 game.sector = randplace(QUADSIZE)
5665 game.torps = game.intorps = 10
5666 game.nprobes = randrange(2, 5)
5668 for i in range(NDEVICES):
5669 game.damage[i] = 0.0
5670 # Set up assorted game parameters
5671 game.battle = Coord()
5672 game.state.date = game.indate = 100.0 * randreal(20, 51)
5673 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5674 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5675 game.isatb = game.state.nplankl = 0
5676 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5677 game.iscraft = "onship"
5682 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5684 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5686 game.state.planets = [] # Planet information
5687 game.state.baseq = [] # Base quadrant coordinates
5688 game.state.kcmdr = [] # Commander quadrant coordinates
5689 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5691 # Starchart is functional but we've never seen it
5692 game.lastchart = FOREVER
5693 # Put stars in the galaxy
5695 for i in range(GALSIZE):
5696 for j in range(GALSIZE):
5697 # Can't have more stars per quadrant than fit in one decimal digit,
5698 # if we do the chart representation will break.
5699 k = randrange(1, min(10, QUADSIZE**2/10))
5701 game.state.galaxy[i][j].stars = k
5702 # Locate star bases in galaxy
5704 prout("=== Allocating %d bases" % game.inbase)
5705 for i in range(game.inbase):
5708 w = randplace(GALSIZE)
5709 if not game.state.galaxy[w.i][w.j].starbase:
5712 # C version: for (j = i-1; j > 0; j--)
5713 # so it did them in the opposite order.
5714 for j in range(1, i):
5715 # Improved placement algorithm to spread out bases
5716 distq = (w - game.state.baseq[j]).distance()
5717 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5720 prout("=== Abandoning base #%d at %s" % (i, w))
5722 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5724 prout("=== Saving base #%d, close to #%d" % (i, j))
5728 prout("=== Placing base #%d in quadrant %s" % (i, w))
5729 game.state.baseq.append(w)
5730 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5731 # Position ordinary Klingon Battle Cruisers
5733 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5734 if klumper > MAXKLQUAD:
5738 klump = int((1.0 - r*r)*klumper)
5743 w = randplace(GALSIZE)
5744 if not game.state.galaxy[w.i][w.j].supernova and \
5745 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5747 game.state.galaxy[w.i][w.j].klingons += klump
5750 # Position Klingon Commander Ships
5751 for i in range(game.incom):
5753 w = randplace(GALSIZE)
5754 if not welcoming(w) or w in game.state.kcmdr:
5756 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5758 game.state.galaxy[w.i][w.j].klingons += 1
5759 game.state.kcmdr.append(w)
5760 # Locate planets in galaxy
5761 for i in range(game.inplan):
5763 w = randplace(GALSIZE)
5764 if game.state.galaxy[w.i][w.j].planet is None:
5768 new.crystals = "absent"
5769 if (game.options & OPTION_WORLDS) and i < NINHAB:
5770 new.pclass = "M" # All inhabited planets are class M
5771 new.crystals = "absent"
5773 new.name = systnames[i]
5774 new.inhabited = True
5776 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5778 new.crystals = "present"
5779 new.known = "unknown"
5780 new.inhabited = False
5781 game.state.galaxy[w.i][w.j].planet = new
5782 game.state.planets.append(new)
5784 for i in range(game.state.nromrem):
5785 w = randplace(GALSIZE)
5786 game.state.galaxy[w.i][w.j].romulans += 1
5787 # Place the Super-Commander if needed
5788 if game.state.nscrem > 0:
5790 w = randplace(GALSIZE)
5793 game.state.kscmdr = w
5794 game.state.galaxy[w.i][w.j].klingons += 1
5795 # Initialize times for extraneous events
5796 schedule(FSNOVA, expran(0.5 * game.intime))
5797 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5798 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5799 schedule(FBATTAK, expran(0.3*game.intime))
5801 if game.state.nscrem:
5802 schedule(FSCMOVE, 0.2777)
5807 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5808 schedule(FDISTR, expran(1.0 + game.intime))
5813 # Place thing (in tournament game, we don't want one!)
5814 # New in SST2K: never place the Thing near a starbase.
5815 # This makes sense and avoids a special case in the old code.
5817 if game.tourn is None:
5819 thing = randplace(GALSIZE)
5820 if thing not in game.state.baseq:
5823 game.state.snap = False
5824 if game.skill == SKILL_NOVICE:
5825 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5826 prout(_("a deadly Klingon invasion force. As captain of the United"))
5827 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5828 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5829 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5830 prout(_("your mission. As you proceed you may be given more time."))
5832 prout(_("You will have %d supporting starbases.") % (game.inbase))
5833 proutn(_("Starbase locations- "))
5835 prout(_("Stardate %d.") % int(game.state.date))
5837 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5838 prout(_("An unknown number of Romulans."))
5839 if game.state.nscrem:
5840 prout(_("And one (GULP) Super-Commander."))
5841 prout(_("%d stardates.") % int(game.intime))
5842 proutn(_("%d starbases in ") % game.inbase)
5843 for i in range(game.inbase):
5844 proutn(repr(game.state.baseq[i]))
5847 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5848 proutn(_(" Sector %s") % game.sector)
5850 prout(_("Good Luck!"))
5851 if game.state.nscrem:
5852 prout(_(" YOU'LL NEED IT."))
5855 setwnd(message_window)
5857 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5859 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5860 attack(torps_ok=False)
5863 "Choose your game type."
5865 game.tourn = game.length = 0
5867 game.skill = SKILL_NONE
5868 # Do not chew here, we want to use command-line tokens
5869 if not scanner.inqueue: # Can start with command line options
5870 proutn(_("Would you like a regular, tournament, or saved game? "))
5872 if scanner.sees("tournament"):
5873 while scanner.nexttok() == "IHEOL":
5874 proutn(_("Type in tournament number-"))
5875 if scanner.real == 0:
5877 continue # We don't want a blank entry
5878 game.tourn = int(round(scanner.real))
5879 random.seed(scanner.real)
5881 logfp.write("# random.seed(%d)\n" % scanner.real)
5883 if scanner.sees("saved") or scanner.sees("frozen"):
5887 if game.passwd is None:
5889 if not game.alldone:
5890 game.thawed = True # No plaque if not finished
5894 if scanner.sees("regular"):
5896 proutn(_("What is \"%s\"? ") % scanner.token)
5898 while game.length==0 or game.skill==SKILL_NONE:
5899 if scanner.nexttok() == "IHALPHA":
5900 if scanner.sees("short"):
5902 elif scanner.sees("medium"):
5904 elif scanner.sees("long"):
5906 elif scanner.sees("novice"):
5907 game.skill = SKILL_NOVICE
5908 elif scanner.sees("fair"):
5909 game.skill = SKILL_FAIR
5910 elif scanner.sees("good"):
5911 game.skill = SKILL_GOOD
5912 elif scanner.sees("expert"):
5913 game.skill = SKILL_EXPERT
5914 elif scanner.sees("emeritus"):
5915 game.skill = SKILL_EMERITUS
5917 proutn(_("What is \""))
5918 proutn(scanner.token)
5923 proutn(_("Would you like a Short, Medium, or Long game? "))
5924 elif game.skill == SKILL_NONE:
5925 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5926 # Choose game options -- added by ESR for SST2K
5927 if scanner.nexttok() != "IHALPHA":
5929 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5931 if scanner.sees("plain"):
5932 # Approximates the UT FORTRAN version.
5933 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)
5934 game.options |= OPTION_PLAIN
5935 elif scanner.sees("almy"):
5936 # Approximates Tom Almy's version.
5937 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
5938 game.options |= OPTION_ALMY
5939 elif scanner.sees("fancy") or scanner.sees("\n"):
5941 elif len(scanner.token):
5942 proutn(_("What is \"%s\"?") % scanner.token)
5944 if game.passwd == "debug":
5946 prout("=== Debug mode enabled.")
5947 # Use parameters to generate initial values of things
5948 game.damfac = 0.5 * game.skill
5949 game.inbase = randrange(BASEMIN, BASEMAX+1)
5951 if game.options & OPTION_PLANETS:
5952 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5953 if game.options & OPTION_WORLDS:
5954 game.inplan += int(NINHAB)
5955 game.state.nromrem = game.inrom = randrange(2 * game.skill)
5956 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5957 game.state.remtime = 7.0 * game.length
5958 game.intime = game.state.remtime
5959 game.inkling = int(2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15))
5960 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5961 game.state.remres = (game.inkling+4*game.incom)*game.intime
5962 game.inresor = game.state.remres
5963 if game.inkling > 50:
5967 def dropin(iquad=None):
5968 "Drop a feature on a random dot in the current quadrant."
5970 w = randplace(QUADSIZE)
5971 if game.quad[w.i][w.j] == '.':
5973 if iquad is not None:
5974 game.quad[w.i][w.j] = iquad
5978 "Update our alert status."
5979 game.condition = "green"
5980 if game.energy < 1000.0:
5981 game.condition = "yellow"
5982 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5983 game.condition = "red"
5985 game.condition="dead"
5988 "Drop new Klingon into current quadrant."
5989 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5992 "Sort enemies by distance so 'nearest' is meaningful."
5993 game.enemies.sort(key=lambda x: x.kdist)
5996 "Set up a new state of quadrant, for when we enter or re-enter it."
5999 game.neutz = game.inorbit = game.landed = False
6000 game.ientesc = game.iseenit = game.isviolreported = False
6001 # Create a blank quadrant
6002 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
6004 # Attempt to escape Super-commander, so tbeam back!
6007 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
6008 # cope with supernova
6011 game.klhere = q.klingons
6012 game.irhere = q.romulans
6014 game.quad[game.sector.i][game.sector.j] = game.ship
6017 # Position ordinary Klingons
6018 for _i in range(game.klhere):
6020 # If we need a commander, promote a Klingon
6021 for cmdr in game.state.kcmdr:
6022 if cmdr == game.quadrant:
6023 e = game.enemies[game.klhere-1]
6024 game.quad[e.location.i][e.location.j] = 'C'
6025 e.power = randreal(950,1350) + 50.0*game.skill
6027 # If we need a super-commander, promote a Klingon
6028 if game.quadrant == game.state.kscmdr:
6030 game.quad[e.location.i][e.location.j] = 'S'
6031 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
6032 game.iscate = (game.remkl() > 1)
6033 # Put in Romulans if needed
6034 for _i in range(q.romulans):
6035 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
6036 # If quadrant needs a starbase, put it in
6038 game.base = dropin('B')
6039 # If quadrant needs a planet, put it in
6041 game.iplnet = q.planet
6042 if not q.planet.inhabited:
6043 game.plnet = dropin('P')
6045 game.plnet = dropin('@')
6046 # Check for condition
6049 if game.irhere > 0 and game.klhere == 0:
6051 if not damaged(DRADIO):
6053 prout(_("LT. Uhura- \"Captain, an urgent message."))
6054 prout(_(" I'll put it on audio.\" CLICK"))
6056 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
6057 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
6058 # Put in THING if needed
6059 if thing == game.quadrant:
6060 Enemy(etype='?', loc=dropin(),
6061 power=randreal(6000,6500.0)+250.0*game.skill)
6062 if not damaged(DSRSENS):
6064 prout(_("Mr. Spock- \"Captain, this is most unusual."))
6065 prout(_(" Please examine your short-range scan.\""))
6066 # Decide if quadrant needs a Tholian; lighten up if skill is low
6067 if game.options & OPTION_THOLIAN:
6068 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
6069 (game.skill == SKILL_GOOD and withprob(0.05)) or \
6070 (game.skill > SKILL_GOOD and withprob(0.08)):
6073 w.i = withprob(0.5) * (QUADSIZE-1)
6074 w.j = withprob(0.5) * (QUADSIZE-1)
6075 if game.quad[w.i][w.j] == '.':
6077 game.tholian = Enemy(etype='T', loc=w,
6078 power=randrange(100, 500) + 25.0*game.skill)
6079 # Reserve unoccupied corners
6080 if game.quad[0][0]=='.':
6081 game.quad[0][0] = 'X'
6082 if game.quad[0][QUADSIZE-1]=='.':
6083 game.quad[0][QUADSIZE-1] = 'X'
6084 if game.quad[QUADSIZE-1][0]=='.':
6085 game.quad[QUADSIZE-1][0] = 'X'
6086 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
6087 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
6089 # And finally the stars
6090 for _i in range(q.stars):
6092 # Put in a few black holes
6093 for _i in range(1, 3+1):
6096 # Take out X's in corners if Tholian present
6098 if game.quad[0][0]=='X':
6099 game.quad[0][0] = '.'
6100 if game.quad[0][QUADSIZE-1]=='X':
6101 game.quad[0][QUADSIZE-1] = '.'
6102 if game.quad[QUADSIZE-1][0]=='X':
6103 game.quad[QUADSIZE-1][0] = '.'
6104 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
6105 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
6106 # This should guarantee that replay games don't lose info about the chart
6107 if (game.options & OPTION_AUTOSCAN) or replayfp:
6111 "Set the self-destruct password."
6112 if game.options & OPTION_PLAIN:
6115 proutn(_("Please type in a secret password- "))
6117 game.passwd = scanner.token
6118 if game.passwd != None:
6122 game.passwd += chr(ord('a')+randrange(26))
6123 game.passwd += chr(ord('a')+randrange(26))
6124 game.passwd += chr(ord('a')+randrange(26))
6126 # Code from sst.c begins here
6129 ("SRSCAN", OPTION_TTY),
6130 ("STATUS", OPTION_TTY),
6131 ("REQUEST", OPTION_TTY),
6132 ("LRSCAN", OPTION_TTY),
6144 ("SENSORS", OPTION_PLANETS),
6145 ("ORBIT", OPTION_PLANETS),
6146 ("TRANSPORT", OPTION_PLANETS),
6147 ("MINE", OPTION_PLANETS),
6148 ("CRYSTALS", OPTION_PLANETS),
6149 ("SHUTTLE", OPTION_PLANETS),
6150 ("PLANETS", OPTION_PLANETS),
6155 ("PROBE", OPTION_PROBE),
6157 ("FREEZE", 0), # Synonym for SAVE
6161 ("CAPTURE", OPTION_CAPTURE),
6162 ("CLOAK", OPTION_CLOAK),
6165 ("SOS", 0), # Synonym for MAYDAY
6166 ("CALL", 0), # Synonym for MAYDAY
6175 "Generate a list of legal commands."
6176 prout(_("LEGAL COMMANDS ARE:"))
6178 for (key, opt) in commands:
6179 if not opt or (opt & game.options):
6180 proutn("%-12s " % key)
6182 if emitted % 5 == 4:
6187 "Browse on-line help."
6188 key = scanner.nexttok()
6191 setwnd(prompt_window)
6192 proutn(_("Help on what command? "))
6193 key = scanner.nexttok()
6194 setwnd(message_window)
6197 cmds = [x[0] for x in commands]
6198 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
6205 cmd = scanner.token.upper()
6206 for directory in docpath:
6208 fp = open(os.path.join(directory, "sst.doc"), "r")
6213 prout(_("Spock- \"Captain, that information is missing from the"))
6214 prout(_(" computer. You need to find sst.doc and put it somewhere"))
6215 proutn(_(" in these directories: %s") % ":".join(docpath))
6217 # This used to continue: "You need to find SST.DOC and put
6218 # it in the current directory."
6221 linebuf = fp.readline()
6223 prout(_("Spock- \"Captain, there is no information on that command.\""))
6226 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
6227 linebuf = linebuf[3:].strip()
6228 if cmd.upper() == linebuf:
6231 prout(_("Spock- \"Captain, I've found the following information:\""))
6234 linebuf = fp.readline()
6235 if "******" in linebuf:
6241 "Command-interpretation loop."
6243 if game.irhere and game.state.date >= ALGERON and not game.isviolreported and game.iscloaked:
6244 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
6246 game.isviolreported = True
6247 while True: # command loop
6249 while True: # get a command
6251 game.optime = game.justin = False
6253 setwnd(prompt_window)
6256 if scanner.nexttok() == "IHEOL":
6257 if game.options & OPTION_CURSES:
6260 elif scanner.token == "":
6264 setwnd(message_window)
6266 abandon_passed = False
6267 cmd = "" # Force cmd to persist after loop
6268 opt = 0 # Force opt to persist after loop
6269 for (cmd, opt) in commands:
6270 # commands after ABANDON cannot be abbreviated
6271 if cmd == "ABANDON":
6272 abandon_passed = True
6273 if cmd == scanner.token.upper() or (not abandon_passed \
6274 and cmd.startswith(scanner.token.upper())):
6279 elif opt and not (opt & game.options):
6283 if game.options & OPTION_CURSES:
6284 prout("COMMAND> %s" % cmd)
6285 if cmd == "SRSCAN": # srscan
6287 elif cmd == "STATUS": # status
6289 elif cmd == "REQUEST": # status request
6291 elif cmd == "LRSCAN": # long range scan
6292 lrscan(silent=False)
6293 elif cmd == "PHASERS": # phasers
6298 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6303 elif cmd == "MOVE": # move under warp
6304 warp(wcourse=None, involuntary=False)
6305 elif cmd == "SHIELDS": # shields
6306 doshield(shraise=False)
6309 game.shldchg = False
6310 elif cmd == "DOCK": # dock at starbase
6313 attack(torps_ok=False)
6314 elif cmd == "DAMAGES": # damage reports
6316 elif cmd == "CHART": # chart
6318 elif cmd == "IMPULSE": # impulse
6320 elif cmd == "REST": # rest
6324 elif cmd == "WARP": # warp
6326 elif cmd == "SENSORS": # sensors
6328 elif cmd == "ORBIT": # orbit
6332 elif cmd == "TRANSPORT": # transport "beam"
6334 elif cmd == "MINE": # mine
6338 elif cmd == "CRYSTALS": # crystals
6342 elif cmd == "SHUTTLE": # shuttle
6346 elif cmd == "PLANETS": # Planet list
6348 elif cmd == "REPORT": # Game Report
6350 elif cmd == "COMPUTER": # use COMPUTER!
6352 elif cmd == "COMMANDS":
6354 elif cmd == "EMEXIT": # Emergency exit
6355 clrscr() # Hide screen
6356 freeze(True) # forced save
6357 raise SystemExit(1) # And quick exit
6358 elif cmd == "PROBE":
6359 probe() # Launch probe
6362 elif cmd == "ABANDON": # Abandon Ship
6364 elif cmd == "DESTRUCT": # Self Destruct
6366 elif cmd == "SAVE": # Save Game
6369 if game.skill > SKILL_GOOD:
6370 prout(_("WARNING--Saved games produce no plaques!"))
6371 elif cmd == "DEATHRAY": # Try a desparation measure
6375 elif cmd == "CAPTURE":
6377 elif cmd == "CLOAK":
6379 elif cmd == "DEBUGCMD": # What do we want for debug???
6381 elif cmd == "MAYDAY": # Call for help
6386 game.alldone = True # quit the game
6389 elif cmd == "SCORE":
6390 score() # see current score
6391 elif cmd == "CURSES":
6392 game.options |= (OPTION_CURSES | OPTION_COLOR)
6396 break # Game has ended
6397 if game.optime != 0.0:
6400 break # Events did us in
6401 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6404 if hitme and not game.justin:
6405 attack(torps_ok=True)
6408 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6419 "Emit the name of an enemy or feature."
6420 if ch == 'R': s = _("Romulan")
6421 elif ch == 'K': s = _("Klingon")
6422 elif ch == 'C': s = _("Commander")
6423 elif ch == 'S': s = _("Super-commander")
6424 elif ch == '*': s = _("Star")
6425 elif ch == 'P': s = _("Planet")
6426 elif ch == 'B': s = _("Starbase")
6427 elif ch == ' ': s = _("Black hole")
6428 elif ch == 'T': s = _("Tholian")
6429 elif ch == '#': s = _("Tholian web")
6430 elif ch == '?': s = _("Stranger")
6431 elif ch == '@': s = _("Inhabited World")
6432 else: s = "Unknown??"
6435 def crmena(loud, enemy, loctype, w):
6436 "Emit the name of an enemy and his location."
6440 buf += cramen(enemy) + _(" at ")
6441 if loctype == "quadrant":
6442 buf += _("Quadrant ")
6443 elif loctype == "sector":
6445 return buf + repr(w)
6448 "Emit our ship name."
6449 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6452 "Emit a line of stars"
6453 prouts("******************************************************")
6457 return -avrage*math.log(1e-7 + randreal())
6459 def randplace(size):
6460 "Choose a random location."
6462 w.i = randrange(size)
6463 w.j = randrange(size)
6473 # Get a token from the user
6476 # Fill the token quue if nothing here
6477 while not self.inqueue:
6479 if curwnd==prompt_window:
6481 setwnd(message_window)
6488 self.inqueue = sline.lstrip().split() + ["\n"]
6489 # From here on in it's all looking at the queue
6490 self.token = self.inqueue.pop(0)
6491 if self.token == "\n":
6495 self.real = float(self.token)
6496 self.type = "IHREAL"
6501 self.token = self.token.lower()
6502 self.type = "IHALPHA"
6505 def append(self, tok):
6506 self.inqueue.append(tok)
6507 def push(self, tok):
6508 self.inqueue.insert(0, tok)
6512 # Demand input for next scan
6514 self.real = self.token = None
6516 # compares s to item and returns true if it matches to the length of s
6517 return s.startswith(self.token)
6519 # Round token value to nearest integer
6520 return int(round(self.real))
6524 if self.type != "IHREAL":
6529 if self.type != "IHREAL":
6535 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6538 "Yes-or-no confirmation."
6542 if scanner.token == 'y':
6544 if scanner.token == 'n':
6547 proutn(_("Please answer with \"y\" or \"n\": "))
6550 "Complain about unparseable input."
6553 prout(_("Beg your pardon, Captain?"))
6556 "Access to the internals for debugging."
6557 proutn("Reset levels? ")
6559 if game.energy < game.inenrg:
6560 game.energy = game.inenrg
6561 game.shield = game.inshld
6562 game.torps = game.intorps
6563 game.lsupres = game.inlsr
6564 proutn("Reset damage? ")
6566 for i in range(NDEVICES):
6567 if game.damage[i] > 0.0:
6568 game.damage[i] = 0.0
6569 proutn("Toggle debug flag? ")
6571 game.idebug = not game.idebug
6573 prout("Debug output ON")
6575 prout("Debug output OFF")
6576 proutn("Cause selective damage? ")
6578 for i in range(NDEVICES):
6579 proutn("Kill %s?" % device[i])
6581 key = scanner.nexttok()
6582 if key == "IHALPHA" and scanner.sees("y"):
6583 game.damage[i] = 10.0
6584 proutn("Examine/change events? ")
6589 FSNOVA: "Supernova ",
6592 FBATTAK: "Base Attack ",
6593 FCDBAS: "Base Destroy ",
6594 FSCMOVE: "SC Move ",
6595 FSCDBAS: "SC Base Destroy ",
6596 FDSPROB: "Probe Move ",
6597 FDISTR: "Distress Call ",
6598 FENSLV: "Enslavement ",
6599 FREPRO: "Klingon Build ",
6601 for i in range(1, NEVENTS):
6604 proutn("%.2f" % (scheduled(i)-game.state.date))
6605 if i == FENSLV or i == FREPRO:
6607 proutn(" in %s" % ev.quadrant)
6612 key = scanner.nexttok()
6616 elif key == "IHREAL":
6617 ev = schedule(i, scanner.real)
6618 if i == FENSLV or i == FREPRO:
6620 proutn("In quadrant- ")
6621 key = scanner.nexttok()
6622 # "IHEOL" says to leave coordinates as they are
6625 prout("Event %d canceled, no x coordinate." % (i))
6628 w.i = int(round(scanner.real))
6629 key = scanner.nexttok()
6631 prout("Event %d canceled, no y coordinate." % (i))
6634 w.j = int(round(scanner.real))
6637 proutn("Induce supernova here? ")
6639 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6642 if __name__ == '__main__':
6644 #global line, thing, game
6648 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6649 if os.getenv("TERM"):
6650 game.options |= OPTION_CURSES
6652 game.options |= OPTION_TTY
6653 seed = int(time.time())
6654 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6656 for (switch, val) in options:
6659 replayfp = open(val, "r")
6661 sys.stderr.write("sst: can't open replay file %s\n" % val)
6664 line = replayfp.readline().strip()
6665 (leader, __, seed) = line.split()
6667 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6668 line = replayfp.readline().strip()
6669 arguments += line.split()[2:]
6672 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6674 game.options |= OPTION_TTY
6675 game.options &=~ OPTION_CURSES
6676 elif switch == '-s':
6678 elif switch == '-t':
6679 game.options |= OPTION_TTY
6680 game.options &=~ OPTION_CURSES
6681 elif switch == '-x':
6683 elif switch == '-V':
6684 print("SST2K", version)
6687 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6689 # where to save the input in case of bugs
6690 if "TMPDIR" in os.environ:
6691 tmpdir = os.environ['TMPDIR']
6695 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6697 sys.stderr.write("sst: warning, can't open logfile\n")
6700 logfp.write("# seed %s\n" % seed)
6701 logfp.write("# options %s\n" % " ".join(arguments))
6702 logfp.write("# SST2K version %s\n" % version)
6703 logfp.write("# recorded by %s@%s on %s\n" % \
6704 (getpass.getuser(),socket.gethostname(),time.ctime()))
6706 scanner = sstscanner()
6707 for arg in arguments:
6711 while True: # Play a game
6712 setwnd(fullscreen_window)
6718 game.alldone = False
6726 if game.tourn and game.alldone:
6727 proutn(_("Do you want your score recorded?"))
6733 proutn(_("Do you want to play again? "))
6737 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6741 except KeyboardInterrupt: