3 sst.py -- Super Star Trek 2K
5 SST2K is a Python translation of a C translation of a FORTRAN
6 original dating back to 1973. Beautiful Python it is not, but it
7 works. Translation by Eric S. Raymond; original game by David Matuszek
8 and Paul Reynolds, with modifications by Don Smith, Tom Almy,
9 Stas Sergeev, and Eric S. Raymond.
11 See the doc/HACKING file in the distribution for designers notes and advice
12 on how to modify (and how not to modify!) this code.
14 import os, sys, math, curses, time, pickle, random, copy, gettext, getpass
15 import getopt, socket, locale
17 # This import only works on Unixes. The intention is to enable
18 # Ctrl-P, Ctrl-N, and friends in Cmd.
24 # Prevent lossage under Python 3
33 docpath = (".", "doc/", "/usr/share/doc/sst/")
36 return gettext.gettext(st)
38 GALSIZE = 8 # Galaxy size in quadrants
39 NINHAB = (GALSIZE * GALSIZE // 2) # Number of inhabited worlds
40 MAXUNINHAB = 10 # Maximum uninhabited worlds
41 QUADSIZE = 10 # Quadrant size in sectors
42 BASEMIN = 2 # Minimum starbases
43 BASEMAX = (GALSIZE * GALSIZE // 12) # Maximum starbases
44 MAXKLGAME = 127 # Maximum Klingons per game
45 MAXKLQUAD = 9 # Maximum Klingons per quadrant
46 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
47 FOREVER = 1e30 # Time for the indefinite future
48 MAXBURST = 3 # Max # of torps you can launch in one turn
49 MINCMDR = 10 # Minimum number of Klingon commanders
50 DOCKFAC = 0.25 # Repair faster when docked
51 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
53 ALGERON = 2311 # Date of the Treaty of Algeron
74 class TrekError(Exception):
77 class JumpOut(Exception):
81 def __init__(self, x=None, y=None):
84 def valid_quadrant(self):
85 return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
86 def valid_sector(self):
87 return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
89 self.i = self.j = None
91 return self.i != None and self.j != None
92 def __eq__(self, other):
93 return other != None and self.i == other.i and self.j == other.j
94 def __ne__(self, other):
95 return other is None or self.i != other.i or self.j != other.j
96 def __add__(self, other):
97 return Coord(self.i+other.i, self.j+other.j)
98 def __sub__(self, other):
99 return Coord(self.i-other.i, self.j-other.j)
100 def __mul__(self, other):
101 return Coord(self.i*other, self.j*other)
102 def __rmul__(self, other):
103 return Coord(self.i*other, self.j*other)
104 def __div__(self, other):
105 return Coord(self.i/other, self.j/other)
106 def __mod__(self, other):
107 return Coord(self.i % other, self.j % other)
108 def __rdiv__(self, other):
109 return Coord(self.i/other, self.j/other)
110 def roundtogrid(self):
111 return Coord(int(round(self.i)), int(round(self.j)))
112 def distance(self, other=None):
115 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
117 return 1.90985*math.atan2(self.j, self.i)
123 s.i = self.i / abs(self.i)
127 s.j = self.j / abs(self.j)
130 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
131 return self.roundtogrid() / QUADSIZE
133 return self.roundtogrid() % QUADSIZE
136 s.i = self.i + randrange(-1, 2)
137 s.j = self.j + randrange(-1, 2)
140 if self.i is None or self.j is None:
142 return "%s - %s" % (self.i+1, self.j+1)
146 "Do not anger the Space Thingy!"
153 return (q.i, q.j) == (self.i, self.j)
157 self.name = None # string-valued if inhabited
158 self.quadrant = Coord() # quadrant located
159 self.pclass = None # could be ""M", "N", "O", or "destroyed"
160 self.crystals = "absent"# could be "mined", "present", "absent"
161 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
162 self.inhabited = False # is it inhabited?
170 self.starbase = False
173 self.supernova = False
175 self.status = "secure" # Could be "secure", "distressed", "enslaved"
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.remkl = 0 # remaining klingons
199 self.nscrem = 0 # remaining super commanders
200 self.starkl = 0 # destroyed stars
201 self.basekl = 0 # destroyed bases
202 self.nromrem = 0 # Romulans remaining
203 self.nplankl = 0 # destroyed uninhabited planets
204 self.nworldkl = 0 # destroyed inhabited planets
205 self.planets = [] # Planet information
206 self.date = 0.0 # stardate
207 self.remres = 0 # remaining resources
208 self.remtime = 0 # remaining time
209 self.baseq = [] # Base quadrant coordinates
210 self.kcmdr = [] # Commander quadrant coordinates
211 self.kscmdr = Coord() # Supercommander quadrant coordinates
213 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
215 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
219 self.date = None # A real number
220 self.quadrant = None # A coord structure
223 OPTION_ALL = 0xffffffff
224 OPTION_TTY = 0x00000001 # old interface
225 OPTION_CURSES = 0x00000002 # new interface
226 OPTION_IOMODES = 0x00000003 # cover both interfaces
227 OPTION_PLANETS = 0x00000004 # planets and mining
228 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
229 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
230 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
231 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
232 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
233 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
234 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
235 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
236 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
237 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
238 OPTION_CAPTURE = 0x00002000 # Enable BSD-Trek capture (Almy, 2013).
239 OPTION_CLOAK = 0x80004000 # Enable BSD-Trek capture (Almy, 2013).
240 OPTION_PLAIN = 0x01000000 # user chose plain game
241 OPTION_ALMY = 0x02000000 # user chose Almy variant
242 OPTION_COLOR = 0x04000000 # enable color display (ESR, 2010)
262 NDEVICES = 17 # Number of devices
272 return (game.damage[dev] != 0.0)
274 return not damaged(DRADIO) or game.condition=="docked"
276 # Define future events
277 FSPY = 0 # Spy event happens always (no future[] entry)
278 # can cause SC to tractor beam Enterprise
279 FSNOVA = 1 # Supernova
280 FTBEAM = 2 # Commander tractor beams Enterprise
281 FSNAP = 3 # Snapshot for time warp
282 FBATTAK = 4 # Commander attacks base
283 FCDBAS = 5 # Commander destroys base
284 FSCMOVE = 6 # Supercommander moves (might attack base)
285 FSCDBAS = 7 # Supercommander destroys base
286 FDSPROB = 8 # Move deep space probe
287 FDISTR = 9 # Emit distress call from an inhabited world
288 FENSLV = 10 # Inhabited word is enslaved */
289 FREPRO = 11 # Klingons build a ship in an enslaved system
292 # Abstract out the event handling -- underlying data structures will change
293 # when we implement stateful events
294 def findevent(evtype):
295 return game.future[evtype]
298 def __init__(self, etype=None, loc=None, power=None):
300 self.location = Coord()
305 self.power = power # enemy energy level
306 game.enemies.append(self)
308 motion = (loc != self.location)
309 if self.location.i is not None and self.location.j is not None:
312 game.quad[self.location.i][self.location.j] = '#'
314 game.quad[self.location.i][self.location.j] = '.'
316 self.location = copy.copy(loc)
317 game.quad[self.location.i][self.location.j] = self.type
318 self.kdist = self.kavgd = (game.sector - loc).distance()
320 self.location = Coord()
321 self.kdist = self.kavgd = None
322 game.enemies.remove(self)
325 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
329 self.options = None # Game options
330 self.state = Snapshot() # A snapshot structure
331 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
332 self.quad = None # contents of our quadrant
333 self.damage = [0.0] * NDEVICES # damage encountered
334 self.future = [] # future events
338 self.future.append(Event())
339 self.passwd = None # Self Destruct password
341 self.quadrant = None # where we are in the large
342 self.sector = None # where we are in the small
343 self.tholian = None # Tholian enemy object
344 self.base = None # position of base in current quadrant
345 self.battle = None # base coordinates being attacked
346 self.plnet = None # location of planet in quadrant
347 self.gamewon = False # Finished!
348 self.ididit = False # action taken -- allows enemy to attack
349 self.alive = False # we are alive (not killed)
350 self.justin = False # just entered quadrant
351 self.shldup = False # shields are up
352 self.shldchg = False # shield is changing (affects efficiency)
353 self.iscate = False # super commander is here
354 self.ientesc = False # attempted escape from supercommander
355 self.resting = False # rest time
356 self.icraft = False # Kirk in Galileo
357 self.landed = False # party on planet (true), on ship (false)
358 self.alldone = False # game is now finished
359 self.neutz = False # Romulan Neutral Zone
360 self.isarmed = False # probe is armed
361 self.inorbit = False # orbiting a planet
362 self.imine = False # mining
363 self.icrystl = False # dilithium crystals aboard
364 self.iseenit = False # seen base attack report
365 self.thawed = False # thawed game
366 self.condition = None # "green", "yellow", "red", "docked", "dead"
367 self.iscraft = None # "onship", "offship", "removed"
368 self.skill = None # Player skill level
369 self.inkling = 0 # initial number of klingons
370 self.inbase = 0 # initial number of bases
371 self.incom = 0 # initial number of commanders
372 self.inscom = 0 # initial number of commanders
373 self.inrom = 0 # initial number of commanders
374 self.instar = 0 # initial stars
375 self.intorps = 0 # initial/max torpedoes
376 self.torps = 0 # number of torpedoes
377 self.ship = 0 # ship type -- 'E' is Enterprise
378 self.abandoned = 0 # count of crew abandoned in space
379 self.length = 0 # length of game
380 self.klhere = 0 # klingons here
381 self.casual = 0 # causalties
382 self.nhelp = 0 # calls for help
383 self.nkinks = 0 # count of energy-barrier crossings
384 self.iplnet = None # planet # in quadrant
385 self.inplan = 0 # initial planets
386 self.irhere = 0 # Romulans in quadrant
387 self.isatb = 0 # =2 if super commander is attacking base
388 self.tourn = None # tournament number
389 self.nprobes = 0 # number of probes available
390 self.inresor = 0.0 # initial resources
391 self.intime = 0.0 # initial time
392 self.inenrg = 0.0 # initial/max energy
393 self.inshld = 0.0 # initial/max shield
394 self.inlsr = 0.0 # initial life support resources
395 self.indate = 0.0 # initial date
396 self.energy = 0.0 # energy level
397 self.shield = 0.0 # shield level
398 self.warpfac = 0.0 # warp speed
399 self.lsupres = 0.0 # life support reserves
400 self.optime = 0.0 # time taken by current operation
401 self.damfac = 0.0 # damage factor
402 self.lastchart = 0.0 # time star chart was last updated
403 self.cryprob = 0.0 # probability that crystal will work
404 self.probe = None # object holding probe course info
405 self.height = 0.0 # height of orbit around planet
406 self.score = 0.0 # overall score
407 self.perdate = 0.0 # rate of kills
408 self.idebug = False # Debugging instrumentation enabled?
409 self.statekscmdr = None # No SuperCommander coordinates yet.
410 self.brigcapacity = 400 # Enterprise brig capacity
411 self.brigfree = 400 # How many klingons can we put in the brig?
412 self.kcaptured = 0 # Total Klingons captured, for scoring.
413 self.iscloaked = False # Cloaking device on?
414 self.ncviol = 0 # Algreon treaty violations
415 self.isviolreported = False # We have been warned
417 # Stas thinks this should be (C expression):
418 # game.state.remkl + len(game.state.kcmdr) > 0 ?
419 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
420 # He says the existing expression is prone to divide-by-zero errors
421 # after killing the last klingon when score is shown -- perhaps also
422 # if the only remaining klingon is SCOM.
423 self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.state.kcmdr))
450 return random.random() < p
452 def randrange(*args):
453 return random.randrange(*args)
458 v *= args[0] # from [0, args[0])
460 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
463 # Code from ai.c begins here
466 "Would this quadrant welcome another Klingon?"
467 return iq.valid_quadrant() and \
468 not game.state.galaxy[iq.i][iq.j].supernova and \
469 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
471 def tryexit(enemy, look, irun):
472 "A bad guy attempts to bug out."
474 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
475 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
476 if not welcoming(iq):
478 if enemy.type == 'R':
479 return False # Romulans cannot escape!
481 # avoid intruding on another commander's territory
482 if enemy.type == 'C':
483 if iq in game.state.kcmdr:
485 # refuse to leave if currently attacking starbase
486 if game.battle == game.quadrant:
488 # don't leave if over 1000 units of energy
489 if enemy.power > 1000.0:
491 oldloc = copy.copy(enemy.location)
492 # handle local matters related to escape
495 if game.condition != "docked":
497 # Handle global matters related to escape
498 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
499 game.state.galaxy[iq.i][iq.j].klingons += 1
500 if enemy.type == 'S':
504 schedule(FSCMOVE, 0.2777)
506 game.state.kscmdr = iq
508 for cmdr in game.state.kcmdr:
509 if cmdr == game.quadrant:
510 game.state.kcmdr.append(iq)
512 # report move out of quadrant.
513 return [(True, enemy, oldloc, iq)]
515 # The bad-guy movement algorithm:
517 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
518 # If both are operating full strength, force is 1000. If both are damaged,
519 # force is -1000. Having shields down subtracts an additional 1000.
521 # 2. Enemy has forces equal to the energy of the attacker plus
522 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
523 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
525 # Attacker Initial energy levels (nominal):
526 # Klingon Romulan Commander Super-Commander
527 # Novice 400 700 1200
529 # Good 450 800 1300 1750
530 # Expert 475 850 1350 1875
531 # Emeritus 500 900 1400 2000
532 # VARIANCE 75 200 200 200
534 # Enemy vessels only move prior to their attack. In Novice - Good games
535 # only commanders move. In Expert games, all enemy vessels move if there
536 # is a commander present. In Emeritus games all enemy vessels move.
538 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
539 # forces are 1000 greater than Enterprise.
541 # Agressive action on average cuts the distance between the ship and
542 # the enemy to 1/4 the original.
544 # 4. At lower energy advantage, movement units are proportional to the
545 # advantage with a 650 advantage being to hold ground, 800 to move forward
546 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
548 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
549 # retreat, especially at high skill levels.
551 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
553 def movebaddy(enemy):
554 "Tactical movement for the bad guys."
558 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
559 if game.skill >= SKILL_EXPERT:
560 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
562 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
563 old_dist = enemy.kdist
564 mdist = int(old_dist + 0.5) # Nearest integer distance
565 # If SC, check with spy to see if should hi-tail it
566 if enemy.type == 'S' and \
567 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
571 # decide whether to advance, retreat, or hold position
572 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
574 forces += 1000 # Good for enemy if shield is down!
575 if not damaged(DPHASER) or not damaged(DPHOTON):
576 if damaged(DPHASER): # phasers damaged
579 forces -= 0.2*(game.energy - 2500.0)
580 if damaged(DPHOTON): # photon torpedoes damaged
583 forces -= 50.0*game.torps
585 # phasers and photon tubes both out!
588 if forces <= 1000.0 and game.condition != "docked": # Typical situation
589 motion = ((forces + randreal(200))/150.0) - 5.0
591 if forces > 1000.0: # Very strong -- move in for kill
592 motion = (1.0 - randreal())**2 * old_dist + 1.0
593 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
594 motion -= game.skill*(2.0-randreal()**2)
596 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
597 # don't move if no motion
600 # Limit motion according to skill
601 if abs(motion) > game.skill:
606 # calculate preferred number of steps
607 nsteps = abs(int(motion))
608 if motion > 0 and nsteps > mdist:
609 nsteps = mdist # don't overshoot
610 if nsteps > QUADSIZE:
611 nsteps = QUADSIZE # This shouldn't be necessary
613 nsteps = 1 # This shouldn't be necessary
615 proutn("NSTEPS = %d:" % nsteps)
616 # Compute preferred values of delta X and Y
617 m = game.sector - enemy.location
618 if 2.0 * abs(m.i) < abs(m.j):
620 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
622 m = (motion * m).sgn()
623 goto = enemy.location
625 for ll in range(nsteps):
627 proutn(" %d" % (ll+1))
628 # Check if preferred position available
639 attempts = 0 # Settle mysterious hang problem
640 while attempts < 20 and not success:
642 if look.i < 0 or look.i >= QUADSIZE:
644 return tryexit(enemy, look, irun)
645 if krawli == m.i or m.j == 0:
647 look.i = goto.i + krawli
649 elif look.j < 0 or look.j >= QUADSIZE:
651 return tryexit(enemy, look, irun)
652 if krawlj == m.j or m.i == 0:
654 look.j = goto.j + krawlj
656 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
657 # See if enemy should ram ship
658 if game.quad[look.i][look.j] == game.ship and \
659 (enemy.type == 'C' or enemy.type == 'S'):
660 collision(rammed=True, enemy=enemy)
662 if krawli != m.i and m.j != 0:
663 look.i = goto.i + krawli
665 elif krawlj != m.j and m.i != 0:
666 look.j = goto.j + krawlj
669 break # we have failed
680 # Enemy moved, but is still in sector
681 return [(False, enemy, old_dist, goto)]
684 "Sequence Klingon tactical movement."
687 # Figure out which Klingon is the commander (or Supercommander)
690 if game.quadrant in game.state.kcmdr:
691 for enemy in game.enemies:
692 if enemy.type == 'C':
693 tacmoves += movebaddy(enemy)
694 if game.state.kscmdr == game.quadrant:
695 for enemy in game.enemies:
696 if enemy.type == 'S':
697 tacmoves += movebaddy(enemy)
699 # If skill level is high, move other Klingons and Romulans too!
700 # Move these last so they can base their actions on what the
702 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
703 for enemy in game.enemies:
704 if enemy.type in ('K', 'R'):
705 tacmoves += movebaddy(enemy)
708 def movescom(iq, avoid):
709 "Commander movement helper."
710 # Avoid quadrants with bases if we want to avoid Enterprise
711 if not welcoming(iq) or (avoid and iq in game.state.baseq):
713 if game.justin and not game.iscate:
716 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
717 game.state.kscmdr = iq
718 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
719 if game.state.kscmdr == game.quadrant:
720 # SC has scooted, remove him from current quadrant
725 for enemy in game.enemies:
726 if enemy.type == 'S':
729 if game.condition != "docked":
732 # check for a helpful planet
733 for i in range(game.inplan):
734 if game.state.planets[i].quadrant == game.state.kscmdr and \
735 game.state.planets[i].crystals == "present":
737 game.state.planets[i].pclass = "destroyed"
738 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
741 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
742 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
743 prout(_(" by the Super-commander.\""))
745 return True # looks good!
747 def supercommander():
748 "Move the Super Commander."
755 prout("== SUPERCOMMANDER")
756 # Decide on being active or passive
757 avoid = ((game.incom - len(game.state.kcmdr) + game.inkling - game.state.remkl)/(game.state.date+0.01-game.indate) < 0.1*game.skill*(game.skill+1.0) or \
758 (game.state.date-game.indate) < 3.0)
759 if not game.iscate and avoid:
760 # compute move away from Enterprise
761 idelta = game.state.kscmdr-game.quadrant
762 if idelta.distance() > 2.0:
764 idelta.i = game.state.kscmdr.j-game.quadrant.j
765 idelta.j = game.quadrant.i-game.state.kscmdr.i
767 # compute distances to starbases
768 if not game.state.baseq:
772 sc = game.state.kscmdr
773 for (i, base) in enumerate(game.state.baseq):
774 basetbl.append((i, (base - sc).distance()))
775 if game.state.baseq > 1:
776 basetbl.sort(key=lambda x: x[1])
777 # look for nearest base without a commander, no Enterprise, and
778 # without too many Klingons, and not already under attack.
779 ifindit = iwhichb = 0
780 for (i2, base) in enumerate(game.state.baseq):
781 i = basetbl[i2][0] # bug in original had it not finding nearest
782 if base == game.quadrant or base == game.battle or not welcoming(base):
784 # if there is a commander, and no other base is appropriate,
785 # we will take the one with the commander
786 for cmdr in game.state.kcmdr:
787 if base == cmdr and ifindit != 2:
791 else: # no commander -- use this one
796 return # Nothing suitable -- wait until next time
797 ibq = game.state.baseq[iwhichb]
798 # decide how to move toward base
799 idelta = ibq - game.state.kscmdr
800 # Maximum movement is 1 quadrant in either or both axes
801 idelta = idelta.sgn()
802 # try moving in both x and y directions
803 # there was what looked like a bug in the Almy C code here,
804 # but it might be this translation is just wrong.
805 iq = game.state.kscmdr + idelta
806 if not movescom(iq, avoid):
807 # failed -- try some other maneuvers
808 if idelta.i == 0 or idelta.j == 0:
811 iq.j = game.state.kscmdr.j + 1
812 if not movescom(iq, avoid):
813 iq.j = game.state.kscmdr.j - 1
816 iq.i = game.state.kscmdr.i + 1
817 if not movescom(iq, avoid):
818 iq.i = game.state.kscmdr.i - 1
821 # try moving just in x or y
822 iq.j = game.state.kscmdr.j
823 if not movescom(iq, avoid):
824 iq.j = game.state.kscmdr.j + idelta.j
825 iq.i = game.state.kscmdr.i
828 if len(game.state.baseq) == 0:
831 for ibq in game.state.baseq:
832 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
835 return # no, don't attack base!
838 schedule(FSCDBAS, randreal(1.0, 3.0))
839 if is_scheduled(FCDBAS):
840 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
841 if not communicating():
845 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
847 prout(_(" reports that it is under attack from the Klingon Super-commander."))
848 proutn(_(" It can survive until stardate %d.\"") \
849 % int(scheduled(FSCDBAS)))
852 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
856 game.optime = 0.0 # actually finished
858 # Check for intelligence report
859 if not game.idebug and \
861 (not communicating()) or \
862 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
865 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
866 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
871 if not game.tholian or game.justin:
874 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
877 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
880 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
883 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
887 # something is wrong!
888 game.tholian.move(None)
889 prout("***Internal error: Tholian in a bad spot.")
891 # do nothing if we are blocked
892 if game.quad[tid.i][tid.j] not in ('.', '#'):
894 here = copy.copy(game.tholian.location)
895 delta = (tid - game.tholian.location).sgn()
897 while here.i != tid.i:
899 if game.quad[here.i][here.j] == '.':
900 game.tholian.move(here)
902 while here.j != tid.j:
904 if game.quad[here.i][here.j] == '.':
905 game.tholian.move(here)
906 # check to see if all holes plugged
907 for i in range(QUADSIZE):
908 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
910 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
912 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
914 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
916 # All plugged up -- Tholian splits
917 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
919 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
920 game.tholian.move(None)
923 # Code from battle.c begins here
926 "Change cloaking-device status."
928 prout(_("Ye Faerie Queene hath no cloaking device."));
931 key = scanner.nexttok()
938 if scanner.sees("on"):
940 prout(_("The cloaking device has already been switched on."))
943 elif scanner.sees("off"):
944 if not game.iscloaked:
945 prout(_("The cloaking device has already been switched off."))
952 if not game.iscloaked:
953 proutn(_("Switch cloaking device on? "))
958 proutn(_("Switch cloaking device off? "))
965 if action == "CLOFF":
966 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
967 prout(_("Spock- \"Captain, the Treaty of Algeron is in effect.\n Are you sure this is wise?\""))
970 prout("Engineer Scott- \"Aye, Sir.\"");
971 game.iscloaked = False;
972 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
973 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
975 game.isviolreported = True
977 #if (neutz and game.state.date >= ALGERON) finish(FCLOAK);
982 prout(_("Engineer Scott- \"The cloaking device is damaged, Sir.\""))
985 if game.condition == "docked":
986 prout(_("You cannot cloak while docked."))
988 if game.state.date >= ALGERON and not game.isviolreported:
989 prout(_("Spock- \"Captain, using the cloaking device is a violation"))
990 prout(_(" of the Treaty of Algeron. Considering the alternatives,"))
991 proutn(_(" are you sure this is wise? "))
994 prout(_("Engineer Scott- \"Cloaking device has engaging, Sir...\""))
996 prout(_("Engineer Scott- \"Cloaking device has engaged, Sir.\""))
997 game.iscloaked = True
999 if game.irhere and game.state.date >= ALGERON and not game.isviolreported:
1000 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
1002 game.isviolreported = True
1004 def doshield(shraise):
1005 "Change shield status."
1011 key = scanner.nexttok()
1012 if key == "IHALPHA":
1013 if scanner.sees("transfer"):
1016 if damaged(DSHIELD):
1017 prout(_("Shields damaged and down."))
1019 if scanner.sees("up"):
1021 elif scanner.sees("down"):
1023 if action == "NONE":
1024 proutn(_("Do you wish to change shield energy? "))
1027 elif damaged(DSHIELD):
1028 prout(_("Shields damaged and down."))
1031 proutn(_("Shields are up. Do you want them down? "))
1038 proutn(_("Shields are down. Do you want them up? "))
1044 if action == "SHUP": # raise shields
1046 prout(_("Shields already up."))
1050 if game.condition != "docked":
1052 prout(_("Shields raised."))
1053 if game.energy <= 0:
1055 prout(_("Shields raising uses up last of energy."))
1060 elif action == "SHDN":
1062 prout(_("Shields already down."))
1066 prout(_("Shields lowered."))
1069 elif action == "NRG":
1070 while scanner.nexttok() != "IHREAL":
1072 proutn(_("Energy to transfer to shields- "))
1077 if nrg > game.energy:
1078 prout(_("Insufficient ship energy."))
1081 if game.shield+nrg >= game.inshld:
1082 prout(_("Shield energy maximized."))
1083 if game.shield+nrg > game.inshld:
1084 prout(_("Excess energy requested returned to ship energy"))
1085 game.energy -= game.inshld-game.shield
1086 game.shield = game.inshld
1088 if nrg < 0.0 and game.energy-nrg > game.inenrg:
1089 # Prevent shield drain loophole
1091 prout(_("Engineering to bridge--"))
1092 prout(_(" Scott here. Power circuit problem, Captain."))
1093 prout(_(" I can't drain the shields."))
1096 if game.shield+nrg < 0:
1097 prout(_("All shield energy transferred to ship."))
1098 game.energy += game.shield
1101 proutn(_("Scotty- \""))
1103 prout(_("Transferring energy to shields.\""))
1105 prout(_("Draining energy from shields.\""))
1111 "Choose a device to damage, at random."
1113 105, # DSRSENS: short range scanners 10.5%
1114 105, # DLRSENS: long range scanners 10.5%
1115 120, # DPHASER: phasers 12.0%
1116 120, # DPHOTON: photon torpedoes 12.0%
1117 25, # DLIFSUP: life support 2.5%
1118 65, # DWARPEN: warp drive 6.5%
1119 70, # DIMPULS: impulse engines 6.5%
1120 145, # DSHIELD: deflector shields 14.5%
1121 30, # DRADIO: subspace radio 3.0%
1122 45, # DSHUTTL: shuttle 4.5%
1123 15, # DCOMPTR: computer 1.5%
1124 20, # NAVCOMP: navigation system 2.0%
1125 75, # DTRANSP: transporter 7.5%
1126 20, # DSHCTRL: high-speed shield controller 2.0%
1127 10, # DDRAY: death ray 1.0%
1128 30, # DDSP: deep-space probes 3.0%
1129 0, # DCLOAK: the cloaking device 0.0
1131 assert(sum(weights) == 1000)
1132 idx = randrange(1000)
1134 for (i, w) in enumerate(weights):
1138 return None # we should never get here
1140 def collision(rammed, enemy):
1141 "Collision handling for rammong events."
1142 prouts(_("***RED ALERT! RED ALERT!"))
1144 prout(_("***COLLISION IMMINENT."))
1148 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1150 proutn(_(" rammed by "))
1153 proutn(crmena(False, enemy.type, "sector", enemy.location))
1155 proutn(_(" (original position)"))
1157 deadkl(enemy.location, enemy.type, game.sector)
1158 proutn("***" + crmshp() + " heavily damaged.")
1159 icas = randrange(10, 30)
1160 prout(_("***Sickbay reports %d casualties") % icas)
1162 game.state.crew -= icas
1163 # In the pre-SST2K version, all devices got equiprobably damaged,
1164 # which was silly. Instead, pick up to half the devices at
1165 # random according to our weighting table,
1166 ncrits = randrange(NDEVICES/2)
1170 if game.damage[dev] < 0:
1172 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1173 # Damage for at least time of travel!
1174 game.damage[dev] += game.optime + extradm
1176 prout(_("***Shields are down."))
1177 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1184 def torpedo(origin, bearing, dispersion, number, nburst):
1185 "Let a photon torpedo fly"
1186 if not damaged(DSRSENS) or game.condition == "docked":
1187 setwnd(srscan_window)
1189 setwnd(message_window)
1190 ac = bearing + 0.25*dispersion # dispersion is a random variable
1191 bullseye = (15.0 - bearing)*0.5235988
1192 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1193 bumpto = Coord(0, 0)
1194 # Loop to move a single torpedo
1195 setwnd(message_window)
1196 for step in range(1, QUADSIZE*2):
1197 if not track.nexttok():
1200 if not w.valid_sector():
1202 iquad = game.quad[w.i][w.j]
1203 tracktorpedo(w, step, number, nburst, iquad)
1207 setwnd(message_window)
1208 if not damaged(DSRSENS) or game.condition == "docked":
1209 skip(1) # start new line after text track
1210 if iquad in ('E', 'F'): # Hit our ship
1212 prout(_("Torpedo hits %s.") % crmshp())
1213 hit = 700.0 + randreal(100) - \
1214 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1215 newcnd() # we're blown out of dock
1216 if game.landed or game.condition == "docked":
1217 return hit # Cheat if on a planet
1218 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1219 # is 143 degrees, which is almost exactly 4.8 clockface units
1220 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1221 displacement.nexttok()
1222 bumpto = displacement.sector()
1223 if not bumpto.valid_sector():
1225 if game.quad[bumpto.i][bumpto.j] == ' ':
1228 if game.quad[bumpto.i][bumpto.j] != '.':
1229 # can't move into object
1231 game.sector = bumpto
1233 game.quad[w.i][w.j] = '.'
1234 game.quad[bumpto.i][bumpto.j] = iquad
1235 prout(_(" displaced by blast to Sector %s ") % bumpto)
1236 for enemy in game.enemies:
1237 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1240 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1242 if iquad in ('C', 'S') and withprob(0.05):
1243 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1244 prout(_(" torpedo neutralized."))
1246 for enemy in game.enemies:
1247 if w == enemy.location:
1248 kp = math.fabs(enemy.power)
1249 h1 = 700.0 + randrange(100) - \
1250 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1258 if enemy.power == 0:
1261 proutn(crmena(True, iquad, "sector", w))
1262 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1263 displacement.nexttok()
1264 bumpto = displacement.sector()
1265 if not bumpto.valid_sector():
1266 prout(_(" damaged but not destroyed."))
1268 if game.quad[bumpto.i][bumpto.j] == ' ':
1269 prout(_(" buffeted into black hole."))
1270 deadkl(w, iquad, bumpto)
1271 if game.quad[bumpto.i][bumpto.j] != '.':
1272 prout(_(" damaged but not destroyed."))
1274 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1275 enemy.location = bumpto
1276 game.quad[w.i][w.j] = '.'
1277 game.quad[bumpto.i][bumpto.j] = iquad
1278 for enemy in game.enemies:
1279 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1283 prout("Internal error, no enemy where expected!")
1286 elif iquad == 'B': # Hit a base
1288 prout(_("***STARBASE DESTROYED.."))
1289 game.state.baseq = [x for x in game.state.baseq if x != game.quadrant]
1290 game.quad[w.i][w.j] = '.'
1291 game.base.invalidate()
1292 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
1293 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = False
1294 game.state.basekl += 1
1297 elif iquad == 'P': # Hit a planet
1298 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1299 game.state.nplankl += 1
1300 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1301 game.iplnet.pclass = "destroyed"
1303 game.plnet.invalidate()
1304 game.quad[w.i][w.j] = '.'
1306 # captain perishes on planet
1309 elif iquad == '@': # Hit an inhabited world -- very bad!
1310 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1311 game.state.nworldkl += 1
1312 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1313 game.iplnet.pclass = "destroyed"
1315 game.plnet.invalidate()
1316 game.quad[w.i][w.j] = '.'
1318 # captain perishes on planet
1320 prout(_("The torpedo destroyed an inhabited planet."))
1322 elif iquad == '*': # Hit a star
1326 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1328 elif iquad == '?': # Hit a thingy
1329 if not (game.options & OPTION_THINGY) or withprob(0.3):
1331 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1333 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1335 proutn(_("Mr. Spock-"))
1336 prouts(_(" \"Fascinating!\""))
1340 # Stas Sergeev added the possibility that
1341 # you can shove the Thingy and piss it off.
1342 # It then becomes an enemy and may fire at you.
1345 elif iquad == ' ': # Black hole
1347 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1349 elif iquad == '#': # hit the web
1351 prout(_("***Torpedo absorbed by Tholian web."))
1353 elif iquad == 'T': # Hit a Tholian
1354 h1 = 700.0 + randrange(100) - \
1355 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1358 game.quad[w.i][w.j] = '.'
1363 proutn(crmena(True, 'T', "sector", w))
1365 prout(_(" survives photon blast."))
1367 prout(_(" disappears."))
1368 game.tholian.move(None)
1369 game.quad[w.i][w.j] = '#'
1374 proutn("Don't know how to handle torpedo collision with ")
1375 proutn(crmena(True, iquad, "sector", w))
1380 setwnd(message_window)
1381 prout(_("Torpedo missed."))
1385 "Critical-hit resolution."
1386 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1388 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1389 proutn(_("***CRITICAL HIT--"))
1390 # Select devices and cause damage
1395 # Cheat to prevent shuttle damage unless on ship
1396 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship") or (j == DCLOAK and game.ship != 'E' or j == DDRAY)):
1399 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1400 game.damage[j] += extradm
1403 for (i, j) in enumerate(cdam):
1405 if skipcount % 3 == 2 and i < len(cdam)-1:
1410 prout(_(" damaged."))
1411 if damaged(DSHIELD) and game.shldup:
1412 prout(_("***Shields knocked down."))
1414 if damaged(DCLOAK) and game.iscloaked:
1415 prout(_("***Cloaking device rendered inoperative."))
1416 game.iscloaked = False
1418 def attack(torps_ok):
1419 # bad guy attacks us
1420 # torps_ok == False forces use of phasers in an attack
1423 # game could be over at this point, check
1433 prout("=== ATTACK!")
1434 # Tholian gets to move before attacking
1437 # if you have just entered the RNZ, you'll get a warning
1438 if game.neutz: # The one chance not to be attacked
1441 # commanders get a chance to tac-move towards you
1442 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:
1443 for (bugout, enemy, old, goto) in moveklings():
1445 # we know about this if either short or long range
1446 # sensors are working
1447 if damaged(DSRSENS) and damaged(DLRSENS) \
1448 and game.condition != "docked":
1449 prout(crmena(True, enemy.type, "sector", old) + \
1450 (_(" escapes to Quadrant %s (and regains strength).") % goto))
1451 else: # Enemy still in-sector
1452 if enemy.move(goto):
1453 if not damaged(DSRSENS) or game.condition == "docked":
1454 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
1455 if enemy.kdist < old:
1456 proutn(_(" advances to "))
1458 proutn(_(" retreats to "))
1459 prout("Sector %s." % goto)
1461 # if no enemies remain after movement, we're done
1462 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing.at(game.quadrant) and not thing.angered):
1464 # set up partial hits if attack happens during shield status change
1465 pfac = 1.0/game.inshld
1467 chgfac = 0.25 + randreal(0.5)
1469 # message verbosity control
1470 if game.skill <= SKILL_FAIR:
1472 for enemy in game.enemies:
1474 continue # too weak to attack
1475 # compute hit strength and diminish shield power
1477 # Increase chance of photon torpedos if docked or enemy energy is low
1478 if game.condition == "docked":
1480 if enemy.power < 500:
1482 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1484 # different enemies have different probabilities of throwing a torp
1485 usephasers = not torps_ok or \
1486 (enemy.type == 'K' and r > 0.0005) or \
1487 (enemy.type == 'C' and r > 0.015) or \
1488 (enemy.type == 'R' and r > 0.3) or \
1489 (enemy.type == 'S' and r > 0.07) or \
1490 (enemy.type == '?' and r > 0.05)
1491 if usephasers: # Enemy uses phasers
1492 if game.condition == "docked":
1493 continue # Don't waste the effort!
1494 attempt = True # Attempt to attack
1495 dustfac = randreal(0.8, 0.85)
1496 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1498 else: # Enemy uses photon torpedo
1499 # We should be able to make the bearing() method work here
1500 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1502 proutn(_("***TORPEDO INCOMING"))
1503 if not damaged(DSRSENS):
1504 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1507 dispersion = (randreal()+randreal())*0.5 - 0.5
1508 dispersion += 0.002*enemy.power*dispersion
1509 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1510 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1511 finish(FWON) # Klingons did themselves in!
1512 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1513 return # Supernova or finished
1516 # incoming phaser or torpedo, shields may dissipate it
1517 if game.shldup or game.shldchg or game.condition == "docked":
1518 # shields will take hits
1519 propor = pfac * game.shield
1520 if game.condition == "docked":
1524 hitsh = propor*chgfac*hit+1.0
1526 if absorb > game.shield:
1527 absorb = game.shield
1528 game.shield -= absorb
1530 # taking a hit blasts us out of a starbase dock
1531 if game.condition == "docked":
1533 # but the shields may take care of it
1534 if propor > 0.1 and hit < 0.005*game.energy:
1536 # hit from this opponent got through shields, so take damage
1538 proutn(_("%d unit hit") % int(hit))
1539 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1540 proutn(_(" on the ") + crmshp())
1541 if not damaged(DSRSENS) and usephasers:
1542 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1544 # Decide if hit is critical
1550 if game.energy <= 0:
1551 # Returning home upon your shield, not with it...
1554 if not attempt and game.condition == "docked":
1555 prout(_("***Enemies decide against attacking your ship."))
1556 percent = 100.0*pfac*game.shield+0.5
1558 # Shields fully protect ship
1559 proutn(_("Enemy attack reduces shield strength to "))
1561 # Emit message if starship suffered hit(s)
1563 proutn(_("Energy left %2d shields ") % int(game.energy))
1566 elif not damaged(DSHIELD):
1569 proutn(_("damaged, "))
1570 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1571 # Check if anyone was hurt
1572 if hitmax >= 200 or hittot >= 500:
1573 icas = randrange(int(hittot * 0.015))
1576 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1577 prout(_(" in that last attack.\""))
1579 game.state.crew -= icas
1580 # After attack, reset average distance to enemies
1581 for enemy in game.enemies:
1582 enemy.kavgd = enemy.kdist
1586 def deadkl(w, etype, mv):
1587 "Kill a Klingon, Tholian, Romulan, or Thingy."
1588 # Added mv to allow enemy to "move" before dying
1589 proutn(crmena(True, etype, "sector", mv))
1590 # Decide what kind of enemy it is and update appropriately
1592 # Chalk up a Romulan
1593 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1595 game.state.nromrem -= 1
1604 # Killed some type of Klingon
1605 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1608 game.state.kcmdr.remove(game.quadrant)
1610 if game.state.kcmdr:
1611 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1612 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1615 game.state.remkl -= 1
1617 game.state.nscrem -= 1
1618 game.state.kscmdr.invalidate()
1623 # For each kind of enemy, finish message to player
1624 prout(_(" destroyed."))
1625 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1628 # Remove enemy ship from arrays describing local conditions
1629 for e in game.enemies:
1636 "Return None if target is invalid, otherwise return a course angle."
1637 if not w.valid_sector():
1641 # C code this was translated from is wacky -- why the sign reversal?
1642 delta.j = (w.j - game.sector.j)
1643 delta.i = (game.sector.i - w.i)
1644 if delta == Coord(0, 0):
1646 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1647 prout(_(" I recommend an immediate review of"))
1648 prout(_(" the Captain's psychological profile.\""))
1651 return delta.bearing()
1654 "Launch photon torpedo salvo."
1657 if damaged(DPHOTON):
1658 prout(_("Photon tubes damaged."))
1662 prout(_("No torpedoes left."))
1665 # First, get torpedo count
1668 if scanner.token == "IHALPHA":
1671 elif scanner.token == "IHEOL" or not scanner.waiting():
1672 prout(_("%d torpedoes left.") % game.torps)
1674 proutn(_("Number of torpedoes to fire- "))
1675 continue # Go back around to get a number
1676 else: # key == "IHREAL"
1678 if n <= 0: # abort command
1683 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1686 scanner.chew() # User requested more torps than available
1687 continue # Go back around
1688 break # All is good, go to next stage
1692 key = scanner.nexttok()
1693 if i == 0 and key == "IHEOL":
1694 break # no coordinate waiting, we will try prompting
1695 if i == 1 and key == "IHEOL":
1696 # direct all torpedoes at one target
1698 target.append(target[0])
1699 tcourse.append(tcourse[0])
1702 scanner.push(scanner.token)
1703 target.append(scanner.getcoord())
1704 if target[-1] is None:
1706 tcourse.append(targetcheck(target[-1]))
1707 if tcourse[-1] is None:
1710 if len(target) == 0:
1711 # prompt for each one
1713 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1715 target.append(scanner.getcoord())
1716 if target[-1] is None:
1718 tcourse.append(targetcheck(target[-1]))
1719 if tcourse[-1] is None:
1722 # Loop for moving <n> torpedoes
1724 if game.condition != "docked":
1726 dispersion = (randreal()+randreal())*0.5 -0.5
1727 if math.fabs(dispersion) >= 0.47:
1729 dispersion *= randreal(1.2, 2.2)
1731 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1733 prouts(_("***TORPEDO MISFIRES."))
1736 prout(_(" Remainder of burst aborted."))
1738 prout(_("***Photon tubes damaged by misfire."))
1739 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1743 elif game.shldup or game.condition == "docked":
1744 dispersion *= 1.0 + 0.0001*game.shield
1745 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1746 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1748 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1752 "Check for phasers overheating."
1754 checkburn = (rpow-1500.0)*0.00038
1755 if withprob(checkburn):
1756 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1757 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1759 def checkshctrl(rpow):
1760 "Check shield control."
1763 prout(_("Shields lowered."))
1765 # Something bad has happened
1766 prouts(_("***RED ALERT! RED ALERT!"))
1768 hit = rpow*game.shield/game.inshld
1769 game.energy -= rpow+hit*0.8
1770 game.shield -= hit*0.2
1771 if game.energy <= 0.0:
1772 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1777 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1779 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1780 icas = randrange(int(hit*0.012))
1785 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1786 prout(_(" %d casualties so far.\"") % icas)
1788 game.state.crew -= icas
1790 prout(_("Phaser energy dispersed by shields."))
1791 prout(_("Enemy unaffected."))
1796 "Register a phaser hit on Klingons and Romulans."
1803 dustfac = randreal(0.9, 1.0)
1804 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1805 kpini = game.enemies[kk].power
1806 kp = math.fabs(kpini)
1807 if PHASEFAC*hit < kp:
1809 if game.enemies[kk].power < 0:
1810 game.enemies[kk].power -= -kp
1812 game.enemies[kk].power -= kp
1813 kpow = game.enemies[kk].power
1814 w = game.enemies[kk].location
1816 if not damaged(DSRSENS):
1818 proutn(_("%d unit hit on ") % int(hit))
1820 proutn(_("Very small hit on "))
1821 ienm = game.quad[w.i][w.j]
1824 proutn(crmena(False, ienm, "sector", w))
1828 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1832 kk -= 1 # don't do the increment
1834 else: # decide whether or not to emasculate klingon
1835 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1836 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1837 prout(_(" has just lost its firepower.\""))
1838 game.enemies[kk].power = -kpow
1843 "Fire phasers at bad guys."
1847 irec = 0 # Cheating inhibitor
1856 # SR sensors and Computer are needed for automode
1857 if damaged(DSRSENS) or damaged(DCOMPTR):
1859 if game.condition == "docked":
1860 prout(_("Phasers can't be fired through base shields."))
1863 if damaged(DPHASER):
1864 prout(_("Phaser control damaged."))
1868 if damaged(DSHCTRL):
1869 prout(_("High speed shield control damaged."))
1872 if game.energy <= 200.0:
1873 prout(_("Insufficient energy to activate high-speed shield control."))
1876 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1878 # Original code so convoluted, I re-did it all
1879 # (That was Tom Almy talking about the C code, I think -- ESR)
1880 while automode == "NOTSET":
1881 key = scanner.nexttok()
1882 if key == "IHALPHA":
1883 if scanner.sees("manual"):
1884 if len(game.enemies)==0:
1885 prout(_("There is no enemy present to select."))
1888 automode = "AUTOMATIC"
1891 key = scanner.nexttok()
1892 elif scanner.sees("automatic"):
1893 if (not itarg) and len(game.enemies) != 0:
1894 automode = "FORCEMAN"
1896 if len(game.enemies)==0:
1897 prout(_("Energy will be expended into space."))
1898 automode = "AUTOMATIC"
1899 key = scanner.nexttok()
1900 elif scanner.sees("no"):
1905 elif key == "IHREAL":
1906 if len(game.enemies)==0:
1907 prout(_("Energy will be expended into space."))
1908 automode = "AUTOMATIC"
1910 automode = "FORCEMAN"
1912 automode = "AUTOMATIC"
1915 if len(game.enemies)==0:
1916 prout(_("Energy will be expended into space."))
1917 automode = "AUTOMATIC"
1919 automode = "FORCEMAN"
1921 proutn(_("Manual or automatic? "))
1926 if automode == "AUTOMATIC":
1927 if key == "IHALPHA" and scanner.sees("no"):
1929 key = scanner.nexttok()
1930 if key != "IHREAL" and len(game.enemies) != 0:
1931 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1936 for i in range(len(game.enemies)):
1937 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1939 proutn(_("%d units required. ") % irec)
1941 proutn(_("Units to fire= "))
1942 key = scanner.nexttok()
1947 proutn(_("Energy available= %.2f") % avail)
1950 if not rpow > avail:
1956 key = scanner.nexttok()
1957 if key == "IHALPHA" and scanner.sees("no"):
1960 game.energy -= 200 # Go and do it!
1961 if checkshctrl(rpow):
1966 if len(game.enemies):
1969 for i in range(len(game.enemies)):
1973 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1974 over = randreal(1.01, 1.06) * hits[i]
1976 powrem -= hits[i] + over
1977 if powrem <= 0 and temp < hits[i]:
1986 if extra > 0 and not game.alldone:
1988 proutn(_("*** Tholian web absorbs "))
1989 if len(game.enemies)>0:
1990 proutn(_("excess "))
1991 prout(_("phaser energy."))
1993 prout(_("%d expended on empty space.") % int(extra))
1994 elif automode == "FORCEMAN":
1997 if damaged(DCOMPTR):
1998 prout(_("Battle computer damaged, manual fire only."))
2001 prouts(_("---WORKING---"))
2003 prout(_("Short-range-sensors-damaged"))
2004 prout(_("Insufficient-data-for-automatic-phaser-fire"))
2005 prout(_("Manual-fire-must-be-used"))
2007 elif automode == "MANUAL":
2009 for k in range(len(game.enemies)):
2010 aim = game.enemies[k].location
2011 ienm = game.quad[aim.i][aim.j]
2013 proutn(_("Energy available= %.2f") % (avail-0.006))
2017 if damaged(DSRSENS) and \
2018 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
2019 prout(cramen(ienm) + _(" can't be located without short range scan."))
2022 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
2027 if itarg and k > kz:
2028 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
2031 if not damaged(DCOMPTR):
2036 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
2037 key = scanner.nexttok()
2038 if key == "IHALPHA" and scanner.sees("no"):
2040 key = scanner.nexttok()
2042 if key == "IHALPHA":
2046 if k == 1: # Let me say I'm baffled by this
2049 if scanner.real < 0:
2053 hits[k] = scanner.real
2054 rpow += scanner.real
2055 # If total requested is too much, inform and start over
2057 prout(_("Available energy exceeded -- try again."))
2060 key = scanner.nexttok() # scan for next value
2063 # zero energy -- abort
2066 if key == "IHALPHA" and scanner.sees("no"):
2071 game.energy -= 200.0
2072 if checkshctrl(rpow):
2076 # Say shield raised or malfunction, if necessary
2083 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
2084 prouts(_(" CLICK CLICK POP . . ."))
2085 prout(_(" No response, sir!"))
2088 prout(_("Shields raised."))
2095 game.ididit = False # Nothing if we fail
2098 # Make sure there is room in the brig */
2099 if game.brigfree == 0:
2100 prout(_("Security reports the brig is already full."))
2104 prout(_("Uhura- \"We have no subspace radio communication, sir.\""))
2107 if damaged(DTRANSP):
2108 prout(_("Scotty- \"Transporter damaged, sir.\""))
2111 # find out if there are any at all
2113 prout(_("Uhura- \"Getting no response, sir.\""))
2116 # if there is more than one Klingon, find out which one */
2117 # Cruddy, just takes one at random. Should ask the captain.
2118 # Nah, just select the weakest one since it is most likely to
2119 # surrender (Tom Almy mod)
2120 klingons = [e for e in game.enemies if e.type == 'K']
2121 weakest = sorted(klingons, key=lambda e: e.power)[0]
2122 game.optime = 0.05 # This action will take some time
2123 game.ididit = True # So any others can strike back
2125 # check out that Klingon
2126 # The algorithm isn't that great and could use some more
2127 # intelligent design
2128 # x = 300 + 25*skill;
2129 x = game.energy / (weakest.power * len(klingons))
2130 #prout(_("Stats: energy = %s, kpower = %s, klingons = %s")
2131 # % (game.energy, weakest.power, len(klingons)))
2132 x *= 2.5 # would originally have been equivalent of 1.4,
2133 # but we want command to work more often, more humanely */
2134 #prout(_("Prob = %.4f" % x))
2135 # x = 100; // For testing, of course!
2136 if x < randreal(100):
2137 # guess what, he surrendered!!! */
2138 prout(_("Klingon captain at %s surrenders.") % weakest.location)
2141 prout(_("%d Klingons commit suicide rather than be taken captive.") % (200 - i))
2142 if i > game.brigfree:
2143 prout(_("%d Klingons die because there is no room for them in the brig.") % (i-brigfree))
2146 prout(_("%d captives taken") % i)
2147 deadkl(weakest.location, weakest.type, game.sector)
2148 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
2152 # big surprise, he refuses to surrender */
2153 prout(_("Fat chance, captain!"))
2155 # Code from events.c begins here.
2157 # This isn't a real event queue a la BSD Trek yet -- you can only have one
2158 # event of each type active at any given time. Mostly these means we can
2159 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
2160 # BSD Trek, from which we swiped the idea, can have up to 5.
2162 def unschedule(evtype):
2163 "Remove an event from the schedule."
2164 game.future[evtype].date = FOREVER
2165 return game.future[evtype]
2167 def is_scheduled(evtype):
2168 "Is an event of specified type scheduled."
2169 return game.future[evtype].date != FOREVER
2171 def scheduled(evtype):
2172 "When will this event happen?"
2173 return game.future[evtype].date
2175 def schedule(evtype, offset):
2176 "Schedule an event of specified type."
2177 game.future[evtype].date = game.state.date + offset
2178 return game.future[evtype]
2180 def postpone(evtype, offset):
2181 "Postpone a scheduled event."
2182 game.future[evtype].date += offset
2185 "Rest period is interrupted by event."
2188 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2190 game.resting = False
2196 "Run through the event queue looking for things to do."
2198 fintim = game.state.date + game.optime
2207 def tractorbeam(yank):
2208 "Tractor-beaming cases merge here."
2210 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2212 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2213 # If Kirk & Co. screwing around on planet, handle
2214 atover(True) # atover(true) is Grab
2217 if game.icraft: # Caught in Galileo?
2220 # Check to see if shuttle is aboard
2221 if game.iscraft == "offship":
2224 prout(_("Galileo, left on the planet surface, is captured"))
2225 prout(_("by aliens and made into a flying McDonald's."))
2226 game.damage[DSHUTTL] = -10
2227 game.iscraft = "removed"
2229 prout(_("Galileo, left on the planet surface, is well hidden."))
2231 game.quadrant = game.state.kscmdr
2233 game.quadrant = game.state.kcmdr[i]
2234 game.sector = randplace(QUADSIZE)
2235 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2236 % (game.quadrant, game.sector))
2238 prout(_("(Remainder of rest/repair period cancelled.)"))
2239 game.resting = False
2241 if not damaged(DSHIELD) and game.shield > 0:
2242 doshield(shraise=True) # raise shields
2243 game.shldchg = False
2245 prout(_("(Shields not currently useable.)"))
2247 # Adjust finish time to time of tractor beaming?
2248 # fintim = game.state.date+game.optime
2249 attack(torps_ok=False)
2250 if not game.state.kcmdr:
2253 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2256 "Code merges here for any commander destroying a starbase."
2257 # Not perfect, but will have to do
2258 # Handle case where base is in same quadrant as starship
2259 if game.battle == game.quadrant:
2260 game.state.chart[game.battle.i][game.battle.j].starbase = False
2261 game.quad[game.base.i][game.base.j] = '.'
2262 game.base.invalidate()
2265 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2266 elif game.state.baseq and communicating():
2267 # Get word via subspace radio
2270 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2271 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2273 prout(_("the Klingon Super-Commander"))
2275 prout(_("a Klingon Commander"))
2276 game.state.chart[game.battle.i][game.battle.j].starbase = False
2277 # Remove Starbase from galaxy
2278 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2279 game.state.baseq = [x for x in game.state.baseq if x != game.battle]
2281 # reinstate a commander's base attack
2285 game.battle.invalidate()
2287 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2288 for i in range(1, NEVENTS):
2289 if i == FSNOVA: proutn("=== Supernova ")
2290 elif i == FTBEAM: proutn("=== T Beam ")
2291 elif i == FSNAP: proutn("=== Snapshot ")
2292 elif i == FBATTAK: proutn("=== Base Attack ")
2293 elif i == FCDBAS: proutn("=== Base Destroy ")
2294 elif i == FSCMOVE: proutn("=== SC Move ")
2295 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2296 elif i == FDSPROB: proutn("=== Probe Move ")
2297 elif i == FDISTR: proutn("=== Distress Call ")
2298 elif i == FENSLV: proutn("=== Enslavement ")
2299 elif i == FREPRO: proutn("=== Klingon Build ")
2301 prout("%.2f" % (scheduled(i)))
2304 radio_was_broken = damaged(DRADIO)
2307 # Select earliest extraneous event, evcode==0 if no events
2312 for l in range(1, NEVENTS):
2313 if game.future[l].date < datemin:
2316 prout("== Event %d fires" % evcode)
2317 datemin = game.future[l].date
2318 xtime = datemin-game.state.date
2320 game.energy -= xtime*500.0
2321 if game.energy <= 0:
2324 game.state.date = datemin
2325 # Decrement Federation resources and recompute remaining time
2326 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2328 if game.state.remtime <= 0:
2331 # Any crew left alive?
2332 if game.state.crew <= 0:
2335 # Is life support adequate?
2336 if damaged(DLIFSUP) and game.condition != "docked":
2337 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2340 game.lsupres -= xtime
2341 if game.damage[DLIFSUP] <= xtime:
2342 game.lsupres = game.inlsr
2345 if game.condition == "docked":
2347 # Don't fix Deathray here
2348 for l in range(NDEVICES):
2349 if game.damage[l] > 0.0 and l != DDRAY:
2350 if game.damage[l]-repair > 0.0:
2351 game.damage[l] -= repair
2353 game.damage[l] = 0.0
2354 # If radio repaired, update star chart and attack reports
2355 if radio_was_broken and not damaged(DRADIO):
2356 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2357 prout(_(" surveillance reports are coming in."))
2359 if not game.iseenit:
2363 prout(_(" The star chart is now up to date.\""))
2365 # Cause extraneous event EVCODE to occur
2366 game.optime -= xtime
2367 if evcode == FSNOVA: # Supernova
2370 schedule(FSNOVA, expran(0.5*game.intime))
2371 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2373 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2374 if game.state.nscrem == 0 or game.iscloaked or \
2375 ictbeam or istract or \
2376 game.condition == "docked" or game.isatb == 1 or game.iscate:
2378 if game.ientesc or \
2379 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2380 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2381 (damaged(DSHIELD) and \
2382 (game.energy < 2500 or damaged(DPHASER)) and \
2383 (game.torps < 5 or damaged(DPHOTON))):
2385 istract = ictbeam = True
2386 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2389 elif evcode == FTBEAM: # Tractor beam
2390 if not game.state.kcmdr:
2393 i = randrange(len(game.state.kcmdr))
2394 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2395 if istract or game.condition == "docked" or game.iscloaked or yank == 0:
2396 # Drats! Have to reschedule
2398 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2402 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2403 game.snapsht = copy.deepcopy(game.state)
2404 game.state.snap = True
2405 schedule(FSNAP, expran(0.5 * game.intime))
2406 elif evcode == FBATTAK: # Commander attacks starbase
2407 if not game.state.kcmdr or not game.state.baseq:
2412 ibq = None # Force battle location to persist past loop
2414 for ibq in game.state.baseq:
2415 for cmdr in game.state.kcmdr:
2416 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2418 # no match found -- try later
2419 schedule(FBATTAK, expran(0.3*game.intime))
2424 # commander + starbase combination found -- launch attack
2426 schedule(FCDBAS, randreal(1.0, 4.0))
2427 if game.isatb: # extra time if SC already attacking
2428 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2429 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2430 game.iseenit = False
2431 if not communicating():
2432 continue # No warning :-(
2436 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2437 prout(_(" reports that it is under attack and that it can"))
2438 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2441 elif evcode == FSCDBAS: # Supercommander destroys base
2444 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2445 continue # WAS RETURN!
2447 game.battle = game.state.kscmdr
2449 elif evcode == FCDBAS: # Commander succeeds in destroying base
2450 if evcode == FCDBAS:
2452 if not game.state.baseq() \
2453 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2454 game.battle.invalidate()
2456 # find the lucky pair
2457 for cmdr in game.state.kcmdr:
2458 if cmdr == game.battle:
2461 # No action to take after all
2464 elif evcode == FSCMOVE: # Supercommander moves
2465 schedule(FSCMOVE, 0.2777)
2466 if not game.ientesc and not istract and game.isatb != 1 and \
2467 (not game.iscate or not game.justin):
2469 elif evcode == FDSPROB: # Move deep space probe
2470 schedule(FDSPROB, 0.01)
2471 if not game.probe.nexttok():
2472 if not game.probe.quadrant().valid_quadrant() or \
2473 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2474 # Left galaxy or ran into supernova
2478 proutn(_("Lt. Uhura- \"The deep space probe "))
2479 if not game.probe.quadrant().valid_quadrant():
2480 prout(_("has left the galaxy.\""))
2482 prout(_("is no longer transmitting.\""))
2488 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2489 pquad = game.probe.quadrant()
2490 pdest = game.state.galaxy[pquad.i][pquad.j]
2492 game.state.chart[pquad.i][pquad.j].klingons = pdest.klingons
2493 game.state.chart[pquad.i][pquad.j].starbase = pdest.starbase
2494 game.state.chart[pquad.i][pquad.j].stars = pdest.stars
2495 pdest.charted = True
2496 game.probe.moves -= 1 # One less to travel
2497 if game.probe.arrived() and game.isarmed and pdest.stars:
2498 supernova(game.probe) # fire in the hole!
2500 if game.state.galaxy[pquad.i][pquad.j].supernova:
2502 elif evcode == FDISTR: # inhabited system issues distress call
2504 # try a whole bunch of times to find something suitable
2505 for i in range(100):
2506 # need a quadrant which is not the current one,
2507 # which has some stars which are inhabited and
2508 # not already under attack, which is not
2509 # supernova'ed, and which has some Klingons in it
2510 w = randplace(GALSIZE)
2511 q = game.state.galaxy[w.i][w.j]
2512 if not (game.quadrant == w or q.planet is None or \
2513 not q.planet.inhabited or \
2514 q.supernova or q.status!="secure" or q.klingons<=0):
2517 # can't seem to find one; ignore this call
2519 prout("=== Couldn't find location for distress event.")
2521 # got one!! Schedule its enslavement
2522 ev = schedule(FENSLV, expran(game.intime))
2524 q.status = "distressed"
2525 # tell the captain about it if we can
2527 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2528 % (q.planet, repr(w)))
2529 prout(_("by a Klingon invasion fleet."))
2532 elif evcode == FENSLV: # starsystem is enslaved
2533 ev = unschedule(FENSLV)
2534 # see if current distress call still active
2535 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2539 q.status = "enslaved"
2541 # play stork and schedule the first baby
2542 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2543 ev2.quadrant = ev.quadrant
2545 # report the disaster if we can
2547 prout(_("Uhura- We've lost contact with starsystem %s") % \
2549 prout(_("in Quadrant %s.\n") % ev.quadrant)
2550 elif evcode == FREPRO: # Klingon reproduces
2551 # If we ever switch to a real event queue, we'll need to
2552 # explicitly retrieve and restore the x and y.
2553 ev = schedule(FREPRO, expran(1.0 * game.intime))
2554 # see if current distress call still active
2555 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2559 if game.state.remkl >= MAXKLGAME:
2560 continue # full right now
2561 # reproduce one Klingon
2564 if game.klhere >= MAXKLQUAD:
2566 # this quadrant not ok, pick an adjacent one
2567 for m.i in range(w.i - 1, w.i + 2):
2568 for m.j in range(w.j - 1, w.j + 2):
2569 if not m.valid_quadrant():
2571 q = game.state.galaxy[m.i][m.j]
2572 # check for this quad ok (not full & no snova)
2573 if q.klingons >= MAXKLQUAD or q.supernova:
2576 # search for eligible quadrant failed
2581 game.state.remkl += 1
2583 if game.quadrant == w:
2585 game.enemies.append(newkling())
2586 # recompute time left
2589 if game.quadrant == w:
2590 prout(_("Spock- sensors indicate the Klingons have"))
2591 prout(_("launched a warship from %s.") % q.planet)
2593 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2594 if q.planet != None:
2595 proutn(_("near %s ") % q.planet)
2596 prout(_("in Quadrant %s.") % w)
2602 key = scanner.nexttok()
2605 proutn(_("How long? "))
2610 origTime = delay = scanner.real
2613 if delay >= game.state.remtime or len(game.enemies) != 0:
2614 proutn(_("Are you sure? "))
2617 # Alternate resting periods (events) with attacks
2621 game.resting = False
2622 if not game.resting:
2623 prout(_("%d stardates left.") % int(game.state.remtime))
2625 temp = game.optime = delay
2626 if len(game.enemies):
2627 rtime = randreal(1.0, 2.0)
2631 if game.optime < delay:
2632 attack(torps_ok=False)
2640 # Repair Deathray if long rest at starbase
2641 if origTime-delay >= 9.99 and game.condition == "docked":
2642 game.damage[DDRAY] = 0.0
2643 # leave if quadrant supernovas
2644 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2646 game.resting = False
2651 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2652 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2654 # Wow! We've supernova'ed
2655 supernova(game.quadrant)
2657 # handle initial nova
2658 game.quad[nov.i][nov.j] = '.'
2659 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2660 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2661 game.state.starkl += 1
2662 # Set up queue to recursively trigger adjacent stars
2668 for offset.i in range(-1, 1+1):
2669 for offset.j in range(-1, 1+1):
2670 if offset.j == 0 and offset.i == 0:
2672 neighbor = start + offset
2673 if not neighbor.valid_sector():
2675 iquad = game.quad[neighbor.i][neighbor.j]
2676 # Empty space ends reaction
2677 if iquad in ('.', '?', ' ', 'T', '#'):
2679 elif iquad == '*': # Affect another star
2681 # This star supernovas
2682 supernova(game.quadrant)
2685 hits.append(neighbor)
2686 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2687 game.state.starkl += 1
2688 proutn(crmena(True, '*', "sector", neighbor))
2690 game.quad[neighbor.i][neighbor.j] = '.'
2692 elif iquad in ('P', '@'): # Destroy planet
2693 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2695 game.state.nplankl += 1
2697 game.state.nworldkl += 1
2698 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2699 game.iplnet.pclass = "destroyed"
2701 game.plnet.invalidate()
2705 game.quad[neighbor.i][neighbor.j] = '.'
2706 elif iquad == 'B': # Destroy base
2707 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2708 game.state.baseq = [x for x in game.state.baseq if x!= game.quadrant]
2709 game.base.invalidate()
2710 game.state.basekl += 1
2712 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2713 game.quad[neighbor.i][neighbor.j] = '.'
2714 elif iquad in ('E', 'F'): # Buffet ship
2715 prout(_("***Starship buffeted by nova."))
2717 if game.shield >= 2000.0:
2718 game.shield -= 2000.0
2720 diff = 2000.0 - game.shield
2724 prout(_("***Shields knocked out."))
2725 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2727 game.energy -= 2000.0
2728 if game.energy <= 0:
2731 # add in course nova contributes to kicking starship
2732 bump += (game.sector-hits[-1]).sgn()
2733 elif iquad == 'K': # kill klingon
2734 deadkl(neighbor, iquad, neighbor)
2735 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2737 for ll in range(len(game.enemies)):
2738 if game.enemies[ll].location == neighbor:
2739 target = game.enemies[ll]
2741 if target is not None:
2742 target.power -= 800.0 # If firepower is lost, die
2743 if target.power <= 0.0:
2744 deadkl(neighbor, iquad, neighbor)
2745 continue # neighbor loop
2746 # Else enemy gets flung by the blast wave
2747 newc = neighbor + neighbor - hits[-1]
2748 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2749 if not newc.valid_sector():
2750 # can't leave quadrant
2753 iquad1 = game.quad[newc.i][newc.j]
2755 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2757 deadkl(neighbor, iquad, newc)
2760 # can't move into something else
2763 proutn(_(", buffeted to Sector %s") % newc)
2764 game.quad[neighbor.i][neighbor.j] = '.'
2765 game.quad[newc.i][newc.j] = iquad
2767 # Starship affected by nova -- kick it away.
2769 direc = ncourse[3*(bump.i+1)+bump.j+2]
2774 scourse = course(bearing=direc, distance=dist)
2775 game.optime = scourse.time(w=4)
2777 prout(_("Force of nova displaces starship."))
2778 imove(scourse, noattack=True)
2779 game.optime = scourse.time(w=4)
2783 "Star goes supernova."
2788 # Scheduled supernova -- select star at random.
2791 for nq.i in range(GALSIZE):
2792 for nq.j in range(GALSIZE):
2793 nstars += game.state.galaxy[nq.i][nq.j].stars
2795 return # nothing to supernova exists
2796 num = randrange(nstars) + 1
2797 for nq.i in range(GALSIZE):
2798 for nq.j in range(GALSIZE):
2799 num -= game.state.galaxy[nq.i][nq.j].stars
2805 proutn("=== Super nova here?")
2808 if not nq == game.quadrant or game.justin:
2809 # it isn't here, or we just entered (treat as enroute)
2812 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2813 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2816 # we are in the quadrant!
2817 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2818 for ns.i in range(QUADSIZE):
2819 for ns.j in range(QUADSIZE):
2820 if game.quad[ns.i][ns.j]=='*':
2827 prouts(_("***RED ALERT! RED ALERT!"))
2829 prout(_("***Incipient supernova detected at Sector %s") % ns)
2830 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2831 proutn(_("Emergency override attempts t"))
2832 prouts("***************")
2836 # destroy any Klingons in supernovaed quadrant
2837 kldead = game.state.galaxy[nq.i][nq.j].klingons
2838 game.state.galaxy[nq.i][nq.j].klingons = 0
2839 if nq == game.state.kscmdr:
2840 # did in the Supercommander!
2841 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2845 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2846 comkills = len(game.state.kcmdr) - len(survivors)
2847 game.state.kcmdr = survivors
2849 if not game.state.kcmdr:
2851 game.state.remkl -= kldead
2852 # destroy Romulans and planets in supernovaed quadrant
2853 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2854 game.state.galaxy[nq.i][nq.j].romulans = 0
2855 game.state.nromrem -= nrmdead
2857 for loop in range(game.inplan):
2858 if game.state.planets[loop].quadrant == nq:
2859 game.state.planets[loop].pclass = "destroyed"
2861 # Destroy any base in supernovaed quadrant
2862 game.state.baseq = [x for x in game.state.baseq if x != nq]
2863 # If starship caused supernova, tally up destruction
2865 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2866 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2867 game.state.nplankl += npdead
2868 # mark supernova in galaxy and in star chart
2869 if game.quadrant == nq or communicating():
2870 game.state.galaxy[nq.i][nq.j].supernova = True
2871 # If supernova destroys last Klingons give special message
2872 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2875 prout(_("Lucky you!"))
2876 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2879 # if some Klingons remain, continue or die in supernova
2884 # Code from finish.c ends here.
2887 "Self-destruct maneuver. Finish with a BANG!"
2889 if damaged(DCOMPTR):
2890 prout(_("Computer damaged; cannot execute destruct sequence."))
2892 prouts(_("---WORKING---")); skip(1)
2893 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2894 prouts(" 10"); skip(1)
2895 prouts(" 9"); skip(1)
2896 prouts(" 8"); skip(1)
2897 prouts(" 7"); skip(1)
2898 prouts(" 6"); skip(1)
2900 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2902 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2904 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2907 if game.passwd != scanner.token:
2908 prouts(_("PASSWORD-REJECTED;"))
2910 prouts(_("CONTINUITY-EFFECTED"))
2913 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2914 prouts(" 5"); skip(1)
2915 prouts(" 4"); skip(1)
2916 prouts(" 3"); skip(1)
2917 prouts(" 2"); skip(1)
2918 prouts(" 1"); skip(1)
2920 prouts(_("GOODBYE-CRUEL-WORLD"))
2928 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2932 if len(game.enemies) != 0:
2933 whammo = 25.0 * game.energy
2934 for l in range(len(game.enemies)):
2935 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2936 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2940 "Compute our rate of kils over time."
2941 elapsed = game.state.date - game.indate
2942 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2945 starting = (game.inkling + game.incom + game.inscom)
2946 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2947 return (starting - remaining)/elapsed
2951 badpt = 5.0*game.state.starkl + \
2953 10.0*game.state.nplankl + \
2954 300*game.state.nworldkl + \
2956 100.0*game.state.basekl +\
2957 3.0*game.abandoned +\
2959 if game.ship == 'F':
2961 elif game.ship is None:
2966 # end the game, with appropriate notifications
2970 prout(_("It is stardate %.1f.") % game.state.date)
2972 if ifin == FWON: # Game has been won
2973 if game.state.nromrem != 0:
2974 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2977 prout(_("You have smashed the Klingon invasion fleet and saved"))
2978 prout(_("the Federation."))
2979 if game.alive and game.brigcapacity-game.brigfree > 0:
2980 game.kcaptured += game.brigcapacity-game.brigfree
2981 prout(_("The %d captured Klingons are transferred to Star Fleet Command.") % (game.brigcapacity-game.brigfree))
2986 badpt = 0.0 # Close enough!
2987 # killsPerDate >= RateMax
2988 if game.state.date-game.indate < 5.0 or \
2989 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2991 prout(_("In fact, you have done so well that Starfleet Command"))
2992 if game.skill == SKILL_NOVICE:
2993 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2994 elif game.skill == SKILL_FAIR:
2995 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2996 elif game.skill == SKILL_GOOD:
2997 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2998 elif game.skill == SKILL_EXPERT:
2999 prout(_("promotes you to Commodore Emeritus."))
3001 prout(_("Now that you think you're really good, try playing"))
3002 prout(_("the \"Emeritus\" game. It will splatter your ego."))
3003 elif game.skill == SKILL_EMERITUS:
3005 proutn(_("Computer- "))
3006 prouts(_("ERROR-ERROR-ERROR-ERROR"))
3008 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
3010 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3012 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3014 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3016 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
3018 prout(_("Now you can retire and write your own Star Trek game!"))
3020 elif game.skill >= SKILL_EXPERT:
3021 if game.thawed and not game.idebug:
3022 prout(_("You cannot get a citation, so..."))
3024 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
3028 # Only grant long life if alive (original didn't!)
3030 prout(_("LIVE LONG AND PROSPER."))
3035 elif ifin == FDEPLETE: # Federation Resources Depleted
3036 prout(_("Your time has run out and the Federation has been"))
3037 prout(_("conquered. Your starship is now Klingon property,"))
3038 prout(_("and you are put on trial as a war criminal. On the"))
3039 proutn(_("basis of your record, you are "))
3040 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
3041 prout(_("acquitted."))
3043 prout(_("LIVE LONG AND PROSPER."))
3045 prout(_("found guilty and"))
3046 prout(_("sentenced to death by slow torture."))
3050 elif ifin == FLIFESUP:
3051 prout(_("Your life support reserves have run out, and"))
3052 prout(_("you die of thirst, starvation, and asphyxiation."))
3053 prout(_("Your starship is a derelict in space."))
3055 prout(_("Your energy supply is exhausted."))
3057 prout(_("Your starship is a derelict in space."))
3058 elif ifin == FBATTLE:
3059 prout(_("The %s has been destroyed in battle.") % crmshp())
3061 prout(_("Dulce et decorum est pro patria mori."))
3063 prout(_("You have made three attempts to cross the negative energy"))
3064 prout(_("barrier which surrounds the galaxy."))
3066 prout(_("Your navigation is abominable."))
3069 prout(_("Your starship has been destroyed by a nova."))
3070 prout(_("That was a great shot."))
3072 elif ifin == FSNOVAED:
3073 prout(_("The %s has been fried by a supernova.") % crmshp())
3074 prout(_("...Not even cinders remain..."))
3075 elif ifin == FABANDN:
3076 prout(_("You have been captured by the Klingons. If you still"))
3077 prout(_("had a starbase to be returned to, you would have been"))
3078 prout(_("repatriated and given another chance. Since you have"))
3079 prout(_("no starbases, you will be mercilessly tortured to death."))
3080 elif ifin == FDILITHIUM:
3081 prout(_("Your starship is now an expanding cloud of subatomic particles"))
3082 elif ifin == FMATERIALIZE:
3083 prout(_("Starbase was unable to re-materialize your starship."))
3084 prout(_("Sic transit gloria mundi"))
3085 elif ifin == FPHASER:
3086 prout(_("The %s has been cremated by its own phasers.") % crmshp())
3088 prout(_("You and your landing party have been"))
3089 prout(_("converted to energy, dissipating through space."))
3090 elif ifin == FMINING:
3091 prout(_("You are left with your landing party on"))
3092 prout(_("a wild jungle planet inhabited by primitive cannibals."))
3094 prout(_("They are very fond of \"Captain Kirk\" soup."))
3096 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3097 elif ifin == FDPLANET:
3098 prout(_("You and your mining party perish."))
3100 prout(_("That was a great shot."))
3103 prout(_("The Galileo is instantly annihilated by the supernova."))
3104 prout(_("You and your mining party are atomized."))
3106 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3107 prout(_("joins the Romulans, wreaking terror on the Federation."))
3108 elif ifin == FPNOVA:
3109 prout(_("You and your mining party are atomized."))
3111 prout(_("Mr. Spock takes command of the %s and") % crmshp())
3112 prout(_("joins the Romulans, wreaking terror on the Federation."))
3113 elif ifin == FSTRACTOR:
3114 prout(_("The shuttle craft Galileo is also caught,"))
3115 prout(_("and breaks up under the strain."))
3117 prout(_("Your debris is scattered for millions of miles."))
3118 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
3120 prout(_("The mutants attack and kill Spock."))
3121 prout(_("Your ship is captured by Klingons, and"))
3122 prout(_("your crew is put on display in a Klingon zoo."))
3123 elif ifin == FTRIBBLE:
3124 prout(_("Tribbles consume all remaining water,"))
3125 prout(_("food, and oxygen on your ship."))
3127 prout(_("You die of thirst, starvation, and asphyxiation."))
3128 prout(_("Your starship is a derelict in space."))
3130 prout(_("Your ship is drawn to the center of the black hole."))
3131 prout(_("You are crushed into extremely dense matter."))
3132 elif ifin == FCLOAK:
3134 prout(_("You have violated the Treaty of Algeron."))
3135 prout(_("The Romulan Empire can never trust you again."))
3137 prout(_("Your last crew member has died."))
3138 if ifin != FWON and ifin != FCLOAK and game.iscloaked:
3139 prout(_("Your ship was cloaked so your subspace radio did not receive anything."))
3140 prout(_("You may have missed some warning messages."))
3142 if game.ship == 'F':
3144 elif game.ship == 'E':
3147 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
3148 goodies = game.state.remres/game.inresor
3149 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
3150 if goodies/baddies >= randreal(1.0, 1.5):
3151 prout(_("As a result of your actions, a treaty with the Klingon"))
3152 prout(_("Empire has been signed. The terms of the treaty are"))
3153 if goodies/baddies >= randreal(3.0):
3154 prout(_("favorable to the Federation."))
3156 prout(_("Congratulations!"))
3158 prout(_("highly unfavorable to the Federation."))
3160 prout(_("The Federation will be destroyed."))
3162 prout(_("Since you took the last Klingon with you, you are a"))
3163 prout(_("martyr and a hero. Someday maybe they'll erect a"))
3164 prout(_("statue in your memory. Rest in peace, and try not"))
3165 prout(_("to think about pigeons."))
3168 scanner.chew() # Clean up leftovers
3171 "Compute player's score."
3172 timused = game.state.date - game.indate
3173 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
3175 game.perdate = killrate()
3176 ithperd = 500*game.perdate + 0.5
3179 iwon = 100*game.skill
3180 if game.ship == 'E':
3182 elif game.ship == 'F':
3186 game.score = 10*(game.inkling - game.state.remkl) \
3187 + 50*(game.incom - len(game.state.kcmdr)) \
3189 + 20*(game.inrom - game.state.nromrem) \
3190 + 200*(game.inscom - game.state.nscrem) \
3191 - game.state.nromrem \
3192 + 3 * game.kcaptured \
3197 prout(_("Your score --"))
3198 if game.inrom - game.state.nromrem:
3199 prout(_("%6d Romulans destroyed %5d") %
3200 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
3201 if game.state.nromrem and game.gamewon:
3202 prout(_("%6d Romulans captured %5d") %
3203 (game.state.nromrem, game.state.nromrem))
3204 if game.inkling - game.state.remkl:
3205 prout(_("%6d ordinary Klingons destroyed %5d") %
3206 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
3207 if game.incom - len(game.state.kcmdr):
3208 prout(_("%6d Klingon commanders destroyed %5d") %
3209 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3211 prout(_("%d Klingons captured %5d") %
3212 (game.kcaptured, 3 * game.kcaptured))
3213 if game.inscom - game.state.nscrem:
3214 prout(_("%6d Super-Commander destroyed %5d") %
3215 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3217 prout(_("%6.2f Klingons per stardate %5d") %
3218 (game.perdate, ithperd))
3219 if game.state.starkl:
3220 prout(_("%6d stars destroyed by your action %5d") %
3221 (game.state.starkl, -5*game.state.starkl))
3222 if game.state.nplankl:
3223 prout(_("%6d planets destroyed by your action %5d") %
3224 (game.state.nplankl, -10*game.state.nplankl))
3225 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3226 prout(_("%6d inhabited planets destroyed by your action %5d") %
3227 (game.state.nworldkl, -300*game.state.nworldkl))
3228 if game.state.basekl:
3229 prout(_("%6d bases destroyed by your action %5d") %
3230 (game.state.basekl, -100*game.state.basekl))
3232 prout(_("%6d calls for help from starbase %5d") %
3233 (game.nhelp, -45*game.nhelp))
3235 prout(_("%6d casualties incurred %5d") %
3236 (game.casual, -game.casual))
3238 prout(_("%6d crew abandoned in space %5d") %
3239 (game.abandoned, -3*game.abandoned))
3241 prout(_("%6d ship(s) lost or destroyed %5d") %
3242 (klship, -100*klship))
3245 prout(_("1 Treaty of Algeron violation -100"))
3247 prout(_("%6d Treaty of Algeron violations %5d\n") %
3248 (ncviol, -100*ncviol))
3250 prout(_("Penalty for getting yourself killed -200"))
3252 proutn(_("Bonus for winning "))
3253 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3254 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3255 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3256 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3257 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3258 prout(" %5d" % iwon)
3260 prout(_("TOTAL SCORE %5d") % game.score)
3263 "Emit winner's commemmorative plaque."
3266 proutn(_("File or device name for your plaque: "))
3269 fp = open(winner, "w")
3272 prout(_("Invalid name."))
3274 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3276 # The 38 below must be 64 for 132-column paper
3277 nskip = 38 - len(winner)/2
3278 fp.write("\n\n\n\n")
3279 # --------DRAW ENTERPRISE PICTURE.
3280 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3281 fp.write(" EEE E : : : E\n" )
3282 fp.write(" EE EEE E : : NCC-1701 : E\n")
3283 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3284 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3285 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3286 fp.write(" EEEEEEE EEEEE E E E E\n")
3287 fp.write(" EEE E E E E\n")
3288 fp.write(" E E E E\n")
3289 fp.write(" EEEEEEEEEEEEE E E\n")
3290 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3291 fp.write(" :E : EEEE E\n")
3292 fp.write(" .-E -:----- E\n")
3293 fp.write(" :E : E\n")
3294 fp.write(" EE : EEEEEEEE\n")
3295 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3297 fp.write(_(" U. S. S. ENTERPRISE\n"))
3298 fp.write("\n\n\n\n")
3299 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3301 fp.write(_(" Starfleet Command bestows to you\n"))
3303 fp.write("%*s%s\n\n" % (nskip, "", winner))
3304 fp.write(_(" the rank of\n\n"))
3305 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3307 if game.skill == SKILL_EXPERT:
3308 fp.write(_(" Expert level\n\n"))
3309 elif game.skill == SKILL_EMERITUS:
3310 fp.write(_("Emeritus level\n\n"))
3312 fp.write(_(" Cheat level\n\n"))
3313 timestring = time.ctime()
3314 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3315 (timestring+4, timestring+20, timestring+11))
3316 fp.write(_(" Your score: %d\n\n") % game.score)
3317 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3320 # Code from io.c begins here
3322 rows = linecount = 0 # for paging
3325 fullscreen_window = None
3326 srscan_window = None # Short range scan
3327 report_window = None # Report legends for status window
3328 status_window = None # The status window itself
3329 lrscan_window = None # Long range scan
3330 message_window = None # Main window for scrolling text
3331 prompt_window = None # Prompt window at bottom of display
3336 # for some recent versions of python2, the following enables UTF8
3337 # for the older ones we probably need to set C locale, and python3
3338 # has no problems at all
3339 if sys.version_info[0] < 3:
3340 locale.setlocale(locale.LC_ALL, "")
3341 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3342 gettext.textdomain("sst")
3343 if not (game.options & OPTION_CURSES):
3344 ln_env = os.getenv("LINES")
3350 stdscr = curses.initscr()
3354 if game.options & OPTION_COLOR:
3355 curses.start_color()
3356 curses.use_default_colors()
3357 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3358 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3359 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3360 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3361 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3362 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3363 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3364 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3365 global fullscreen_window, srscan_window, report_window, status_window
3366 global lrscan_window, message_window, prompt_window
3367 (rows, _columns) = stdscr.getmaxyx()
3368 fullscreen_window = stdscr
3369 srscan_window = curses.newwin(12, 25, 0, 0)
3370 report_window = curses.newwin(11, 0, 1, 25)
3371 status_window = curses.newwin(10, 0, 1, 39)
3372 lrscan_window = curses.newwin(5, 0, 0, 64)
3373 message_window = curses.newwin(0, 0, 12, 0)
3374 prompt_window = curses.newwin(1, 0, rows-2, 0)
3375 message_window.scrollok(True)
3376 setwnd(fullscreen_window)
3380 if game.options & OPTION_CURSES:
3381 stdscr.keypad(False)
3387 "Wait for user action -- OK to do nothing if on a TTY"
3388 if game.options & OPTION_CURSES:
3393 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3397 if game.skill > SKILL_FAIR:
3398 prompt = _("[CONTINUE?]")
3400 prompt = _("[PRESS ENTER TO CONTINUE]")
3402 if game.options & OPTION_CURSES:
3404 setwnd(prompt_window)
3405 prompt_window.clear()
3406 prompt_window.addstr(prompt)
3407 prompt_window.getstr()
3408 prompt_window.clear()
3409 prompt_window.refresh()
3410 setwnd(message_window)
3413 sys.stdout.write('\n')
3417 sys.stdout.write('\n' * rows)
3421 "Skip i lines. Pause game if this would cause a scrolling event."
3422 for _dummy in range(i):
3423 if game.options & OPTION_CURSES:
3424 (y, _x) = curwnd.getyx()
3427 except curses.error:
3432 if rows and linecount >= rows:
3435 sys.stdout.write('\n')
3437 def proutn(proutntline):
3438 "Utter a line with no following line feed."
3439 if game.options & OPTION_CURSES:
3440 (y, x) = curwnd.getyx()
3441 (my, _mx) = curwnd.getmaxyx()
3442 if curwnd == message_window and y >= my - 2:
3445 # Uncomment this to debug curses problems
3447 logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(proutntline)))
3448 curwnd.addstr(proutntline)
3451 sys.stdout.write(proutntline)
3454 def prout(proutline):
3458 def prouts(proutsline):
3460 for c in proutsline:
3461 if not replayfp or replayfp.closed: # Don't slow down replays
3464 if game.options & OPTION_CURSES:
3468 if not replayfp or replayfp.closed:
3472 "Get a line of input."
3473 if game.options & OPTION_CURSES:
3474 linein = curwnd.getstr() + "\n"
3477 if replayfp and not replayfp.closed:
3479 linein = replayfp.readline()
3482 prout("*** Replay finished")
3485 elif linein[0] != "#":
3489 linein = my_input() + "\n"
3498 "Change windows -- OK for this to be a no-op in tty mode."
3500 if game.options & OPTION_CURSES:
3501 # Uncomment this to debug curses problems
3503 if wnd == fullscreen_window:
3504 legend = "fullscreen"
3505 elif wnd == srscan_window:
3507 elif wnd == report_window:
3509 elif wnd == status_window:
3511 elif wnd == lrscan_window:
3513 elif wnd == message_window:
3515 elif wnd == prompt_window:
3519 logfp.write("#curses: setwnd(%s)\n" % legend)
3521 # Some curses implementations get confused when you try this.
3523 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3524 except curses.error:
3528 "Clear to end of line -- can be a no-op in tty mode"
3529 if game.options & OPTION_CURSES:
3534 "Clear screen -- can be a no-op in tty mode."
3536 if game.options & OPTION_CURSES:
3542 def textcolor(color=DEFAULT):
3543 if (game.options & OPTION_COLOR) and (game.options & OPTION_CURSES):
3544 if color == DEFAULT:
3546 elif color == BLACK:
3547 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3549 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3550 elif color == GREEN:
3551 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3553 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3555 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3556 elif color == MAGENTA:
3557 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3558 elif color == BROWN:
3559 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3560 elif color == LIGHTGRAY:
3561 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3562 elif color == DARKGRAY:
3563 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3564 elif color == LIGHTBLUE:
3565 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3566 elif color == LIGHTGREEN:
3567 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3568 elif color == LIGHTCYAN:
3569 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3570 elif color == LIGHTRED:
3571 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3572 elif color == LIGHTMAGENTA:
3573 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3574 elif color == YELLOW:
3575 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3576 elif color == WHITE:
3577 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3580 if (game.options & OPTION_COLOR) and (game.options & OPTION_CURSES):
3581 curwnd.attron(curses.A_REVERSE)
3584 # Things past this point have policy implications.
3588 "Hook to be called after moving to redraw maps."
3589 if game.options & OPTION_CURSES:
3592 setwnd(srscan_window)
3596 setwnd(status_window)
3597 status_window.clear()
3598 status_window.move(0, 0)
3599 setwnd(report_window)
3600 report_window.clear()
3601 report_window.move(0, 0)
3603 setwnd(lrscan_window)
3604 lrscan_window.clear()
3605 lrscan_window.move(0, 0)
3606 lrscan(silent=False)
3608 def put_srscan_sym(w, sym):
3609 "Emit symbol for short-range scan."
3610 srscan_window.move(w.i+1, w.j*2+2)
3611 srscan_window.addch(sym)
3612 srscan_window.refresh()
3615 "Enemy fall down, go boom."
3616 if game.options & OPTION_CURSES:
3618 setwnd(srscan_window)
3619 srscan_window.attron(curses.A_REVERSE)
3620 put_srscan_sym(w, game.quad[w.i][w.j])
3624 srscan_window.attroff(curses.A_REVERSE)
3625 put_srscan_sym(w, game.quad[w.i][w.j])
3626 curses.delay_output(500)
3627 setwnd(message_window)
3630 "Sound and visual effects for teleportation."
3631 if game.options & OPTION_CURSES:
3633 setwnd(message_window)
3635 prouts(" . . . . . ")
3636 if game.options & OPTION_CURSES:
3637 #curses.delay_output(1000)
3641 def tracktorpedo(w, step, i, n, iquad):
3642 "Torpedo-track animation."
3643 if not game.options & OPTION_CURSES:
3647 proutn(_("Track for torpedo number %d- ") % (i+1))
3650 proutn(_("Torpedo track- "))
3651 elif step==4 or step==9:
3655 if not damaged(DSRSENS) or game.condition=="docked":
3656 if i != 0 and step == 1:
3659 if (iquad=='.') or (iquad==' '):
3660 put_srscan_sym(w, '+')
3664 put_srscan_sym(w, iquad)
3666 curwnd.attron(curses.A_REVERSE)
3667 put_srscan_sym(w, iquad)
3671 curwnd.attroff(curses.A_REVERSE)
3672 put_srscan_sym(w, iquad)
3677 "Display the current galaxy chart."
3678 if game.options & OPTION_CURSES:
3679 setwnd(message_window)
3680 message_window.clear()
3682 if game.options & OPTION_TTY:
3687 def prstat(txt, data):
3689 if game.options & OPTION_CURSES:
3691 setwnd(status_window)
3693 proutn(" " * (NSYM - len(txt)))
3696 if game.options & OPTION_CURSES:
3697 setwnd(report_window)
3699 # Code from moving.c begins here
3701 def imove(icourse=None, noattack=False):
3702 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3705 def newquadrant(noattack):
3706 # Leaving quadrant -- allow final enemy attack
3707 # Don't set up attack if being pushed by nova or cloaked
3708 if len(game.enemies) != 0 and not noattack and not game.iscloaked:
3710 for enemy in game.enemies:
3711 finald = (w - enemy.location).distance()
3712 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3713 # Stas Sergeev added the condition
3714 # that attacks only happen if Klingons
3715 # are present and your skill is good.
3716 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3717 attack(torps_ok=False)
3720 # check for edge of galaxy
3726 if icourse.final.i < 0:
3727 icourse.final.i = -icourse.final.i
3729 if icourse.final.j < 0:
3730 icourse.final.j = -icourse.final.j
3732 if icourse.final.i >= GALSIZE*QUADSIZE:
3733 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3735 if icourse.final.j >= GALSIZE*QUADSIZE:
3736 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3744 if game.nkinks == 3:
3745 # Three strikes -- you're out!
3749 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3750 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3751 prout(_("YOU WILL BE DESTROYED."))
3752 # Compute final position in new quadrant
3753 if trbeam: # Don't bother if we are to be beamed
3755 game.quadrant = icourse.final.quadrant()
3756 game.sector = icourse.final.sector()
3758 prout(_("Entering Quadrant %s.") % game.quadrant)
3759 game.quad[game.sector.i][game.sector.j] = game.ship
3761 if game.skill>SKILL_NOVICE:
3762 attack(torps_ok=False)
3764 def check_collision(h):
3765 iquad = game.quad[h.i][h.j]
3767 # object encountered in flight path
3768 stopegy = 50.0*icourse.distance/game.optime
3769 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3770 for enemy in game.enemies:
3771 if enemy.location == game.sector:
3772 collision(rammed=False, enemy=enemy)
3774 # This should not happen
3775 prout(_("Which way did he go?"))
3779 prouts(_("***RED ALERT! RED ALERT!"))
3781 proutn("***" + crmshp())
3782 proutn(_(" pulled into black hole at Sector %s") % h)
3783 # Getting pulled into a black hole was certain
3784 # death in Almy's original. Stas Sergeev added a
3785 # possibility that you'll get timewarped instead.
3787 for m in range(NDEVICES):
3788 if game.damage[m]>0:
3790 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3791 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3801 prout(_(" encounters Tholian web at %s;") % h)
3803 prout(_(" blocked by object at %s;") % h)
3804 proutn(_("Emergency stop required "))
3805 prout(_("%2d units of energy.") % int(stopegy))
3806 game.energy -= stopegy
3807 if game.energy <= 0:
3814 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3815 game.inorbit = False
3816 # If tractor beam is to occur, don't move full distance
3817 if game.state.date+game.optime >= scheduled(FTBEAM):
3819 # We can't be tractor beamed if cloaked,
3820 # so move the event into the future
3821 postpone(FTBEAM, game.optime + expran(1.5*game.intime/len(game.kcmdr)))
3825 game.condition = "red"
3826 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3827 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3829 game.quad[game.sector.i][game.sector.j] = '.'
3830 for _m in range(icourse.moves):
3832 w = icourse.sector()
3833 if icourse.origin.quadrant() != icourse.location.quadrant():
3834 newquadrant(noattack)
3836 elif check_collision(w):
3837 print("Collision detected")
3841 # We're in destination quadrant -- compute new average enemy distances
3842 game.quad[game.sector.i][game.sector.j] = game.ship
3844 for enemy in game.enemies:
3845 finald = (w-enemy.location).distance()
3846 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3847 enemy.kdist = finald
3849 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3850 attack(torps_ok=False)
3851 for enemy in game.enemies:
3852 enemy.kavgd = enemy.kdist
3855 setwnd(message_window)
3859 "Dock our ship at a starbase."
3861 if game.condition == "docked" and verbose:
3862 prout(_("Already docked."))
3865 prout(_("You must first leave standard orbit."))
3867 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3868 prout(crmshp() + _(" not adjacent to base."))
3871 prout(_("You cannot dock while cloaked."))
3873 game.condition = "docked"
3877 if game.energy < game.inenrg:
3878 game.energy = game.inenrg
3879 game.shield = game.inshld
3880 game.torps = game.intorps
3881 game.lsupres = game.inlsr
3882 game.state.crew = FULLCREW
3883 if game.brigcapacity-game.brigfree > 0:
3884 prout(_("%d captured Klingons transferred to base") % (game.brigcapacity-game.brigfree))
3885 game.kcaptured += game.brigcapacity-game.brigfree
3886 game.brigfree = game.brigcapacity
3887 if not damaged(DRADIO) and \
3888 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3889 # get attack report from base
3890 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3894 def cartesian(loc1=None, loc2=None):
3896 return game.quadrant * QUADSIZE + game.sector
3898 return game.quadrant * QUADSIZE + loc1
3900 return loc1 * QUADSIZE + loc2
3902 def getcourse(isprobe):
3903 "Get a course and distance from the user."
3905 dquad = copy.copy(game.quadrant)
3906 navmode = "unspecified"
3910 if game.landed and not isprobe:
3911 prout(_("Dummy! You can't leave standard orbit until you"))
3912 proutn(_("are back aboard the ship."))
3915 while navmode == "unspecified":
3916 if damaged(DNAVSYS):
3918 prout(_("Computer damaged; manual navigation only"))
3920 prout(_("Computer damaged; manual movement only"))
3925 key = scanner.nexttok()
3927 proutn(_("Manual or automatic- "))
3930 elif key == "IHALPHA":
3931 if scanner.sees("manual"):
3933 key = scanner.nexttok()
3935 elif scanner.sees("automatic"):
3936 navmode = "automatic"
3937 key = scanner.nexttok()
3945 prout(_("(Manual navigation assumed.)"))
3947 prout(_("(Manual movement assumed.)"))
3951 if navmode == "automatic":
3952 while key == "IHEOL":
3954 proutn(_("Target quadrant or quadrant§or- "))
3956 proutn(_("Destination sector or quadrant§or- "))
3959 key = scanner.nexttok()
3963 xi = int(round(scanner.real))-1
3964 key = scanner.nexttok()
3968 xj = int(round(scanner.real))-1
3969 key = scanner.nexttok()
3971 # both quadrant and sector specified
3972 xk = int(round(scanner.real))-1
3973 key = scanner.nexttok()
3977 xl = int(round(scanner.real))-1
3983 # only one pair of numbers was specified
3985 # only quadrant specified -- go to center of dest quad
3988 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3990 # only sector specified
3994 if not dquad.valid_quadrant() or not dsect.valid_sector():
4001 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
4003 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
4004 # the actual deltas get computed here
4005 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
4006 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
4008 while key == "IHEOL":
4009 proutn(_("X and Y displacements- "))
4012 key = scanner.nexttok()
4015 delta.j = scanner.real
4019 key = scanner.nexttok()
4021 delta.i = scanner.real
4024 # Check for zero movement
4025 if delta.i == 0 and delta.j == 0:
4028 if itemp == "verbose" and not isprobe:
4030 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
4032 return course(bearing=delta.bearing(), distance=delta.distance())
4035 def __init__(self, bearing, distance, origin=None):
4036 self.distance = distance
4037 self.bearing = bearing
4039 self.origin = cartesian(game.quadrant, game.sector)
4041 self.origin = origin
4042 # The bearing() code we inherited from FORTRAN is actually computing
4043 # clockface directions!
4044 if self.bearing < 0.0:
4045 self.bearing += 12.0
4046 self.angle = ((15.0 - self.bearing) * 0.5235988)
4047 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
4048 bigger = max(abs(self.increment.i), abs(self.increment.j))
4049 self.increment /= bigger
4050 self.moves = int(round(10*self.distance*bigger))
4052 self.final = (self.location + self.moves*self.increment).roundtogrid()
4053 self.location = self.origin
4054 self.nextlocation = None
4056 self.location = self.origin
4059 return self.location.roundtogrid() == self.final
4061 "Next step on course."
4063 self.nextlocation = self.location + self.increment
4064 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
4065 self.location = self.nextlocation
4068 return self.location.quadrant()
4070 return self.location.sector()
4072 return self.distance*(w**3)*(game.shldup+1)
4074 return 10.0*self.distance/w**2
4077 "Move under impulse power."
4079 if damaged(DIMPULS):
4082 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4084 if game.energy > 30.0:
4086 icourse = getcourse(isprobe=False)
4089 power = 20.0 + 100.0*icourse.distance
4092 if power >= game.energy:
4093 # Insufficient power for trip
4095 prout(_("First Officer Spock- \"Captain, the impulse engines"))
4096 prout(_("require 20.0 units to engage, plus 100.0 units per"))
4097 if game.energy > 30:
4098 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
4099 int(0.01 * (game.energy-20.0)-0.05))
4100 prout(_(" quadrants.\""))
4102 prout(_("quadrant. They are, therefore, useless.\""))
4105 # Make sure enough time is left for the trip
4106 game.optime = icourse.distance/0.095
4107 if game.optime >= game.state.remtime:
4108 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
4109 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
4110 proutn(_("we dare spend the time?\" "))
4113 # Activate impulse engines and pay the cost
4114 imove(icourse, noattack=False)
4118 power = 20.0 + 100.0*icourse.distance
4119 game.energy -= power
4120 game.optime = icourse.distance/0.095
4121 if game.energy <= 0:
4125 def warp(wcourse, involuntary):
4126 "ove under warp drive."
4127 blooey = False; twarp = False
4128 if not involuntary: # Not WARPX entry
4133 prout(_("Engineer Scott- \"The warp engines can not be used while cloaked, Sir.\""))
4135 if game.damage[DWARPEN] > 10.0:
4138 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
4140 if damaged(DWARPEN) and game.warpfac > 4.0:
4143 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4144 prout(_(" is repaired, I can only give you warp 4.\""))
4146 # Read in course and distance
4149 wcourse = getcourse(isprobe=False)
4152 # Make sure starship has enough energy for the trip
4153 # Note: this formula is slightly different from the C version,
4154 # and lets you skate a bit closer to the edge.
4155 if wcourse.power(game.warpfac) >= game.energy:
4156 # Insufficient power for trip
4159 prout(_("Engineering to bridge--"))
4160 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
4161 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
4163 prout(_("We can't do it, Captain. We don't have enough energy."))
4165 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4168 prout(_("if you'll lower the shields."))
4172 prout(_("We haven't the energy to go that far with the shields up."))
4174 # Make sure enough time is left for the trip
4175 game.optime = wcourse.time(game.warpfac)
4176 if game.optime >= 0.8*game.state.remtime:
4178 prout(_("First Officer Spock- \"Captain, I compute that such"))
4179 proutn(_(" a trip would require approximately %2.0f") %
4180 (100.0*game.optime/game.state.remtime))
4181 prout(_(" percent of our"))
4182 proutn(_(" remaining time. Are you sure this is wise?\" "))
4188 if game.warpfac > 6.0:
4189 # Decide if engine damage will occur
4190 # ESR: Seems wrong. Probability of damage goes *down* with distance?
4191 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
4192 if prob > randreal():
4194 wcourse.distance = randreal(wcourse.distance)
4195 # Decide if time warp will occur
4196 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
4198 if game.idebug and game.warpfac==10 and not twarp:
4200 proutn("=== Force time warp? ")
4204 # If time warp or engine damage, check path
4205 # If it is obstructed, don't do warp or damage
4206 look = wcourse.moves
4210 w = wcourse.sector()
4211 if not w.valid_sector():
4213 if game.quad[w.i][w.j] != '.':
4217 # Activate Warp Engines and pay the cost
4218 imove(wcourse, noattack=False)
4221 game.energy -= wcourse.power(game.warpfac)
4222 if game.energy <= 0:
4224 game.optime = wcourse.time(game.warpfac)
4228 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4230 prout(_("Engineering to bridge--"))
4231 prout(_(" Scott here. The warp engines are damaged."))
4232 prout(_(" We'll have to reduce speed to warp 4."))
4237 "Change the warp factor."
4239 key=scanner.nexttok()
4243 proutn(_("Warp factor- "))
4247 if game.damage[DWARPEN] > 10.0:
4248 prout(_("Warp engines inoperative."))
4250 if damaged(DWARPEN) and scanner.real > 4.0:
4251 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4252 prout(_(" but right now we can only go warp 4.\""))
4254 if scanner.real > 10.0:
4255 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4257 if scanner.real < 1.0:
4258 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4260 oldfac = game.warpfac
4261 game.warpfac = scanner.real
4262 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4263 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4266 if game.warpfac < 8.00:
4267 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4269 if game.warpfac == 10.0:
4270 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4272 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4276 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4278 # is captain on planet?
4280 if damaged(DTRANSP):
4283 prout(_("Scotty rushes to the transporter controls."))
4285 prout(_("But with the shields up it's hopeless."))
4287 prouts(_("His desperate attempt to rescue you . . ."))
4292 prout(_("SUCCEEDS!"))
4295 proutn(_("The crystals mined were "))
4303 # Check to see if captain in shuttle craft
4308 # Inform captain of attempt to reach safety
4312 prouts(_("***RED ALERT! RED ALERT!"))
4314 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4315 prouts(_(" a supernova."))
4317 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4318 prout(_("safely out of quadrant."))
4319 if not damaged(DRADIO):
4320 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4321 # Try to use warp engines
4322 if damaged(DWARPEN):
4324 prout(_("Warp engines damaged."))
4327 game.warpfac = randreal(6.0, 8.0)
4328 prout(_("Warp factor set to %d") % int(game.warpfac))
4329 power = 0.75*game.energy
4330 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4331 dist = max(dist, randreal(math.sqrt(2)))
4332 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4333 game.optime = bugout.time(game.warpfac)
4335 game.inorbit = False
4336 warp(bugout, involuntary=True)
4338 # This is bad news, we didn't leave quadrant.
4342 prout(_("Insufficient energy to leave quadrant."))
4345 # Repeat if another snova
4346 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4348 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4349 finish(FWON) # Snova killed remaining enemy.
4352 "Let's do the time warp again."
4353 prout(_("***TIME WARP ENTERED."))
4354 if game.state.snap and withprob(0.5):
4356 prout(_("You are traveling backwards in time %d stardates.") %
4357 int(game.state.date-game.snapsht.date))
4358 game.state = game.snapsht
4359 game.state.snap = False
4360 if len(game.state.kcmdr):
4361 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4362 schedule(FBATTAK, expran(0.3*game.intime))
4363 schedule(FSNOVA, expran(0.5*game.intime))
4364 # next snapshot will be sooner
4365 schedule(FSNAP, expran(0.25*game.state.remtime))
4367 if game.state.nscrem:
4368 schedule(FSCMOVE, 0.2777)
4372 game.battle.invalidate()
4373 # Make sure Galileo is consistant -- Snapshot may have been taken
4374 # when on planet, which would give us two Galileos!
4376 for l in range(game.inplan):
4377 if game.state.planets[l].known == "shuttle_down":
4379 if game.iscraft == "onship" and game.ship=='E':
4380 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4381 game.iscraft = "offship"
4382 # Likewise, if in the original time the Galileo was abandoned, but
4383 # was on ship earlier, it would have vanished -- let's restore it.
4384 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4385 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4386 game.iscraft = "onship"
4387 # There used to be code to do the actual reconstrction here,
4388 # but the starchart is now part of the snapshotted galaxy state.
4389 prout(_("Spock has reconstructed a correct star chart from memory"))
4391 # Go forward in time
4392 game.optime = expran(0.5*game.intime)
4393 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4394 # cheat to make sure no tractor beams occur during time warp
4395 postpone(FTBEAM, game.optime)
4396 game.damage[DRADIO] += game.optime
4398 events() # Stas Sergeev added this -- do pending events
4401 "Launch deep-space probe."
4402 # New code to launch a deep space probe
4403 if game.nprobes == 0:
4406 if game.ship == 'E':
4407 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4409 prout(_("Ye Faerie Queene has no deep space probes."))
4414 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4416 if is_scheduled(FDSPROB):
4419 if damaged(DRADIO) and game.condition != "docked":
4420 prout(_("Spock- \"Records show the previous probe has not yet"))
4421 prout(_(" reached its destination.\""))
4423 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4425 key = scanner.nexttok()
4427 if game.nprobes == 1:
4428 prout(_("1 probe left."))
4430 prout(_("%d probes left") % game.nprobes)
4431 proutn(_("Are you sure you want to fire a probe? "))
4434 game.isarmed = False
4435 if key == "IHALPHA" and scanner.token == "armed":
4437 key = scanner.nexttok()
4438 elif key == "IHEOL":
4439 proutn(_("Arm NOVAMAX warhead? "))
4441 elif key == "IHREAL": # first element of course
4442 scanner.push(scanner.token)
4444 game.probe = getcourse(isprobe=True)
4448 schedule(FDSPROB, 0.01) # Time to move one sector
4449 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4454 "Yell for help from nearest starbase."
4455 # There's more than one way to move in this game!
4457 # Test for conditions which prevent calling for help
4458 if game.condition == "docked":
4459 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4462 prout(_("Subspace radio damaged."))
4464 if not game.state.baseq:
4465 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4468 prout(_("You must be aboard the %s.") % crmshp())
4470 # OK -- call for help from nearest starbase
4473 # There's one in this quadrant
4474 ddist = (game.base - game.sector).distance()
4476 ibq = None # Force base-quadrant game to persist past loop
4478 for ibq in game.state.baseq:
4479 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4483 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4485 # Since starbase not in quadrant, set up new quadrant
4488 # dematerialize starship
4489 game.quad[game.sector.i][game.sector.j]='.'
4490 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4491 % (game.quadrant, crmshp()))
4492 game.sector.invalidate()
4493 for m in range(1, 5+1):
4494 w = game.base.scatter()
4495 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4496 # found one -- finish up
4499 if not game.sector.is_valid():
4500 prout(_("You have been lost in space..."))
4501 finish(FMATERIALIZE)
4503 # Give starbase three chances to rematerialize starship
4504 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4505 for m in range(1, 3+1):
4506 if m == 1: proutn(_("1st"))
4507 elif m == 2: proutn(_("2nd"))
4508 elif m == 3: proutn(_("3rd"))
4509 proutn(_(" attempt to re-materialize ") + crmshp())
4510 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4513 if randreal() > probf:
4517 curses.delay_output(500)
4519 game.quad[game.sector.i][game.sector.j]='?'
4522 setwnd(message_window)
4523 finish(FMATERIALIZE)
4525 game.quad[game.sector.i][game.sector.j]=game.ship
4527 prout(_("succeeds."))
4531 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4536 if game.condition=="docked":
4538 prout(_("You cannot abandon Ye Faerie Queene."))
4541 # Must take shuttle craft to exit
4542 if game.damage[DSHUTTL]==-1:
4543 prout(_("Ye Faerie Queene has no shuttle craft."))
4545 if game.damage[DSHUTTL]<0:
4546 prout(_("Shuttle craft now serving Big Macs."))
4548 if game.damage[DSHUTTL]>0:
4549 prout(_("Shuttle craft damaged."))
4552 prout(_("You must be aboard the ship."))
4554 if game.iscraft != "onship":
4555 prout(_("Shuttle craft not currently available."))
4557 # Emit abandon ship messages
4559 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4561 prouts(_("***ALL HANDS ABANDON SHIP!"))
4563 prout(_("Captain and crew escape in shuttle craft."))
4564 if not game.state.baseq:
4565 # Oops! no place to go...
4568 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4570 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4571 prout(_("Remainder of ship's complement beam down"))
4572 prout(_("to nearest habitable planet."))
4573 elif q.planet != None and not damaged(DTRANSP):
4574 prout(_("Remainder of ship's complement beam down to %s.") %
4577 prout(_("Entire crew of %d left to die in outer space.") %
4579 game.casual += game.state.crew
4580 game.abandoned += game.state.crew
4581 # If at least one base left, give 'em the Faerie Queene
4583 game.icrystl = False # crystals are lost
4584 game.nprobes = 0 # No probes
4585 prout(_("You are captured by Klingons and released to"))
4586 prout(_("the Federation in a prisoner-of-war exchange."))
4587 nb = randrange(len(game.state.baseq))
4588 # Set up quadrant and position FQ adjacient to base
4589 if not game.quadrant == game.state.baseq[nb]:
4590 game.quadrant = game.state.baseq[nb]
4591 game.sector.i = game.sector.j = 5
4594 # position next to base by trial and error
4595 game.quad[game.sector.i][game.sector.j] = '.'
4597 for l in range(QUADSIZE):
4598 game.sector = game.base.scatter()
4599 if game.sector.valid_sector() and \
4600 game.quad[game.sector.i][game.sector.j] == '.':
4603 break # found a spot
4604 game.sector.i=QUADSIZE/2
4605 game.sector.j=QUADSIZE/2
4607 # Get new commission
4608 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4609 game.state.crew = FULLCREW
4610 prout(_("Starfleet puts you in command of another ship,"))
4611 prout(_("the Faerie Queene, which is antiquated but,"))
4612 prout(_("still useable."))
4614 prout(_("The dilithium crystals have been moved."))
4616 game.iscraft = "offship" # Galileo disappears
4618 game.condition="docked"
4619 for l in range(NDEVICES):
4620 game.damage[l] = 0.0
4621 game.damage[DSHUTTL] = -1
4622 game.energy = game.inenrg = 3000.0
4623 game.shield = game.inshld = 1250.0
4624 game.torps = game.intorps = 6
4625 game.lsupres=game.inlsr=3.0
4628 game.brigfree = game.brigcapacity = 300
4631 # Code from planets.c begins here.
4634 "Abort a lengthy operation if an event interrupts it."
4637 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4642 "Report on (uninhabited) planets in the galaxy."
4646 prout(_("Spock- \"Planet report follows, Captain.\""))
4648 for i in range(game.inplan):
4649 if game.state.planets[i].pclass == "destroyed":
4651 if (game.state.planets[i].known != "unknown" \
4652 and not game.state.planets[i].inhabited) \
4655 if game.idebug and game.state.planets[i].known=="unknown":
4656 proutn("(Unknown) ")
4657 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4658 proutn(_(" class "))
4659 proutn(game.state.planets[i].pclass)
4661 if game.state.planets[i].crystals != "present":
4663 prout(_("dilithium crystals present."))
4664 if game.state.planets[i].known=="shuttle_down":
4665 prout(_(" Shuttle Craft Galileo on surface."))
4667 prout(_("No information available."))
4670 "Enter standard orbit."
4674 prout(_("Already in standard orbit."))
4676 if damaged(DWARPEN) and damaged(DIMPULS):
4677 prout(_("Both warp and impulse engines damaged."))
4679 if not game.plnet.is_valid():
4680 prout("There is no planet in this sector.")
4682 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4683 prout(crmshp() + _(" not adjacent to planet."))
4686 game.optime = randreal(0.02, 0.05)
4687 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4691 game.height = randreal(1400, 8600)
4692 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4697 "Examine planets in this quadrant."
4698 if damaged(DSRSENS):
4699 if game.options & OPTION_TTY:
4700 prout(_("Short range sensors damaged."))
4702 if game.iplnet is None:
4703 if game.options & OPTION_TTY:
4704 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4706 if game.iplnet.known == "unknown":
4707 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4709 prout(_(" Planet at Sector %s is of class %s.") %
4710 (game.plnet, game.iplnet.pclass))
4711 if game.iplnet.known=="shuttle_down":
4712 prout(_(" Sensors show Galileo still on surface."))
4713 proutn(_(" Readings indicate"))
4714 if game.iplnet.crystals != "present":
4716 prout(_(" dilithium crystals present.\""))
4717 if game.iplnet.known == "unknown":
4718 game.iplnet.known = "known"
4719 elif game.iplnet.inhabited:
4720 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4721 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4724 "Use the transporter."
4728 if damaged(DTRANSP):
4729 prout(_("Transporter damaged."))
4730 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4732 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4736 if not game.inorbit:
4737 prout(crmshp() + _(" not in standard orbit."))
4740 prout(_("Impossible to transport through shields."))
4742 if game.iplnet.known=="unknown":
4743 prout(_("Spock- \"Captain, we have no information on this planet"))
4744 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4745 prout(_(" you may not go down.\""))
4747 if not game.landed and game.iplnet.crystals=="absent":
4748 prout(_("Spock- \"Captain, I fail to see the logic in"))
4749 prout(_(" exploring a planet with no dilithium crystals."))
4750 proutn(_(" Are you sure this is wise?\" "))
4754 if not (game.options & OPTION_PLAIN):
4755 nrgneed = 50 * game.skill + game.height / 100.0
4756 if nrgneed > game.energy:
4757 prout(_("Engineering to bridge--"))
4758 prout(_(" Captain, we don't have enough energy for transportation."))
4760 if not game.landed and nrgneed * 2 > game.energy:
4761 prout(_("Engineering to bridge--"))
4762 prout(_(" Captain, we have enough energy only to transport you down to"))
4763 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4764 if game.iplnet.known == "shuttle_down":
4765 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4766 proutn(_(" Are you sure this is wise?\" "))
4771 # Coming from planet
4772 if game.iplnet.known=="shuttle_down":
4773 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4777 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4778 prout(_("Landing party assembled, ready to beam up."))
4780 prout(_("Kirk whips out communicator..."))
4781 prouts(_("BEEP BEEP BEEP"))
4783 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4786 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4788 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4790 prout(_("Kirk- \"Energize.\""))
4793 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4795 if not withprob(0.98):
4796 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4798 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4801 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4802 game.landed = not game.landed
4803 game.energy -= nrgneed
4805 prout(_("Transport complete."))
4806 if game.landed and game.iplnet.known=="shuttle_down":
4807 prout(_("The shuttle craft Galileo is here!"))
4808 if not game.landed and game.imine:
4815 "Strip-mine a world for dilithium."
4819 prout(_("Mining party not on planet."))
4821 if game.iplnet.crystals == "mined":
4822 prout(_("This planet has already been strip-mined for dilithium."))
4824 elif game.iplnet.crystals == "absent":
4825 prout(_("No dilithium crystals on this planet."))
4828 prout(_("You've already mined enough crystals for this trip."))
4830 if game.icrystl and game.cryprob == 0.05:
4831 prout(_("With all those fresh crystals aboard the ") + crmshp())
4832 prout(_("there's no reason to mine more at this time."))
4834 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4837 prout(_("Mining operation complete."))
4838 game.iplnet.crystals = "mined"
4839 game.imine = game.ididit = True
4842 "Use dilithium crystals."
4846 if not game.icrystl:
4847 prout(_("No dilithium crystals available."))
4849 if game.energy >= 1000:
4850 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4851 prout(_(" except when Condition Yellow exists."))
4853 prout(_("Spock- \"Captain, I must warn you that loading"))
4854 prout(_(" raw dilithium crystals into the ship's power"))
4855 prout(_(" system may risk a severe explosion."))
4856 proutn(_(" Are you sure this is wise?\" "))
4861 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4862 prout(_(" Mr. Spock and I will try it.\""))
4864 prout(_("Spock- \"Crystals in place, Sir."))
4865 prout(_(" Ready to activate circuit.\""))
4867 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4869 if withprob(game.cryprob):
4870 prouts(_(" \"Activating now! - - No good! It's***"))
4872 prouts(_("***RED ALERT! RED A*L********************************"))
4875 prouts(_("****************** KA-BOOM!!!! *******************"))
4879 game.energy += randreal(5000.0, 5500.0)
4880 prouts(_(" \"Activating now! - - "))
4881 prout(_("The instruments"))
4882 prout(_(" are going crazy, but I think it's"))
4883 prout(_(" going to work!! Congratulations, Sir!\""))
4888 "Use shuttlecraft for planetary jaunt."
4891 if damaged(DSHUTTL):
4892 if game.damage[DSHUTTL] == -1.0:
4893 if game.inorbit and game.iplnet.known == "shuttle_down":
4894 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4896 prout(_("Ye Faerie Queene had no shuttle craft."))
4897 elif game.damage[DSHUTTL] > 0:
4898 prout(_("The Galileo is damaged."))
4899 else: # game.damage[DSHUTTL] < 0
4900 prout(_("Shuttle craft is now serving Big Macs."))
4902 if not game.inorbit:
4903 prout(crmshp() + _(" not in standard orbit."))
4905 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4906 prout(_("Shuttle craft not currently available."))
4908 if not game.landed and game.iplnet.known=="shuttle_down":
4909 prout(_("You will have to beam down to retrieve the shuttle craft."))
4911 if game.shldup or game.condition == "docked":
4912 prout(_("Shuttle craft cannot pass through shields."))
4914 if game.iplnet.known=="unknown":
4915 prout(_("Spock- \"Captain, we have no information on this planet"))
4916 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4917 prout(_(" you may not fly down.\""))
4919 game.optime = 3.0e-5*game.height
4920 if game.optime >= 0.8*game.state.remtime:
4921 prout(_("First Officer Spock- \"Captain, I compute that such"))
4922 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4923 int(100*game.optime/game.state.remtime))
4924 prout(_("remaining time."))
4925 proutn(_("Are you sure this is wise?\" "))
4931 if game.iscraft == "onship":
4933 if not damaged(DTRANSP):
4934 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4938 proutn(_("Shuttle crew"))
4940 proutn(_("Rescue party"))
4941 prout(_(" boards Galileo and swoops toward planet surface."))
4942 game.iscraft = "offship"
4946 game.iplnet.known="shuttle_down"
4947 prout(_("Trip complete."))
4950 # Ready to go back to ship
4951 prout(_("You and your mining party board the"))
4952 prout(_("shuttle craft for the trip back to the Enterprise."))
4954 prouts(_("The short hop begins . . ."))
4956 game.iplnet.known="known"
4962 game.iscraft = "onship"
4968 prout(_("Trip complete."))
4971 # Kirk on ship and so is Galileo
4972 prout(_("Mining party assembles in the hangar deck,"))
4973 prout(_("ready to board the shuttle craft \"Galileo\"."))
4975 prouts(_("The hangar doors open; the trip begins."))
4978 game.iscraft = "offship"
4981 game.iplnet.known = "shuttle_down"
4984 prout(_("Trip complete."))
4988 "Use the big zapper."
4992 if game.ship != 'E':
4993 prout(_("Ye Faerie Queene has no death ray."))
4995 if len(game.enemies)==0:
4996 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4999 prout(_("Death Ray is damaged."))
5001 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
5002 prout(_(" is highly unpredictible. Considering the alternatives,"))
5003 proutn(_(" are you sure this is wise?\" "))
5006 prout(_("Spock- \"Acknowledged.\""))
5009 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
5011 prout(_("Crew scrambles in emergency preparation."))
5012 prout(_("Spock and Scotty ready the death ray and"))
5013 prout(_("prepare to channel all ship's power to the device."))
5015 prout(_("Spock- \"Preparations complete, sir.\""))
5016 prout(_("Kirk- \"Engage!\""))
5018 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
5021 if game.options & OPTION_PLAIN:
5025 prouts(_("Sulu- \"Captain! It's working!\""))
5027 while len(game.enemies) > 0:
5028 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
5029 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
5030 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
5032 if (game.options & OPTION_PLAIN) == 0:
5033 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
5035 prout(_(" is still operational.\""))
5037 prout(_(" has been rendered nonfunctional.\""))
5038 game.damage[DDRAY] = 39.95
5040 r = randreal() # Pick failure method
5042 prouts(_("Sulu- \"Captain! It's working!\""))
5044 prouts(_("***RED ALERT! RED ALERT!"))
5046 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
5048 prouts(_("***RED ALERT! RED A*L********************************"))
5051 prouts(_("****************** KA-BOOM!!!! *******************"))
5056 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
5058 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
5060 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
5061 prout(_(" have apparently been transformed into strange mutations."))
5062 prout(_(" Vulcans do not seem to be affected."))
5064 prout(_("Kirk- \"Raauch! Raauch!\""))
5068 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
5070 proutn(_("Spock- \"I believe the word is"))
5071 prouts(_(" *ASTONISHING*"))
5072 prout(_(" Mr. Sulu."))
5073 for i in range(QUADSIZE):
5074 for j in range(QUADSIZE):
5075 if game.quad[i][j] == '.':
5076 game.quad[i][j] = '?'
5077 prout(_(" Captain, our quadrant is now infested with"))
5078 prouts(_(" - - - - - - *THINGS*."))
5080 prout(_(" I have no logical explanation.\""))
5082 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
5084 prout(_("Scotty- \"There are so many tribbles down here"))
5085 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
5089 # Code from reports.c begins here
5091 def attackreport(curt):
5092 "eport status of bases under attack."
5094 if is_scheduled(FCDBAS):
5095 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
5096 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
5097 elif game.isatb == 1:
5098 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
5099 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
5101 prout(_("No Starbase is currently under attack."))
5103 if is_scheduled(FCDBAS):
5104 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
5106 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
5110 # report on general game status
5112 s1 = (game.thawed and _("thawed ")) or ""
5113 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
5114 s3 = (None, _("novice"), _("fair"),
5115 _("good"), _("expert"), _("emeritus"))[game.skill]
5116 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
5117 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
5118 prout(_("No plaque is allowed."))
5120 prout(_("This is tournament game %d.") % game.tourn)
5121 prout(_("Your secret password is \"%s\"") % game.passwd)
5122 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
5123 (game.inkling + game.incom + game.inscom)))
5124 if game.incom - len(game.state.kcmdr):
5125 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
5126 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
5127 prout(_(", but no Commanders."))
5130 if game.skill > SKILL_FAIR:
5131 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
5132 if len(game.state.baseq) != game.inbase:
5134 if game.inbase-len(game.state.baseq)==1:
5135 proutn(_("has been 1 base"))
5137 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
5138 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
5140 prout(_("There are %d bases.") % game.inbase)
5141 if communicating() or game.iseenit:
5142 # Don't report this if not seen and
5143 # either the radio is dead or not at base!
5147 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
5148 if game.brigcapacity != game.brigfree:
5149 embriggened = brigcapacity-brigfree
5150 if embriggened == 1:
5151 prout(_("1 Klingon in brig"))
5153 prout(_("%d Klingons in brig.") % embriggened)
5154 if game.kcaptured == 0:
5156 elif game.kcaptured == 1:
5157 prout(_("1 captured Klingon turned in to Starfleet."))
5159 prout(_("%d captured Klingons turned in to Star Fleet.") % game.kcaptured)
5161 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
5162 if game.ship == 'E':
5163 proutn(_("You have "))
5165 proutn("%d" % (game.nprobes))
5168 proutn(_(" deep space probe"))
5172 if communicating() and is_scheduled(FDSPROB):
5174 proutn(_("An armed deep space probe is in "))
5176 proutn(_("A deep space probe is in "))
5177 prout("Quadrant %s." % game.probe.quadrant())
5179 if game.cryprob <= .05:
5180 prout(_("Dilithium crystals aboard ship... not yet used."))
5184 while game.cryprob > ai:
5187 prout(_("Dilithium crystals have been used %d time%s.") % \
5188 (i, (_("s"), "")[i==1]))
5192 "Long-range sensor scan."
5193 if damaged(DLRSENS):
5194 # Now allow base's sensors if docked
5195 if game.condition != "docked":
5197 prout(_("LONG-RANGE SENSORS DAMAGED."))
5200 prout(_("Starbase's long-range scan"))
5202 prout(_("Long-range scan"))
5203 for x in range(game.quadrant.i-1, game.quadrant.i+2):
5206 for y in range(game.quadrant.j-1, game.quadrant.j+2):
5207 if not Coord(x, y).valid_quadrant():
5211 if not damaged(DRADIO):
5212 game.state.galaxy[x][y].charted = True
5213 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5214 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5215 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5216 if not silent and game.state.galaxy[x][y].supernova:
5219 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
5227 for i in range(NDEVICES):
5230 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5231 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5233 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5234 game.damage[i]+0.05,
5235 DOCKFAC*game.damage[i]+0.005))
5237 prout(_("All devices functional."))
5240 "Update the chart in the Enterprise's computer from galaxy data."
5241 game.lastchart = game.state.date
5242 for i in range(GALSIZE):
5243 for j in range(GALSIZE):
5244 if game.state.galaxy[i][j].charted:
5245 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5246 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5247 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5250 "Display the star chart."
5252 if (game.options & OPTION_AUTOSCAN):
5254 if not damaged(DRADIO):
5256 if game.lastchart < game.state.date and game.condition == "docked":
5257 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5259 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5260 if game.state.date > game.lastchart:
5261 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5262 prout(" 1 2 3 4 5 6 7 8")
5263 for i in range(GALSIZE):
5264 proutn("%d |" % (i+1))
5265 for j in range(GALSIZE):
5266 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5270 if game.state.galaxy[i][j].supernova:
5272 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5274 elif game.state.galaxy[i][j].charted:
5275 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5279 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5287 def sectscan(goodScan, i, j):
5288 "Light up an individual dot in a sector."
5289 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5290 if game.quad[i][j] in ('E', 'F'):
5293 textcolor({"green":GREEN,
5297 "dead":BROWN}[game.condition])
5299 textcolor({'?':LIGHTMAGENTA,
5305 }.get(game.quad[i][j], DEFAULT))
5306 proutn("%c " % game.quad[i][j])
5312 "Emit status report lines"
5313 if not req or req == 1:
5314 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5315 % (game.state.date, game.state.remtime))
5316 if not req or req == 2:
5317 if game.condition != "docked":
5319 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5320 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5322 prout(_(", CLOAKED"))
5323 if not req or req == 3:
5324 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5325 if not req or req == 4:
5326 if damaged(DLIFSUP):
5327 if game.condition == "docked":
5328 s = _("DAMAGED, Base provides")
5330 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5333 prstat(_("Life Support"), s)
5334 if not req or req == 5:
5335 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5336 if not req or req == 6:
5338 if game.icrystl and (game.options & OPTION_SHOWME):
5339 extra = _(" (have crystals)")
5340 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5341 if not req or req == 7:
5342 prstat(_("Torpedoes"), "%d" % (game.torps))
5343 if not req or req == 8:
5344 if damaged(DSHIELD):
5350 data = _(" %d%% %.1f units") \
5351 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5352 prstat(_("Shields"), s+data)
5353 if not req or req == 9:
5354 prstat(_("Klingons Left"), "%d" \
5355 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5356 if not req or req == 10:
5357 if game.options & OPTION_WORLDS:
5358 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5359 if plnet and plnet.inhabited:
5360 prstat(_("Major system"), plnet.name)
5362 prout(_("Sector is uninhabited"))
5363 elif not req or req == 11:
5364 attackreport(not req)
5367 "Request specified status data, a historical relic from slow TTYs."
5368 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5369 while scanner.nexttok() == "IHEOL":
5370 proutn(_("Information desired? "))
5372 if scanner.token in requests:
5373 status(requests.index(scanner.token))
5375 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5376 prout((" date, condition, position, lsupport, warpfactor,"))
5377 prout((" energy, torpedoes, shields, klingons, system, time."))
5382 if damaged(DSRSENS):
5383 # Allow base's sensors if docked
5384 if game.condition != "docked":
5385 prout(_(" S.R. SENSORS DAMAGED!"))
5388 prout(_(" [Using Base's sensors]"))
5390 prout(_(" Short-range scan"))
5391 if goodScan and not damaged(DRADIO):
5392 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5393 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5394 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5395 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5396 prout(" 1 2 3 4 5 6 7 8 9 10")
5397 if game.condition != "docked":
5399 for i in range(QUADSIZE):
5400 proutn("%2d " % (i+1))
5401 for j in range(QUADSIZE):
5402 sectscan(goodScan, i, j)
5406 "Use computer to get estimated time of arrival for a warp jump."
5407 w1 = Coord(); w2 = Coord()
5409 if damaged(DCOMPTR):
5410 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5413 if scanner.nexttok() != "IHREAL":
5416 proutn(_("Destination quadrant and/or sector? "))
5417 if scanner.nexttok()!="IHREAL":
5420 w1.j = int(scanner.real-0.5)
5421 if scanner.nexttok() != "IHREAL":
5424 w1.i = int(scanner.real-0.5)
5425 if scanner.nexttok() == "IHREAL":
5426 w2.j = int(scanner.real-0.5)
5427 if scanner.nexttok() != "IHREAL":
5430 w2.i = int(scanner.real-0.5)
5432 if game.quadrant.j>w1.i:
5436 if game.quadrant.i>w1.j:
5440 if not w1.valid_quadrant() or not w2.valid_sector():
5443 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5444 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5447 prout(_("Answer \"no\" if you don't know the value:"))
5450 proutn(_("Time or arrival date? "))
5451 if scanner.nexttok()=="IHREAL":
5452 ttime = scanner.real
5453 if ttime > game.state.date:
5454 ttime -= game.state.date # Actually a star date
5455 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5456 if ttime <= 1e-10 or twarp > 10:
5457 prout(_("We'll never make it, sir."))
5464 proutn(_("Warp factor? "))
5465 if scanner.nexttok()== "IHREAL":
5467 twarp = scanner.real
5468 if twarp<1.0 or twarp > 10.0:
5472 prout(_("Captain, certainly you can give me one of these."))
5475 ttime = (10.0*dist)/twarp**2
5476 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5477 if tpower >= game.energy:
5478 prout(_("Insufficient energy, sir."))
5479 if not game.shldup or tpower > game.energy*2.0:
5482 proutn(_("New warp factor to try? "))
5483 if scanner.nexttok() == "IHREAL":
5485 twarp = scanner.real
5486 if twarp<1.0 or twarp > 10.0:
5494 prout(_("But if you lower your shields,"))
5495 proutn(_("remaining"))
5498 proutn(_("Remaining"))
5499 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5501 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5503 prout(_("Any warp speed is adequate."))
5505 prout(_("Minimum warp needed is %.2f,") % (twarp))
5506 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5507 if game.state.remtime < ttime:
5508 prout(_("Unfortunately, the Federation will be destroyed by then."))
5510 prout(_("You'll be taking risks at that speed, Captain"))
5511 if (game.isatb==1 and game.state.kscmdr == w1 and \
5512 scheduled(FSCDBAS)< ttime+game.state.date) or \
5513 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5514 prout(_("The starbase there will be destroyed by then."))
5515 proutn(_("New warp factor to try? "))
5516 if scanner.nexttok() == "IHREAL":
5518 twarp = scanner.real
5519 if twarp<1.0 or twarp > 10.0:
5527 # Code from setup.c begins here
5530 "Issue a historically correct banner."
5532 prout(_("-SUPER- STAR TREK"))
5534 # From the FORTRAN original
5535 # prout(_("Latest update-21 Sept 78"))
5541 scanner.push("emsave.trk")
5542 key = scanner.nexttok()
5544 proutn(_("File name: "))
5545 key = scanner.nexttok()
5546 if key != "IHALPHA":
5549 if '.' not in scanner.token:
5550 scanner.token += ".trk"
5552 fp = open(scanner.token, "wb")
5554 prout(_("Can't freeze game as file %s") % scanner.token)
5556 pickle.dump(game, fp)
5561 "Retrieve saved game."
5564 key = scanner.nexttok()
5566 proutn(_("File name: "))
5567 key = scanner.nexttok()
5568 if key != "IHALPHA":
5571 if '.' not in scanner.token:
5572 scanner.token += ".trk"
5574 fp = open(scanner.token, "rb")
5576 prout(_("Can't thaw game in %s") % scanner.token)
5578 game = pickle.load(fp)
5583 # I used <http://www.memory-alpha.org> to find planets
5584 # with references in ST:TOS. Earth and the Alpha Centauri
5585 # Colony have been omitted.
5587 # Some planets marked Class G and P here will be displayed as class M
5588 # because of the way planets are generated. This is a known bug.
5591 _("Andoria (Fesoan)"), # several episodes
5592 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5593 _("Vulcan (T'Khasi)"), # many episodes
5594 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5595 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5596 _("Ardana"), # TOS: "The Cloud Minders"
5597 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5598 _("Gideon"), # TOS: "The Mark of Gideon"
5599 _("Aldebaran III"), # TOS: "The Deadly Years"
5600 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5601 _("Altair IV"), # TOS: "Amok Time
5602 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5603 _("Benecia"), # TOS: "The Conscience of the King"
5604 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5605 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5606 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5607 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5608 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5609 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5610 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5611 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5612 _("Ingraham B"), # TOS: "Operation: Annihilate"
5613 _("Janus IV"), # TOS: "The Devil in the Dark"
5614 _("Makus III"), # TOS: "The Galileo Seven"
5615 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5616 _("Omega IV"), # TOS: "The Omega Glory"
5617 _("Regulus V"), # TOS: "Amok Time
5618 _("Deneva"), # TOS: "Operation -- Annihilate!"
5619 # Worlds from BSD Trek
5620 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5621 _("Beta III"), # TOS: "The Return of the Archons"
5622 _("Triacus"), # TOS: "And the Children Shall Lead",
5623 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5625 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5626 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5627 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5628 # _("Izar"), # TOS: "Whom Gods Destroy"
5629 # _("Tiburon"), # TOS: "The Way to Eden"
5630 # _("Merak II"), # TOS: "The Cloud Minders"
5631 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5632 # _("Iotia"), # TOS: "A Piece of the Action"
5636 _("S. R. Sensors"), \
5637 _("L. R. Sensors"), \
5639 _("Photon Tubes"), \
5640 _("Life Support"), \
5641 _("Warp Engines"), \
5642 _("Impulse Engines"), \
5644 _("Subspace Radio"), \
5645 _("Shuttle Craft"), \
5647 _("Navigation System"), \
5649 _("Shield Control"), \
5652 _("Cloaking Device"), \
5656 "Prepare to play, set up cosmos."
5658 # Decide how many of everything
5660 return # frozen game
5661 # Prepare the Enterprise
5662 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5664 game.state.crew = FULLCREW
5665 game.energy = game.inenrg = 5000.0
5666 game.shield = game.inshld = 2500.0
5669 game.quadrant = randplace(GALSIZE)
5670 game.sector = randplace(QUADSIZE)
5671 game.torps = game.intorps = 10
5672 game.nprobes = randrange(2, 5)
5674 for i in range(NDEVICES):
5675 game.damage[i] = 0.0
5676 # Set up assorted game parameters
5677 game.battle = Coord()
5678 game.state.date = game.indate = 100.0 * randreal(20, 51)
5679 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5680 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5681 game.isatb = game.state.nplankl = 0
5682 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5683 game.iscraft = "onship"
5688 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5690 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5692 game.state.planets = [] # Planet information
5693 game.state.baseq = [] # Base quadrant coordinates
5694 game.state.kcmdr = [] # Commander quadrant coordinates
5695 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5697 # Starchart is functional but we've never seen it
5698 game.lastchart = FOREVER
5699 # Put stars in the galaxy
5701 for i in range(GALSIZE):
5702 for j in range(GALSIZE):
5703 # Can't have more stars per quadrant than fit in one decimal digit,
5704 # if we do the chart representation will break.
5705 k = randrange(1, min(10, QUADSIZE**2/10))
5707 game.state.galaxy[i][j].stars = k
5708 # Locate star bases in galaxy
5710 prout("=== Allocating %d bases" % game.inbase)
5711 for i in range(game.inbase):
5714 w = randplace(GALSIZE)
5715 if not game.state.galaxy[w.i][w.j].starbase:
5718 # C version: for (j = i-1; j > 0; j--)
5719 # so it did them in the opposite order.
5720 for j in range(1, i):
5721 # Improved placement algorithm to spread out bases
5722 distq = (w - game.state.baseq[j]).distance()
5723 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5726 prout("=== Abandoning base #%d at %s" % (i, w))
5728 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5730 prout("=== Saving base #%d, close to #%d" % (i, j))
5734 prout("=== Placing base #%d in quadrant %s" % (i, w))
5735 game.state.baseq.append(w)
5736 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5737 # Position ordinary Klingon Battle Cruisers
5739 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5740 if klumper > MAXKLQUAD:
5744 klump = (1.0 - r*r)*klumper
5749 w = randplace(GALSIZE)
5750 if not game.state.galaxy[w.i][w.j].supernova and \
5751 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5753 game.state.galaxy[w.i][w.j].klingons += int(klump)
5756 # Position Klingon Commander Ships
5757 for i in range(game.incom):
5759 w = randplace(GALSIZE)
5760 if not welcoming(w) or w in game.state.kcmdr:
5762 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5764 game.state.galaxy[w.i][w.j].klingons += 1
5765 game.state.kcmdr.append(w)
5766 # Locate planets in galaxy
5767 for i in range(game.inplan):
5769 w = randplace(GALSIZE)
5770 if game.state.galaxy[w.i][w.j].planet is None:
5774 new.crystals = "absent"
5775 if (game.options & OPTION_WORLDS) and i < NINHAB:
5776 new.pclass = "M" # All inhabited planets are class M
5777 new.crystals = "absent"
5779 new.name = systnames[i]
5780 new.inhabited = True
5782 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5784 new.crystals = "present"
5785 new.known = "unknown"
5786 new.inhabited = False
5787 game.state.galaxy[w.i][w.j].planet = new
5788 game.state.planets.append(new)
5790 for i in range(game.state.nromrem):
5791 w = randplace(GALSIZE)
5792 game.state.galaxy[w.i][w.j].romulans += 1
5793 # Place the Super-Commander if needed
5794 if game.state.nscrem > 0:
5796 w = randplace(GALSIZE)
5799 game.state.kscmdr = w
5800 game.state.galaxy[w.i][w.j].klingons += 1
5801 # Initialize times for extraneous events
5802 schedule(FSNOVA, expran(0.5 * game.intime))
5803 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5804 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5805 schedule(FBATTAK, expran(0.3*game.intime))
5807 if game.state.nscrem:
5808 schedule(FSCMOVE, 0.2777)
5813 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5814 schedule(FDISTR, expran(1.0 + game.intime))
5819 # Place thing (in tournament game, we don't want one!)
5820 # New in SST2K: never place the Thing near a starbase.
5821 # This makes sense and avoids a special case in the old code.
5823 if game.tourn is None:
5825 thing = randplace(GALSIZE)
5826 if thing not in game.state.baseq:
5829 game.state.snap = False
5830 if game.skill == SKILL_NOVICE:
5831 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5832 prout(_("a deadly Klingon invasion force. As captain of the United"))
5833 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5834 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5835 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5836 prout(_("your mission. As you proceed you may be given more time."))
5838 prout(_("You will have %d supporting starbases.") % (game.inbase))
5839 proutn(_("Starbase locations- "))
5841 prout(_("Stardate %d.") % int(game.state.date))
5843 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5844 prout(_("An unknown number of Romulans."))
5845 if game.state.nscrem:
5846 prout(_("And one (GULP) Super-Commander."))
5847 prout(_("%d stardates.") % int(game.intime))
5848 proutn(_("%d starbases in ") % game.inbase)
5849 for i in range(game.inbase):
5850 proutn(repr(game.state.baseq[i]))
5853 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5854 proutn(_(" Sector %s") % game.sector)
5856 prout(_("Good Luck!"))
5857 if game.state.nscrem:
5858 prout(_(" YOU'LL NEED IT."))
5861 setwnd(message_window)
5863 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5865 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5866 attack(torps_ok=False)
5869 "Choose your game type."
5871 game.tourn = game.length = 0
5873 game.skill = SKILL_NONE
5874 # Do not chew here, we want to use command-line tokens
5875 if not scanner.inqueue: # Can start with command line options
5876 proutn(_("Would you like a regular, tournament, or saved game? "))
5878 if scanner.sees("tournament"):
5879 while scanner.nexttok() == "IHEOL":
5880 proutn(_("Type in tournament number-"))
5881 if scanner.real == 0:
5883 continue # We don't want a blank entry
5884 game.tourn = int(round(scanner.real))
5885 random.seed(scanner.real)
5887 logfp.write("# random.seed(%d)\n" % scanner.real)
5889 if scanner.sees("saved") or scanner.sees("frozen"):
5893 if game.passwd is None:
5895 if not game.alldone:
5896 game.thawed = True # No plaque if not finished
5900 if scanner.sees("regular"):
5902 proutn(_("What is \"%s\"? ") % scanner.token)
5904 while game.length==0 or game.skill==SKILL_NONE:
5905 if scanner.nexttok() == "IHALPHA":
5906 if scanner.sees("short"):
5908 elif scanner.sees("medium"):
5910 elif scanner.sees("long"):
5912 elif scanner.sees("novice"):
5913 game.skill = SKILL_NOVICE
5914 elif scanner.sees("fair"):
5915 game.skill = SKILL_FAIR
5916 elif scanner.sees("good"):
5917 game.skill = SKILL_GOOD
5918 elif scanner.sees("expert"):
5919 game.skill = SKILL_EXPERT
5920 elif scanner.sees("emeritus"):
5921 game.skill = SKILL_EMERITUS
5923 proutn(_("What is \""))
5924 proutn(scanner.token)
5929 proutn(_("Would you like a Short, Medium, or Long game? "))
5930 elif game.skill == SKILL_NONE:
5931 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5932 # Choose game options -- added by ESR for SST2K
5933 if scanner.nexttok() != "IHALPHA":
5935 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5937 if scanner.sees("plain"):
5938 # Approximates the UT FORTRAN version.
5939 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)
5940 game.options |= OPTION_PLAIN
5941 elif scanner.sees("almy"):
5942 # Approximates Tom Almy's version.
5943 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
5944 game.options |= OPTION_ALMY
5945 elif scanner.sees("fancy") or scanner.sees("\n"):
5947 elif len(scanner.token):
5948 proutn(_("What is \"%s\"?") % scanner.token)
5950 if game.passwd == "debug":
5952 prout("=== Debug mode enabled.")
5953 # Use parameters to generate initial values of things
5954 game.damfac = 0.5 * game.skill
5955 game.inbase = randrange(BASEMIN, BASEMAX+1)
5957 if game.options & OPTION_PLANETS:
5958 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5959 if game.options & OPTION_WORLDS:
5960 game.inplan += int(NINHAB)
5961 game.state.nromrem = game.inrom = randrange(2 * game.skill)
5962 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5963 game.state.remtime = 7.0 * game.length
5964 game.intime = game.state.remtime
5965 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5966 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5967 game.state.remres = (game.inkling+4*game.incom)*game.intime
5968 game.inresor = game.state.remres
5969 if game.inkling > 50:
5973 def dropin(iquad=None):
5974 "Drop a feature on a random dot in the current quadrant."
5976 w = randplace(QUADSIZE)
5977 if game.quad[w.i][w.j] == '.':
5979 if iquad is not None:
5980 game.quad[w.i][w.j] = iquad
5984 "Update our alert status."
5985 game.condition = "green"
5986 if game.energy < 1000.0:
5987 game.condition = "yellow"
5988 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5989 game.condition = "red"
5991 game.condition="dead"
5994 "Drop new Klingon into current quadrant."
5995 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5998 "Sort enemies by distance so 'nearest' is meaningful."
5999 game.enemies.sort(key=lambda x: x.kdist)
6002 "Set up a new state of quadrant, for when we enter or re-enter it."
6005 game.neutz = game.inorbit = game.landed = False
6006 game.ientesc = game.iseenit = game.isviolreported = False
6007 # Create a blank quadrant
6008 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
6010 # Attempt to escape Super-commander, so tbeam back!
6013 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
6014 # cope with supernova
6017 game.klhere = q.klingons
6018 game.irhere = q.romulans
6020 game.quad[game.sector.i][game.sector.j] = game.ship
6023 # Position ordinary Klingons
6024 for _i in range(game.klhere):
6026 # If we need a commander, promote a Klingon
6027 for cmdr in game.state.kcmdr:
6028 if cmdr == game.quadrant:
6029 e = game.enemies[game.klhere-1]
6030 game.quad[e.location.i][e.location.j] = 'C'
6031 e.power = randreal(950,1350) + 50.0*game.skill
6033 # If we need a super-commander, promote a Klingon
6034 if game.quadrant == game.state.kscmdr:
6036 game.quad[e.location.i][e.location.j] = 'S'
6037 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
6038 game.iscate = (game.state.remkl > 1)
6039 # Put in Romulans if needed
6040 for _i in range(q.romulans):
6041 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
6042 # If quadrant needs a starbase, put it in
6044 game.base = dropin('B')
6045 # If quadrant needs a planet, put it in
6047 game.iplnet = q.planet
6048 if not q.planet.inhabited:
6049 game.plnet = dropin('P')
6051 game.plnet = dropin('@')
6052 # Check for condition
6055 if game.irhere > 0 and game.klhere == 0:
6057 if not damaged(DRADIO):
6059 prout(_("LT. Uhura- \"Captain, an urgent message."))
6060 prout(_(" I'll put it on audio.\" CLICK"))
6062 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
6063 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
6064 # Put in THING if needed
6065 if thing == game.quadrant:
6066 Enemy(etype='?', loc=dropin(),
6067 power=randreal(6000,6500.0)+250.0*game.skill)
6068 if not damaged(DSRSENS):
6070 prout(_("Mr. Spock- \"Captain, this is most unusual."))
6071 prout(_(" Please examine your short-range scan.\""))
6072 # Decide if quadrant needs a Tholian; lighten up if skill is low
6073 if game.options & OPTION_THOLIAN:
6074 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
6075 (game.skill == SKILL_GOOD and withprob(0.05)) or \
6076 (game.skill > SKILL_GOOD and withprob(0.08)):
6079 w.i = withprob(0.5) * (QUADSIZE-1)
6080 w.j = withprob(0.5) * (QUADSIZE-1)
6081 if game.quad[w.i][w.j] == '.':
6083 game.tholian = Enemy(etype='T', loc=w,
6084 power=randrange(100, 500) + 25.0*game.skill)
6085 # Reserve unoccupied corners
6086 if game.quad[0][0]=='.':
6087 game.quad[0][0] = 'X'
6088 if game.quad[0][QUADSIZE-1]=='.':
6089 game.quad[0][QUADSIZE-1] = 'X'
6090 if game.quad[QUADSIZE-1][0]=='.':
6091 game.quad[QUADSIZE-1][0] = 'X'
6092 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
6093 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
6095 # And finally the stars
6096 for _i in range(q.stars):
6098 # Put in a few black holes
6099 for _i in range(1, 3+1):
6102 # Take out X's in corners if Tholian present
6104 if game.quad[0][0]=='X':
6105 game.quad[0][0] = '.'
6106 if game.quad[0][QUADSIZE-1]=='X':
6107 game.quad[0][QUADSIZE-1] = '.'
6108 if game.quad[QUADSIZE-1][0]=='X':
6109 game.quad[QUADSIZE-1][0] = '.'
6110 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
6111 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
6114 "Set the self-destruct password."
6115 if game.options & OPTION_PLAIN:
6118 proutn(_("Please type in a secret password- "))
6120 game.passwd = scanner.token
6121 if game.passwd != None:
6125 game.passwd += chr(ord('a')+randrange(26))
6126 game.passwd += chr(ord('a')+randrange(26))
6127 game.passwd += chr(ord('a')+randrange(26))
6129 # Code from sst.c begins here
6132 ("SRSCAN", OPTION_TTY),
6133 ("STATUS", OPTION_TTY),
6134 ("REQUEST", OPTION_TTY),
6135 ("LRSCAN", OPTION_TTY),
6147 ("SENSORS", OPTION_PLANETS),
6148 ("ORBIT", OPTION_PLANETS),
6149 ("TRANSPORT", OPTION_PLANETS),
6150 ("MINE", OPTION_PLANETS),
6151 ("CRYSTALS", OPTION_PLANETS),
6152 ("SHUTTLE", OPTION_PLANETS),
6153 ("PLANETS", OPTION_PLANETS),
6158 ("PROBE", OPTION_PROBE),
6160 ("FREEZE", 0), # Synonym for SAVE
6164 ("CAPTURE", OPTION_CAPTURE),
6165 ("CLOAK", OPTION_CLOAK),
6168 ("SOS", 0), # Synonym for MAYDAY
6169 ("CALL", 0), # Synonym for MAYDAY
6177 "Generate a list of legal commands."
6178 prout(_("LEGAL COMMANDS ARE:"))
6180 for (key, opt) in commands:
6181 if not opt or (opt & game.options):
6182 proutn("%-12s " % key)
6184 if emitted % 5 == 4:
6189 "Browse on-line help."
6190 key = scanner.nexttok()
6193 setwnd(prompt_window)
6194 proutn(_("Help on what command? "))
6195 key = scanner.nexttok()
6196 setwnd(message_window)
6199 cmds = [x[0] for x in commands]
6200 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
6207 cmd = scanner.token.upper()
6208 for directory in docpath:
6210 fp = open(os.path.join(directory, "sst.doc"), "r")
6215 prout(_("Spock- \"Captain, that information is missing from the"))
6216 prout(_(" computer. You need to find sst.doc and put it somewhere"))
6217 proutn(_(" in these directories: %s") % ":".join(docpath))
6219 # This used to continue: "You need to find SST.DOC and put
6220 # it in the current directory."
6223 linebuf = fp.readline()
6225 prout(_("Spock- \"Captain, there is no information on that command.\""))
6228 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
6229 linebuf = linebuf[3:].strip()
6230 if cmd.upper() == linebuf:
6233 prout(_("Spock- \"Captain, I've found the following information:\""))
6236 linebuf = fp.readline()
6237 if "******" in linebuf:
6243 "Command-interpretation loop."
6245 if game.irhere and game.state.date >= ALGERON and not game.isviolreported and game.iscloaked:
6246 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
6248 game.isviolreported = True
6249 while True: # command loop
6251 while True: # get a command
6253 game.optime = game.justin = False
6255 setwnd(prompt_window)
6258 if scanner.nexttok() == "IHEOL":
6259 if game.options & OPTION_CURSES:
6262 elif scanner.token == "":
6266 setwnd(message_window)
6268 abandon_passed = False
6269 cmd = "" # Force cmd to persist after loop
6270 opt = 0 # Force opt to persist after loop
6271 for (cmd, opt) in commands:
6272 # commands after ABANDON cannot be abbreviated
6273 if cmd == "ABANDON":
6274 abandon_passed = True
6275 if cmd == scanner.token.upper() or (not abandon_passed \
6276 and cmd.startswith(scanner.token.upper())):
6281 elif opt and not (opt & game.options):
6285 if 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
6393 break # Game has ended
6394 if game.optime != 0.0:
6397 break # Events did us in
6398 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6401 if hitme and not game.justin:
6402 attack(torps_ok=True)
6405 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6416 "Emit the name of an enemy or feature."
6417 if ch == 'R': s = _("Romulan")
6418 elif ch == 'K': s = _("Klingon")
6419 elif ch == 'C': s = _("Commander")
6420 elif ch == 'S': s = _("Super-commander")
6421 elif ch == '*': s = _("Star")
6422 elif ch == 'P': s = _("Planet")
6423 elif ch == 'B': s = _("Starbase")
6424 elif ch == ' ': s = _("Black hole")
6425 elif ch == 'T': s = _("Tholian")
6426 elif ch == '#': s = _("Tholian web")
6427 elif ch == '?': s = _("Stranger")
6428 elif ch == '@': s = _("Inhabited World")
6429 else: s = "Unknown??"
6432 def crmena(loud, enemy, loctype, w):
6433 "Emit the name of an enemy and his location."
6437 buf += cramen(enemy) + _(" at ")
6438 if loctype == "quadrant":
6439 buf += _("Quadrant ")
6440 elif loctype == "sector":
6442 return buf + repr(w)
6445 "Emit our ship name."
6446 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6449 "Emit a line of stars"
6450 prouts("******************************************************")
6454 return -avrage*math.log(1e-7 + randreal())
6456 def randplace(size):
6457 "Choose a random location."
6459 w.i = randrange(size)
6460 w.j = randrange(size)
6470 # Get a token from the user
6473 # Fill the token quue if nothing here
6474 while not self.inqueue:
6476 if curwnd==prompt_window:
6478 setwnd(message_window)
6485 self.inqueue = sline.lstrip().split() + ["\n"]
6486 # From here on in it's all looking at the queue
6487 self.token = self.inqueue.pop(0)
6488 if self.token == "\n":
6492 self.real = float(self.token)
6493 self.type = "IHREAL"
6498 self.token = self.token.lower()
6499 self.type = "IHALPHA"
6502 def append(self, tok):
6503 self.inqueue.append(tok)
6504 def push(self, tok):
6505 self.inqueue.insert(0, tok)
6509 # Demand input for next scan
6511 self.real = self.token = None
6513 # compares s to item and returns true if it matches to the length of s
6514 return s.startswith(self.token)
6516 # Round token value to nearest integer
6517 return int(round(self.real))
6521 if self.type != "IHREAL":
6526 if self.type != "IHREAL":
6532 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6535 "Yes-or-no confirmation."
6539 if scanner.token == 'y':
6541 if scanner.token == 'n':
6544 proutn(_("Please answer with \"y\" or \"n\": "))
6547 "Complain about unparseable input."
6550 prout(_("Beg your pardon, Captain?"))
6553 "Access to the internals for debugging."
6554 proutn("Reset levels? ")
6556 if game.energy < game.inenrg:
6557 game.energy = game.inenrg
6558 game.shield = game.inshld
6559 game.torps = game.intorps
6560 game.lsupres = game.inlsr
6561 proutn("Reset damage? ")
6563 for i in range(NDEVICES):
6564 if game.damage[i] > 0.0:
6565 game.damage[i] = 0.0
6566 proutn("Toggle debug flag? ")
6568 game.idebug = not game.idebug
6570 prout("Debug output ON")
6572 prout("Debug output OFF")
6573 proutn("Cause selective damage? ")
6575 for i in range(NDEVICES):
6576 proutn("Kill %s?" % device[i])
6578 key = scanner.nexttok()
6579 if key == "IHALPHA" and scanner.sees("y"):
6580 game.damage[i] = 10.0
6581 proutn("Examine/change events? ")
6586 FSNOVA: "Supernova ",
6589 FBATTAK: "Base Attack ",
6590 FCDBAS: "Base Destroy ",
6591 FSCMOVE: "SC Move ",
6592 FSCDBAS: "SC Base Destroy ",
6593 FDSPROB: "Probe Move ",
6594 FDISTR: "Distress Call ",
6595 FENSLV: "Enslavement ",
6596 FREPRO: "Klingon Build ",
6598 for i in range(1, NEVENTS):
6601 proutn("%.2f" % (scheduled(i)-game.state.date))
6602 if i == FENSLV or i == FREPRO:
6604 proutn(" in %s" % ev.quadrant)
6609 key = scanner.nexttok()
6613 elif key == "IHREAL":
6614 ev = schedule(i, scanner.real)
6615 if i == FENSLV or i == FREPRO:
6617 proutn("In quadrant- ")
6618 key = scanner.nexttok()
6619 # "IHEOL" says to leave coordinates as they are
6622 prout("Event %d canceled, no x coordinate." % (i))
6625 w.i = int(round(scanner.real))
6626 key = scanner.nexttok()
6628 prout("Event %d canceled, no y coordinate." % (i))
6631 w.j = int(round(scanner.real))
6634 proutn("Induce supernova here? ")
6636 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6639 if __name__ == '__main__':
6641 #global line, thing, game
6645 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6646 if os.getenv("TERM"):
6647 game.options |= OPTION_CURSES
6649 game.options |= OPTION_TTY
6650 seed = int(time.time())
6651 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6653 for (switch, val) in options:
6656 replayfp = open(val, "r")
6658 sys.stderr.write("sst: can't open replay file %s\n" % val)
6661 line = replayfp.readline().strip()
6662 (leader, __, seed) = line.split()
6664 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6665 line = replayfp.readline().strip()
6666 arguments += line.split()[2:]
6669 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6671 game.options |= OPTION_TTY
6672 game.options &=~ OPTION_CURSES
6673 elif switch == '-s':
6675 elif switch == '-t':
6676 game.options |= OPTION_TTY
6677 game.options &=~ OPTION_CURSES
6678 elif switch == '-x':
6680 elif switch == '-V':
6681 print("SST2K", version)
6684 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6686 # where to save the input in case of bugs
6687 if "TMPDIR" in os.environ:
6688 tmpdir = os.environ['TMPDIR']
6692 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6694 sys.stderr.write("sst: warning, can't open logfile\n")
6697 logfp.write("# seed %s\n" % seed)
6698 logfp.write("# options %s\n" % " ".join(arguments))
6699 logfp.write("# SST2K version %s\n" % version)
6700 logfp.write("# recorded by %s@%s on %s\n" % \
6701 (getpass.getuser(),socket.gethostname(),time.ctime()))
6703 scanner = sstscanner()
6704 for arg in arguments:
6708 while True: # Play a game
6709 setwnd(fullscreen_window)
6715 game.alldone = False
6723 if game.tourn and game.alldone:
6724 proutn(_("Do you want your score recorded?"))
6730 proutn(_("Do you want to play again? "))
6734 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6738 except KeyboardInterrupt: