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()
4017 delta.j = scanner.real
4018 key = scanner.nexttok()
4022 delta.i = scanner.real
4023 # Check for zero movement
4024 if delta.i == 0 and delta.j == 0:
4027 if itemp == "verbose" and not isprobe:
4029 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
4031 return course(bearing=delta.bearing(), distance=delta.distance())
4034 def __init__(self, bearing, distance, origin=None):
4035 self.distance = distance
4036 self.bearing = bearing
4038 self.origin = cartesian(game.quadrant, game.sector)
4040 self.origin = origin
4041 # The bearing() code we inherited from FORTRAN is actually computing
4042 # clockface directions!
4043 if self.bearing < 0.0:
4044 self.bearing += 12.0
4045 self.angle = ((15.0 - self.bearing) * 0.5235988)
4046 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
4047 bigger = max(abs(self.increment.i), abs(self.increment.j))
4048 self.increment /= bigger
4049 self.moves = int(round(10*self.distance*bigger))
4051 self.final = (self.location + self.moves*self.increment).roundtogrid()
4052 self.location = self.origin
4053 self.nextlocation = None
4055 self.location = self.origin
4058 return self.location.roundtogrid() == self.final
4060 "Next step on course."
4062 self.nextlocation = self.location + self.increment
4063 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
4064 self.location = self.nextlocation
4067 return self.location.quadrant()
4069 return self.location.sector()
4071 return self.distance*(w**3)*(game.shldup+1)
4073 return 10.0*self.distance/w**2
4076 "Move under impulse power."
4078 if damaged(DIMPULS):
4081 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4083 if game.energy > 30.0:
4085 icourse = getcourse(isprobe=False)
4088 power = 20.0 + 100.0*icourse.distance
4091 if power >= game.energy:
4092 # Insufficient power for trip
4094 prout(_("First Officer Spock- \"Captain, the impulse engines"))
4095 prout(_("require 20.0 units to engage, plus 100.0 units per"))
4096 if game.energy > 30:
4097 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
4098 int(0.01 * (game.energy-20.0)-0.05))
4099 prout(_(" quadrants.\""))
4101 prout(_("quadrant. They are, therefore, useless.\""))
4104 # Make sure enough time is left for the trip
4105 game.optime = icourse.distance/0.095
4106 if game.optime >= game.state.remtime:
4107 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
4108 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
4109 proutn(_("we dare spend the time?\" "))
4112 # Activate impulse engines and pay the cost
4113 imove(icourse, noattack=False)
4117 power = 20.0 + 100.0*icourse.distance
4118 game.energy -= power
4119 game.optime = icourse.distance/0.095
4120 if game.energy <= 0:
4124 def warp(wcourse, involuntary):
4125 "ove under warp drive."
4126 blooey = False; twarp = False
4127 if not involuntary: # Not WARPX entry
4132 prout(_("Engineer Scott- \"The warp engines can not be used while cloaked, Sir.\""))
4134 if game.damage[DWARPEN] > 10.0:
4137 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
4139 if damaged(DWARPEN) and game.warpfac > 4.0:
4142 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4143 prout(_(" is repaired, I can only give you warp 4.\""))
4145 # Read in course and distance
4148 wcourse = getcourse(isprobe=False)
4151 # Make sure starship has enough energy for the trip
4152 # Note: this formula is slightly different from the C version,
4153 # and lets you skate a bit closer to the edge.
4154 if wcourse.power(game.warpfac) >= game.energy:
4155 # Insufficient power for trip
4158 prout(_("Engineering to bridge--"))
4159 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
4160 iwarp = (game.energy/(wcourse.distance+0.05)) ** 0.333333333
4162 prout(_("We can't do it, Captain. We don't have enough energy."))
4164 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4167 prout(_("if you'll lower the shields."))
4171 prout(_("We haven't the energy to go that far with the shields up."))
4173 # Make sure enough time is left for the trip
4174 game.optime = wcourse.time(game.warpfac)
4175 if game.optime >= 0.8*game.state.remtime:
4177 prout(_("First Officer Spock- \"Captain, I compute that such"))
4178 proutn(_(" a trip would require approximately %2.0f") %
4179 (100.0*game.optime/game.state.remtime))
4180 prout(_(" percent of our"))
4181 proutn(_(" remaining time. Are you sure this is wise?\" "))
4187 if game.warpfac > 6.0:
4188 # Decide if engine damage will occur
4189 # ESR: Seems wrong. Probability of damage goes *down* with distance?
4190 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
4191 if prob > randreal():
4193 wcourse.distance = randreal(wcourse.distance)
4194 # Decide if time warp will occur
4195 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
4197 if game.idebug and game.warpfac==10 and not twarp:
4199 proutn("=== Force time warp? ")
4203 # If time warp or engine damage, check path
4204 # If it is obstructed, don't do warp or damage
4205 look = wcourse.moves
4209 w = wcourse.sector()
4210 if not w.valid_sector():
4212 if game.quad[w.i][w.j] != '.':
4216 # Activate Warp Engines and pay the cost
4217 imove(wcourse, noattack=False)
4220 game.energy -= wcourse.power(game.warpfac)
4221 if game.energy <= 0:
4223 game.optime = wcourse.time(game.warpfac)
4227 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
4229 prout(_("Engineering to bridge--"))
4230 prout(_(" Scott here. The warp engines are damaged."))
4231 prout(_(" We'll have to reduce speed to warp 4."))
4236 "Change the warp factor."
4238 key=scanner.nexttok()
4242 proutn(_("Warp factor- "))
4246 if game.damage[DWARPEN] > 10.0:
4247 prout(_("Warp engines inoperative."))
4249 if damaged(DWARPEN) and scanner.real > 4.0:
4250 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4251 prout(_(" but right now we can only go warp 4.\""))
4253 if scanner.real > 10.0:
4254 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4256 if scanner.real < 1.0:
4257 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4259 oldfac = game.warpfac
4260 game.warpfac = scanner.real
4261 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4262 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4265 if game.warpfac < 8.00:
4266 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4268 if game.warpfac == 10.0:
4269 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4271 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4275 "Cope with being tossed out of quadrant by supernova or yanked by beam."
4277 # is captain on planet?
4279 if damaged(DTRANSP):
4282 prout(_("Scotty rushes to the transporter controls."))
4284 prout(_("But with the shields up it's hopeless."))
4286 prouts(_("His desperate attempt to rescue you . . ."))
4291 prout(_("SUCCEEDS!"))
4294 proutn(_("The crystals mined were "))
4302 # Check to see if captain in shuttle craft
4307 # Inform captain of attempt to reach safety
4311 prouts(_("***RED ALERT! RED ALERT!"))
4313 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4314 prouts(_(" a supernova."))
4316 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4317 prout(_("safely out of quadrant."))
4318 if not damaged(DRADIO):
4319 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4320 # Try to use warp engines
4321 if damaged(DWARPEN):
4323 prout(_("Warp engines damaged."))
4326 game.warpfac = randreal(6.0, 8.0)
4327 prout(_("Warp factor set to %d") % int(game.warpfac))
4328 power = 0.75*game.energy
4329 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4330 dist = max(dist, randreal(math.sqrt(2)))
4331 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4332 game.optime = bugout.time(game.warpfac)
4334 game.inorbit = False
4335 warp(bugout, involuntary=True)
4337 # This is bad news, we didn't leave quadrant.
4341 prout(_("Insufficient energy to leave quadrant."))
4344 # Repeat if another snova
4345 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4347 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4348 finish(FWON) # Snova killed remaining enemy.
4351 "Let's do the time warp again."
4352 prout(_("***TIME WARP ENTERED."))
4353 if game.state.snap and withprob(0.5):
4355 prout(_("You are traveling backwards in time %d stardates.") %
4356 int(game.state.date-game.snapsht.date))
4357 game.state = game.snapsht
4358 game.state.snap = False
4359 if len(game.state.kcmdr):
4360 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4361 schedule(FBATTAK, expran(0.3*game.intime))
4362 schedule(FSNOVA, expran(0.5*game.intime))
4363 # next snapshot will be sooner
4364 schedule(FSNAP, expran(0.25*game.state.remtime))
4366 if game.state.nscrem:
4367 schedule(FSCMOVE, 0.2777)
4371 game.battle.invalidate()
4372 # Make sure Galileo is consistant -- Snapshot may have been taken
4373 # when on planet, which would give us two Galileos!
4375 for l in range(game.inplan):
4376 if game.state.planets[l].known == "shuttle_down":
4378 if game.iscraft == "onship" and game.ship=='E':
4379 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4380 game.iscraft = "offship"
4381 # Likewise, if in the original time the Galileo was abandoned, but
4382 # was on ship earlier, it would have vanished -- let's restore it.
4383 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4384 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4385 game.iscraft = "onship"
4386 # There used to be code to do the actual reconstrction here,
4387 # but the starchart is now part of the snapshotted galaxy state.
4388 prout(_("Spock has reconstructed a correct star chart from memory"))
4390 # Go forward in time
4391 game.optime = expran(0.5*game.intime)
4392 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4393 # cheat to make sure no tractor beams occur during time warp
4394 postpone(FTBEAM, game.optime)
4395 game.damage[DRADIO] += game.optime
4397 events() # Stas Sergeev added this -- do pending events
4400 "Launch deep-space probe."
4401 # New code to launch a deep space probe
4402 if game.nprobes == 0:
4405 if game.ship == 'E':
4406 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4408 prout(_("Ye Faerie Queene has no deep space probes."))
4413 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4415 if is_scheduled(FDSPROB):
4418 if damaged(DRADIO) and game.condition != "docked":
4419 prout(_("Spock- \"Records show the previous probe has not yet"))
4420 prout(_(" reached its destination.\""))
4422 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4424 key = scanner.nexttok()
4426 if game.nprobes == 1:
4427 prout(_("1 probe left."))
4429 prout(_("%d probes left") % game.nprobes)
4430 proutn(_("Are you sure you want to fire a probe? "))
4433 game.isarmed = False
4434 if key == "IHALPHA" and scanner.token == "armed":
4436 key = scanner.nexttok()
4437 elif key == "IHEOL":
4438 proutn(_("Arm NOVAMAX warhead? "))
4440 elif key == "IHREAL": # first element of course
4441 scanner.push(scanner.token)
4443 game.probe = getcourse(isprobe=True)
4447 schedule(FDSPROB, 0.01) # Time to move one sector
4448 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4453 "Yell for help from nearest starbase."
4454 # There's more than one way to move in this game!
4456 # Test for conditions which prevent calling for help
4457 if game.condition == "docked":
4458 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4461 prout(_("Subspace radio damaged."))
4463 if not game.state.baseq:
4464 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4467 prout(_("You must be aboard the %s.") % crmshp())
4469 # OK -- call for help from nearest starbase
4472 # There's one in this quadrant
4473 ddist = (game.base - game.sector).distance()
4475 ibq = None # Force base-quadrant game to persist past loop
4477 for ibq in game.state.baseq:
4478 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4482 prout(_("No starbases remain. You are alone in a hostile galaxy."))
4484 # Since starbase not in quadrant, set up new quadrant
4487 # dematerialize starship
4488 game.quad[game.sector.i][game.sector.j]='.'
4489 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4490 % (game.quadrant, crmshp()))
4491 game.sector.invalidate()
4492 for m in range(1, 5+1):
4493 w = game.base.scatter()
4494 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4495 # found one -- finish up
4498 if not game.sector.is_valid():
4499 prout(_("You have been lost in space..."))
4500 finish(FMATERIALIZE)
4502 # Give starbase three chances to rematerialize starship
4503 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4504 for m in range(1, 3+1):
4505 if m == 1: proutn(_("1st"))
4506 elif m == 2: proutn(_("2nd"))
4507 elif m == 3: proutn(_("3rd"))
4508 proutn(_(" attempt to re-materialize ") + crmshp())
4509 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4512 if randreal() > probf:
4516 curses.delay_output(500)
4518 game.quad[game.sector.i][game.sector.j]='?'
4521 setwnd(message_window)
4522 finish(FMATERIALIZE)
4524 game.quad[game.sector.i][game.sector.j]=game.ship
4526 prout(_("succeeds."))
4530 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4535 if game.condition=="docked":
4537 prout(_("You cannot abandon Ye Faerie Queene."))
4540 # Must take shuttle craft to exit
4541 if game.damage[DSHUTTL]==-1:
4542 prout(_("Ye Faerie Queene has no shuttle craft."))
4544 if game.damage[DSHUTTL]<0:
4545 prout(_("Shuttle craft now serving Big Macs."))
4547 if game.damage[DSHUTTL]>0:
4548 prout(_("Shuttle craft damaged."))
4551 prout(_("You must be aboard the ship."))
4553 if game.iscraft != "onship":
4554 prout(_("Shuttle craft not currently available."))
4556 # Emit abandon ship messages
4558 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4560 prouts(_("***ALL HANDS ABANDON SHIP!"))
4562 prout(_("Captain and crew escape in shuttle craft."))
4563 if not game.state.baseq:
4564 # Oops! no place to go...
4567 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4569 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4570 prout(_("Remainder of ship's complement beam down"))
4571 prout(_("to nearest habitable planet."))
4572 elif q.planet != None and not damaged(DTRANSP):
4573 prout(_("Remainder of ship's complement beam down to %s.") %
4576 prout(_("Entire crew of %d left to die in outer space.") %
4578 game.casual += game.state.crew
4579 game.abandoned += game.state.crew
4580 # If at least one base left, give 'em the Faerie Queene
4582 game.icrystl = False # crystals are lost
4583 game.nprobes = 0 # No probes
4584 prout(_("You are captured by Klingons and released to"))
4585 prout(_("the Federation in a prisoner-of-war exchange."))
4586 nb = randrange(len(game.state.baseq))
4587 # Set up quadrant and position FQ adjacient to base
4588 if not game.quadrant == game.state.baseq[nb]:
4589 game.quadrant = game.state.baseq[nb]
4590 game.sector.i = game.sector.j = 5
4593 # position next to base by trial and error
4594 game.quad[game.sector.i][game.sector.j] = '.'
4596 for l in range(QUADSIZE):
4597 game.sector = game.base.scatter()
4598 if game.sector.valid_sector() and \
4599 game.quad[game.sector.i][game.sector.j] == '.':
4602 break # found a spot
4603 game.sector.i=QUADSIZE/2
4604 game.sector.j=QUADSIZE/2
4606 # Get new commission
4607 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4608 game.state.crew = FULLCREW
4609 prout(_("Starfleet puts you in command of another ship,"))
4610 prout(_("the Faerie Queene, which is antiquated but,"))
4611 prout(_("still useable."))
4613 prout(_("The dilithium crystals have been moved."))
4615 game.iscraft = "offship" # Galileo disappears
4617 game.condition="docked"
4618 for l in range(NDEVICES):
4619 game.damage[l] = 0.0
4620 game.damage[DSHUTTL] = -1
4621 game.energy = game.inenrg = 3000.0
4622 game.shield = game.inshld = 1250.0
4623 game.torps = game.intorps = 6
4624 game.lsupres=game.inlsr=3.0
4627 game.brigfree = game.brigcapacity = 300
4630 # Code from planets.c begins here.
4633 "Abort a lengthy operation if an event interrupts it."
4636 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4641 "Report on (uninhabited) planets in the galaxy."
4645 prout(_("Spock- \"Planet report follows, Captain.\""))
4647 for i in range(game.inplan):
4648 if game.state.planets[i].pclass == "destroyed":
4650 if (game.state.planets[i].known != "unknown" \
4651 and not game.state.planets[i].inhabited) \
4654 if game.idebug and game.state.planets[i].known=="unknown":
4655 proutn("(Unknown) ")
4656 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4657 proutn(_(" class "))
4658 proutn(game.state.planets[i].pclass)
4660 if game.state.planets[i].crystals != "present":
4662 prout(_("dilithium crystals present."))
4663 if game.state.planets[i].known=="shuttle_down":
4664 prout(_(" Shuttle Craft Galileo on surface."))
4666 prout(_("No information available."))
4669 "Enter standard orbit."
4673 prout(_("Already in standard orbit."))
4675 if damaged(DWARPEN) and damaged(DIMPULS):
4676 prout(_("Both warp and impulse engines damaged."))
4678 if not game.plnet.is_valid():
4679 prout("There is no planet in this sector.")
4681 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4682 prout(crmshp() + _(" not adjacent to planet."))
4685 game.optime = randreal(0.02, 0.05)
4686 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4690 game.height = randreal(1400, 8600)
4691 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4696 "Examine planets in this quadrant."
4697 if damaged(DSRSENS):
4698 if game.options & OPTION_TTY:
4699 prout(_("Short range sensors damaged."))
4701 if game.iplnet is None:
4702 if game.options & OPTION_TTY:
4703 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4705 if game.iplnet.known == "unknown":
4706 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4708 prout(_(" Planet at Sector %s is of class %s.") %
4709 (game.plnet, game.iplnet.pclass))
4710 if game.iplnet.known=="shuttle_down":
4711 prout(_(" Sensors show Galileo still on surface."))
4712 proutn(_(" Readings indicate"))
4713 if game.iplnet.crystals != "present":
4715 prout(_(" dilithium crystals present.\""))
4716 if game.iplnet.known == "unknown":
4717 game.iplnet.known = "known"
4718 elif game.iplnet.inhabited:
4719 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4720 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4723 "Use the transporter."
4727 if damaged(DTRANSP):
4728 prout(_("Transporter damaged."))
4729 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4731 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4735 if not game.inorbit:
4736 prout(crmshp() + _(" not in standard orbit."))
4739 prout(_("Impossible to transport through shields."))
4741 if game.iplnet.known=="unknown":
4742 prout(_("Spock- \"Captain, we have no information on this planet"))
4743 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4744 prout(_(" you may not go down.\""))
4746 if not game.landed and game.iplnet.crystals=="absent":
4747 prout(_("Spock- \"Captain, I fail to see the logic in"))
4748 prout(_(" exploring a planet with no dilithium crystals."))
4749 proutn(_(" Are you sure this is wise?\" "))
4753 if not (game.options & OPTION_PLAIN):
4754 nrgneed = 50 * game.skill + game.height / 100.0
4755 if nrgneed > game.energy:
4756 prout(_("Engineering to bridge--"))
4757 prout(_(" Captain, we don't have enough energy for transportation."))
4759 if not game.landed and nrgneed * 2 > game.energy:
4760 prout(_("Engineering to bridge--"))
4761 prout(_(" Captain, we have enough energy only to transport you down to"))
4762 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4763 if game.iplnet.known == "shuttle_down":
4764 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4765 proutn(_(" Are you sure this is wise?\" "))
4770 # Coming from planet
4771 if game.iplnet.known=="shuttle_down":
4772 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4776 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4777 prout(_("Landing party assembled, ready to beam up."))
4779 prout(_("Kirk whips out communicator..."))
4780 prouts(_("BEEP BEEP BEEP"))
4782 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4785 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4787 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4789 prout(_("Kirk- \"Energize.\""))
4792 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4794 if not withprob(0.98):
4795 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4797 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4800 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4801 game.landed = not game.landed
4802 game.energy -= nrgneed
4804 prout(_("Transport complete."))
4805 if game.landed and game.iplnet.known=="shuttle_down":
4806 prout(_("The shuttle craft Galileo is here!"))
4807 if not game.landed and game.imine:
4814 "Strip-mine a world for dilithium."
4818 prout(_("Mining party not on planet."))
4820 if game.iplnet.crystals == "mined":
4821 prout(_("This planet has already been strip-mined for dilithium."))
4823 elif game.iplnet.crystals == "absent":
4824 prout(_("No dilithium crystals on this planet."))
4827 prout(_("You've already mined enough crystals for this trip."))
4829 if game.icrystl and game.cryprob == 0.05:
4830 prout(_("With all those fresh crystals aboard the ") + crmshp())
4831 prout(_("there's no reason to mine more at this time."))
4833 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4836 prout(_("Mining operation complete."))
4837 game.iplnet.crystals = "mined"
4838 game.imine = game.ididit = True
4841 "Use dilithium crystals."
4845 if not game.icrystl:
4846 prout(_("No dilithium crystals available."))
4848 if game.energy >= 1000:
4849 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4850 prout(_(" except when Condition Yellow exists."))
4852 prout(_("Spock- \"Captain, I must warn you that loading"))
4853 prout(_(" raw dilithium crystals into the ship's power"))
4854 prout(_(" system may risk a severe explosion."))
4855 proutn(_(" Are you sure this is wise?\" "))
4860 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4861 prout(_(" Mr. Spock and I will try it.\""))
4863 prout(_("Spock- \"Crystals in place, Sir."))
4864 prout(_(" Ready to activate circuit.\""))
4866 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4868 if withprob(game.cryprob):
4869 prouts(_(" \"Activating now! - - No good! It's***"))
4871 prouts(_("***RED ALERT! RED A*L********************************"))
4874 prouts(_("****************** KA-BOOM!!!! *******************"))
4878 game.energy += randreal(5000.0, 5500.0)
4879 prouts(_(" \"Activating now! - - "))
4880 prout(_("The instruments"))
4881 prout(_(" are going crazy, but I think it's"))
4882 prout(_(" going to work!! Congratulations, Sir!\""))
4887 "Use shuttlecraft for planetary jaunt."
4890 if damaged(DSHUTTL):
4891 if game.damage[DSHUTTL] == -1.0:
4892 if game.inorbit and game.iplnet.known == "shuttle_down":
4893 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4895 prout(_("Ye Faerie Queene had no shuttle craft."))
4896 elif game.damage[DSHUTTL] > 0:
4897 prout(_("The Galileo is damaged."))
4898 else: # game.damage[DSHUTTL] < 0
4899 prout(_("Shuttle craft is now serving Big Macs."))
4901 if not game.inorbit:
4902 prout(crmshp() + _(" not in standard orbit."))
4904 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4905 prout(_("Shuttle craft not currently available."))
4907 if not game.landed and game.iplnet.known=="shuttle_down":
4908 prout(_("You will have to beam down to retrieve the shuttle craft."))
4910 if game.shldup or game.condition == "docked":
4911 prout(_("Shuttle craft cannot pass through shields."))
4913 if game.iplnet.known=="unknown":
4914 prout(_("Spock- \"Captain, we have no information on this planet"))
4915 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4916 prout(_(" you may not fly down.\""))
4918 game.optime = 3.0e-5*game.height
4919 if game.optime >= 0.8*game.state.remtime:
4920 prout(_("First Officer Spock- \"Captain, I compute that such"))
4921 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4922 int(100*game.optime/game.state.remtime))
4923 prout(_("remaining time."))
4924 proutn(_("Are you sure this is wise?\" "))
4930 if game.iscraft == "onship":
4932 if not damaged(DTRANSP):
4933 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4937 proutn(_("Shuttle crew"))
4939 proutn(_("Rescue party"))
4940 prout(_(" boards Galileo and swoops toward planet surface."))
4941 game.iscraft = "offship"
4945 game.iplnet.known="shuttle_down"
4946 prout(_("Trip complete."))
4949 # Ready to go back to ship
4950 prout(_("You and your mining party board the"))
4951 prout(_("shuttle craft for the trip back to the Enterprise."))
4953 prouts(_("The short hop begins . . ."))
4955 game.iplnet.known="known"
4961 game.iscraft = "onship"
4967 prout(_("Trip complete."))
4970 # Kirk on ship and so is Galileo
4971 prout(_("Mining party assembles in the hangar deck,"))
4972 prout(_("ready to board the shuttle craft \"Galileo\"."))
4974 prouts(_("The hangar doors open; the trip begins."))
4977 game.iscraft = "offship"
4980 game.iplnet.known = "shuttle_down"
4983 prout(_("Trip complete."))
4987 "Use the big zapper."
4991 if game.ship != 'E':
4992 prout(_("Ye Faerie Queene has no death ray."))
4994 if len(game.enemies)==0:
4995 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4998 prout(_("Death Ray is damaged."))
5000 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
5001 prout(_(" is highly unpredictible. Considering the alternatives,"))
5002 proutn(_(" are you sure this is wise?\" "))
5005 prout(_("Spock- \"Acknowledged.\""))
5008 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
5010 prout(_("Crew scrambles in emergency preparation."))
5011 prout(_("Spock and Scotty ready the death ray and"))
5012 prout(_("prepare to channel all ship's power to the device."))
5014 prout(_("Spock- \"Preparations complete, sir.\""))
5015 prout(_("Kirk- \"Engage!\""))
5017 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
5020 if game.options & OPTION_PLAIN:
5024 prouts(_("Sulu- \"Captain! It's working!\""))
5026 while len(game.enemies) > 0:
5027 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
5028 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
5029 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
5031 if (game.options & OPTION_PLAIN) == 0:
5032 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
5034 prout(_(" is still operational.\""))
5036 prout(_(" has been rendered nonfunctional.\""))
5037 game.damage[DDRAY] = 39.95
5039 r = randreal() # Pick failure method
5041 prouts(_("Sulu- \"Captain! It's working!\""))
5043 prouts(_("***RED ALERT! RED ALERT!"))
5045 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
5047 prouts(_("***RED ALERT! RED A*L********************************"))
5050 prouts(_("****************** KA-BOOM!!!! *******************"))
5055 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
5057 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
5059 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
5060 prout(_(" have apparently been transformed into strange mutations."))
5061 prout(_(" Vulcans do not seem to be affected."))
5063 prout(_("Kirk- \"Raauch! Raauch!\""))
5067 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
5069 proutn(_("Spock- \"I believe the word is"))
5070 prouts(_(" *ASTONISHING*"))
5071 prout(_(" Mr. Sulu."))
5072 for i in range(QUADSIZE):
5073 for j in range(QUADSIZE):
5074 if game.quad[i][j] == '.':
5075 game.quad[i][j] = '?'
5076 prout(_(" Captain, our quadrant is now infested with"))
5077 prouts(_(" - - - - - - *THINGS*."))
5079 prout(_(" I have no logical explanation.\""))
5081 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
5083 prout(_("Scotty- \"There are so many tribbles down here"))
5084 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
5088 # Code from reports.c begins here
5090 def attackreport(curt):
5091 "eport status of bases under attack."
5093 if is_scheduled(FCDBAS):
5094 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
5095 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
5096 elif game.isatb == 1:
5097 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
5098 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
5100 prout(_("No Starbase is currently under attack."))
5102 if is_scheduled(FCDBAS):
5103 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
5105 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
5109 # report on general game status
5111 s1 = (game.thawed and _("thawed ")) or ""
5112 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
5113 s3 = (None, _("novice"), _("fair"),
5114 _("good"), _("expert"), _("emeritus"))[game.skill]
5115 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
5116 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
5117 prout(_("No plaque is allowed."))
5119 prout(_("This is tournament game %d.") % game.tourn)
5120 prout(_("Your secret password is \"%s\"") % game.passwd)
5121 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
5122 (game.inkling + game.incom + game.inscom)))
5123 if game.incom - len(game.state.kcmdr):
5124 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
5125 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
5126 prout(_(", but no Commanders."))
5129 if game.skill > SKILL_FAIR:
5130 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
5131 if len(game.state.baseq) != game.inbase:
5133 if game.inbase-len(game.state.baseq)==1:
5134 proutn(_("has been 1 base"))
5136 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
5137 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
5139 prout(_("There are %d bases.") % game.inbase)
5140 if communicating() or game.iseenit:
5141 # Don't report this if not seen and
5142 # either the radio is dead or not at base!
5146 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
5147 if game.brigcapacity != game.brigfree:
5148 embriggened = brigcapacity-brigfree
5149 if embriggened == 1:
5150 prout(_("1 Klingon in brig"))
5152 prout(_("%d Klingons in brig.") % embriggened)
5153 if game.kcaptured == 0:
5155 elif game.kcaptured == 1:
5156 prout(_("1 captured Klingon turned in to Starfleet."))
5158 prout(_("%d captured Klingons turned in to Star Fleet.") % game.kcaptured)
5160 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
5161 if game.ship == 'E':
5162 proutn(_("You have "))
5164 proutn("%d" % (game.nprobes))
5167 proutn(_(" deep space probe"))
5171 if communicating() and is_scheduled(FDSPROB):
5173 proutn(_("An armed deep space probe is in "))
5175 proutn(_("A deep space probe is in "))
5176 prout("Quadrant %s." % game.probe.quadrant())
5178 if game.cryprob <= .05:
5179 prout(_("Dilithium crystals aboard ship... not yet used."))
5183 while game.cryprob > ai:
5186 prout(_("Dilithium crystals have been used %d time%s.") % \
5187 (i, (_("s"), "")[i==1]))
5191 "Long-range sensor scan."
5192 if damaged(DLRSENS):
5193 # Now allow base's sensors if docked
5194 if game.condition != "docked":
5196 prout(_("LONG-RANGE SENSORS DAMAGED."))
5199 prout(_("Starbase's long-range scan"))
5201 prout(_("Long-range scan"))
5202 for x in range(game.quadrant.i-1, game.quadrant.i+2):
5205 for y in range(game.quadrant.j-1, game.quadrant.j+2):
5206 if not Coord(x, y).valid_quadrant():
5210 if not damaged(DRADIO):
5211 game.state.galaxy[x][y].charted = True
5212 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5213 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5214 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5215 if not silent and game.state.galaxy[x][y].supernova:
5218 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
5226 for i in range(NDEVICES):
5229 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5230 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5232 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
5233 game.damage[i]+0.05,
5234 DOCKFAC*game.damage[i]+0.005))
5236 prout(_("All devices functional."))
5239 "Update the chart in the Enterprise's computer from galaxy data."
5240 game.lastchart = game.state.date
5241 for i in range(GALSIZE):
5242 for j in range(GALSIZE):
5243 if game.state.galaxy[i][j].charted:
5244 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5245 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5246 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5249 "Display the star chart."
5251 if (game.options & OPTION_AUTOSCAN):
5253 if not damaged(DRADIO):
5255 if game.lastchart < game.state.date and game.condition == "docked":
5256 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
5258 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
5259 if game.state.date > game.lastchart:
5260 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5261 prout(" 1 2 3 4 5 6 7 8")
5262 for i in range(GALSIZE):
5263 proutn("%d |" % (i+1))
5264 for j in range(GALSIZE):
5265 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5269 if game.state.galaxy[i][j].supernova:
5271 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5273 elif game.state.galaxy[i][j].charted:
5274 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
5278 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
5286 def sectscan(goodScan, i, j):
5287 "Light up an individual dot in a sector."
5288 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
5289 if game.quad[i][j] in ('E', 'F'):
5292 textcolor({"green":GREEN,
5296 "dead":BROWN}[game.condition])
5298 textcolor({'?':LIGHTMAGENTA,
5304 }.get(game.quad[i][j], DEFAULT))
5305 proutn("%c " % game.quad[i][j])
5311 "Emit status report lines"
5312 if not req or req == 1:
5313 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5314 % (game.state.date, game.state.remtime))
5315 if not req or req == 2:
5316 if game.condition != "docked":
5318 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5319 (game.condition.upper(), sum([x > 0 for x in game.damage])))
5321 prout(_(", CLOAKED"))
5322 if not req or req == 3:
5323 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5324 if not req or req == 4:
5325 if damaged(DLIFSUP):
5326 if game.condition == "docked":
5327 s = _("DAMAGED, Base provides")
5329 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5332 prstat(_("Life Support"), s)
5333 if not req or req == 5:
5334 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5335 if not req or req == 6:
5337 if game.icrystl and (game.options & OPTION_SHOWME):
5338 extra = _(" (have crystals)")
5339 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5340 if not req or req == 7:
5341 prstat(_("Torpedoes"), "%d" % (game.torps))
5342 if not req or req == 8:
5343 if damaged(DSHIELD):
5349 data = _(" %d%% %.1f units") \
5350 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5351 prstat(_("Shields"), s+data)
5352 if not req or req == 9:
5353 prstat(_("Klingons Left"), "%d" \
5354 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5355 if not req or req == 10:
5356 if game.options & OPTION_WORLDS:
5357 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5358 if plnet and plnet.inhabited:
5359 prstat(_("Major system"), plnet.name)
5361 prout(_("Sector is uninhabited"))
5362 elif not req or req == 11:
5363 attackreport(not req)
5366 "Request specified status data, a historical relic from slow TTYs."
5367 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5368 while scanner.nexttok() == "IHEOL":
5369 proutn(_("Information desired? "))
5371 if scanner.token in requests:
5372 status(requests.index(scanner.token))
5374 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5375 prout((" date, condition, position, lsupport, warpfactor,"))
5376 prout((" energy, torpedoes, shields, klingons, system, time."))
5381 if damaged(DSRSENS):
5382 # Allow base's sensors if docked
5383 if game.condition != "docked":
5384 prout(_(" S.R. SENSORS DAMAGED!"))
5387 prout(_(" [Using Base's sensors]"))
5389 prout(_(" Short-range scan"))
5390 if goodScan and not damaged(DRADIO):
5391 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5392 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5393 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5394 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5395 prout(" 1 2 3 4 5 6 7 8 9 10")
5396 if game.condition != "docked":
5398 for i in range(QUADSIZE):
5399 proutn("%2d " % (i+1))
5400 for j in range(QUADSIZE):
5401 sectscan(goodScan, i, j)
5405 "Use computer to get estimated time of arrival for a warp jump."
5406 w1 = Coord(); w2 = Coord()
5408 if damaged(DCOMPTR):
5409 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5412 if scanner.nexttok() != "IHREAL":
5415 proutn(_("Destination quadrant and/or sector? "))
5416 if scanner.nexttok()!="IHREAL":
5419 w1.j = int(scanner.real-0.5)
5420 if scanner.nexttok() != "IHREAL":
5423 w1.i = int(scanner.real-0.5)
5424 if scanner.nexttok() == "IHREAL":
5425 w2.j = int(scanner.real-0.5)
5426 if scanner.nexttok() != "IHREAL":
5429 w2.i = int(scanner.real-0.5)
5431 if game.quadrant.j>w1.i:
5435 if game.quadrant.i>w1.j:
5439 if not w1.valid_quadrant() or not w2.valid_sector():
5442 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5443 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5446 prout(_("Answer \"no\" if you don't know the value:"))
5449 proutn(_("Time or arrival date? "))
5450 if scanner.nexttok()=="IHREAL":
5451 ttime = scanner.real
5452 if ttime > game.state.date:
5453 ttime -= game.state.date # Actually a star date
5454 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5455 if ttime <= 1e-10 or twarp > 10:
5456 prout(_("We'll never make it, sir."))
5463 proutn(_("Warp factor? "))
5464 if scanner.nexttok()== "IHREAL":
5466 twarp = scanner.real
5467 if twarp<1.0 or twarp > 10.0:
5471 prout(_("Captain, certainly you can give me one of these."))
5474 ttime = (10.0*dist)/twarp**2
5475 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5476 if tpower >= game.energy:
5477 prout(_("Insufficient energy, sir."))
5478 if not game.shldup or tpower > game.energy*2.0:
5481 proutn(_("New warp factor to try? "))
5482 if scanner.nexttok() == "IHREAL":
5484 twarp = scanner.real
5485 if twarp<1.0 or twarp > 10.0:
5493 prout(_("But if you lower your shields,"))
5494 proutn(_("remaining"))
5497 proutn(_("Remaining"))
5498 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5500 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5502 prout(_("Any warp speed is adequate."))
5504 prout(_("Minimum warp needed is %.2f,") % (twarp))
5505 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5506 if game.state.remtime < ttime:
5507 prout(_("Unfortunately, the Federation will be destroyed by then."))
5509 prout(_("You'll be taking risks at that speed, Captain"))
5510 if (game.isatb==1 and game.state.kscmdr == w1 and \
5511 scheduled(FSCDBAS)< ttime+game.state.date) or \
5512 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5513 prout(_("The starbase there will be destroyed by then."))
5514 proutn(_("New warp factor to try? "))
5515 if scanner.nexttok() == "IHREAL":
5517 twarp = scanner.real
5518 if twarp<1.0 or twarp > 10.0:
5526 # Code from setup.c begins here
5529 "Issue a historically correct banner."
5531 prout(_("-SUPER- STAR TREK"))
5533 # From the FORTRAN original
5534 # prout(_("Latest update-21 Sept 78"))
5540 scanner.push("emsave.trk")
5541 key = scanner.nexttok()
5543 proutn(_("File name: "))
5544 key = scanner.nexttok()
5545 if key != "IHALPHA":
5548 if '.' not in scanner.token:
5549 scanner.token += ".trk"
5551 fp = open(scanner.token, "wb")
5553 prout(_("Can't freeze game as file %s") % scanner.token)
5555 pickle.dump(game, fp)
5560 "Retrieve saved game."
5563 key = scanner.nexttok()
5565 proutn(_("File name: "))
5566 key = scanner.nexttok()
5567 if key != "IHALPHA":
5570 if '.' not in scanner.token:
5571 scanner.token += ".trk"
5573 fp = open(scanner.token, "rb")
5575 prout(_("Can't thaw game in %s") % scanner.token)
5577 game = pickle.load(fp)
5582 # I used <http://www.memory-alpha.org> to find planets
5583 # with references in ST:TOS. Earth and the Alpha Centauri
5584 # Colony have been omitted.
5586 # Some planets marked Class G and P here will be displayed as class M
5587 # because of the way planets are generated. This is a known bug.
5590 _("Andoria (Fesoan)"), # several episodes
5591 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5592 _("Vulcan (T'Khasi)"), # many episodes
5593 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5594 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5595 _("Ardana"), # TOS: "The Cloud Minders"
5596 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5597 _("Gideon"), # TOS: "The Mark of Gideon"
5598 _("Aldebaran III"), # TOS: "The Deadly Years"
5599 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5600 _("Altair IV"), # TOS: "Amok Time
5601 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5602 _("Benecia"), # TOS: "The Conscience of the King"
5603 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5604 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5605 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5606 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5607 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5608 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5609 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5610 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5611 _("Ingraham B"), # TOS: "Operation: Annihilate"
5612 _("Janus IV"), # TOS: "The Devil in the Dark"
5613 _("Makus III"), # TOS: "The Galileo Seven"
5614 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5615 _("Omega IV"), # TOS: "The Omega Glory"
5616 _("Regulus V"), # TOS: "Amok Time
5617 _("Deneva"), # TOS: "Operation -- Annihilate!"
5618 # Worlds from BSD Trek
5619 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5620 _("Beta III"), # TOS: "The Return of the Archons"
5621 _("Triacus"), # TOS: "And the Children Shall Lead",
5622 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5624 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5625 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5626 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5627 # _("Izar"), # TOS: "Whom Gods Destroy"
5628 # _("Tiburon"), # TOS: "The Way to Eden"
5629 # _("Merak II"), # TOS: "The Cloud Minders"
5630 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5631 # _("Iotia"), # TOS: "A Piece of the Action"
5635 _("S. R. Sensors"), \
5636 _("L. R. Sensors"), \
5638 _("Photon Tubes"), \
5639 _("Life Support"), \
5640 _("Warp Engines"), \
5641 _("Impulse Engines"), \
5643 _("Subspace Radio"), \
5644 _("Shuttle Craft"), \
5646 _("Navigation System"), \
5648 _("Shield Control"), \
5651 _("Cloaking Device"), \
5655 "Prepare to play, set up cosmos."
5657 # Decide how many of everything
5659 return # frozen game
5660 # Prepare the Enterprise
5661 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5663 game.state.crew = FULLCREW
5664 game.energy = game.inenrg = 5000.0
5665 game.shield = game.inshld = 2500.0
5668 game.quadrant = randplace(GALSIZE)
5669 game.sector = randplace(QUADSIZE)
5670 game.torps = game.intorps = 10
5671 game.nprobes = randrange(2, 5)
5673 for i in range(NDEVICES):
5674 game.damage[i] = 0.0
5675 # Set up assorted game parameters
5676 game.battle = Coord()
5677 game.state.date = game.indate = 100.0 * randreal(20, 51)
5678 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5679 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5680 game.isatb = game.state.nplankl = 0
5681 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5682 game.iscraft = "onship"
5687 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5689 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5691 game.state.planets = [] # Planet information
5692 game.state.baseq = [] # Base quadrant coordinates
5693 game.state.kcmdr = [] # Commander quadrant coordinates
5694 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5696 # Starchart is functional but we've never seen it
5697 game.lastchart = FOREVER
5698 # Put stars in the galaxy
5700 for i in range(GALSIZE):
5701 for j in range(GALSIZE):
5702 # Can't have more stars per quadrant than fit in one decimal digit,
5703 # if we do the chart representation will break.
5704 k = randrange(1, min(10, QUADSIZE**2/10))
5706 game.state.galaxy[i][j].stars = k
5707 # Locate star bases in galaxy
5709 prout("=== Allocating %d bases" % game.inbase)
5710 for i in range(game.inbase):
5713 w = randplace(GALSIZE)
5714 if not game.state.galaxy[w.i][w.j].starbase:
5717 # C version: for (j = i-1; j > 0; j--)
5718 # so it did them in the opposite order.
5719 for j in range(1, i):
5720 # Improved placement algorithm to spread out bases
5721 distq = (w - game.state.baseq[j]).distance()
5722 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5725 prout("=== Abandoning base #%d at %s" % (i, w))
5727 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5729 prout("=== Saving base #%d, close to #%d" % (i, j))
5733 prout("=== Placing base #%d in quadrant %s" % (i, w))
5734 game.state.baseq.append(w)
5735 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5736 # Position ordinary Klingon Battle Cruisers
5738 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5739 if klumper > MAXKLQUAD:
5743 klump = (1.0 - r*r)*klumper
5748 w = randplace(GALSIZE)
5749 if not game.state.galaxy[w.i][w.j].supernova and \
5750 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5752 game.state.galaxy[w.i][w.j].klingons += int(klump)
5755 # Position Klingon Commander Ships
5756 for i in range(game.incom):
5758 w = randplace(GALSIZE)
5759 if not welcoming(w) or w in game.state.kcmdr:
5761 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5763 game.state.galaxy[w.i][w.j].klingons += 1
5764 game.state.kcmdr.append(w)
5765 # Locate planets in galaxy
5766 for i in range(game.inplan):
5768 w = randplace(GALSIZE)
5769 if game.state.galaxy[w.i][w.j].planet is None:
5773 new.crystals = "absent"
5774 if (game.options & OPTION_WORLDS) and i < NINHAB:
5775 new.pclass = "M" # All inhabited planets are class M
5776 new.crystals = "absent"
5778 new.name = systnames[i]
5779 new.inhabited = True
5781 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5783 new.crystals = "present"
5784 new.known = "unknown"
5785 new.inhabited = False
5786 game.state.galaxy[w.i][w.j].planet = new
5787 game.state.planets.append(new)
5789 for i in range(game.state.nromrem):
5790 w = randplace(GALSIZE)
5791 game.state.galaxy[w.i][w.j].romulans += 1
5792 # Place the Super-Commander if needed
5793 if game.state.nscrem > 0:
5795 w = randplace(GALSIZE)
5798 game.state.kscmdr = w
5799 game.state.galaxy[w.i][w.j].klingons += 1
5800 # Initialize times for extraneous events
5801 schedule(FSNOVA, expran(0.5 * game.intime))
5802 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5803 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5804 schedule(FBATTAK, expran(0.3*game.intime))
5806 if game.state.nscrem:
5807 schedule(FSCMOVE, 0.2777)
5812 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5813 schedule(FDISTR, expran(1.0 + game.intime))
5818 # Place thing (in tournament game, we don't want one!)
5819 # New in SST2K: never place the Thing near a starbase.
5820 # This makes sense and avoids a special case in the old code.
5822 if game.tourn is None:
5824 thing = randplace(GALSIZE)
5825 if thing not in game.state.baseq:
5828 game.state.snap = False
5829 if game.skill == SKILL_NOVICE:
5830 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5831 prout(_("a deadly Klingon invasion force. As captain of the United"))
5832 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5833 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5834 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5835 prout(_("your mission. As you proceed you may be given more time."))
5837 prout(_("You will have %d supporting starbases.") % (game.inbase))
5838 proutn(_("Starbase locations- "))
5840 prout(_("Stardate %d.") % int(game.state.date))
5842 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5843 prout(_("An unknown number of Romulans."))
5844 if game.state.nscrem:
5845 prout(_("And one (GULP) Super-Commander."))
5846 prout(_("%d stardates.") % int(game.intime))
5847 proutn(_("%d starbases in ") % game.inbase)
5848 for i in range(game.inbase):
5849 proutn(repr(game.state.baseq[i]))
5852 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5853 proutn(_(" Sector %s") % game.sector)
5855 prout(_("Good Luck!"))
5856 if game.state.nscrem:
5857 prout(_(" YOU'LL NEED IT."))
5860 setwnd(message_window)
5862 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5864 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5865 attack(torps_ok=False)
5868 "Choose your game type."
5870 game.tourn = game.length = 0
5872 game.skill = SKILL_NONE
5873 # Do not chew here, we want to use command-line tokens
5874 if not scanner.inqueue: # Can start with command line options
5875 proutn(_("Would you like a regular, tournament, or saved game? "))
5877 if scanner.sees("tournament"):
5878 while scanner.nexttok() == "IHEOL":
5879 proutn(_("Type in tournament number-"))
5880 if scanner.real == 0:
5882 continue # We don't want a blank entry
5883 game.tourn = int(round(scanner.real))
5884 random.seed(scanner.real)
5886 logfp.write("# random.seed(%d)\n" % scanner.real)
5888 if scanner.sees("saved") or scanner.sees("frozen"):
5892 if game.passwd is None:
5894 if not game.alldone:
5895 game.thawed = True # No plaque if not finished
5899 if scanner.sees("regular"):
5901 proutn(_("What is \"%s\"? ") % scanner.token)
5903 while game.length==0 or game.skill==SKILL_NONE:
5904 if scanner.nexttok() == "IHALPHA":
5905 if scanner.sees("short"):
5907 elif scanner.sees("medium"):
5909 elif scanner.sees("long"):
5911 elif scanner.sees("novice"):
5912 game.skill = SKILL_NOVICE
5913 elif scanner.sees("fair"):
5914 game.skill = SKILL_FAIR
5915 elif scanner.sees("good"):
5916 game.skill = SKILL_GOOD
5917 elif scanner.sees("expert"):
5918 game.skill = SKILL_EXPERT
5919 elif scanner.sees("emeritus"):
5920 game.skill = SKILL_EMERITUS
5922 proutn(_("What is \""))
5923 proutn(scanner.token)
5928 proutn(_("Would you like a Short, Medium, or Long game? "))
5929 elif game.skill == SKILL_NONE:
5930 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5931 # Choose game options -- added by ESR for SST2K
5932 if scanner.nexttok() != "IHALPHA":
5934 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5936 if scanner.sees("plain"):
5937 # Approximates the UT FORTRAN version.
5938 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)
5939 game.options |= OPTION_PLAIN
5940 elif scanner.sees("almy"):
5941 # Approximates Tom Almy's version.
5942 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
5943 game.options |= OPTION_ALMY
5944 elif scanner.sees("fancy") or scanner.sees("\n"):
5946 elif len(scanner.token):
5947 proutn(_("What is \"%s\"?") % scanner.token)
5949 if game.passwd == "debug":
5951 prout("=== Debug mode enabled.")
5952 # Use parameters to generate initial values of things
5953 game.damfac = 0.5 * game.skill
5954 game.inbase = randrange(BASEMIN, BASEMAX+1)
5956 if game.options & OPTION_PLANETS:
5957 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5958 if game.options & OPTION_WORLDS:
5959 game.inplan += int(NINHAB)
5960 game.state.nromrem = game.inrom = randrange(2 * game.skill)
5961 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5962 game.state.remtime = 7.0 * game.length
5963 game.intime = game.state.remtime
5964 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5965 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5966 game.state.remres = (game.inkling+4*game.incom)*game.intime
5967 game.inresor = game.state.remres
5968 if game.inkling > 50:
5972 def dropin(iquad=None):
5973 "Drop a feature on a random dot in the current quadrant."
5975 w = randplace(QUADSIZE)
5976 if game.quad[w.i][w.j] == '.':
5978 if iquad is not None:
5979 game.quad[w.i][w.j] = iquad
5983 "Update our alert status."
5984 game.condition = "green"
5985 if game.energy < 1000.0:
5986 game.condition = "yellow"
5987 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5988 game.condition = "red"
5990 game.condition="dead"
5993 "Drop new Klingon into current quadrant."
5994 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5997 "Sort enemies by distance so 'nearest' is meaningful."
5998 game.enemies.sort(key=lambda x: x.kdist)
6001 "Set up a new state of quadrant, for when we enter or re-enter it."
6004 game.neutz = game.inorbit = game.landed = False
6005 game.ientesc = game.iseenit = game.isviolreported = False
6006 # Create a blank quadrant
6007 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
6009 # Attempt to escape Super-commander, so tbeam back!
6012 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
6013 # cope with supernova
6016 game.klhere = q.klingons
6017 game.irhere = q.romulans
6019 game.quad[game.sector.i][game.sector.j] = game.ship
6022 # Position ordinary Klingons
6023 for _i in range(game.klhere):
6025 # If we need a commander, promote a Klingon
6026 for cmdr in game.state.kcmdr:
6027 if cmdr == game.quadrant:
6028 e = game.enemies[game.klhere-1]
6029 game.quad[e.location.i][e.location.j] = 'C'
6030 e.power = randreal(950,1350) + 50.0*game.skill
6032 # If we need a super-commander, promote a Klingon
6033 if game.quadrant == game.state.kscmdr:
6035 game.quad[e.location.i][e.location.j] = 'S'
6036 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
6037 game.iscate = (game.state.remkl > 1)
6038 # Put in Romulans if needed
6039 for _i in range(q.romulans):
6040 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
6041 # If quadrant needs a starbase, put it in
6043 game.base = dropin('B')
6044 # If quadrant needs a planet, put it in
6046 game.iplnet = q.planet
6047 if not q.planet.inhabited:
6048 game.plnet = dropin('P')
6050 game.plnet = dropin('@')
6051 # Check for condition
6054 if game.irhere > 0 and game.klhere == 0:
6056 if not damaged(DRADIO):
6058 prout(_("LT. Uhura- \"Captain, an urgent message."))
6059 prout(_(" I'll put it on audio.\" CLICK"))
6061 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
6062 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
6063 # Put in THING if needed
6064 if thing == game.quadrant:
6065 Enemy(etype='?', loc=dropin(),
6066 power=randreal(6000,6500.0)+250.0*game.skill)
6067 if not damaged(DSRSENS):
6069 prout(_("Mr. Spock- \"Captain, this is most unusual."))
6070 prout(_(" Please examine your short-range scan.\""))
6071 # Decide if quadrant needs a Tholian; lighten up if skill is low
6072 if game.options & OPTION_THOLIAN:
6073 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
6074 (game.skill == SKILL_GOOD and withprob(0.05)) or \
6075 (game.skill > SKILL_GOOD and withprob(0.08)):
6078 w.i = withprob(0.5) * (QUADSIZE-1)
6079 w.j = withprob(0.5) * (QUADSIZE-1)
6080 if game.quad[w.i][w.j] == '.':
6082 game.tholian = Enemy(etype='T', loc=w,
6083 power=randrange(100, 500) + 25.0*game.skill)
6084 # Reserve unoccupied corners
6085 if game.quad[0][0]=='.':
6086 game.quad[0][0] = 'X'
6087 if game.quad[0][QUADSIZE-1]=='.':
6088 game.quad[0][QUADSIZE-1] = 'X'
6089 if game.quad[QUADSIZE-1][0]=='.':
6090 game.quad[QUADSIZE-1][0] = 'X'
6091 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
6092 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
6094 # And finally the stars
6095 for _i in range(q.stars):
6097 # Put in a few black holes
6098 for _i in range(1, 3+1):
6101 # Take out X's in corners if Tholian present
6103 if game.quad[0][0]=='X':
6104 game.quad[0][0] = '.'
6105 if game.quad[0][QUADSIZE-1]=='X':
6106 game.quad[0][QUADSIZE-1] = '.'
6107 if game.quad[QUADSIZE-1][0]=='X':
6108 game.quad[QUADSIZE-1][0] = '.'
6109 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
6110 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
6113 "Set the self-destruct password."
6114 if game.options & OPTION_PLAIN:
6117 proutn(_("Please type in a secret password- "))
6119 game.passwd = scanner.token
6120 if game.passwd != None:
6124 game.passwd += chr(ord('a')+randrange(26))
6125 game.passwd += chr(ord('a')+randrange(26))
6126 game.passwd += chr(ord('a')+randrange(26))
6128 # Code from sst.c begins here
6131 ("SRSCAN", OPTION_TTY),
6132 ("STATUS", OPTION_TTY),
6133 ("REQUEST", OPTION_TTY),
6134 ("LRSCAN", OPTION_TTY),
6146 ("SENSORS", OPTION_PLANETS),
6147 ("ORBIT", OPTION_PLANETS),
6148 ("TRANSPORT", OPTION_PLANETS),
6149 ("MINE", OPTION_PLANETS),
6150 ("CRYSTALS", OPTION_PLANETS),
6151 ("SHUTTLE", OPTION_PLANETS),
6152 ("PLANETS", OPTION_PLANETS),
6157 ("PROBE", OPTION_PROBE),
6159 ("FREEZE", 0), # Synonym for SAVE
6163 ("CAPTURE", OPTION_CAPTURE),
6164 ("CLOAK", OPTION_CLOAK),
6167 ("SOS", 0), # Synonym for MAYDAY
6168 ("CALL", 0), # Synonym for MAYDAY
6176 "Generate a list of legal commands."
6177 prout(_("LEGAL COMMANDS ARE:"))
6179 for (key, opt) in commands:
6180 if not opt or (opt & game.options):
6181 proutn("%-12s " % key)
6183 if emitted % 5 == 4:
6188 "Browse on-line help."
6189 key = scanner.nexttok()
6192 setwnd(prompt_window)
6193 proutn(_("Help on what command? "))
6194 key = scanner.nexttok()
6195 setwnd(message_window)
6198 cmds = [x[0] for x in commands]
6199 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
6206 cmd = scanner.token.upper()
6207 for directory in docpath:
6209 fp = open(os.path.join(directory, "sst.doc"), "r")
6214 prout(_("Spock- \"Captain, that information is missing from the"))
6215 prout(_(" computer. You need to find sst.doc and put it somewhere"))
6216 proutn(_(" in these directories: %s") % ":".join(docpath))
6218 # This used to continue: "You need to find SST.DOC and put
6219 # it in the current directory."
6222 linebuf = fp.readline()
6224 prout(_("Spock- \"Captain, there is no information on that command.\""))
6227 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
6228 linebuf = linebuf[3:].strip()
6229 if cmd.upper() == linebuf:
6232 prout(_("Spock- \"Captain, I've found the following information:\""))
6235 linebuf = fp.readline()
6236 if "******" in linebuf:
6242 "Command-interpretation loop."
6244 if game.irhere and game.state.date >= ALGERON and not game.isviolreported and game.iscloaked:
6245 prout(_("The Romulan ship discovers you are breaking the Treaty of Algeron!"))
6247 game.isviolreported = True
6248 while True: # command loop
6250 while True: # get a command
6252 game.optime = game.justin = False
6254 setwnd(prompt_window)
6257 if scanner.nexttok() == "IHEOL":
6258 if game.options & OPTION_CURSES:
6261 elif scanner.token == "":
6265 setwnd(message_window)
6267 abandon_passed = False
6268 cmd = "" # Force cmd to persist after loop
6269 opt = 0 # Force opt to persist after loop
6270 for (cmd, opt) in commands:
6271 # commands after ABANDON cannot be abbreviated
6272 if cmd == "ABANDON":
6273 abandon_passed = True
6274 if cmd == scanner.token.upper() or (not abandon_passed \
6275 and cmd.startswith(scanner.token.upper())):
6280 elif opt and not (opt & game.options):
6284 if cmd == "SRSCAN": # srscan
6286 elif cmd == "STATUS": # status
6288 elif cmd == "REQUEST": # status request
6290 elif cmd == "LRSCAN": # long range scan
6291 lrscan(silent=False)
6292 elif cmd == "PHASERS": # phasers
6297 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
6302 elif cmd == "MOVE": # move under warp
6303 warp(wcourse=None, involuntary=False)
6304 elif cmd == "SHIELDS": # shields
6305 doshield(shraise=False)
6308 game.shldchg = False
6309 elif cmd == "DOCK": # dock at starbase
6312 attack(torps_ok=False)
6313 elif cmd == "DAMAGES": # damage reports
6315 elif cmd == "CHART": # chart
6317 elif cmd == "IMPULSE": # impulse
6319 elif cmd == "REST": # rest
6323 elif cmd == "WARP": # warp
6325 elif cmd == "SENSORS": # sensors
6327 elif cmd == "ORBIT": # orbit
6331 elif cmd == "TRANSPORT": # transport "beam"
6333 elif cmd == "MINE": # mine
6337 elif cmd == "CRYSTALS": # crystals
6341 elif cmd == "SHUTTLE": # shuttle
6345 elif cmd == "PLANETS": # Planet list
6347 elif cmd == "REPORT": # Game Report
6349 elif cmd == "COMPUTER": # use COMPUTER!
6351 elif cmd == "COMMANDS":
6353 elif cmd == "EMEXIT": # Emergency exit
6354 clrscr() # Hide screen
6355 freeze(True) # forced save
6356 raise SystemExit(1) # And quick exit
6357 elif cmd == "PROBE":
6358 probe() # Launch probe
6361 elif cmd == "ABANDON": # Abandon Ship
6363 elif cmd == "DESTRUCT": # Self Destruct
6365 elif cmd == "SAVE": # Save Game
6368 if game.skill > SKILL_GOOD:
6369 prout(_("WARNING--Saved games produce no plaques!"))
6370 elif cmd == "DEATHRAY": # Try a desparation measure
6374 elif cmd == "CAPTURE":
6376 elif cmd == "CLOAK":
6378 elif cmd == "DEBUGCMD": # What do we want for debug???
6380 elif cmd == "MAYDAY": # Call for help
6385 game.alldone = True # quit the game
6388 elif cmd == "SCORE":
6389 score() # see current score
6392 break # Game has ended
6393 if game.optime != 0.0:
6396 break # Events did us in
6397 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6400 if hitme and not game.justin:
6401 attack(torps_ok=True)
6404 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6415 "Emit the name of an enemy or feature."
6416 if ch == 'R': s = _("Romulan")
6417 elif ch == 'K': s = _("Klingon")
6418 elif ch == 'C': s = _("Commander")
6419 elif ch == 'S': s = _("Super-commander")
6420 elif ch == '*': s = _("Star")
6421 elif ch == 'P': s = _("Planet")
6422 elif ch == 'B': s = _("Starbase")
6423 elif ch == ' ': s = _("Black hole")
6424 elif ch == 'T': s = _("Tholian")
6425 elif ch == '#': s = _("Tholian web")
6426 elif ch == '?': s = _("Stranger")
6427 elif ch == '@': s = _("Inhabited World")
6428 else: s = "Unknown??"
6431 def crmena(loud, enemy, loctype, w):
6432 "Emit the name of an enemy and his location."
6436 buf += cramen(enemy) + _(" at ")
6437 if loctype == "quadrant":
6438 buf += _("Quadrant ")
6439 elif loctype == "sector":
6441 return buf + repr(w)
6444 "Emit our ship name."
6445 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6448 "Emit a line of stars"
6449 prouts("******************************************************")
6453 return -avrage*math.log(1e-7 + randreal())
6455 def randplace(size):
6456 "Choose a random location."
6458 w.i = randrange(size)
6459 w.j = randrange(size)
6469 # Get a token from the user
6472 # Fill the token quue if nothing here
6473 while not self.inqueue:
6475 if curwnd==prompt_window:
6477 setwnd(message_window)
6484 self.inqueue = sline.lstrip().split() + ["\n"]
6485 # From here on in it's all looking at the queue
6486 self.token = self.inqueue.pop(0)
6487 if self.token == "\n":
6491 self.real = float(self.token)
6492 self.type = "IHREAL"
6497 self.token = self.token.lower()
6498 self.type = "IHALPHA"
6501 def append(self, tok):
6502 self.inqueue.append(tok)
6503 def push(self, tok):
6504 self.inqueue.insert(0, tok)
6508 # Demand input for next scan
6510 self.real = self.token = None
6512 # compares s to item and returns true if it matches to the length of s
6513 return s.startswith(self.token)
6515 # Round token value to nearest integer
6516 return int(round(self.real))
6520 if self.type != "IHREAL":
6525 if self.type != "IHREAL":
6531 return "<sstcanner: token=%s, type=%s, queue=%s>" % (self.token, self.type, self.inqueue)
6534 "Yes-or-no confirmation."
6538 if scanner.token == 'y':
6540 if scanner.token == 'n':
6543 proutn(_("Please answer with \"y\" or \"n\": "))
6546 "Complain about unparseable input."
6549 prout(_("Beg your pardon, Captain?"))
6552 "Access to the internals for debugging."
6553 proutn("Reset levels? ")
6555 if game.energy < game.inenrg:
6556 game.energy = game.inenrg
6557 game.shield = game.inshld
6558 game.torps = game.intorps
6559 game.lsupres = game.inlsr
6560 proutn("Reset damage? ")
6562 for i in range(NDEVICES):
6563 if game.damage[i] > 0.0:
6564 game.damage[i] = 0.0
6565 proutn("Toggle debug flag? ")
6567 game.idebug = not game.idebug
6569 prout("Debug output ON")
6571 prout("Debug output OFF")
6572 proutn("Cause selective damage? ")
6574 for i in range(NDEVICES):
6575 proutn("Kill %s?" % device[i])
6577 key = scanner.nexttok()
6578 if key == "IHALPHA" and scanner.sees("y"):
6579 game.damage[i] = 10.0
6580 proutn("Examine/change events? ")
6585 FSNOVA: "Supernova ",
6588 FBATTAK: "Base Attack ",
6589 FCDBAS: "Base Destroy ",
6590 FSCMOVE: "SC Move ",
6591 FSCDBAS: "SC Base Destroy ",
6592 FDSPROB: "Probe Move ",
6593 FDISTR: "Distress Call ",
6594 FENSLV: "Enslavement ",
6595 FREPRO: "Klingon Build ",
6597 for i in range(1, NEVENTS):
6600 proutn("%.2f" % (scheduled(i)-game.state.date))
6601 if i == FENSLV or i == FREPRO:
6603 proutn(" in %s" % ev.quadrant)
6608 key = scanner.nexttok()
6612 elif key == "IHREAL":
6613 ev = schedule(i, scanner.real)
6614 if i == FENSLV or i == FREPRO:
6616 proutn("In quadrant- ")
6617 key = scanner.nexttok()
6618 # "IHEOL" says to leave coordinates as they are
6621 prout("Event %d canceled, no x coordinate." % (i))
6624 w.i = int(round(scanner.real))
6625 key = scanner.nexttok()
6627 prout("Event %d canceled, no y coordinate." % (i))
6630 w.j = int(round(scanner.real))
6633 proutn("Induce supernova here? ")
6635 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6638 if __name__ == '__main__':
6640 #global line, thing, game
6644 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6645 if os.getenv("TERM"):
6646 game.options |= OPTION_CURSES
6648 game.options |= OPTION_TTY
6649 seed = int(time.time())
6650 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6652 for (switch, val) in options:
6655 replayfp = open(val, "r")
6657 sys.stderr.write("sst: can't open replay file %s\n" % val)
6660 line = replayfp.readline().strip()
6661 (leader, __, seed) = line.split()
6663 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6664 line = replayfp.readline().strip()
6665 arguments += line.split()[2:]
6668 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6670 game.options |= OPTION_TTY
6671 game.options &=~ OPTION_CURSES
6672 elif switch == '-s':
6674 elif switch == '-t':
6675 game.options |= OPTION_TTY
6676 game.options &=~ OPTION_CURSES
6677 elif switch == '-x':
6679 elif switch == '-V':
6680 print("SST2K", version)
6683 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6685 # where to save the input in case of bugs
6686 if "TMPDIR" in os.environ:
6687 tmpdir = os.environ['TMPDIR']
6691 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6693 sys.stderr.write("sst: warning, can't open logfile\n")
6696 logfp.write("# seed %s\n" % seed)
6697 logfp.write("# options %s\n" % " ".join(arguments))
6698 logfp.write("# SST2K version %s\n" % version)
6699 logfp.write("# recorded by %s@%s on %s\n" % \
6700 (getpass.getuser(),socket.gethostname(),time.ctime()))
6702 scanner = sstscanner()
6703 for arg in arguments:
6707 while True: # Play a game
6708 setwnd(fullscreen_window)
6714 game.alldone = False
6722 if game.tourn and game.alldone:
6723 proutn(_("Do you want your score recorded?"))
6729 proutn(_("Do you want to play again? "))
6733 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6737 except KeyboardInterrupt: