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 ion how to modify (and how not to modify!) this code.
14 import os, sys, math, curses, time, readline, cPickle, random, copy, gettext
16 SSTDOC = "/usr/share/doc/sst/sst.doc"
19 def _(str): return gettext.gettext(str)
23 NINHAB = (GALSIZE * GALSIZE / 2)
25 PLNETMAX = (NINHAB + MAXUNINHAB)
28 BASEMAX = (GALSIZE * GALSIZE / 12)
31 FULLCREW = 428 # BSD Trek was 387, that's wrong
40 def __init__(self, x=None, y=None):
43 def valid_quadrant(self):
44 return self.i>=0 and self.i<GALSIZE and self.j>=0 and self.j<GALSIZE
45 def valid_sector(self):
46 return self.i>=0 and self.i<QUADSIZE and self.j>=0 and self.j<QUADSIZE
48 self.i = self.j = None
50 return self.i != None and self.j != None
51 def __eq__(self, other):
52 return other != None and self.i == other.i and self.j == other.j
53 def __ne__(self, other):
54 return other == None or self.i != other.i or self.j != other.j
55 def __add__(self, other):
56 return coord(self.i+other.i, self.j+other.j)
57 def __sub__(self, other):
58 return coord(self.i-other.i, self.j-other.j)
59 def __mul__(self, other):
60 return coord(self.i*other, self.j*other)
61 def __rmul__(self, other):
62 return coord(self.i*other, self.j*other)
63 def __div__(self, other):
64 return coord(self.i/other, self.j/other)
65 def __mod__(self, other):
66 return coord(self.i % other, self.j % other)
67 def __rdiv__(self, other):
68 return coord(self.i/other, self.j/other)
69 def roundtogrid(self):
70 return coord(int(round(self.i)), int(round(self.j)))
71 def distance(self, other=None):
72 if not other: other = coord(0, 0)
73 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
75 return 1.90985*math.atan2(self.j, self.i)
81 s.i = self.i / abs(self.i)
85 s.j = self.j / abs(self.j)
88 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
89 return self.roundtogrid() / QUADSIZE
91 return self.roundtogrid() % QUADSIZE
94 s.i = self.i + randrange(-1, 2)
95 s.j = self.j + randrange(-1, 2)
98 if self.i == None or self.j == None:
100 return "%s - %s" % (self.i+1, self.j+1)
105 self.name = None # string-valued if inhabited
106 self.quadrant = coord() # quadrant located
107 self.pclass = None # could be ""M", "N", "O", or "destroyed"
108 self.crystals = "absent"# could be "mined", "present", "absent"
109 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
110 self.inhabited = False # is it inhabites?
118 self.starbase = False
121 self.supernova = False
123 self.status = "secure" # Could be "secure", "distressed", "enslaved"
131 def fill2d(size, fillfun):
132 "Fill an empty list in 2D."
134 for i in range(size):
136 for j in range(size):
137 lst[i].append(fillfun(i, j))
142 self.snap = False # snapshot taken
143 self.crew = 0 # crew complement
144 self.remkl = 0 # remaining klingons
145 self.nscrem = 0 # remaining super commanders
146 self.starkl = 0 # destroyed stars
147 self.basekl = 0 # destroyed bases
148 self.nromrem = 0 # Romulans remaining
149 self.nplankl = 0 # destroyed uninhabited planets
150 self.nworldkl = 0 # destroyed inhabited planets
151 self.planets = [] # Planet information
152 self.date = 0.0 # stardate
153 self.remres = 0 # remaining resources
154 self.remtime = 0 # remaining time
155 self.baseq = [] # Base quadrant coordinates
156 self.kcmdr = [] # Commander quadrant coordinates
157 self.kscmdr = coord() # Supercommander quadrant coordinates
159 self.galaxy = fill2d(GALSIZE, lambda i, j: quadrant())
161 self.chart = fill2d(GALSIZE, lambda i, j: page())
165 self.date = None # A real number
166 self.quadrant = None # A coord structure
169 OPTION_ALL = 0xffffffff
170 OPTION_TTY = 0x00000001 # old interface
171 OPTION_CURSES = 0x00000002 # new interface
172 OPTION_IOMODES = 0x00000003 # cover both interfaces
173 OPTION_PLANETS = 0x00000004 # planets and mining
174 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
175 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
176 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
177 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
178 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
179 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
180 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
181 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
182 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
183 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
184 OPTION_PLAIN = 0x01000000 # user chose plain game
185 OPTION_ALMY = 0x02000000 # user chose Almy variant
204 NDEVICES= 16 # Number of devices
213 def damaged(dev): return (game.damage[dev] != 0.0)
214 def communicating(): return not damaged(DRADIO) or game.condition=="docked"
216 # Define future events
217 FSPY = 0 # Spy event happens always (no future[] entry)
218 # can cause SC to tractor beam Enterprise
219 FSNOVA = 1 # Supernova
220 FTBEAM = 2 # Commander tractor beams Enterprise
221 FSNAP = 3 # Snapshot for time warp
222 FBATTAK = 4 # Commander attacks base
223 FCDBAS = 5 # Commander destroys base
224 FSCMOVE = 6 # Supercommander moves (might attack base)
225 FSCDBAS = 7 # Supercommander destroys base
226 FDSPROB = 8 # Move deep space probe
227 FDISTR = 9 # Emit distress call from an inhabited world
228 FENSLV = 10 # Inhabited word is enslaved */
229 FREPRO = 11 # Klingons build a ship in an enslaved system
233 # abstract out the event handling -- underlying data structures will change
234 # when we implement stateful events
236 def findevent(evtype): return game.future[evtype]
239 def __init__(self, type=None, loc=None, power=None):
244 self.kpower = power # enemy energy level
245 game.enemies.append(self)
247 motion = (loc != self.kloc)
248 if self.kloc.i is not None and self.kloc.j is not None:
251 game.quad[self.kloc.i][self.kloc.j] = '#'
253 game.quad[self.kloc.i][self.kloc.j] = '.'
255 self.kloc = copy.copy(loc)
256 game.quad[self.kloc.i][self.kloc.j] = self.type
257 self.kdist = self.kavgd = (game.sector - loc).distance()
260 self.kdist = self.kavgd = None
261 game.enemies.remove(self)
264 return "<%s,%s.%f>" % (self.type, self.kloc, self.kpower) # For debugging
268 self.options = None # Game options
269 self.state = snapshot() # A snapshot structure
270 self.snapsht = snapshot() # Last snapshot taken for time-travel purposes
271 self.quad = None # contents of our quadrant
272 self.damage = [0.0] * NDEVICES # damage encountered
273 self.future = [] # future events
274 for i in range(NEVENTS):
275 self.future.append(event())
276 self.passwd = None; # Self Destruct password
278 self.quadrant = None # where we are in the large
279 self.sector = None # where we are in the small
280 self.tholian = None # Tholian enemy object
281 self.base = None # position of base in current quadrant
282 self.battle = None # base coordinates being attacked
283 self.plnet = None # location of planet in quadrant
284 self.gamewon = False # Finished!
285 self.ididit = False # action taken -- allows enemy to attack
286 self.alive = False # we are alive (not killed)
287 self.justin = False # just entered quadrant
288 self.shldup = False # shields are up
289 self.shldchg = False # shield is changing (affects efficiency)
290 self.iscate = False # super commander is here
291 self.ientesc = False # attempted escape from supercommander
292 self.resting = False # rest time
293 self.icraft = False # Kirk in Galileo
294 self.landed = False # party on planet (true), on ship (false)
295 self.alldone = False # game is now finished
296 self.neutz = False # Romulan Neutral Zone
297 self.isarmed = False # probe is armed
298 self.inorbit = False # orbiting a planet
299 self.imine = False # mining
300 self.icrystl = False # dilithium crystals aboard
301 self.iseenit = False # seen base attack report
302 self.thawed = False # thawed game
303 self.condition = None # "green", "yellow", "red", "docked", "dead"
304 self.iscraft = None # "onship", "offship", "removed"
305 self.skill = None # Player skill level
306 self.inkling = 0 # initial number of klingons
307 self.inbase = 0 # initial number of bases
308 self.incom = 0 # initial number of commanders
309 self.inscom = 0 # initial number of commanders
310 self.inrom = 0 # initial number of commanders
311 self.instar = 0 # initial stars
312 self.intorps = 0 # initial/max torpedoes
313 self.torps = 0 # number of torpedoes
314 self.ship = 0 # ship type -- 'E' is Enterprise
315 self.abandoned = 0 # count of crew abandoned in space
316 self.length = 0 # length of game
317 self.klhere = 0 # klingons here
318 self.casual = 0 # causalties
319 self.nhelp = 0 # calls for help
320 self.nkinks = 0 # count of energy-barrier crossings
321 self.iplnet = None # planet # in quadrant
322 self.inplan = 0 # initial planets
323 self.irhere = 0 # Romulans in quadrant
324 self.isatb = 0 # =1 if super commander is attacking base
325 self.tourn = None # tournament number
326 self.nprobes = 0 # number of probes available
327 self.inresor = 0.0 # initial resources
328 self.intime = 0.0 # initial time
329 self.inenrg = 0.0 # initial/max energy
330 self.inshld = 0.0 # initial/max shield
331 self.inlsr = 0.0 # initial life support resources
332 self.indate = 0.0 # initial date
333 self.energy = 0.0 # energy level
334 self.shield = 0.0 # shield level
335 self.warpfac = 0.0 # warp speed
336 self.wfacsq = 0.0 # squared warp factor
337 self.lsupres = 0.0 # life support reserves
338 self.optime = 0.0 # time taken by current operation
339 self.docfac = 0.0 # repair factor when docking (constant?)
340 self.damfac = 0.0 # damage factor
341 self.lastchart = 0.0 # time star chart was last updated
342 self.cryprob = 0.0 # probability that crystal will work
343 self.probe = None # object holding probe course info
344 self.height = 0.0 # height of orbit around planet
346 # Stas thinks this should be (C expression):
347 # game.state.remkl + len(game.state.kcmdr) > 0 ?
348 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
349 # He says the existing expression is prone to divide-by-zero errors
350 # after killing the last klingon when score is shown -- perhaps also
351 # if the only remaining klingon is SCOM.
352 game.state.remtime = game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr))
379 #logfp.write("# withprob(%s) -> %f (%s) at %s\n" % (p, v, v<p, traceback.extract_stack()[-2][1:]))
382 def randrange(*args):
383 v = random.randrange(*args)
384 #logfp.write("# randrange%s -> %s at %s\n" % (args, v, traceback.extract_stack()[-2][1:]))
390 v *= args[0] # returns from [0, args[0])
392 v = args[0] + v*(args[1]-args[0]) # returns from [args[0], args[1])
393 #logfp.write("# randreal%s -> %s at %s\n" % (args, v, traceback.extract_stack()[-2][1:]))
396 # Code from ai.c begins here
399 "Would this quadrant welcome another Klingon?"
400 return iq.valid_quadrant() and \
401 not game.state.galaxy[iq.i][iq.j].supernova and \
402 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
404 def tryexit(enemy, look, irun):
405 "A bad guy attempts to bug out."
407 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
408 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
409 if not welcoming(iq):
411 if enemy.type == 'R':
412 return False; # Romulans cannot escape!
414 # avoid intruding on another commander's territory
415 if enemy.type == 'C':
416 if iq in game.state.kcmdr:
418 # refuse to leave if currently attacking starbase
419 if game.battle == game.quadrant:
421 # don't leave if over 1000 units of energy
422 if enemy.kpower > 1000.0:
424 # emit escape message and move out of quadrant.
425 # we know this if either short or long range sensors are working
426 if not damaged(DSRSENS) or not damaged(DLRSENS) or \
427 game.condition == "docked":
428 prout(crmena(True, enemy.type, "sector", enemy.kloc) + \
429 (_(" escapes to Quadrant %s (and regains strength).") % q))
430 # handle local matters related to escape
433 if game.condition != "docked":
435 # Handle global matters related to escape
436 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
437 game.state.galaxy[iq.i][iq.j].klingons += 1
442 schedule(FSCMOVE, 0.2777)
446 for cmdr in game.state.kcmdr:
447 if cmdr == game.quadrant:
448 game.state.kcmdr[n] = iq
450 return True; # success
452 # The bad-guy movement algorithm:
454 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
455 # If both are operating full strength, force is 1000. If both are damaged,
456 # force is -1000. Having shields down subtracts an additional 1000.
458 # 2. Enemy has forces equal to the energy of the attacker plus
459 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
460 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
462 # Attacker Initial energy levels (nominal):
463 # Klingon Romulan Commander Super-Commander
464 # Novice 400 700 1200
466 # Good 450 800 1300 1750
467 # Expert 475 850 1350 1875
468 # Emeritus 500 900 1400 2000
469 # VARIANCE 75 200 200 200
471 # Enemy vessels only move prior to their attack. In Novice - Good games
472 # only commanders move. In Expert games, all enemy vessels move if there
473 # is a commander present. In Emeritus games all enemy vessels move.
475 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
476 # forces are 1000 greater than Enterprise.
478 # Agressive action on average cuts the distance between the ship and
479 # the enemy to 1/4 the original.
481 # 4. At lower energy advantage, movement units are proportional to the
482 # advantage with a 650 advantage being to hold ground, 800 to move forward
483 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
485 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
486 # retreat, especially at high skill levels.
488 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
490 def movebaddy(enemy):
491 "Tactical movement for the bad guys."
492 next = coord(); look = coord()
494 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
495 if game.skill >= SKILL_EXPERT:
496 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
498 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
500 mdist = int(dist1 + 0.5); # Nearest integer distance
501 # If SC, check with spy to see if should hi-tail it
502 if enemy.type=='S' and \
503 (enemy.kpower <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
507 # decide whether to advance, retreat, or hold position
508 forces = enemy.kpower+100.0*len(game.enemies)+400*(nbaddys-1)
510 forces += 1000; # Good for enemy if shield is down!
511 if not damaged(DPHASER) or not damaged(DPHOTON):
512 if damaged(DPHASER): # phasers damaged
515 forces -= 0.2*(game.energy - 2500.0)
516 if damaged(DPHOTON): # photon torpedoes damaged
519 forces -= 50.0*game.torps
521 # phasers and photon tubes both out!
524 if forces <= 1000.0 and game.condition != "docked": # Typical situation
525 motion = ((forces + randreal(200))/150.0) - 5.0
527 if forces > 1000.0: # Very strong -- move in for kill
528 motion = (1.0 - randreal())**2 * dist1 + 1.0
529 if game.condition=="docked" and (game.options & OPTION_BASE): # protected by base -- back off !
530 motion -= game.skill*(2.0-randreal()**2)
532 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
533 # don't move if no motion
536 # Limit motion according to skill
537 if abs(motion) > game.skill:
542 # calculate preferred number of steps
543 nsteps = abs(int(motion))
544 if motion > 0 and nsteps > mdist:
545 nsteps = mdist; # don't overshoot
546 if nsteps > QUADSIZE:
547 nsteps = QUADSIZE; # This shouldn't be necessary
549 nsteps = 1; # This shouldn't be necessary
551 proutn("NSTEPS = %d:" % nsteps)
552 # Compute preferred values of delta X and Y
553 m = game.sector - enemy.kloc
554 if 2.0 * abs(m.i) < abs(m.j):
556 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.kloc.i):
558 m = (motion * m).sgn()
561 for ll in range(nsteps):
563 proutn(" %d" % (ll+1))
564 # Check if preferred position available
575 attempts = 0; # Settle mysterious hang problem
576 while attempts < 20 and not success:
578 if look.i < 0 or look.i >= QUADSIZE:
579 if motion < 0 and tryexit(enemy, look, irun):
581 if krawli == m.i or m.j == 0:
583 look.i = next.i + krawli
585 elif look.j < 0 or look.j >= QUADSIZE:
586 if motion < 0 and tryexit(enemy, look, irun):
588 if krawlj == m.j or m.i == 0:
590 look.j = next.j + krawlj
592 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
593 # See if enemy should ram ship
594 if game.quad[look.i][look.j] == game.ship and \
595 (enemy.type == 'C' or enemy.type == 'S'):
596 collision(rammed=True, enemy=enemy)
598 if krawli != m.i and m.j != 0:
599 look.i = next.i + krawli
601 elif krawlj != m.j and m.i != 0:
602 look.j = next.j + krawlj
605 break; # we have failed
617 if not damaged(DSRSENS) or game.condition == "docked":
618 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.kloc))
619 if enemy.kdist < dist1:
620 proutn(_(" advances to "))
622 proutn(_(" retreats to "))
623 prout("Sector %s." % next)
626 "Sequence Klingon tactical movement."
629 # Figure out which Klingon is the commander (or Supercommander)
631 if game.quadrant in game.state.kcmdr:
632 for enemy in game.enemies:
633 if enemy.type == 'C':
635 if game.state.kscmdr==game.quadrant:
636 for enemy in game.enemies:
637 if enemy.type == 'S':
640 # If skill level is high, move other Klingons and Romulans too!
641 # Move these last so they can base their actions on what the
643 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
644 for enemy in game.enemies:
645 if enemy.type in ('K', 'R'):
647 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
649 def movescom(iq, avoid):
650 "Commander movement helper."
651 # Avoid quadrants with bases if we want to avoid Enterprise
652 if not welcoming(iq) or (avoid and iq in game.state.baseq):
654 if game.justin and not game.iscate:
657 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
658 game.state.kscmdr = iq
659 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
660 if game.state.kscmdr==game.quadrant:
661 # SC has scooted, Remove him from current quadrant
666 for enemy in game.enemies:
667 if enemy.type == 'S':
671 if game.condition != "docked":
673 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
674 # check for a helpful planet
675 for i in range(game.inplan):
676 if game.state.planets[i].quadrant == game.state.kscmdr and \
677 game.state.planets[i].crystals == "present":
679 game.state.planets[i].pclass = "destroyed"
680 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
683 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
684 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
685 prout(_(" by the Super-commander.\""))
687 return True; # looks good!
689 def supercommander():
690 "Move the Super Commander."
691 iq = coord(); sc = coord(); ibq = coord(); idelta = coord()
694 prout("== SUPERCOMMANDER")
695 # Decide on being active or passive
696 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 \
697 (game.state.date-game.indate) < 3.0)
698 if not game.iscate and avoid:
699 # compute move away from Enterprise
700 idelta = game.state.kscmdr-game.quadrant
701 if idelta.distance() > 2.0:
703 idelta.i = game.state.kscmdr.j-game.quadrant.j
704 idelta.j = game.quadrant.i-game.state.kscmdr.i
706 # compute distances to starbases
707 if not game.state.baseq:
711 sc = game.state.kscmdr
712 for base in game.state.baseq:
713 basetbl.append((i, (base - sc).distance()))
714 if game.state.baseq > 1:
715 basetbl.sort(lambda x, y: cmp(x[1]. y[1]))
716 # look for nearest base without a commander, no Enterprise, and
717 # without too many Klingons, and not already under attack.
718 ifindit = iwhichb = 0
719 for (i2, base) in enumerate(game.state.baseq):
720 i = basetbl[i2][0]; # bug in original had it not finding nearest
721 if base==game.quadrant or base==game.battle or not welcoming(base):
723 # if there is a commander, and no other base is appropriate,
724 # we will take the one with the commander
725 for cmdr in game.state.kcmdr:
726 if base == cmdr and ifindit != 2:
730 else: # no commander -- use this one
735 return # Nothing suitable -- wait until next time
736 ibq = game.state.baseq[iwhichb]
737 # decide how to move toward base
738 idelta = ibq - game.state.kscmdr
739 # Maximum movement is 1 quadrant in either or both axes
740 idelta = idelta.sgn()
741 # try moving in both x and y directions
742 # there was what looked like a bug in the Almy C code here,
743 # but it might be this translation is just wrong.
744 iq = game.state.kscmdr + idelta
745 if not movescom(iq, avoid):
746 # failed -- try some other maneuvers
747 if idelta.i==0 or idelta.j==0:
750 iq.j = game.state.kscmdr.j + 1
751 if not movescom(iq, avoid):
752 iq.j = game.state.kscmdr.j - 1
755 iq.i = game.state.kscmdr.i + 1
756 if not movescom(iq, avoid):
757 iq.i = game.state.kscmdr.i - 1
760 # try moving just in x or y
761 iq.j = game.state.kscmdr.j
762 if not movescom(iq, avoid):
763 iq.j = game.state.kscmdr.j + idelta.j
764 iq.i = game.state.kscmdr.i
767 if len(game.state.baseq) == 0:
770 for ibq in game.state.baseq:
771 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
774 return # no, don't attack base!
777 schedule(FSCDBAS, randreal(1.0, 3.0))
778 if is_scheduled(FCDBAS):
779 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
780 if not communicating():
784 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
786 prout(_(" reports that it is under attack from the Klingon Super-commander."))
787 proutn(_(" It can survive until stardate %d.\"") \
788 % int(scheduled(FSCDBAS)))
791 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
795 game.optime = 0.0; # actually finished
797 # Check for intelligence report
800 (not communicating()) or \
801 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
804 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
805 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
810 if not game.tholian or game.justin:
813 if game.tholian.kloc.i == 0 and game.tholian.kloc.j == 0:
814 id.i = 0; id.j = QUADSIZE-1
815 elif game.tholian.kloc.i == 0 and game.tholian.kloc.j == QUADSIZE-1:
816 id.i = QUADSIZE-1; id.j = QUADSIZE-1
817 elif game.tholian.kloc.i == QUADSIZE-1 and game.tholian.kloc.j == QUADSIZE-1:
818 id.i = QUADSIZE-1; id.j = 0
819 elif game.tholian.kloc.i == QUADSIZE-1 and game.tholian.kloc.j == 0:
822 # something is wrong!
823 game.tholian.move(None)
824 prout("***Internal error: Tholian in a bad spot.")
826 # do nothing if we are blocked
827 if game.quad[id.i][id.j] not in ('.', '#'):
829 here = copy.copy(game.tholian.kloc)
830 delta = (id - game.tholian.kloc).sgn()
832 while here.i != id.i:
834 if game.quad[here.i][here.j]=='.':
835 game.tholian.move(here)
837 while here.j != id.j:
839 if game.quad[here.i][here.j]=='.':
840 game.tholian.move(here)
841 # check to see if all holes plugged
842 for i in range(QUADSIZE):
843 if game.quad[0][i]!='#' and game.quad[0][i]!='T':
845 if game.quad[QUADSIZE-1][i]!='#' and game.quad[QUADSIZE-1][i]!='T':
847 if game.quad[i][0]!='#' and game.quad[i][0]!='T':
849 if game.quad[i][QUADSIZE-1]!='#' and game.quad[i][QUADSIZE-1]!='T':
851 # All plugged up -- Tholian splits
852 game.quad[game.tholian.kloc.i][game.tholian.kloc.j]='#'
854 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
855 game.tholian.move(None)
858 # Code from battle.c begins here
860 def doshield(shraise):
861 "Change shield status."
869 if scanner.sees("transfer"):
873 prout(_("Shields damaged and down."))
875 if scanner.sees("up"):
877 elif scanner.sees("down"):
880 proutn(_("Do you wish to change shield energy? "))
882 proutn(_("Energy to transfer to shields- "))
884 elif damaged(DSHIELD):
885 prout(_("Shields damaged and down."))
888 proutn(_("Shields are up. Do you want them down? "))
895 proutn(_("Shields are down. Do you want them up? "))
901 if action == "SHUP": # raise shields
903 prout(_("Shields already up."))
907 if game.condition != "docked":
909 prout(_("Shields raised."))
912 prout(_("Shields raising uses up last of energy."))
917 elif action == "SHDN":
919 prout(_("Shields already down."))
923 prout(_("Shields lowered."))
926 elif action == "NRG":
927 while scanner.next() != "IHREAL":
929 proutn(_("Energy to transfer to shields- "))
931 if scanner.real == 0:
933 if scanner.real > game.energy:
934 prout(_("Insufficient ship energy."))
937 if game.shield+scanner.real >= game.inshld:
938 prout(_("Shield energy maximized."))
939 if game.shield+scanner.real > game.inshld:
940 prout(_("Excess energy requested returned to ship energy"))
941 game.energy -= game.inshld-game.shield
942 game.shield = game.inshld
944 if scanner.real < 0.0 and game.energy-scanner.real > game.inenrg:
945 # Prevent shield drain loophole
947 prout(_("Engineering to bridge--"))
948 prout(_(" Scott here. Power circuit problem, Captain."))
949 prout(_(" I can't drain the shields."))
952 if game.shield+scanner.real < 0:
953 prout(_("All shield energy transferred to ship."))
954 game.energy += game.shield
957 proutn(_("Scotty- \""))
959 prout(_("Transferring energy to shields.\""))
961 prout(_("Draining energy from shields.\""))
962 game.shield += scanner.real
963 game.energy -= scanner.real
967 "Choose a device to damage, at random."
968 # Quoth Eric Allman in the code of BSD-Trek:
969 # "Under certain conditions you can get a critical hit. This
970 # sort of hit damages devices. The probability that a given
971 # device is damaged depends on the device. Well protected
972 # devices (such as the computer, which is in the core of the
973 # ship and has considerable redundancy) almost never get
974 # damaged, whereas devices which are exposed (such as the
975 # warp engines) or which are particularly delicate (such as
976 # the transporter) have a much higher probability of being
979 # This is one place where OPTION_PLAIN does not restore the
980 # original behavior, which was equiprobable damage across
981 # all devices. If we wanted that, we'd return randrange(NDEVICES)
982 # and have done with it. Also, in the original game, DNAVYS
983 # and DCOMPTR were the same device.
985 # Instead, we use a table of weights similar to the one from BSD Trek.
986 # BSD doesn't have the shuttle, shield controller, death ray, or probes.
987 # We don't have a cloaking device. The shuttle got the allocation
988 # for the cloaking device, then we shaved a half-percent off
989 # everything to have some weight to give DSHCTRL/DDRAY/DDSP.
991 105, # DSRSENS: short range scanners 10.5%
992 105, # DLRSENS: long range scanners 10.5%
993 120, # DPHASER: phasers 12.0%
994 120, # DPHOTON: photon torpedoes 12.0%
995 25, # DLIFSUP: life support 2.5%
996 65, # DWARPEN: warp drive 6.5%
997 70, # DIMPULS: impulse engines 6.5%
998 145, # DSHIELD: deflector shields 14.5%
999 30, # DRADIO: subspace radio 3.0%
1000 45, # DSHUTTL: shuttle 4.5%
1001 15, # DCOMPTR: computer 1.5%
1002 20, # NAVCOMP: navigation system 2.0%
1003 75, # DTRANSP: transporter 7.5%
1004 20, # DSHCTRL: high-speed shield controller 2.0%
1005 10, # DDRAY: death ray 1.0%
1006 30, # DDSP: deep-space probes 3.0%
1008 idx = randrange(1000) # weights must sum to 1000
1010 for (i, w) in enumerate(weights):
1014 return None; # we should never get here
1016 def collision(rammed, enemy):
1017 "Collision handling fot rammong events."
1018 prouts(_("***RED ALERT! RED ALERT!"))
1020 prout(_("***COLLISION IMMINENT."))
1024 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1026 proutn(_(" rammed by "))
1029 proutn(crmena(False, enemy.type, "sector", enemy.kloc))
1031 proutn(_(" (original position)"))
1033 deadkl(enemy.kloc, enemy.type, game.sector)
1034 proutn("***" + crmship() + " heavily damaged.")
1035 icas = randrange(10, 30)
1036 prout(_("***Sickbay reports %d casualties"), icas)
1038 game.state.crew -= icas
1039 # In the pre-SST2K version, all devices got equiprobably damaged,
1040 # which was silly. Instead, pick up to half the devices at
1041 # random according to our weighting table,
1042 ncrits = randrange(NDEVICES/2)
1043 for m in range(ncrits):
1045 if game.damage[dev] < 0:
1047 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1048 # Damage for at least time of travel!
1049 game.damage[dev] += game.optime + extradm
1051 prout(_("***Shields are down."))
1052 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1059 def torpedo(origin, bearing, dispersion, number, nburst):
1060 "Let a photon torpedo fly"
1061 if not damaged(DSRSENS) or game.condition=="docked":
1062 setwnd(srscan_window)
1064 setwnd(message_window)
1065 ac = bearing + 0.25*dispersion # dispersion is a random variable
1066 bullseye = (15.0 - bearing)*0.5235988
1067 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1068 bumpto = coord(0, 0)
1069 # Loop to move a single torpedo
1070 setwnd(message_window)
1071 for step in range(1, QUADSIZE*2):
1072 if not track.next(): break
1074 if not w.valid_sector():
1076 iquad=game.quad[w.i][w.j]
1077 tracktorpedo(origin, w, step, number, nburst, iquad)
1081 if not damaged(DSRSENS) or game.condition == "docked":
1082 skip(1); # start new line after text track
1083 if iquad in ('E', 'F'): # Hit our ship
1085 prout(_("Torpedo hits %s.") % crmshp())
1086 hit = 700.0 + randreal(100) - \
1087 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1088 newcnd(); # we're blown out of dock
1089 if game.landed or game.condition=="docked":
1090 return hit # Cheat if on a planet
1091 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1092 # is 143 degrees, which is almost exactly 4.8 clockface units
1093 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1095 bumpto = displacement.sector()
1096 if not bumpto.valid_sector():
1098 if game.quad[bumpto.i][bumpto.j]==' ':
1101 if game.quad[bumpto.i][bumpto.j]!='.':
1102 # can't move into object
1104 game.sector = bumpto
1106 game.quad[w.i][w.j]='.'
1107 game.quad[bumpto.i][bumpto.j]=iquad
1108 prout(_(" displaced by blast to Sector %s ") % bumpto)
1109 for enemy in game.enemies:
1110 enemy.kdist = enemy.kavgd = (game.sector-enemy.kloc).distance()
1111 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1113 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1115 if iquad in ('C', 'S') and withprob(0.05):
1116 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1117 prout(_(" torpedo neutralized."))
1119 for enemy in game.enemies:
1122 kp = math.fabs(enemy.kpower)
1123 h1 = 700.0 + randrange(100) - \
1124 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1128 if enemy.kpower < 0:
1132 if enemy.kpower == 0:
1135 proutn(crmena(True, iquad, "sector", w))
1136 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1138 bumpto = displacement.sector()
1139 if not bumpto.valid_sector():
1140 prout(_(" damaged but not destroyed."))
1142 if game.quad[bumpto.i][bumpto.j] == ' ':
1143 prout(_(" buffeted into black hole."))
1144 deadkl(w, iquad, bumpto)
1145 if game.quad[bumpto.i][bumpto.j] != '.':
1146 prout(_(" damaged but not destroyed."))
1148 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1150 game.quad[w.i][w.j]='.'
1151 game.quad[bumpto.i][bumpto.j]=iquad
1152 for enemy in game.enemies:
1153 enemy.kdist = enemy.kavgd = (game.sector-enemy.kloc).distance()
1154 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1156 elif iquad == 'B': # Hit a base
1158 prout(_("***STARBASE DESTROYED.."))
1159 game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
1160 game.quad[w.i][w.j]='.'
1161 game.base.invalidate()
1162 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1
1163 game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1
1164 game.state.basekl += 1
1167 elif iquad == 'P': # Hit a planet
1168 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1169 game.state.nplankl += 1
1170 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1171 game.iplnet.pclass = "destroyed"
1173 game.plnet.invalidate()
1174 game.quad[w.i][w.j] = '.'
1176 # captain perishes on planet
1179 elif iquad == '@': # Hit an inhabited world -- very bad!
1180 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1181 game.state.nworldkl += 1
1182 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1183 game.iplnet.pclass = "destroyed"
1185 game.plnet.invalidate()
1186 game.quad[w.i][w.j] = '.'
1188 # captain perishes on planet
1190 prout(_("The torpedo destroyed an inhabited planet."))
1192 elif iquad == '*': # Hit a star
1196 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1198 elif iquad == '?': # Hit a thingy
1199 if not (game.options & OPTION_THINGY) or withprob(0.3):
1201 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1203 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1205 proutn(_("Mr. Spock-"))
1206 prouts(_(" \"Fascinating!\""))
1210 # Stas Sergeev added the possibility that
1211 # you can shove the Thingy and piss it off.
1212 # It then becomes an enemy and may fire at you.
1216 elif iquad == ' ': # Black hole
1218 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1220 elif iquad == '#': # hit the web
1222 prout(_("***Torpedo absorbed by Tholian web."))
1224 elif iquad == 'T': # Hit a Tholian
1225 h1 = 700.0 + randrange(100) - \
1226 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle))
1229 game.quad[w.i][w.j] = '.'
1234 proutn(crmena(True, 'T', "sector", w))
1236 prout(_(" survives photon blast."))
1238 prout(_(" disappears."))
1239 game.tholian.move(None)
1240 game.quad[w.i][w.j] = '#'
1245 proutn("Don't know how to handle torpedo collision with ")
1246 proutn(crmena(True, iquad, "sector", w))
1251 prout(_("Torpedo missed."))
1255 "Critical-hit resolution."
1256 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1258 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1259 proutn(_("***CRITICAL HIT--"))
1260 # Select devices and cause damage
1262 for loop1 in range(ncrit):
1265 # Cheat to prevent shuttle damage unless on ship
1266 if not (game.damage[j]<0.0 or (j==DSHUTTL and game.iscraft != "onship")):
1269 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1270 game.damage[j] += extradm
1272 for (i, j) in enumerate(cdam):
1274 if skipcount % 3 == 2 and i < len(cdam)-1:
1279 prout(_(" damaged."))
1280 if damaged(DSHIELD) and game.shldup:
1281 prout(_("***Shields knocked down."))
1284 def attack(torps_ok):
1285 # bad guy attacks us
1286 # torps_ok == False forces use of phasers in an attack
1287 # game could be over at this point, check
1290 attempt = False; ihurt = False;
1291 hitmax=0.0; hittot=0.0; chgfac=1.0
1294 prout("=== ATTACK!")
1295 # Tholian gets to move before attacking
1298 # if you have just entered the RNZ, you'll get a warning
1299 if game.neutz: # The one chance not to be attacked
1302 # commanders get a chance to tac-move towards you
1303 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:
1305 # if no enemies remain after movement, we're done
1306 if len(game.enemies)==0 or (len(game.enemies)==1 and thing == game.quadrant and not thing.angry):
1308 # set up partial hits if attack happens during shield status change
1309 pfac = 1.0/game.inshld
1311 chgfac = 0.25 + randreal(0.5)
1313 # message verbosity control
1314 if game.skill <= SKILL_FAIR:
1316 for enemy in game.enemies:
1317 if enemy.kpower < 0:
1318 continue; # too weak to attack
1319 # compute hit strength and diminish shield power
1321 # Increase chance of photon torpedos if docked or enemy energy is low
1322 if game.condition == "docked":
1324 if enemy.kpower < 500:
1326 if enemy.type=='T' or (enemy.type=='?' and not thing.angry):
1328 # different enemies have different probabilities of throwing a torp
1329 usephasers = not torps_ok or \
1330 (enemy.type == 'K' and r > 0.0005) or \
1331 (enemy.type=='C' and r > 0.015) or \
1332 (enemy.type=='R' and r > 0.3) or \
1333 (enemy.type=='S' and r > 0.07) or \
1334 (enemy.type=='?' and r > 0.05)
1335 if usephasers: # Enemy uses phasers
1336 if game.condition == "docked":
1337 continue; # Don't waste the effort!
1338 attempt = True; # Attempt to attack
1339 dustfac = randreal(0.8, 0.85)
1340 hit = enemy.kpower*math.pow(dustfac,enemy.kavgd)
1341 enemy.kpower *= 0.75
1342 else: # Enemy uses photon torpedo
1343 # We should be able to make the bearing() method work here
1344 course = 1.90985*math.atan2(game.sector.j-enemy.kloc.j, enemy.kloc.i-game.sector.i)
1346 proutn(_("***TORPEDO INCOMING"))
1347 if not damaged(DSRSENS):
1348 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.kloc))
1351 dispersion = (randreal()+randreal())*0.5 - 0.5
1352 dispersion += 0.002*enemy.kpower*dispersion
1353 hit = torpedo(enemy.kloc, course, dispersion, number=1, nburst=1)
1354 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1355 finish(FWON); # Klingons did themselves in!
1356 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1357 return # Supernova or finished
1360 # incoming phaser or torpedo, shields may dissipate it
1361 if game.shldup or game.shldchg or game.condition=="docked":
1362 # shields will take hits
1363 propor = pfac * game.shield
1364 if game.condition =="docked":
1368 hitsh = propor*chgfac*hit+1.0
1370 if absorb > game.shield:
1371 absorb = game.shield
1372 game.shield -= absorb
1374 # taking a hit blasts us out of a starbase dock
1375 if game.condition == "docked":
1377 # but the shields may take care of it
1378 if propor > 0.1 and hit < 0.005*game.energy:
1380 # hit from this opponent got through shields, so take damage
1382 proutn(_("%d unit hit") % int(hit))
1383 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1384 proutn(_(" on the ") + crmshp())
1385 if not damaged(DSRSENS) and usephasers:
1386 prout(_(" from ") + crmena(False, enemy.type, where, enemy.kloc))
1388 # Decide if hit is critical
1394 if game.energy <= 0:
1395 # Returning home upon your shield, not with it...
1398 if not attempt and game.condition == "docked":
1399 prout(_("***Enemies decide against attacking your ship."))
1400 percent = 100.0*pfac*game.shield+0.5
1402 # Shields fully protect ship
1403 proutn(_("Enemy attack reduces shield strength to "))
1405 # Emit message if starship suffered hit(s)
1407 proutn(_("Energy left %2d shields ") % int(game.energy))
1410 elif not damaged(DSHIELD):
1413 proutn(_("damaged, "))
1414 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1415 # Check if anyone was hurt
1416 if hitmax >= 200 or hittot >= 500:
1417 icas = randrange(int(hittot * 0.015))
1420 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1421 prout(_(" in that last attack.\""))
1423 game.state.crew -= icas
1424 # After attack, reset average distance to enemies
1425 for enemy in game.enemies:
1426 enemy.kavgd = enemy.kdist
1427 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1430 def deadkl(w, type, mv):
1431 "Kill a Klingon, Tholian, Romulan, or Thingy."
1432 # Added mv to allow enemy to "move" before dying
1433 proutn(crmena(True, type, "sector", mv))
1434 # Decide what kind of enemy it is and update appropriately
1436 # Chalk up a Romulan
1437 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1439 game.state.nromrem -= 1
1448 # Killed some type of Klingon
1449 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1452 game.state.kcmdr.remove(game.quadrant)
1454 if game.state.kcmdr:
1455 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1456 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1459 game.state.remkl -= 1
1461 game.state.nscrem -= 1
1462 game.state.kscmdr.invalidate()
1467 # For each kind of enemy, finish message to player
1468 prout(_(" destroyed."))
1469 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1472 # Remove enemy ship from arrays describing local conditions
1473 for e in game.enemies:
1480 "Return None if target is invalid, otherwise return a course angle."
1481 if not w.valid_sector():
1485 # FIXME: C code this was translated from is wacky -- why the sign reversal?
1486 delta.j = (w.j - game.sector.j);
1487 delta.i = (game.sector.i - w.i);
1488 if delta == coord(0, 0):
1490 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1491 prout(_(" I recommend an immediate review of"))
1492 prout(_(" the Captain's psychological profile.\""))
1495 return delta.bearing()
1498 "Launch photon torpedo."
1501 if damaged(DPHOTON):
1502 prout(_("Photon tubes damaged."))
1506 prout(_("No torpedoes left."))
1509 # First, get torpedo count
1512 if scanner.token == "IHALPHA":
1515 elif scanner.token == "IHEOL" or not scanner.waiting():
1516 prout(_("%d torpedoes left.") % game.torps)
1518 proutn(_("Number of torpedoes to fire- "))
1519 continue # Go back around to get a number
1520 else: # key == "IHREAL"
1522 if n <= 0: # abort command
1527 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1530 scanner.chew() # User requested more torps than available
1531 continue # Go back around
1532 break # All is good, go to next stage
1536 key = scanner.next()
1537 if i==0 and key == "IHEOL":
1538 break; # no coordinate waiting, we will try prompting
1539 if i==1 and key == "IHEOL":
1540 # direct all torpedoes at one target
1542 target.append(target[0])
1543 course.append(course[0])
1546 scanner.push(scanner.token)
1547 target.append(scanner.getcoord())
1548 if target[-1] == None:
1550 course.append(targetcheck(target[-1]))
1551 if course[-1] == None:
1554 if len(target) == 0:
1555 # prompt for each one
1557 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1559 target.append(scanner.getcoord())
1560 if target[-1] == None:
1562 course.append(targetcheck(target[-1]))
1563 if course[-1] == None:
1566 # Loop for moving <n> torpedoes
1568 if game.condition != "docked":
1570 dispersion = (randreal()+randreal())*0.5 -0.5
1571 if math.fabs(dispersion) >= 0.47:
1573 dispersion *= randreal(1.2, 2.2)
1575 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1577 prouts(_("***TORPEDO MISFIRES."))
1580 prout(_(" Remainder of burst aborted."))
1582 prout(_("***Photon tubes damaged by misfire."))
1583 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1585 if game.shldup or game.condition == "docked":
1586 dispersion *= 1.0 + 0.0001*game.shield
1587 torpedo(game.sector, course[i], dispersion, number=i, nburst=n)
1588 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1590 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1594 "Check for phasers overheating."
1596 checkburn = (rpow-1500.0)*0.00038
1597 if withprob(checkburn):
1598 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1599 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1601 def checkshctrl(rpow):
1602 "Check shield control."
1605 prout(_("Shields lowered."))
1607 # Something bad has happened
1608 prouts(_("***RED ALERT! RED ALERT!"))
1610 hit = rpow*game.shield/game.inshld
1611 game.energy -= rpow+hit*0.8
1612 game.shield -= hit*0.2
1613 if game.energy <= 0.0:
1614 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1619 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1621 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1622 icas = randrange(int(hit*0.012))
1627 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1628 prout(_(" %d casualties so far.\"") % icas)
1630 game.state.crew -= icas
1632 prout(_("Phaser energy dispersed by shields."))
1633 prout(_("Enemy unaffected."))
1638 "Register a phaser hit on Klingons and Romulans."
1639 nenhr2 = len(game.enemies); kk=0
1642 for (k, wham) in enumerate(hits):
1645 dustfac = randreal(0.9, 1.0)
1646 hit = wham*math.pow(dustfac,game.enemies[kk].kdist)
1647 kpini = game.enemies[kk].kpower
1648 kp = math.fabs(kpini)
1649 if PHASEFAC*hit < kp:
1651 if game.enemies[kk].kpower < 0:
1652 game.enemies[kk].kpower -= -kp
1654 game.enemies[kk].kpower -= kp
1655 kpow = game.enemies[kk].kpower
1656 w = game.enemies[kk].kloc
1658 if not damaged(DSRSENS):
1660 proutn(_("%d unit hit on ") % int(hit))
1662 proutn(_("Very small hit on "))
1663 ienm = game.quad[w.i][w.j]
1666 proutn(crmena(False, ienm, "sector", w))
1670 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1674 kk -= 1 # don't do the increment
1676 else: # decide whether or not to emasculate klingon
1677 if kpow>0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1678 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1679 prout(_(" has just lost its firepower.\""))
1680 game.enemies[kk].kpower = -kpow
1685 "Fire phasers at bad guys."
1687 kz = 0; k = 1; irec=0 # Cheating inhibitor
1688 ifast = False; no = False; itarg = True; msgflag = True; rpow=0
1692 # SR sensors and Computer are needed for automode
1693 if damaged(DSRSENS) or damaged(DCOMPTR):
1695 if game.condition == "docked":
1696 prout(_("Phasers can't be fired through base shields."))
1699 if damaged(DPHASER):
1700 prout(_("Phaser control damaged."))
1704 if damaged(DSHCTRL):
1705 prout(_("High speed shield control damaged."))
1708 if game.energy <= 200.0:
1709 prout(_("Insufficient energy to activate high-speed shield control."))
1712 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1714 # Original code so convoluted, I re-did it all
1715 # (That was Tom Almy talking about the C code, I think -- ESR)
1716 while automode=="NOTSET":
1718 if key == "IHALPHA":
1719 if scanner.sees("manual"):
1720 if len(game.enemies)==0:
1721 prout(_("There is no enemy present to select."))
1724 automode="AUTOMATIC"
1727 key = scanner.next()
1728 elif scanner.sees("automatic"):
1729 if (not itarg) and len(game.enemies) != 0:
1730 automode = "FORCEMAN"
1732 if len(game.enemies)==0:
1733 prout(_("Energy will be expended into space."))
1734 automode = "AUTOMATIC"
1735 key = scanner.next()
1736 elif scanner.sees("no"):
1741 elif key == "IHREAL":
1742 if len(game.enemies)==0:
1743 prout(_("Energy will be expended into space."))
1744 automode = "AUTOMATIC"
1746 automode = "FORCEMAN"
1748 automode = "AUTOMATIC"
1751 if len(game.enemies)==0:
1752 prout(_("Energy will be expended into space."))
1753 automode = "AUTOMATIC"
1755 automode = "FORCEMAN"
1757 proutn(_("Manual or automatic? "))
1762 if automode == "AUTOMATIC":
1763 if key == "IHALPHA" and scanner.sees("no"):
1765 key = scanner.next()
1766 if key != "IHREAL" and len(game.enemies) != 0:
1767 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1772 for i in range(len(game.enemies)):
1773 irec += math.fabs(game.enemies[i].kpower)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1775 proutn(_("%d units required. ") % irec)
1777 proutn(_("Units to fire= "))
1778 key = scanner.next()
1783 proutn(_("Energy available= %.2f") % avail)
1786 if not rpow > avail:
1793 if key == "IHALPHA" and scanner.sees("no"):
1796 game.energy -= 200; # Go and do it!
1797 if checkshctrl(rpow):
1802 if len(game.enemies):
1805 for i in range(len(game.enemies)):
1809 hits[i] = math.fabs(game.enemies[i].kpower)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))
1810 over = randreal(1.01, 1.06) * hits[i]
1812 powrem -= hits[i] + over
1813 if powrem <= 0 and temp < hits[i]:
1822 if extra > 0 and not game.alldone:
1824 proutn(_("*** Tholian web absorbs "))
1825 if len(game.enemies)>0:
1826 proutn(_("excess "))
1827 prout(_("phaser energy."))
1829 prout(_("%d expended on empty space.") % int(extra))
1830 elif automode == "FORCEMAN":
1833 if damaged(DCOMPTR):
1834 prout(_("Battle computer damaged, manual fire only."))
1837 prouts(_("---WORKING---"))
1839 prout(_("Short-range-sensors-damaged"))
1840 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1841 prout(_("Manual-fire-must-be-used"))
1843 elif automode == "MANUAL":
1845 for k in range(len(game.enemies)):
1846 aim = game.enemies[k].kloc
1847 ienm = game.quad[aim.i][aim.j]
1849 proutn(_("Energy available= %.2f") % (avail-0.006))
1853 if damaged(DSRSENS) and \
1854 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1855 prout(cramen(ienm) + _(" can't be located without short range scan."))
1858 hits[k] = 0; # prevent overflow -- thanks to Alexei Voitenko
1863 if itarg and k > kz:
1864 irec=(abs(game.enemies[k].kpower)/(PHASEFAC*math.pow(0.9,game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1867 if not damaged(DCOMPTR):
1872 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1873 key = scanner.next()
1874 if key == "IHALPHA" and scanner.sees("no"):
1876 key = scanner.next()
1878 if key == "IHALPHA":
1882 if k==1: # Let me say I'm baffled by this
1885 if scanner.real < 0:
1889 hits[k] = scanner.real
1890 rpow += scanner.real
1891 # If total requested is too much, inform and start over
1893 prout(_("Available energy exceeded -- try again."))
1896 key = scanner.next(); # scan for next value
1899 # zero energy -- abort
1902 if key == "IHALPHA" and scanner.sees("no"):
1907 game.energy -= 200.0
1908 if checkshctrl(rpow):
1912 # Say shield raised or malfunction, if necessary
1919 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1920 prouts(_(" CLICK CLICK POP . . ."))
1921 prout(_(" No response, sir!"))
1924 prout(_("Shields raised."))
1929 # Code from events,c begins here.
1931 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1932 # event of each type active at any given time. Mostly these means we can
1933 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1934 # BSD Trek, from which we swiped the idea, can have up to 5.
1936 def unschedule(evtype):
1937 "Remove an event from the schedule."
1938 game.future[evtype].date = FOREVER
1939 return game.future[evtype]
1941 def is_scheduled(evtype):
1942 "Is an event of specified type scheduled."
1943 return game.future[evtype].date != FOREVER
1945 def scheduled(evtype):
1946 "When will this event happen?"
1947 return game.future[evtype].date
1949 def schedule(evtype, offset):
1950 "Schedule an event of specified type."
1951 game.future[evtype].date = game.state.date + offset
1952 return game.future[evtype]
1954 def postpone(evtype, offset):
1955 "Postpone a scheduled event."
1956 game.future[evtype].date += offset
1959 "Rest period is interrupted by event."
1962 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
1964 game.resting = False
1970 "Run through the event queue looking for things to do."
1972 fintim = game.state.date + game.optime; yank=0
1973 ictbeam = False; istract = False
1974 w = coord(); hold = coord()
1975 ev = event(); ev2 = event()
1977 def tractorbeam(yank):
1978 "Tractor-beaming cases merge here."
1980 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
1982 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
1983 # If Kirk & Co. screwing around on planet, handle
1984 atover(True) # atover(true) is Grab
1987 if game.icraft: # Caught in Galileo?
1990 # Check to see if shuttle is aboard
1991 if game.iscraft == "offship":
1994 prout(_("Galileo, left on the planet surface, is captured"))
1995 prout(_("by aliens and made into a flying McDonald's."))
1996 game.damage[DSHUTTL] = -10
1997 game.iscraft = "removed"
1999 prout(_("Galileo, left on the planet surface, is well hidden."))
2001 game.quadrant = game.state.kscmdr
2003 game.quadrant = game.state.kcmdr[i]
2004 game.sector = randplace(QUADSIZE)
2005 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2006 % (game.quadrant, game.sector))
2008 prout(_("(Remainder of rest/repair period cancelled.)"))
2009 game.resting = False
2011 if not damaged(DSHIELD) and game.shield > 0:
2012 doshield(shraise=True) # raise shields
2013 game.shldchg = False
2015 prout(_("(Shields not currently useable.)"))
2017 # Adjust finish time to time of tractor beaming
2018 fintim = game.state.date+game.optime
2019 attack(torps_ok=False)
2020 if not game.state.kcmdr:
2023 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2026 "Code merges here for any commander destroying a starbase."
2027 # Not perfect, but will have to do
2028 # Handle case where base is in same quadrant as starship
2029 if game.battle == game.quadrant:
2030 game.state.chart[game.battle.i][game.battle.j].starbase = False
2031 game.quad[game.base.i][game.base.j] = '.'
2032 game.base.invalidate()
2035 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2036 elif game.state.baseq and communicating():
2037 # Get word via subspace radio
2040 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2041 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2043 prout(_("the Klingon Super-Commander"))
2045 prout(_("a Klingon Commander"))
2046 game.state.chart[game.battle.i][game.battle.j].starbase = False
2047 # Remove Starbase from galaxy
2048 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2049 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2051 # reinstate a commander's base attack
2055 game.battle.invalidate()
2057 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2058 for i in range(1, NEVENTS):
2059 if i == FSNOVA: proutn("=== Supernova ")
2060 elif i == FTBEAM: proutn("=== T Beam ")
2061 elif i == FSNAP: proutn("=== Snapshot ")
2062 elif i == FBATTAK: proutn("=== Base Attack ")
2063 elif i == FCDBAS: proutn("=== Base Destroy ")
2064 elif i == FSCMOVE: proutn("=== SC Move ")
2065 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2066 elif i == FDSPROB: proutn("=== Probe Move ")
2067 elif i == FDISTR: proutn("=== Distress Call ")
2068 elif i == FENSLV: proutn("=== Enslavement ")
2069 elif i == FREPRO: proutn("=== Klingon Build ")
2071 prout("%.2f" % (scheduled(i)))
2074 radio_was_broken = damaged(DRADIO)
2077 # Select earliest extraneous event, evcode==0 if no events
2082 for l in range(1, NEVENTS):
2083 if game.future[l].date < datemin:
2086 prout("== Event %d fires" % evcode)
2087 datemin = game.future[l].date
2088 xtime = datemin-game.state.date
2089 game.state.date = datemin
2090 # Decrement Federation resources and recompute remaining time
2091 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2093 if game.state.remtime <=0:
2096 # Any crew left alive?
2097 if game.state.crew <=0:
2100 # Is life support adequate?
2101 if damaged(DLIFSUP) and game.condition != "docked":
2102 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2105 game.lsupres -= xtime
2106 if game.damage[DLIFSUP] <= xtime:
2107 game.lsupres = game.inlsr
2110 if game.condition == "docked":
2111 repair /= game.docfac
2112 # Don't fix Deathray here
2113 for l in range(NDEVICES):
2114 if game.damage[l] > 0.0 and l != DDRAY:
2115 if game.damage[l]-repair > 0.0:
2116 game.damage[l] -= repair
2118 game.damage[l] = 0.0
2119 # If radio repaired, update star chart and attack reports
2120 if radio_was_broken and not damaged(DRADIO):
2121 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2122 prout(_(" surveillance reports are coming in."))
2124 if not game.iseenit:
2128 prout(_(" The star chart is now up to date.\""))
2130 # Cause extraneous event EVCODE to occur
2131 game.optime -= xtime
2132 if evcode == FSNOVA: # Supernova
2135 schedule(FSNOVA, expran(0.5*game.intime))
2136 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2138 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2139 if game.state.nscrem == 0 or \
2140 ictbeam or istract or \
2141 game.condition=="docked" or game.isatb==1 or game.iscate:
2143 if game.ientesc or \
2144 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2145 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2146 (damaged(DSHIELD) and \
2147 (game.energy < 2500 or damaged(DPHASER)) and \
2148 (game.torps < 5 or damaged(DPHOTON))):
2150 istract = ictbeam = True
2151 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2154 elif evcode == FTBEAM: # Tractor beam
2155 if not game.state.kcmdr:
2158 i = randrange(len(game.state.kcmdr))
2159 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2160 if istract or game.condition == "docked" or yank == 0:
2161 # Drats! Have to reschedule
2163 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2167 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2168 game.snapsht = copy.deepcopy(game.state)
2169 game.state.snap = True
2170 schedule(FSNAP, expran(0.5 * game.intime))
2171 elif evcode == FBATTAK: # Commander attacks starbase
2172 if not game.state.kcmdr or not game.state.baseq:
2178 for ibq in game.state.baseq:
2179 for cmdr in game.state.kcmdr:
2180 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2183 # no match found -- try later
2184 schedule(FBATTAK, expran(0.3*game.intime))
2189 # commander + starbase combination found -- launch attack
2191 schedule(FCDBAS, randreal(1.0, 4.0))
2192 if game.isatb: # extra time if SC already attacking
2193 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2194 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2195 game.iseenit = False
2196 if not communicating():
2197 continue # No warning :-(
2201 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2202 prout(_(" reports that it is under attack and that it can"))
2203 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2206 elif evcode == FSCDBAS: # Supercommander destroys base
2209 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2210 continue # WAS RETURN!
2212 game.battle = game.state.kscmdr
2214 elif evcode == FCDBAS: # Commander succeeds in destroying base
2217 if not game.state.baseq() \
2218 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2219 game.battle.invalidate()
2221 # find the lucky pair
2222 for cmdr in game.state.kcmdr:
2223 if cmdr == game.battle:
2226 # No action to take after all
2229 elif evcode == FSCMOVE: # Supercommander moves
2230 schedule(FSCMOVE, 0.2777)
2231 if not game.ientesc and not istract and game.isatb != 1 and \
2232 (not game.iscate or not game.justin):
2234 elif evcode == FDSPROB: # Move deep space probe
2235 schedule(FDSPROB, 0.01)
2236 if not game.probe.next():
2237 if not game.probe.quadrant().valid_quadrant() or \
2238 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2239 # Left galaxy or ran into supernova
2243 proutn(_("Lt. Uhura- \"The deep space probe "))
2244 if not game.probe.quadrant().valid_quadrant():
2245 prout(_("has left the galaxy.\""))
2247 prout(_("is no longer transmitting.\""))
2253 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2254 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2256 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2257 chp.klingons = pdest.klingons
2258 chp.starbase = pdest.starbase
2259 chp.stars = pdest.stars
2260 pdest.charted = True
2261 game.probe.moves -= 1 # One less to travel
2262 if game.probe.arrived() and game.isarmed and pdest.stars:
2263 supernova(game.probe) # fire in the hole!
2265 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2267 elif evcode == FDISTR: # inhabited system issues distress call
2269 # try a whole bunch of times to find something suitable
2270 for i in range(100):
2271 # need a quadrant which is not the current one,
2272 # which has some stars which are inhabited and
2273 # not already under attack, which is not
2274 # supernova'ed, and which has some Klingons in it
2275 w = randplace(GALSIZE)
2276 q = game.state.galaxy[w.i][w.j]
2277 if not (game.quadrant == w or q.planet == None or \
2278 not q.planet.inhabited or \
2279 q.supernova or q.status!="secure" or q.klingons<=0):
2282 # can't seem to find one; ignore this call
2284 prout("=== Couldn't find location for distress event.")
2286 # got one!! Schedule its enslavement
2287 ev = schedule(FENSLV, expran(game.intime))
2289 q.status = "distressed"
2290 # tell the captain about it if we can
2292 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2294 prout(_("by a Klingon invasion fleet."))
2297 elif evcode == FENSLV: # starsystem is enslaved
2298 ev = unschedule(FENSLV)
2299 # see if current distress call still active
2300 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2304 q.status = "enslaved"
2306 # play stork and schedule the first baby
2307 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2308 ev2.quadrant = ev.quadrant
2310 # report the disaster if we can
2312 prout(_("Uhura- We've lost contact with starsystem %s") % \
2314 prout(_("in Quadrant %s.\n") % ev.quadrant)
2315 elif evcode == FREPRO: # Klingon reproduces
2316 # If we ever switch to a real event queue, we'll need to
2317 # explicitly retrieve and restore the x and y.
2318 ev = schedule(FREPRO, expran(1.0 * game.intime))
2319 # see if current distress call still active
2320 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2324 if game.state.remkl >=MAXKLGAME:
2325 continue # full right now
2326 # reproduce one Klingon
2329 if game.klhere >= MAXKLQUAD:
2331 # this quadrant not ok, pick an adjacent one
2332 for m.i in range(w.i - 1, w.i + 2):
2333 for m.j in range(w.j - 1, w.j + 2):
2334 if not m.valid_quadrant():
2336 q = game.state.galaxy[m.i][m.j]
2337 # check for this quad ok (not full & no snova)
2338 if q.klingons >= MAXKLQUAD or q.supernova:
2342 continue # search for eligible quadrant failed
2346 game.state.remkl += 1
2348 if game.quadrant == w:
2350 game.enemies.append(newkling())
2351 # recompute time left
2354 if game.quadrant == w:
2355 prout(_("Spock- sensors indicate the Klingons have"))
2356 prout(_("launched a warship from %s.") % q.planet)
2358 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2359 if q.planet != None:
2360 proutn(_("near %s") % q.planet)
2361 prout(_("in Quadrant %s.") % w)
2367 key = scanner.next()
2370 proutn(_("How long? "))
2375 origTime = delay = scanner.real
2378 if delay >= game.state.remtime or len(game.enemies) != 0:
2379 proutn(_("Are you sure? "))
2382 # Alternate resting periods (events) with attacks
2386 game.resting = False
2387 if not game.resting:
2388 prout(_("%d stardates left.") % int(game.state.remtime))
2390 temp = game.optime = delay
2391 if len(game.enemies):
2392 rtime = randreal(1.0, 2.0)
2396 if game.optime < delay:
2397 attack(torps_ok=False)
2405 # Repair Deathray if long rest at starbase
2406 if origTime-delay >= 9.99 and game.condition == "docked":
2407 game.damage[DDRAY] = 0.0
2408 # leave if quadrant supernovas
2409 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2411 game.resting = False
2416 course = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2417 newc = coord(); neighbor = coord(); bump = coord(0, 0)
2419 # Wow! We've supernova'ed
2420 supernova(game.quadrant)
2422 # handle initial nova
2423 game.quad[nov.i][nov.j] = '.'
2424 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2425 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2426 game.state.starkl += 1
2427 # Set up queue to recursively trigger adjacent stars
2433 for offset.i in range(-1, 1+1):
2434 for offset.j in range(-1, 1+1):
2435 if offset.j==0 and offset.i==0:
2437 neighbor = start + offset
2438 if not neighbor.valid_sector():
2440 iquad = game.quad[neighbor.i][neighbor.j]
2441 # Empty space ends reaction
2442 if iquad in ('.', '?', ' ', 'T', '#'):
2444 elif iquad == '*': # Affect another star
2446 # This star supernovas
2447 supernova(game.quadrant)
2450 hits.append(neighbor)
2451 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2452 game.state.starkl += 1
2453 proutn(crmena(True, '*', "sector", neighbor))
2455 game.quad[neighbor.i][neighbor.j] = '.'
2457 elif iquad in ('P', '@'): # Destroy planet
2458 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2460 game.state.nplankl += 1
2462 game.state.worldkl += 1
2463 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2464 game.iplnet.pclass = "destroyed"
2466 game.plnet.invalidate()
2470 game.quad[neighbor.i][neighbor.j] = '.'
2471 elif iquad == 'B': # Destroy base
2472 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2473 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2474 game.base.invalidate()
2475 game.state.basekl += 1
2477 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2478 game.quad[neighbor.i][neighbor.j] = '.'
2479 elif iquad in ('E', 'F'): # Buffet ship
2480 prout(_("***Starship buffeted by nova."))
2482 if game.shield >= 2000.0:
2483 game.shield -= 2000.0
2485 diff = 2000.0 - game.shield
2489 prout(_("***Shields knocked out."))
2490 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2492 game.energy -= 2000.0
2493 if game.energy <= 0:
2496 # add in course nova contributes to kicking starship
2497 bump += (game.sector-hits[mm]).sgn()
2498 elif iquad == 'K': # kill klingon
2499 deadkl(neighbor, iquad, neighbor)
2500 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2501 for ll in range(len(game.enemies)):
2502 if game.enemies[ll].kloc == neighbor:
2504 game.enemies[ll].kpower -= 800.0 # If firepower is lost, die
2505 if game.enemies[ll].kpower <= 0.0:
2506 deadkl(neighbor, iquad, neighbor)
2508 newc = neighbor + neighbor - hits[mm]
2509 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2510 if not newc.valid_sector():
2511 # can't leave quadrant
2514 iquad1 = game.quad[newc.i][newc.j]
2516 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2518 deadkl(neighbor, iquad, newc)
2521 # can't move into something else
2524 proutn(_(", buffeted to Sector %s") % newc)
2525 game.quad[neighbor.i][neighbor.j] = '.'
2526 game.quad[newc.i][newc.j] = iquad
2527 game.enemies[ll].move(newc)
2528 # Starship affected by nova -- kick it away.
2530 direc = course[3*(bump.i+1)+bump.j+2]
2535 course = course(bearing=direc, distance=dist)
2536 game.optime = course.time(warp=4)
2538 prout(_("Force of nova displaces starship."))
2539 imove(course, noattack=True)
2540 game.optime = course.time(warp=4)
2544 "Star goes supernova."
2549 # Scheduled supernova -- select star at random.
2552 for nq.i in range(GALSIZE):
2553 for nq.j in range(GALSIZE):
2554 stars += game.state.galaxy[nq.i][nq.j].stars
2556 return # nothing to supernova exists
2557 num = randrange(stars) + 1
2558 for nq.i in range(GALSIZE):
2559 for nq.j in range(GALSIZE):
2560 num -= game.state.galaxy[nq.i][nq.j].stars
2566 proutn("=== Super nova here?")
2569 if not nq == game.quadrant or game.justin:
2570 # it isn't here, or we just entered (treat as enroute)
2573 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2574 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2577 # we are in the quadrant!
2578 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2579 for ns.i in range(QUADSIZE):
2580 for ns.j in range(QUADSIZE):
2581 if game.quad[ns.i][ns.j]=='*':
2588 prouts(_("***RED ALERT! RED ALERT!"))
2590 prout(_("***Incipient supernova detected at Sector %s") % ns)
2591 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2592 proutn(_("Emergency override attempts t"))
2593 prouts("***************")
2597 # destroy any Klingons in supernovaed quadrant
2598 kldead = game.state.galaxy[nq.i][nq.j].klingons
2599 game.state.galaxy[nq.i][nq.j].klingons = 0
2600 if nq == game.state.kscmdr:
2601 # did in the Supercommander!
2602 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2606 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2607 comkills = len(game.state.kcmdr) - len(survivors)
2608 game.state.kcmdr = survivors
2610 if not game.state.kcmdr:
2612 game.state.remkl -= kldead
2613 # destroy Romulans and planets in supernovaed quadrant
2614 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2615 game.state.galaxy[nq.i][nq.j].romulans = 0
2616 game.state.nromrem -= nrmdead
2618 for loop in range(game.inplan):
2619 if game.state.planets[loop].quadrant == nq:
2620 game.state.planets[loop].pclass = "destroyed"
2622 # Destroy any base in supernovaed quadrant
2623 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2624 # If starship caused supernova, tally up destruction
2626 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2627 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2628 game.state.nplankl += npdead
2629 # mark supernova in galaxy and in star chart
2630 if game.quadrant == nq or communicating():
2631 game.state.galaxy[nq.i][nq.j].supernova = True
2632 # If supernova destroys last Klingons give special message
2633 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2636 prout(_("Lucky you!"))
2637 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2640 # if some Klingons remain, continue or die in supernova
2645 # Code from finish.c ends here.
2648 "Self-destruct maneuver. Finish with a BANG!"
2650 if damaged(DCOMPTR):
2651 prout(_("Computer damaged; cannot execute destruct sequence."))
2653 prouts(_("---WORKING---")); skip(1)
2654 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2655 prouts(" 10"); skip(1)
2656 prouts(" 9"); skip(1)
2657 prouts(" 8"); skip(1)
2658 prouts(" 7"); skip(1)
2659 prouts(" 6"); skip(1)
2661 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2663 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2665 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2669 if game.passwd != scanner.token:
2670 prouts(_("PASSWORD-REJECTED;"))
2672 prouts(_("CONTINUITY-EFFECTED"))
2675 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2676 prouts(" 5"); skip(1)
2677 prouts(" 4"); skip(1)
2678 prouts(" 3"); skip(1)
2679 prouts(" 2"); skip(1)
2680 prouts(" 1"); skip(1)
2682 prouts(_("GOODBYE-CRUEL-WORLD"))
2690 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2694 if len(game.enemies) != 0:
2695 whammo = 25.0 * game.energy
2697 while l <= len(game.enemies):
2698 if game.enemies[l].kpower*game.enemies[l].kdist <= whammo:
2699 deadkl(game.enemies[l].kloc, game.quad[game.enemies[l].kloc.i][game.enemies[l].kloc.j], game.enemies[l].kloc)
2704 "Compute our rate of kils over time."
2705 elapsed = game.state.date - game.indate
2706 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2709 starting = (game.inkling + game.incom + game.inscom)
2710 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2711 return (starting - remaining)/elapsed
2715 badpt = 5.0*game.state.starkl + \
2717 10.0*game.state.nplankl + \
2718 300*game.state.nworldkl + \
2720 100.0*game.state.basekl +\
2722 if game.ship == 'F':
2724 elif game.ship == None:
2729 # end the game, with appropriate notfications
2733 prout(_("It is stardate %.1f.") % game.state.date)
2735 if ifin == FWON: # Game has been won
2736 if game.state.nromrem != 0:
2737 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2740 prout(_("You have smashed the Klingon invasion fleet and saved"))
2741 prout(_("the Federation."))
2746 badpt = 0.0 # Close enough!
2747 # killsPerDate >= RateMax
2748 if game.state.date-game.indate < 5.0 or \
2749 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2751 prout(_("In fact, you have done so well that Starfleet Command"))
2752 if game.skill == SKILL_NOVICE:
2753 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2754 elif game.skill == SKILL_FAIR:
2755 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2756 elif game.skill == SKILL_GOOD:
2757 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2758 elif game.skill == SKILL_EXPERT:
2759 prout(_("promotes you to Commodore Emeritus."))
2761 prout(_("Now that you think you're really good, try playing"))
2762 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2763 elif game.skill == SKILL_EMERITUS:
2765 proutn(_("Computer- "))
2766 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2768 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2770 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2772 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2774 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2776 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2778 prout(_("Now you can retire and write your own Star Trek game!"))
2780 elif game.skill >= SKILL_EXPERT:
2781 if game.thawed and not idebug:
2782 prout(_("You cannot get a citation, so..."))
2784 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2788 # Only grant long life if alive (original didn't!)
2790 prout(_("LIVE LONG AND PROSPER."))
2795 elif ifin == FDEPLETE: # Federation Resources Depleted
2796 prout(_("Your time has run out and the Federation has been"))
2797 prout(_("conquered. Your starship is now Klingon property,"))
2798 prout(_("and you are put on trial as a war criminal. On the"))
2799 proutn(_("basis of your record, you are "))
2800 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2801 prout(_("acquitted."))
2803 prout(_("LIVE LONG AND PROSPER."))
2805 prout(_("found guilty and"))
2806 prout(_("sentenced to death by slow torture."))
2810 elif ifin == FLIFESUP:
2811 prout(_("Your life support reserves have run out, and"))
2812 prout(_("you die of thirst, starvation, and asphyxiation."))
2813 prout(_("Your starship is a derelict in space."))
2815 prout(_("Your energy supply is exhausted."))
2817 prout(_("Your starship is a derelict in space."))
2818 elif ifin == FBATTLE:
2819 prout(_("The %s has been destroyed in battle.") % crmshp())
2821 prout(_("Dulce et decorum est pro patria mori."))
2823 prout(_("You have made three attempts to cross the negative energy"))
2824 prout(_("barrier which surrounds the galaxy."))
2826 prout(_("Your navigation is abominable."))
2829 prout(_("Your starship has been destroyed by a nova."))
2830 prout(_("That was a great shot."))
2832 elif ifin == FSNOVAED:
2833 prout(_("The %s has been fried by a supernova.") % crmshp())
2834 prout(_("...Not even cinders remain..."))
2835 elif ifin == FABANDN:
2836 prout(_("You have been captured by the Klingons. If you still"))
2837 prout(_("had a starbase to be returned to, you would have been"))
2838 prout(_("repatriated and given another chance. Since you have"))
2839 prout(_("no starbases, you will be mercilessly tortured to death."))
2840 elif ifin == FDILITHIUM:
2841 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2842 elif ifin == FMATERIALIZE:
2843 prout(_("Starbase was unable to re-materialize your starship."))
2844 prout(_("Sic transit gloria mundi"))
2845 elif ifin == FPHASER:
2846 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2848 prout(_("You and your landing party have been"))
2849 prout(_("converted to energy, disipating through space."))
2850 elif ifin == FMINING:
2851 prout(_("You are left with your landing party on"))
2852 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2854 prout(_("They are very fond of \"Captain Kirk\" soup."))
2856 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2857 elif ifin == FDPLANET:
2858 prout(_("You and your mining party perish."))
2860 prout(_("That was a great shot."))
2863 prout(_("The Galileo is instantly annihilated by the supernova."))
2864 prout(_("You and your mining party are atomized."))
2866 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2867 prout(_("joins the Romulans, wreaking terror on the Federation."))
2868 elif ifin == FPNOVA:
2869 prout(_("You and your mining party are atomized."))
2871 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2872 prout(_("joins the Romulans, wreaking terror on the Federation."))
2873 elif ifin == FSTRACTOR:
2874 prout(_("The shuttle craft Galileo is also caught,"))
2875 prout(_("and breaks up under the strain."))
2877 prout(_("Your debris is scattered for millions of miles."))
2878 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2880 prout(_("The mutants attack and kill Spock."))
2881 prout(_("Your ship is captured by Klingons, and"))
2882 prout(_("your crew is put on display in a Klingon zoo."))
2883 elif ifin == FTRIBBLE:
2884 prout(_("Tribbles consume all remaining water,"))
2885 prout(_("food, and oxygen on your ship."))
2887 prout(_("You die of thirst, starvation, and asphyxiation."))
2888 prout(_("Your starship is a derelict in space."))
2890 prout(_("Your ship is drawn to the center of the black hole."))
2891 prout(_("You are crushed into extremely dense matter."))
2893 prout(_("Your last crew member has died."))
2894 if game.ship == 'F':
2896 elif game.ship == 'E':
2899 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2900 goodies = game.state.remres/game.inresor
2901 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2902 if goodies/baddies >= randreal(1.0, 1.5):
2903 prout(_("As a result of your actions, a treaty with the Klingon"))
2904 prout(_("Empire has been signed. The terms of the treaty are"))
2905 if goodies/baddies >= randreal(3.0):
2906 prout(_("favorable to the Federation."))
2908 prout(_("Congratulations!"))
2910 prout(_("highly unfavorable to the Federation."))
2912 prout(_("The Federation will be destroyed."))
2914 prout(_("Since you took the last Klingon with you, you are a"))
2915 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2916 prout(_("statue in your memory. Rest in peace, and try not"))
2917 prout(_("to think about pigeons."))
2922 "Compute player's score."
2923 timused = game.state.date - game.indate
2925 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2927 perdate = killrate()
2928 ithperd = 500*perdate + 0.5
2931 iwon = 100*game.skill
2932 if game.ship == 'E':
2934 elif game.ship == 'F':
2938 if not game.gamewon:
2939 game.state.nromrem = 0 # None captured if no win
2940 iscore = 10*(game.inkling - game.state.remkl) \
2941 + 50*(game.incom - len(game.state.kcmdr)) \
2943 + 20*(game.inrom - game.state.nromrem) \
2944 + 200*(game.inscom - game.state.nscrem) \
2945 - game.state.nromrem \
2950 prout(_("Your score --"))
2951 if game.inrom - game.state.nromrem:
2952 prout(_("%6d Romulans destroyed %5d") %
2953 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
2954 if game.state.nromrem:
2955 prout(_("%6d Romulans captured %5d") %
2956 (game.state.nromrem, game.state.nromrem))
2957 if game.inkling - game.state.remkl:
2958 prout(_("%6d ordinary Klingons destroyed %5d") %
2959 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
2960 if game.incom - len(game.state.kcmdr):
2961 prout(_("%6d Klingon commanders destroyed %5d") %
2962 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
2963 if game.inscom - game.state.nscrem:
2964 prout(_("%6d Super-Commander destroyed %5d") %
2965 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
2967 prout(_("%6.2f Klingons per stardate %5d") %
2969 if game.state.starkl:
2970 prout(_("%6d stars destroyed by your action %5d") %
2971 (game.state.starkl, -5*game.state.starkl))
2972 if game.state.nplankl:
2973 prout(_("%6d planets destroyed by your action %5d") %
2974 (game.state.nplankl, -10*game.state.nplankl))
2975 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
2976 prout(_("%6d inhabited planets destroyed by your action %5d") %
2977 (game.state.nplankl, -300*game.state.nworldkl))
2978 if game.state.basekl:
2979 prout(_("%6d bases destroyed by your action %5d") %
2980 (game.state.basekl, -100*game.state.basekl))
2982 prout(_("%6d calls for help from starbase %5d") %
2983 (game.nhelp, -45*game.nhelp))
2985 prout(_("%6d casualties incurred %5d") %
2986 (game.casual, -game.casual))
2988 prout(_("%6d crew abandoned in space %5d") %
2989 (game.abandoned, -3*game.abandoned))
2991 prout(_("%6d ship(s) lost or destroyed %5d") %
2992 (klship, -100*klship))
2994 prout(_("Penalty for getting yourself killed -200"))
2996 proutn(_("Bonus for winning "))
2997 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
2998 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
2999 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3000 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3001 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3002 prout(" %5d" % iwon)
3004 prout(_("TOTAL SCORE %5d") % iscore)
3007 "Emit winner's commemmorative plaque."
3010 proutn(_("File or device name for your plaque: "))
3013 fp = open(winner, "w")
3016 prout(_("Invalid name."))
3018 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3020 # The 38 below must be 64 for 132-column paper
3021 nskip = 38 - len(winner)/2
3022 fp.write("\n\n\n\n")
3023 # --------DRAW ENTERPRISE PICTURE.
3024 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3025 fp.write(" EEE E : : : E\n" )
3026 fp.write(" EE EEE E : : NCC-1701 : E\n")
3027 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3028 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3029 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3030 fp.write(" EEEEEEE EEEEE E E E E\n")
3031 fp.write(" EEE E E E E\n")
3032 fp.write(" E E E E\n")
3033 fp.write(" EEEEEEEEEEEEE E E\n")
3034 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3035 fp.write(" :E : EEEE E\n")
3036 fp.write(" .-E -:----- E\n")
3037 fp.write(" :E : E\n")
3038 fp.write(" EE : EEEEEEEE\n")
3039 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3041 fp.write(_(" U. S. S. ENTERPRISE\n"))
3042 fp.write("\n\n\n\n")
3043 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3045 fp.write(_(" Starfleet Command bestows to you\n"))
3047 fp.write("%*s%s\n\n" % (nskip, "", winner))
3048 fp.write(_(" the rank of\n\n"))
3049 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3051 if game.skill == SKILL_EXPERT:
3052 fp.write(_(" Expert level\n\n"))
3053 elif game.skill == SKILL_EMERITUS:
3054 fp.write(_("Emeritus level\n\n"))
3056 fp.write(_(" Cheat level\n\n"))
3057 timestring = time.ctime()
3058 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3059 (timestring+4, timestring+20, timestring+11))
3060 fp.write(_(" Your score: %d\n\n") % iscore)
3061 fp.write(_(" Klingons per stardate: %.2f\n") % perdate)
3064 # Code from io.c begins here
3066 rows = linecount = 0 # for paging
3069 fullscreen_window = None
3070 srscan_window = None
3071 report_window = None
3072 status_window = None
3073 lrscan_window = None
3074 message_window = None
3075 prompt_window = None
3080 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3081 gettext.textdomain("sst")
3082 if not (game.options & OPTION_CURSES):
3083 ln_env = os.getenv("LINES")
3089 stdscr = curses.initscr()
3093 global fullscreen_window, srscan_window, report_window, status_window
3094 global lrscan_window, message_window, prompt_window
3095 (rows, columns) = stdscr.getmaxyx()
3096 fullscreen_window = stdscr
3097 srscan_window = curses.newwin(12, 25, 0, 0)
3098 report_window = curses.newwin(11, 0, 1, 25)
3099 status_window = curses.newwin(10, 0, 1, 39)
3100 lrscan_window = curses.newwin(5, 0, 0, 64)
3101 message_window = curses.newwin(0, 0, 12, 0)
3102 prompt_window = curses.newwin(1, 0, rows-2, 0)
3103 message_window.scrollok(True)
3104 setwnd(fullscreen_window)
3108 if game.options & OPTION_CURSES:
3109 stdscr.keypad(False)
3115 "Wait for user action -- OK to do nothing if on a TTY"
3116 if game.options & OPTION_CURSES:
3121 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3125 if game.skill > SKILL_FAIR:
3126 prompt = _("[CONTINUE?]")
3128 prompt = _("[PRESS ENTER TO CONTINUE]")
3130 if game.options & OPTION_CURSES:
3132 setwnd(prompt_window)
3133 prompt_window.clear()
3134 prompt_window.addstr(prompt)
3135 prompt_window.getstr()
3136 prompt_window.clear()
3137 prompt_window.refresh()
3138 setwnd(message_window)
3141 sys.stdout.write('\n')
3144 for j in range(rows):
3145 sys.stdout.write('\n')
3149 "Skip i lines. Pause game if this would cause a scrolling event."
3150 for dummy in range(i):
3151 if game.options & OPTION_CURSES:
3152 (y, x) = curwnd.getyx()
3153 (my, mx) = curwnd.getmaxyx()
3154 if curwnd == message_window and y >= my - 3:
3160 except curses.error:
3165 if rows and linecount >= rows:
3168 sys.stdout.write('\n')
3171 "Utter a line with no following line feed."
3172 if game.options & OPTION_CURSES:
3176 sys.stdout.write(line)
3186 if not replayfp or replayfp.closed: # Don't slow down replays
3189 if game.options & OPTION_CURSES:
3193 if not replayfp or replayfp.closed:
3197 "Get a line of input."
3198 if game.options & OPTION_CURSES:
3199 line = curwnd.getstr() + "\n"
3202 if replayfp and not replayfp.closed:
3204 line = replayfp.readline()
3207 prout("*** Replay finished")
3210 elif line[0] != "#":
3213 line = raw_input() + "\n"
3219 "Change windows -- OK for this to be a no-op in tty mode."
3221 if game.options & OPTION_CURSES:
3223 curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window)
3226 "Clear to end of line -- can be a no-op in tty mode"
3227 if game.options & OPTION_CURSES:
3232 "Clear screen -- can be a no-op in tty mode."
3234 if game.options & OPTION_CURSES:
3241 # Things past this point have policy implications.
3245 "Hook to be called after moving to redraw maps."
3246 if game.options & OPTION_CURSES:
3249 setwnd(srscan_window)
3253 setwnd(status_window)
3254 status_window.clear()
3255 status_window.move(0, 0)
3256 setwnd(report_window)
3257 report_window.clear()
3258 report_window.move(0, 0)
3260 setwnd(lrscan_window)
3261 lrscan_window.clear()
3262 lrscan_window.move(0, 0)
3263 lrscan(silent=False)
3265 def put_srscan_sym(w, sym):
3266 "Emit symbol for short-range scan."
3267 srscan_window.move(w.i+1, w.j*2+2)
3268 srscan_window.addch(sym)
3269 srscan_window.refresh()
3272 "Enemy fall down, go boom."
3273 if game.options & OPTION_CURSES:
3275 setwnd(srscan_window)
3276 srscan_window.attron(curses.A_REVERSE)
3277 put_srscan_sym(w, game.quad[w.i][w.j])
3281 srscan_window.attroff(curses.A_REVERSE)
3282 put_srscan_sym(w, game.quad[w.i][w.j])
3283 curses.delay_output(500)
3284 setwnd(message_window)
3287 "Sound and visual effects for teleportation."
3288 if game.options & OPTION_CURSES:
3290 setwnd(message_window)
3292 prouts(" . . . . . ")
3293 if game.options & OPTION_CURSES:
3294 #curses.delay_output(1000)
3298 def tracktorpedo(origin, w, step, i, n, iquad):
3299 "Torpedo-track animation."
3300 if not game.options & OPTION_CURSES:
3304 proutn(_("Track for torpedo number %d- ") % (i+1))
3307 proutn(_("Torpedo track- "))
3308 elif step==4 or step==9:
3312 if not damaged(DSRSENS) or game.condition=="docked":
3313 if i != 0 and step == 1:
3316 if (iquad=='.') or (iquad==' '):
3317 put_srscan_sym(w, '+')
3321 put_srscan_sym(w, iquad)
3323 curwnd.attron(curses.A_REVERSE)
3324 put_srscan_sym(w, iquad)
3328 curwnd.attroff(curses.A_REVERSE)
3329 put_srscan_sym(w, iquad)
3334 "Display the current galaxy chart."
3335 if game.options & OPTION_CURSES:
3336 setwnd(message_window)
3337 message_window.clear()
3339 if game.options & OPTION_TTY:
3344 def prstat(txt, data):
3346 if game.options & OPTION_CURSES:
3348 setwnd(status_window)
3350 proutn(" " * (NSYM - len(txt)))
3353 if game.options & OPTION_CURSES:
3354 setwnd(report_window)
3356 # Code from moving.c begins here
3358 def imove(course=None, noattack=False):
3359 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3362 def newquadrant(noattack):
3363 # Leaving quadrant -- allow final enemy attack
3364 # Don't do it if being pushed by Nova
3365 if len(game.enemies) != 0 and not noattack:
3367 for enemy in game.enemies:
3368 finald = (w - enemy.kloc).distance()
3369 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3370 # Stas Sergeev added the condition
3371 # that attacks only happen if Klingons
3372 # are present and your skill is good.
3373 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3374 attack(torps_ok=False)
3377 # check for edge of galaxy
3381 if course.final.i < 0:
3382 course.final.i = -course.final.i
3384 if course.final.j < 0:
3385 course.final.j = -course.final.j
3387 if course.final.i >= GALSIZE*QUADSIZE:
3388 course.final.i = (GALSIZE*QUADSIZE*2) - course.final.i
3390 if course.final.j >= GALSIZE*QUADSIZE:
3391 course.final.j = (GALSIZE*QUADSIZE*2) - course.final.j
3399 if game.nkinks == 3:
3400 # Three strikes -- you're out!
3404 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3405 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3406 prout(_("YOU WILL BE DESTROYED."))
3407 # Compute final position in new quadrant
3408 if trbeam: # Don't bother if we are to be beamed
3410 game.quadrant = course.final.quadrant()
3411 game.sector = course.final.sector()
3413 prout(_("Entering Quadrant %s.") % game.quadrant)
3414 game.quad[game.sector.i][game.sector.j] = game.ship
3416 if game.skill>SKILL_NOVICE:
3417 attack(torps_ok=False)
3419 def check_collision(h):
3420 iquad = game.quad[h.i][h.j]
3422 # object encountered in flight path
3423 stopegy = 50.0*course.distance/game.optime
3424 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3425 for enemy in game.enemies:
3426 if enemy.kloc == game.sector:
3428 collision(rammed=False, enemy=enemy)
3432 prouts(_("***RED ALERT! RED ALERT!"))
3434 proutn("***" + crmshp())
3435 proutn(_(" pulled into black hole at Sector %s") % h)
3436 # Getting pulled into a black hole was certain
3437 # death in Almy's original. Stas Sergeev added a
3438 # possibility that you'll get timewarped instead.
3440 for m in range(NDEVICES):
3441 if game.damage[m]>0:
3443 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3444 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3454 prout(_(" encounters Tholian web at %s;") % h)
3456 prout(_(" blocked by object at %s;") % h)
3457 proutn(_("Emergency stop required "))
3458 prout(_("%2d units of energy.") % int(stopegy))
3459 game.energy -= stopegy
3460 if game.energy <= 0:
3467 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3468 game.inorbit = False
3469 # If tractor beam is to occur, don't move full distance
3470 if game.state.date+game.optime >= scheduled(FTBEAM):
3472 game.condition = "red"
3473 course.distance = course.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3474 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3476 game.quad[game.sector.i][game.sector.j] = '.'
3477 for m in range(course.moves):
3480 if course.origin.quadrant() != course.location.quadrant():
3481 newquadrant(noattack)
3483 elif check_collision(w):
3484 print "Collision detected"
3488 # We're in destination quadrant -- compute new average enemy distances
3489 game.quad[game.sector.i][game.sector.j] = game.ship
3491 for enemy in game.enemies:
3492 finald = (w-enemy.kloc).distance()
3493 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3494 enemy.kdist = finald
3495 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
3496 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3497 attack(torps_ok=False)
3498 for enemy in game.enemies:
3499 enemy.kavgd = enemy.kdist
3502 setwnd(message_window)
3506 "Dock our ship at a starbase."
3508 if game.condition == "docked" and verbose:
3509 prout(_("Already docked."))
3512 prout(_("You must first leave standard orbit."))
3514 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3515 prout(crmshp() + _(" not adjacent to base."))
3517 game.condition = "docked"
3521 if game.energy < game.inenrg:
3522 game.energy = game.inenrg
3523 game.shield = game.inshld
3524 game.torps = game.intorps
3525 game.lsupres = game.inlsr
3526 game.state.crew = FULLCREW
3527 if not damaged(DRADIO) and \
3528 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3529 # get attack report from base
3530 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3534 def cartesian(loc1=None, loc2=None):
3536 return game.quadrant * QUADSIZE + game.sector
3538 return game.quadrant * QUADSIZE + loc1
3540 return loc1 * QUADSIZE + loc2
3542 def getcourse(isprobe):
3543 "Get a course and distance from the user."
3545 dquad = copy.copy(game.quadrant)
3546 navmode = "unspecified"
3550 if game.landed and not isprobe:
3551 prout(_("Dummy! You can't leave standard orbit until you"))
3552 proutn(_("are back aboard the ship."))
3555 while navmode == "unspecified":
3556 if damaged(DNAVSYS):
3558 prout(_("Computer damaged; manual navigation only"))
3560 prout(_("Computer damaged; manual movement only"))
3565 key = scanner.next()
3567 proutn(_("Manual or automatic- "))
3570 elif key == "IHALPHA":
3571 if scanner.sees("manual"):
3573 key = scanner.next()
3575 elif scanner.sees("automatic"):
3576 navmode = "automatic"
3577 key = scanner.next()
3585 prout(_("(Manual navigation assumed.)"))
3587 prout(_("(Manual movement assumed.)"))
3591 if navmode == "automatic":
3592 while key == "IHEOL":
3594 proutn(_("Target quadrant or quadrant§or- "))
3596 proutn(_("Destination sector or quadrant§or- "))
3599 key = scanner.next()
3603 xi = int(round(scanner.real))-1
3604 key = scanner.next()
3608 xj = int(round(scanner.real))-1
3609 key = scanner.next()
3611 # both quadrant and sector specified
3612 xk = int(round(scanner.real))-1
3613 key = scanner.next()
3617 xl = int(round(scanner.real))-1
3623 # only one pair of numbers was specified
3625 # only quadrant specified -- go to center of dest quad
3628 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3630 # only sector specified
3634 if not dquad.valid_quadrant() or not dsect.valid_sector():
3641 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3643 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3644 # the actual deltas get computed here
3645 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3646 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3648 while key == "IHEOL":
3649 proutn(_("X and Y displacements- "))
3652 key = scanner.next()
3657 delta.j = scanner.real
3658 key = scanner.next()
3662 delta.i = scanner.real
3663 # Check for zero movement
3664 if delta.i == 0 and delta.j == 0:
3667 if itemp == "verbose" and not isprobe:
3669 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3671 return course(bearing=delta.bearing(), distance=delta.distance())
3674 def __init__(self, bearing, distance, origin=None):
3675 self.distance = distance
3676 self.bearing = bearing
3678 self.origin = cartesian(game.quadrant, game.sector)
3680 self.origin = origin
3681 # The bearing() code we inherited from FORTRAN is actually computing
3682 # clockface directions!
3683 if self.bearing < 0.0:
3684 self.bearing += 12.0
3685 self.angle = ((15.0 - self.bearing) * 0.5235988)
3687 self.origin = cartesian(game.quadrant, game.sector)
3689 self.origin = cartesian(game.quadrant, origin)
3690 self.increment = coord(-math.sin(self.angle), math.cos(self.angle))
3691 bigger = max(abs(self.increment.i), abs(self.increment.j))
3692 self.increment /= bigger
3693 self.moves = int(round(10*self.distance*bigger))
3695 self.final = (self.location + self.moves*self.increment).roundtogrid()
3697 self.location = self.origin
3700 return self.location.roundtogrid() == self.final
3702 "Next step on course."
3704 self.nextlocation = self.location + self.increment
3705 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3706 self.location = self.nextlocation
3709 return self.location.quadrant()
3711 return self.location.sector()
3712 def power(self, warp):
3713 return self.distance*(warp**3)*(game.shldup+1)
3714 def time(self, warp):
3715 return 10.0*self.distance/warp**2
3718 "Move under impulse power."
3720 if damaged(DIMPULS):
3723 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3725 if game.energy > 30.0:
3727 course = getcourse(isprobe=False)
3730 power = 20.0 + 100.0*course.distance
3733 if power >= game.energy:
3734 # Insufficient power for trip
3736 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3737 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3738 if game.energy > 30:
3739 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3740 int(0.01 * (game.energy-20.0)-0.05))
3741 prout(_(" quadrants.\""))
3743 prout(_("quadrant. They are, therefore, useless.\""))
3746 # Make sure enough time is left for the trip
3747 game.optime = course.dist/0.095
3748 if game.optime >= game.state.remtime:
3749 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3750 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3751 proutn(_("we dare spend the time?\" "))
3754 # Activate impulse engines and pay the cost
3755 imove(course, noattack=False)
3759 power = 20.0 + 100.0*course.dist
3760 game.energy -= power
3761 game.optime = course.dist/0.095
3762 if game.energy <= 0:
3766 def warp(course, involuntary):
3767 "ove under warp drive."
3768 blooey = False; twarp = False
3769 if not involuntary: # Not WARPX entry
3771 if game.damage[DWARPEN] > 10.0:
3774 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3776 if damaged(DWARPEN) and game.warpfac > 4.0:
3779 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3780 prout(_(" is repaired, I can only give you warp 4.\""))
3782 # Read in course and distance
3785 course = getcourse(isprobe=False)
3788 # Make sure starship has enough energy for the trip
3789 # Note: this formula is slightly different from the C version,
3790 # and lets you skate a bit closer to the edge.
3791 if course.power(game.warpfac) >= game.energy:
3792 # Insufficient power for trip
3795 prout(_("Engineering to bridge--"))
3796 if not game.shldup or 0.5*power > game.energy:
3797 iwarp = (game.energy/(course.dist+0.05)) ** 0.333333333
3799 prout(_("We can't do it, Captain. We don't have enough energy."))
3801 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3804 prout(_("if you'll lower the shields."))
3808 prout(_("We haven't the energy to go that far with the shields up."))
3810 # Make sure enough time is left for the trip
3811 game.optime = course.time(game.warpfac)
3812 if game.optime >= 0.8*game.state.remtime:
3814 prout(_("First Officer Spock- \"Captain, I compute that such"))
3815 proutn(_(" a trip would require approximately %2.0f") %
3816 (100.0*game.optime/game.state.remtime))
3817 prout(_(" percent of our"))
3818 proutn(_(" remaining time. Are you sure this is wise?\" "))
3824 if game.warpfac > 6.0:
3825 # Decide if engine damage will occur
3826 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3827 prob = course.distance*(6.0-game.warpfac)**2/66.666666666
3828 if prob > randreal():
3830 course.distance = randreal(course.distance)
3831 # Decide if time warp will occur
3832 if 0.5*course.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3834 if idebug and game.warpfac==10 and not twarp:
3836 proutn("=== Force time warp? ")
3840 # If time warp or engine damage, check path
3841 # If it is obstructed, don't do warp or damage
3842 for m in range(course.moves):
3845 if not w.valid_sector():
3847 if game.quad[w.i][w.j] != '.':
3851 # Activate Warp Engines and pay the cost
3852 imove(course, noattack=False)
3855 game.energy -= course.power(game.warpfac)
3856 if game.energy <= 0:
3858 game.optime = course.time(game.warpfac)
3862 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
3864 prout(_("Engineering to bridge--"))
3865 prout(_(" Scott here. The warp engines are damaged."))
3866 prout(_(" We'll have to reduce speed to warp 4."))
3871 "Change the warp factor."
3877 proutn(_("Warp factor- "))
3882 if game.damage[DWARPEN] > 10.0:
3883 prout(_("Warp engines inoperative."))
3885 if damaged(DWARPEN) and scanner.real > 4.0:
3886 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
3887 prout(_(" but right now we can only go warp 4.\""))
3889 if scanner.real > 10.0:
3890 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
3892 if scanner.real < 1.0:
3893 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
3895 oldfac = game.warpfac
3896 game.warpfac = scanner.real
3897 if game.warpfac <= oldfac or game.warpfac <= 6.0:
3898 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
3901 if game.warpfac < 8.00:
3902 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
3904 if game.warpfac == 10.0:
3905 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
3907 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
3911 "Cope with being tossed out of quadrant by supernova or yanked by beam."
3913 # is captain on planet?
3915 if damaged(DTRANSP):
3918 prout(_("Scotty rushes to the transporter controls."))
3920 prout(_("But with the shields up it's hopeless."))
3922 prouts(_("His desperate attempt to rescue you . . ."))
3927 prout(_("SUCCEEDS!"))
3930 proutn(_("The crystals mined were "))
3938 # Check to see if captain in shuttle craft
3943 # Inform captain of attempt to reach safety
3947 prouts(_("***RED ALERT! RED ALERT!"))
3949 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
3950 prouts(_(" a supernova."))
3952 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
3953 prout(_("safely out of quadrant."))
3954 if not damaged(DRADIO):
3955 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
3956 # Try to use warp engines
3957 if damaged(DWARPEN):
3959 prout(_("Warp engines damaged."))
3962 game.warpfac = randreal(6.0, 8.0)
3963 prout(_("Warp factor set to %d") % int(game.warpfac))
3964 power = 0.75*game.energy
3965 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
3966 dist = max(dist, randreal(math.sqrt(2)))
3967 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
3968 game.optime = bugout.time(game.warpfac)
3970 game.inorbit = False
3971 warp(bugout, involuntary=True)
3973 # This is bad news, we didn't leave quadrant.
3977 prout(_("Insufficient energy to leave quadrant."))
3980 # Repeat if another snova
3981 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3983 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
3984 finish(FWON) # Snova killed remaining enemy.
3987 "Let's do the time warp again."
3988 prout(_("***TIME WARP ENTERED."))
3989 if game.state.snap and withprob(0.5):
3991 prout(_("You are traveling backwards in time %d stardates.") %
3992 int(game.state.date-game.snapsht.date))
3993 game.state = game.snapsht
3994 game.state.snap = False
3995 if len(game.state.kcmdr):
3996 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
3997 schedule(FBATTAK, expran(0.3*game.intime))
3998 schedule(FSNOVA, expran(0.5*game.intime))
3999 # next snapshot will be sooner
4000 schedule(FSNAP, expran(0.25*game.state.remtime))
4002 if game.state.nscrem:
4003 schedule(FSCMOVE, 0.2777)
4007 game.battle.invalidate()
4008 # Make sure Galileo is consistant -- Snapshot may have been taken
4009 # when on planet, which would give us two Galileos!
4011 for l in range(game.inplan):
4012 if game.state.planets[l].known == "shuttle_down":
4014 if game.iscraft == "onship" and game.ship=='E':
4015 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4016 game.iscraft = "offship"
4017 # Likewise, if in the original time the Galileo was abandoned, but
4018 # was on ship earlier, it would have vanished -- let's restore it.
4019 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4020 prout(_("Checkov- \"Security reports the Galileo has reappeared in the dock!\""))
4021 game.iscraft = "onship"
4022 # There used to be code to do the actual reconstrction here,
4023 # but the starchart is now part of the snapshotted galaxy state.
4024 prout(_("Spock has reconstructed a correct star chart from memory"))
4026 # Go forward in time
4027 game.optime = -0.5*game.intime*math.log(randreal())
4028 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4029 # cheat to make sure no tractor beams occur during time warp
4030 postpone(FTBEAM, game.optime)
4031 game.damage[DRADIO] += game.optime
4033 events() # Stas Sergeev added this -- do pending events
4036 "Launch deep-space probe."
4037 # New code to launch a deep space probe
4038 if game.nprobes == 0:
4041 if game.ship == 'E':
4042 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4044 prout(_("Ye Faerie Queene has no deep space probes."))
4049 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4051 if is_scheduled(FDSPROB):
4054 if damaged(DRADIO) and game.condition != "docked":
4055 prout(_("Spock- \"Records show the previous probe has not yet"))
4056 prout(_(" reached its destination.\""))
4058 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4060 key = scanner.next()
4062 if game.nprobes == 1:
4063 prout(_("1 probe left."))
4065 prout(_("%d probes left") % game.nprobes)
4066 proutn(_("Are you sure you want to fire a probe? "))
4069 game.isarmed = False
4070 if key == "IHALPHA" and scanner.token == "armed":
4072 key = scanner.next()
4073 elif key == "IHEOL":
4074 proutn(_("Arm NOVAMAX warhead? "))
4076 elif key == "IHREAL": # first element of course
4077 scanner.push(scanner.token)
4079 game.probe = getcourse(isprobe=True)
4083 schedule(FDSPROB, 0.01) # Time to move one sector
4084 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4089 "Yell for help from nearest starbase."
4090 # There's more than one way to move in this game!
4092 # Test for conditions which prevent calling for help
4093 if game.condition == "docked":
4094 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4097 prout(_("Subspace radio damaged."))
4099 if not game.state.baseq:
4100 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4103 prout(_("You must be aboard the %s.") % crmshp())
4105 # OK -- call for help from nearest starbase
4108 # There's one in this quadrant
4109 ddist = (game.base - game.sector).distance()
4112 for ibq in game.state.baseq:
4113 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4116 # Since starbase not in quadrant, set up new quadrant
4119 # dematerialize starship
4120 game.quad[game.sector.i][game.sector.j]='.'
4121 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4122 % (game.quadrant, crmshp()))
4123 game.sector.invalidate()
4124 for m in range(1, 5+1):
4125 w = game.base.scatter()
4126 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4127 # found one -- finish up
4130 if not game.sector.is_valid():
4131 prout(_("You have been lost in space..."))
4132 finish(FMATERIALIZE)
4134 # Give starbase three chances to rematerialize starship
4135 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4136 for m in range(1, 3+1):
4137 if m == 1: proutn(_("1st"))
4138 elif m == 2: proutn(_("2nd"))
4139 elif m == 3: proutn(_("3rd"))
4140 proutn(_(" attempt to re-materialize ") + crmshp())
4141 game.quad[ix][iy]=('-','o','O')[m-1]
4143 if randreal() > probf:
4146 curses.delay_output(500)
4148 game.quad[ix][iy]='?'
4151 setwnd(message_window)
4152 finish(FMATERIALIZE)
4154 game.quad[ix][iy]=game.ship
4155 prout(_("succeeds."))
4158 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4163 if game.condition=="docked":
4165 prout(_("You cannot abandon Ye Faerie Queene."))
4168 # Must take shuttle craft to exit
4169 if game.damage[DSHUTTL]==-1:
4170 prout(_("Ye Faerie Queene has no shuttle craft."))
4172 if game.damage[DSHUTTL]<0:
4173 prout(_("Shuttle craft now serving Big Macs."))
4175 if game.damage[DSHUTTL]>0:
4176 prout(_("Shuttle craft damaged."))
4179 prout(_("You must be aboard the ship."))
4181 if game.iscraft != "onship":
4182 prout(_("Shuttle craft not currently available."))
4184 # Emit abandon ship messages
4186 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4188 prouts(_("***ALL HANDS ABANDON SHIP!"))
4190 prout(_("Captain and crew escape in shuttle craft."))
4191 if not game.state.baseq:
4192 # Oops! no place to go...
4195 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4197 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4198 prout(_("Remainder of ship's complement beam down"))
4199 prout(_("to nearest habitable planet."))
4200 elif q.planet != None and not damaged(DTRANSP):
4201 prout(_("Remainder of ship's complement beam down to %s.") %
4204 prout(_("Entire crew of %d left to die in outer space.") %
4206 game.casual += game.state.crew
4207 game.abandoned += game.state.crew
4208 # If at least one base left, give 'em the Faerie Queene
4210 game.icrystl = False # crystals are lost
4211 game.nprobes = 0 # No probes
4212 prout(_("You are captured by Klingons and released to"))
4213 prout(_("the Federation in a prisoner-of-war exchange."))
4214 nb = randrange(len(game.state.baseq))
4215 # Set up quadrant and position FQ adjacient to base
4216 if not game.quadrant == game.state.baseq[nb]:
4217 game.quadrant = game.state.baseq[nb]
4218 game.sector.i = game.sector.j = 5
4221 # position next to base by trial and error
4222 game.quad[game.sector.i][game.sector.j] = '.'
4223 for l in range(QUADSIZE):
4224 game.sector = game.base.scatter()
4225 if game.sector.valid_sector() and \
4226 game.quad[game.sector.i][game.sector.j] == '.':
4229 break # found a spot
4230 game.sector.i=QUADSIZE/2
4231 game.sector.j=QUADSIZE/2
4233 # Get new commission
4234 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4235 game.state.crew = FULLCREW
4236 prout(_("Starfleet puts you in command of another ship,"))
4237 prout(_("the Faerie Queene, which is antiquated but,"))
4238 prout(_("still useable."))
4240 prout(_("The dilithium crystals have been moved."))
4242 game.iscraft = "offship" # Galileo disappears
4244 game.condition="docked"
4245 for l in range(NDEVICES):
4246 game.damage[l] = 0.0
4247 game.damage[DSHUTTL] = -1
4248 game.energy = game.inenrg = 3000.0
4249 game.shield = game.inshld = 1250.0
4250 game.torps = game.intorps = 6
4251 game.lsupres=game.inlsr=3.0
4256 # Code from planets.c begins here.
4259 "Abort a lengthy operation if an event interrupts it."
4262 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4267 "Report on (uninhabited) planets in the galaxy."
4271 prout(_("Spock- \"Planet report follows, Captain.\""))
4273 for i in range(game.inplan):
4274 if game.state.planets[i].pclass == "destroyed":
4276 if (game.state.planets[i].known != "unknown" \
4277 and not game.state.planets[i].inhabited) \
4280 if idebug and game.state.planets[i].known=="unknown":
4281 proutn("(Unknown) ")
4282 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4283 proutn(_(" class "))
4284 proutn(game.state.planets[i].pclass)
4286 if game.state.planets[i].crystals != present:
4288 prout(_("dilithium crystals present."))
4289 if game.state.planets[i].known=="shuttle_down":
4290 prout(_(" Shuttle Craft Galileo on surface."))
4292 prout(_("No information available."))
4295 "Enter standard orbit."
4299 prout(_("Already in standard orbit."))
4301 if damaged(DWARPEN) and damaged(DIMPULS):
4302 prout(_("Both warp and impulse engines damaged."))
4304 if not game.plnet.is_valid():
4305 prout("There is no planet in this sector.")
4307 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4308 prout(crmshp() + _(" not adjacent to planet."))
4311 game.optime = randreal(0.02, 0.05)
4312 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4316 game.height = randreal(1400, 8600)
4317 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4322 "Examine planets in this quadrant."
4323 if damaged(DSRSENS):
4324 if game.options & OPTION_TTY:
4325 prout(_("Short range sensors damaged."))
4327 if game.iplnet == None:
4328 if game.options & OPTION_TTY:
4329 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4331 if game.iplnet.known == "unknown":
4332 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4334 prout(_(" Planet at Sector %s is of class %s.") %
4335 (game.plnet, game.iplnet.pclass))
4336 if game.iplnet.known=="shuttle_down":
4337 prout(_(" Sensors show Galileo still on surface."))
4338 proutn(_(" Readings indicate"))
4339 if game.iplnet.crystals != "present":
4341 prout(_(" dilithium crystals present.\""))
4342 if game.iplnet.known == "unknown":
4343 game.iplnet.known = "known"
4344 elif game.iplnet.inhabited:
4345 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4346 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4349 "Use the transporter."
4353 if damaged(DTRANSP):
4354 prout(_("Transporter damaged."))
4355 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4357 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4361 if not game.inorbit:
4362 prout(crmshp() + _(" not in standard orbit."))
4365 prout(_("Impossible to transport through shields."))
4367 if game.iplnet.known=="unknown":
4368 prout(_("Spock- \"Captain, we have no information on this planet"))
4369 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4370 prout(_(" you may not go down.\""))
4372 if not game.landed and game.iplnet.crystals=="absent":
4373 prout(_("Spock- \"Captain, I fail to see the logic in"))
4374 prout(_(" exploring a planet with no dilithium crystals."))
4375 proutn(_(" Are you sure this is wise?\" "))
4379 if not (game.options & OPTION_PLAIN):
4380 nrgneed = 50 * game.skill + game.height / 100.0
4381 if nrgneed > game.energy:
4382 prout(_("Engineering to bridge--"))
4383 prout(_(" Captain, we don't have enough energy for transportation."))
4385 if not game.landed and nrgneed * 2 > game.energy:
4386 prout(_("Engineering to bridge--"))
4387 prout(_(" Captain, we have enough energy only to transport you down to"))
4388 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4389 if game.iplnet.known == "shuttle_down":
4390 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4391 proutn(_(" Are you sure this is wise?\" "))
4396 # Coming from planet
4397 if game.iplnet.known=="shuttle_down":
4398 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4402 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4403 prout(_("Landing party assembled, ready to beam up."))
4405 prout(_("Kirk whips out communicator..."))
4406 prouts(_("BEEP BEEP BEEP"))
4408 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4411 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4413 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4415 prout(_("Kirk- \"Energize.\""))
4418 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4421 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4423 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4426 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4427 game.landed = not game.landed
4428 game.energy -= nrgneed
4430 prout(_("Transport complete."))
4431 if game.landed and game.iplnet.known=="shuttle_down":
4432 prout(_("The shuttle craft Galileo is here!"))
4433 if not game.landed and game.imine:
4440 "Strip-mine a world for dilithium."
4444 prout(_("Mining party not on planet."))
4446 if game.iplnet.crystals == "mined":
4447 prout(_("This planet has already been strip-mined for dilithium."))
4449 elif game.iplnet.crystals == "absent":
4450 prout(_("No dilithium crystals on this planet."))
4453 prout(_("You've already mined enough crystals for this trip."))
4455 if game.icrystl and game.cryprob == 0.05:
4456 prout(_("With all those fresh crystals aboard the ") + crmshp())
4457 prout(_("there's no reason to mine more at this time."))
4459 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4462 prout(_("Mining operation complete."))
4463 game.iplnet.crystals = "mined"
4464 game.imine = game.ididit = True
4467 "Use dilithium crystals."
4471 if not game.icrystl:
4472 prout(_("No dilithium crystals available."))
4474 if game.energy >= 1000:
4475 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4476 prout(_(" except when Condition Yellow exists."))
4478 prout(_("Spock- \"Captain, I must warn you that loading"))
4479 prout(_(" raw dilithium crystals into the ship's power"))
4480 prout(_(" system may risk a severe explosion."))
4481 proutn(_(" Are you sure this is wise?\" "))
4486 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4487 prout(_(" Mr. Spock and I will try it.\""))
4489 prout(_("Spock- \"Crystals in place, Sir."))
4490 prout(_(" Ready to activate circuit.\""))
4492 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4494 if with(game.cryprob):
4495 prouts(_(" \"Activating now! - - No good! It's***"))
4497 prouts(_("***RED ALERT! RED A*L********************************"))
4500 prouts(_("****************** KA-BOOM!!!! *******************"))
4504 game.energy += randreal(5000.0, 5500.0)
4505 prouts(_(" \"Activating now! - - "))
4506 prout(_("The instruments"))
4507 prout(_(" are going crazy, but I think it's"))
4508 prout(_(" going to work!! Congratulations, Sir!\""))
4513 "Use shuttlecraft for planetary jaunt."
4516 if damaged(DSHUTTL):
4517 if game.damage[DSHUTTL] == -1.0:
4518 if game.inorbit and game.iplnet.known == "shuttle_down":
4519 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4521 prout(_("Ye Faerie Queene had no shuttle craft."))
4522 elif game.damage[DSHUTTL] > 0:
4523 prout(_("The Galileo is damaged."))
4524 else: # game.damage[DSHUTTL] < 0
4525 prout(_("Shuttle craft is now serving Big Macs."))
4527 if not game.inorbit:
4528 prout(crmshp() + _(" not in standard orbit."))
4530 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4531 prout(_("Shuttle craft not currently available."))
4533 if not game.landed and game.iplnet.known=="shuttle_down":
4534 prout(_("You will have to beam down to retrieve the shuttle craft."))
4536 if game.shldup or game.condition == "docked":
4537 prout(_("Shuttle craft cannot pass through shields."))
4539 if game.iplnet.known=="unknown":
4540 prout(_("Spock- \"Captain, we have no information on this planet"))
4541 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4542 prout(_(" you may not fly down.\""))
4544 game.optime = 3.0e-5*game.height
4545 if game.optime >= 0.8*game.state.remtime:
4546 prout(_("First Officer Spock- \"Captain, I compute that such"))
4547 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4548 int(100*game.optime/game.state.remtime))
4549 prout(_("remaining time."))
4550 proutn(_("Are you sure this is wise?\" "))
4556 if game.iscraft == "onship":
4558 if not damaged(DTRANSP):
4559 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4563 proutn(_("Shuttle crew"))
4565 proutn(_("Rescue party"))
4566 prout(_(" boards Galileo and swoops toward planet surface."))
4567 game.iscraft = "offship"
4571 game.iplnet.known="shuttle_down"
4572 prout(_("Trip complete."))
4575 # Ready to go back to ship
4576 prout(_("You and your mining party board the"))
4577 prout(_("shuttle craft for the trip back to the Enterprise."))
4579 prouts(_("The short hop begins . . ."))
4581 game.iplnet.known="known"
4587 game.iscraft = "onship"
4593 prout(_("Trip complete."))
4596 # Kirk on ship and so is Galileo
4597 prout(_("Mining party assembles in the hangar deck,"))
4598 prout(_("ready to board the shuttle craft \"Galileo\"."))
4600 prouts(_("The hangar doors open; the trip begins."))
4603 game.iscraft = "offship"
4606 game.iplnet.known = "shuttle_down"
4609 prout(_("Trip complete."))
4613 "Use the big zapper."
4617 if game.ship != 'E':
4618 prout(_("Ye Faerie Queene has no death ray."))
4620 if len(game.enemies)==0:
4621 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4624 prout(_("Death Ray is damaged."))
4626 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4627 prout(_(" is highly unpredictible. Considering the alternatives,"))
4628 proutn(_(" are you sure this is wise?\" "))
4631 prout(_("Spock- \"Acknowledged.\""))
4634 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4636 prout(_("Crew scrambles in emergency preparation."))
4637 prout(_("Spock and Scotty ready the death ray and"))
4638 prout(_("prepare to channel all ship's power to the device."))
4640 prout(_("Spock- \"Preparations complete, sir.\""))
4641 prout(_("Kirk- \"Engage!\""))
4643 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4646 if game.options & OPTION_PLAIN:
4650 prouts(_("Sulu- \"Captain! It's working!\""))
4652 while len(game.enemies) > 0:
4653 deadkl(game.enemies[1].kloc, game.quad[game.enemies[1].kloc.i][game.enemies[1].kloc.j],game.enemies[1].kloc)
4654 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4655 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4657 if (game.options & OPTION_PLAIN) == 0:
4658 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4660 prout(_(" is still operational.\""))
4662 prout(_(" has been rendered nonfunctional.\""))
4663 game.damage[DDRAY] = 39.95
4665 r = randreal() # Pick failure method
4667 prouts(_("Sulu- \"Captain! It's working!\""))
4669 prouts(_("***RED ALERT! RED ALERT!"))
4671 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4673 prouts(_("***RED ALERT! RED A*L********************************"))
4676 prouts(_("****************** KA-BOOM!!!! *******************"))
4681 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4683 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4685 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4686 prout(_(" have apparently been transformed into strange mutations."))
4687 prout(_(" Vulcans do not seem to be affected."))
4689 prout(_("Kirk- \"Raauch! Raauch!\""))
4694 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4696 proutn(_("Spock- \"I believe the word is"))
4697 prouts(_(" *ASTONISHING*"))
4698 prout(_(" Mr. Sulu."))
4699 for i in range(QUADSIZE):
4700 for j in range(QUADSIZE):
4701 if game.quad[i][j] == '.':
4702 game.quad[i][j] = '?'
4703 prout(_(" Captain, our quadrant is now infested with"))
4704 prouts(_(" - - - - - - *THINGS*."))
4706 prout(_(" I have no logical explanation.\""))
4708 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4710 prout(_("Scotty- \"There are so many tribbles down here"))
4711 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4715 # Code from reports.c begins here
4717 def attackreport(curt):
4718 "eport status of bases under attack."
4720 if is_scheduled(FCDBAS):
4721 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4722 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4723 elif game.isatb == 1:
4724 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4725 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4727 prout(_("No Starbase is currently under attack."))
4729 if is_scheduled(FCDBAS):
4730 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4732 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4736 # report on general game status
4738 s1 = "" and game.thawed and _("thawed ")
4739 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4740 s3 = (None, _("novice"). _("fair"),
4741 _("good"), _("expert"), _("emeritus"))[game.skill]
4742 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4743 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4744 prout(_("No plaque is allowed."))
4746 prout(_("This is tournament game %d.") % game.tourn)
4747 prout(_("Your secret password is \"%s\"") % game.passwd)
4748 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4749 (game.inkling + game.incom + game.inscom)))
4750 if game.incom - len(game.state.kcmdr):
4751 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4752 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4753 prout(_(", but no Commanders."))
4756 if game.skill > SKILL_FAIR:
4757 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4758 if len(game.state.baseq) != game.inbase:
4760 if game.inbase-len(game.state.baseq)==1:
4761 proutn(_("has been 1 base"))
4763 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4764 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4766 prout(_("There are %d bases.") % game.inbase)
4767 if communicating() or game.iseenit:
4768 # Don't report this if not seen and
4769 # either the radio is dead or not at base!
4773 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4775 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4776 if game.ship == 'E':
4777 proutn(_("You have "))
4779 proutn("%d" % (game.nprobes))
4782 proutn(_(" deep space probe"))
4786 if communicating() and is_scheduled(FDSPROB):
4788 proutn(_("An armed deep space probe is in "))
4790 proutn(_("A deep space probe is in "))
4791 prout("Quadrant %s." % game.probec)
4793 if game.cryprob <= .05:
4794 prout(_("Dilithium crystals aboard ship... not yet used."))
4798 while game.cryprob > ai:
4801 prout(_("Dilithium crystals have been used %d time%s.") % \
4802 (i, (_("s"), "")[i==1]))
4806 "Long-range sensor scan."
4807 if damaged(DLRSENS):
4808 # Now allow base's sensors if docked
4809 if game.condition != "docked":
4811 prout(_("LONG-RANGE SENSORS DAMAGED."))
4814 prout(_("Starbase's long-range scan"))
4816 prout(_("Long-range scan"))
4817 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4820 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4821 if not coord(x, y).valid_quadrant():
4825 if not damaged(DRADIO):
4826 game.state.galaxy[x][y].charted = True
4827 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4828 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4829 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4830 if not silent and game.state.galaxy[x][y].supernova:
4833 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4840 for i in range(NDEVICES):
4843 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4844 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4846 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4847 game.damage[i]+0.05,
4848 game.docfac*game.damage[i]+0.005))
4850 prout(_("All devices functional."))
4853 "Update the chart in the Enterprise's computer from galaxy data."
4854 game.lastchart = game.state.date
4855 for i in range(GALSIZE):
4856 for j in range(GALSIZE):
4857 if game.state.galaxy[i][j].charted:
4858 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
4859 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
4860 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
4863 "Display the star chart."
4865 if (game.options & OPTION_AUTOSCAN):
4867 if not damaged(DRADIO):
4869 if game.lastchart < game.state.date and game.condition == "docked":
4870 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
4872 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
4873 if game.state.date > game.lastchart:
4874 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
4875 prout(" 1 2 3 4 5 6 7 8")
4876 for i in range(GALSIZE):
4877 proutn("%d |" % (i+1))
4878 for j in range(GALSIZE):
4879 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4883 if game.state.galaxy[i][j].supernova:
4885 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
4887 elif game.state.galaxy[i][j].charted:
4888 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
4892 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4900 def sectscan(goodScan, i, j):
4901 "Light up an individual dot in a sector."
4902 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
4903 proutn("%c " % game.quad[i][j])
4908 "Emit status report lines"
4909 if not req or req == 1:
4910 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
4911 % (game.state.date, game.state.remtime))
4912 if not req or req == 2:
4913 if game.condition != "docked":
4915 prstat(_("Condition"), _("%s, %i DAMAGES") % \
4916 (game.condition.upper(), sum(map(lambda x: x > 0, game.damage))))
4917 if not req or req == 3:
4918 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
4919 if not req or req == 4:
4920 if damaged(DLIFSUP):
4921 if game.condition == "docked":
4922 s = _("DAMAGED, Base provides")
4924 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
4927 prstat(_("Life Support"), s)
4928 if not req or req == 5:
4929 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
4930 if not req or req == 6:
4932 if game.icrystl and (game.options & OPTION_SHOWME):
4933 extra = _(" (have crystals)")
4934 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
4935 if not req or req == 7:
4936 prstat(_("Torpedoes"), "%d" % (game.torps))
4937 if not req or req == 8:
4938 if damaged(DSHIELD):
4944 data = _(" %d%% %.1f units") \
4945 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
4946 prstat(_("Shields"), s+data)
4947 if not req or req == 9:
4948 prstat(_("Klingons Left"), "%d" \
4949 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
4950 if not req or req == 10:
4951 if game.options & OPTION_WORLDS:
4952 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
4953 if plnet and plnet.inhabited:
4954 prstat(_("Major system"), plnet.name)
4956 prout(_("Sector is uninhabited"))
4957 elif not req or req == 11:
4958 attackreport(not req)
4961 "Request specified status data, a historical relic from slow TTYs."
4962 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
4963 while scanner.next() == "IHEOL":
4964 proutn(_("Information desired? "))
4966 if scanner.token in requests:
4967 status(requests.index(scanner.token))
4969 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
4970 prout((" date, condition, position, lsupport, warpfactor,"))
4971 prout((" energy, torpedoes, shields, klingons, system, time."))
4976 if damaged(DSRSENS):
4977 # Allow base's sensors if docked
4978 if game.condition != "docked":
4979 prout(_(" S.R. SENSORS DAMAGED!"))
4982 prout(_(" [Using Base's sensors]"))
4984 prout(_(" Short-range scan"))
4985 if goodScan and not damaged(DRADIO):
4986 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
4987 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
4988 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
4989 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4990 prout(" 1 2 3 4 5 6 7 8 9 10")
4991 if game.condition != "docked":
4993 for i in range(QUADSIZE):
4994 proutn("%2d " % (i+1))
4995 for j in range(QUADSIZE):
4996 sectscan(goodScan, i, j)
5000 "Use computer to get estimated time of arrival for a warp jump."
5001 w1 = coord(); w2 = coord()
5003 if damaged(DCOMPTR):
5004 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5007 if scanner.next() != "IHREAL":
5010 proutn(_("Destination quadrant and/or sector? "))
5011 if scanner.next()!="IHREAL":
5014 w1.j = int(scanner.real-0.5)
5015 if scanner.next() != "IHREAL":
5018 w1.i = int(scanner.real-0.5)
5019 if scanner.next() == "IHREAL":
5020 w2.j = int(scanner.real-0.5)
5021 if scanner.next() != "IHREAL":
5024 w2.i = int(scanner.real-0.5)
5026 if game.quadrant.j>w1.i:
5030 if game.quadrant.i>w1.j:
5034 if not w1.valid_quadrant() or not w2.valid_sector():
5037 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5038 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5041 prout(_("Answer \"no\" if you don't know the value:"))
5044 proutn(_("Time or arrival date? "))
5045 if scanner.next()=="IHREAL":
5046 ttime = scanner.real
5047 if ttime > game.state.date:
5048 ttime -= game.state.date # Actually a star date
5049 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5050 if ttime <= 1e-10 or twarp > 10:
5051 prout(_("We'll never make it, sir."))
5058 proutn(_("Warp factor? "))
5059 if scanner.next()== "IHREAL":
5061 twarp = scanner.real
5062 if twarp<1.0 or twarp > 10.0:
5066 prout(_("Captain, certainly you can give me one of these."))
5069 ttime = (10.0*dist)/twarp**2
5070 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5071 if tpower >= game.energy:
5072 prout(_("Insufficient energy, sir."))
5073 if not game.shldup or tpower > game.energy*2.0:
5076 proutn(_("New warp factor to try? "))
5077 if scanner.next() == "IHREAL":
5079 twarp = scanner.real
5080 if twarp<1.0 or twarp > 10.0:
5088 prout(_("But if you lower your shields,"))
5089 proutn(_("remaining"))
5092 proutn(_("Remaining"))
5093 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5095 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5097 prout(_("Any warp speed is adequate."))
5099 prout(_("Minimum warp needed is %.2f,") % (twarp))
5100 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5101 if game.state.remtime < ttime:
5102 prout(_("Unfortunately, the Federation will be destroyed by then."))
5104 prout(_("You'll be taking risks at that speed, Captain"))
5105 if (game.isatb==1 and game.state.kscmdr == w1 and \
5106 scheduled(FSCDBAS)< ttime+game.state.date) or \
5107 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5108 prout(_("The starbase there will be destroyed by then."))
5109 proutn(_("New warp factor to try? "))
5110 if scanner.next() == "IHREAL":
5112 twarp = scanner.real
5113 if twarp<1.0 or twarp > 10.0:
5121 # Code from setup.c begins here
5124 "Issue a historically correct banner."
5126 prout(_("-SUPER- STAR TREK"))
5128 # From the FORTRAN original
5129 # prout(_("Latest update-21 Sept 78"))
5135 scanner.push("emsave.trk")
5136 key = scanner.next()
5138 proutn(_("File name: "))
5139 key = scanner.next()
5140 if key != "IHALPHA":
5144 if '.' not in scanner.token:
5145 scanner.token += ".trk"
5147 fp = open(scanner.token, "wb")
5149 prout(_("Can't freeze game as file %s") % scanner.token)
5151 cPickle.dump(game, fp)
5155 "Retrieve saved game."
5156 game.passwd[0] = '\0'
5157 key = scanner.next()
5159 proutn(_("File name: "))
5160 key = scanner.next()
5161 if key != "IHALPHA":
5165 if '.' not in scanner.token:
5166 scanner.token += ".trk"
5168 fp = open(scanner.token, "rb")
5170 prout(_("Can't thaw game in %s") % scanner.token)
5172 game = cPickle.load(fp)
5176 # I used <http://www.memory-alpha.org> to find planets
5177 # with references in ST:TOS. Eath and the Alpha Centauri
5178 # Colony have been omitted.
5180 # Some planets marked Class G and P here will be displayed as class M
5181 # because of the way planets are generated. This is a known bug.
5184 _("Andoria (Fesoan)"), # several episodes
5185 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5186 _("Vulcan (T'Khasi)"), # many episodes
5187 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5188 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5189 _("Ardana"), # TOS: "The Cloud Minders"
5190 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5191 _("Gideon"), # TOS: "The Mark of Gideon"
5192 _("Aldebaran III"), # TOS: "The Deadly Years"
5193 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5194 _("Altair IV"), # TOS: "Amok Time
5195 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5196 _("Benecia"), # TOS: "The Conscience of the King"
5197 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5198 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5199 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5200 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5201 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5202 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5203 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5204 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5205 _("Ingraham B"), # TOS: "Operation: Annihilate"
5206 _("Janus IV"), # TOS: "The Devil in the Dark"
5207 _("Makus III"), # TOS: "The Galileo Seven"
5208 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5209 _("Omega IV"), # TOS: "The Omega Glory"
5210 _("Regulus V"), # TOS: "Amok Time
5211 _("Deneva"), # TOS: "Operation -- Annihilate!"
5212 # Worlds from BSD Trek
5213 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5214 _("Beta III"), # TOS: "The Return of the Archons"
5215 _("Triacus"), # TOS: "And the Children Shall Lead",
5216 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5218 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5219 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5220 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5221 # _("Izar"), # TOS: "Whom Gods Destroy"
5222 # _("Tiburon"), # TOS: "The Way to Eden"
5223 # _("Merak II"), # TOS: "The Cloud Minders"
5224 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5225 # _("Iotia"), # TOS: "A Piece of the Action"
5229 _("S. R. Sensors"), \
5230 _("L. R. Sensors"), \
5232 _("Photon Tubes"), \
5233 _("Life Support"), \
5234 _("Warp Engines"), \
5235 _("Impulse Engines"), \
5237 _("Subspace Radio"), \
5238 _("Shuttle Craft"), \
5240 _("Navigation System"), \
5242 _("Shield Control"), \
5248 "Prepare to play, set up cosmos."
5250 # Decide how many of everything
5252 return # frozen game
5253 # Prepare the Enterprise
5254 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5256 game.state.crew = FULLCREW
5257 game.energy = game.inenrg = 5000.0
5258 game.shield = game.inshld = 2500.0
5261 game.quadrant = randplace(GALSIZE)
5262 game.sector = randplace(QUADSIZE)
5263 game.torps = game.intorps = 10
5264 game.nprobes = randrange(2, 5)
5266 for i in range(NDEVICES):
5267 game.damage[i] = 0.0
5268 # Set up assorted game parameters
5269 game.battle = coord()
5270 game.state.date = game.indate = 100.0 * randreal(20, 51)
5271 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5272 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5273 game.isatb = game.state.nplankl = 0
5274 game.state.starkl = game.state.basekl = 0
5275 game.iscraft = "onship"
5279 # Starchart is functional but we've never seen it
5280 game.lastchart = FOREVER
5281 # Put stars in the galaxy
5283 for i in range(GALSIZE):
5284 for j in range(GALSIZE):
5285 k = randrange(1, QUADSIZE**2/10+1)
5287 game.state.galaxy[i][j].stars = k
5288 # Locate star bases in galaxy
5289 for i in range(game.inbase):
5292 w = randplace(GALSIZE)
5293 if not game.state.galaxy[w.i][w.j].starbase:
5296 # C version: for (j = i-1; j > 0; j--)
5297 # so it did them in the opposite order.
5298 for j in range(1, i):
5299 # Improved placement algorithm to spread out bases
5300 distq = (w - game.state.baseq[j]).distance()
5301 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5304 prout("=== Abandoning base #%d at %s" % (i, w))
5306 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5308 prout("=== Saving base #%d, close to #%d" % (i, j))
5311 game.state.baseq.append(w)
5312 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5313 # Position ordinary Klingon Battle Cruisers
5315 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5316 if klumper > MAXKLQUAD:
5320 klump = (1.0 - r*r)*klumper
5325 w = randplace(GALSIZE)
5326 if not game.state.galaxy[w.i][w.j].supernova and \
5327 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5329 game.state.galaxy[w.i][w.j].klingons += int(klump)
5332 # Position Klingon Commander Ships
5333 for i in range(game.incom):
5335 w = randplace(GALSIZE)
5336 if not welcoming(w) or w in game.state.kcmdr:
5338 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5340 game.state.galaxy[w.i][w.j].klingons += 1
5341 game.state.kcmdr.append(w)
5342 # Locate planets in galaxy
5343 for i in range(game.inplan):
5345 w = randplace(GALSIZE)
5346 if game.state.galaxy[w.i][w.j].planet == None:
5350 new.crystals = "absent"
5351 if (game.options & OPTION_WORLDS) and i < NINHAB:
5352 new.pclass = "M" # All inhabited planets are class M
5353 new.crystals = "absent"
5355 new.name = systnames[i]
5356 new.inhabited = True
5358 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5360 new.crystals = "present"
5361 new.known = "unknown"
5362 new.inhabited = False
5363 game.state.galaxy[w.i][w.j].planet = new
5364 game.state.planets.append(new)
5366 for i in range(game.state.nromrem):
5367 w = randplace(GALSIZE)
5368 game.state.galaxy[w.i][w.j].romulans += 1
5369 # Place the Super-Commander if needed
5370 if game.state.nscrem > 0:
5372 w = randplace(GALSIZE)
5375 game.state.kscmdr = w
5376 game.state.galaxy[w.i][w.j].klingons += 1
5377 # Initialize times for extraneous events
5378 schedule(FSNOVA, expran(0.5 * game.intime))
5379 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5380 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5381 schedule(FBATTAK, expran(0.3*game.intime))
5383 if game.state.nscrem:
5384 schedule(FSCMOVE, 0.2777)
5389 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5390 schedule(FDISTR, expran(1.0 + game.intime))
5395 # Place thing (in tournament game, we don't want one!)
5396 # New in SST2K: never place the Thing near a starbase.
5397 # This makes sense and avoids a special case in the old code.
5399 if game.tourn is None:
5401 thing = randplace(GALSIZE)
5402 if thing not in game.state.baseq:
5405 game.state.snap = False
5406 if game.skill == SKILL_NOVICE:
5407 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5408 prout(_("a deadly Klingon invasion force. As captain of the United"))
5409 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5410 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5411 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5412 prout(_("your mission. As you proceed you may be given more time."))
5414 prout(_("You will have %d supporting starbases.") % (game.inbase))
5415 proutn(_("Starbase locations- "))
5417 prout(_("Stardate %d.") % int(game.state.date))
5419 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5420 prout(_("An unknown number of Romulans."))
5421 if game.state.nscrem:
5422 prout(_("And one (GULP) Super-Commander."))
5423 prout(_("%d stardates.") % int(game.intime))
5424 proutn(_("%d starbases in ") % game.inbase)
5425 for i in range(game.inbase):
5426 proutn(`game.state.baseq[i]`)
5429 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5430 proutn(_(" Sector %s") % game.sector)
5432 prout(_("Good Luck!"))
5433 if game.state.nscrem:
5434 prout(_(" YOU'LL NEED IT."))
5437 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5439 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5440 attack(torps_ok=False)
5443 "Choose your game type."
5448 game.skill = SKILL_NONE
5450 if not scanner.inqueue: # Can start with command line options
5451 proutn(_("Would you like a regular, tournament, or saved game? "))
5453 if scanner.sees("tournament"):
5454 while scanner.next() == "IHEOL":
5455 proutn(_("Type in tournament number-"))
5456 if scanner.real == 0:
5458 continue # We don't want a blank entry
5459 game.tourn = int(round(scanner.real))
5460 random.seed(scanner.real)
5462 logfp.write("# random.seed(%d)\n" % scanner.real)
5464 if scanner.sees("saved") or scanner.sees("frozen"):
5468 if game.passwd == None:
5470 if not game.alldone:
5471 game.thawed = True # No plaque if not finished
5475 if scanner.sees("regular"):
5477 proutn(_("What is \"%s\"?") % scanner.token)
5479 while game.length==0 or game.skill==SKILL_NONE:
5480 if scanner.next() == "IHALPHA":
5481 if scanner.sees("short"):
5483 elif scanner.sees("medium"):
5485 elif scanner.sees("long"):
5487 elif scanner.sees("novice"):
5488 game.skill = SKILL_NOVICE
5489 elif scanner.sees("fair"):
5490 game.skill = SKILL_FAIR
5491 elif scanner.sees("good"):
5492 game.skill = SKILL_GOOD
5493 elif scanner.sees("expert"):
5494 game.skill = SKILL_EXPERT
5495 elif scanner.sees("emeritus"):
5496 game.skill = SKILL_EMERITUS
5498 proutn(_("What is \""))
5499 proutn(scanner.token)
5504 proutn(_("Would you like a Short, Medium, or Long game? "))
5505 elif game.skill == SKILL_NONE:
5506 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5507 # Choose game options -- added by ESR for SST2K
5508 if scanner.next() != "IHALPHA":
5510 proutn(_("Choose your game style (or just press enter): "))
5512 if scanner.sees("plain"):
5513 # Approximates the UT FORTRAN version.
5514 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5515 game.options |= OPTION_PLAIN
5516 elif scanner.sees("almy"):
5517 # Approximates Tom Almy's version.
5518 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5519 game.options |= OPTION_ALMY
5520 elif scanner.sees("fancy") or scanner.sees("\n"):
5522 elif len(scanner.token):
5523 proutn(_("What is \"%s\"?") % scanner.token)
5525 if game.passwd == "debug":
5527 prout("=== Debug mode enabled.")
5528 # Use parameters to generate initial values of things
5529 game.damfac = 0.5 * game.skill
5530 game.inbase = randrange(BASEMIN, BASEMAX+1)
5532 if game.options & OPTION_PLANETS:
5533 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5534 if game.options & OPTION_WORLDS:
5535 game.inplan += int(NINHAB)
5536 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5537 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5538 game.state.remtime = 7.0 * game.length
5539 game.intime = game.state.remtime
5540 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5541 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5542 game.state.remres = (game.inkling+4*game.incom)*game.intime
5543 game.inresor = game.state.remres
5544 if game.inkling > 50:
5545 game.state.inbase += 1
5548 def dropin(iquad=None):
5549 "Drop a feature on a random dot in the current quadrant."
5551 w = randplace(QUADSIZE)
5552 if game.quad[w.i][w.j] == '.':
5554 if iquad is not None:
5555 game.quad[w.i][w.j] = iquad
5559 "Update our alert status."
5560 game.condition = "green"
5561 if game.energy < 1000.0:
5562 game.condition = "yellow"
5563 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5564 game.condition = "red"
5566 game.condition="dead"
5569 "Drop new Klingon into current quadrant."
5570 return enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5573 "Set up a new state of quadrant, for when we enter or re-enter it."
5576 game.neutz = game.inorbit = game.landed = False
5577 game.ientesc = game.iseenit = False
5578 # Create a blank quadrant
5579 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5581 # Attempt to escape Super-commander, so tbeam back!
5584 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5585 # cope with supernova
5588 game.klhere = q.klingons
5589 game.irhere = q.romulans
5591 game.quad[game.sector.i][game.sector.j] = game.ship
5594 # Position ordinary Klingons
5595 for i in range(game.klhere):
5597 # If we need a commander, promote a Klingon
5598 for cmdr in game.state.kcmdr:
5599 if cmdr == game.quadrant:
5600 e = game.enemies[game.klhere-1]
5601 game.quad[e.kloc.i][e.kloc.j] = 'C'
5602 e.kpower = randreal(950,1350) + 50.0*game.skill
5604 # If we need a super-commander, promote a Klingon
5605 if game.quadrant == game.state.kscmdr:
5607 game.quad[e.kloc.i][e.kloc.j] = 'S'
5608 e.kpower = randreal(1175.0, 1575.0) + 125.0*game.skill
5609 game.iscate = (game.state.remkl > 1)
5610 # Put in Romulans if needed
5611 for i in range(q.romulans):
5612 enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5613 # If quadrant needs a starbase, put it in
5615 game.base = dropin('B')
5616 # If quadrant needs a planet, put it in
5618 game.iplnet = q.planet
5619 if not q.planet.inhabited:
5620 game.plnet = dropin('P')
5622 game.plnet = dropin('@')
5623 # Check for condition
5626 if game.irhere > 0 and game.klhere == 0:
5628 if not damaged(DRADIO):
5630 prout(_("LT. Uhura- \"Captain, an urgent message."))
5631 prout(_(" I'll put it on audio.\" CLICK"))
5633 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5634 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5635 # Put in THING if needed
5636 if thing == game.quadrant:
5637 enemy(type='?', loc=dropin(),
5638 power=randreal(6000,6500.0)+250.0*game.skill)
5639 if not damaged(DSRSENS):
5641 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5642 prout(_(" Please examine your short-range scan.\""))
5643 # Decide if quadrant needs a Tholian; lighten up if skill is low
5644 if game.options & OPTION_THOLIAN:
5645 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5646 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5647 (game.skill > SKILL_GOOD and withprob(0.08)):
5650 w.i = withprob(0.5) * (QUADSIZE-1)
5651 w.j = withprob(0.5) * (QUADSIZE-1)
5652 if game.quad[w.i][w.j] == '.':
5654 game.tholian = enemy(type='T', loc=w,
5655 power=randrange(100, 500) + 25.0*game.skill)
5656 # Reserve unoccupied corners
5657 if game.quad[0][0]=='.':
5658 game.quad[0][0] = 'X'
5659 if game.quad[0][QUADSIZE-1]=='.':
5660 game.quad[0][QUADSIZE-1] = 'X'
5661 if game.quad[QUADSIZE-1][0]=='.':
5662 game.quad[QUADSIZE-1][0] = 'X'
5663 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5664 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5665 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
5666 # And finally the stars
5667 for i in range(q.stars):
5669 # Put in a few black holes
5670 for i in range(1, 3+1):
5673 # Take out X's in corners if Tholian present
5675 if game.quad[0][0]=='X':
5676 game.quad[0][0] = '.'
5677 if game.quad[0][QUADSIZE-1]=='X':
5678 game.quad[0][QUADSIZE-1] = '.'
5679 if game.quad[QUADSIZE-1][0]=='X':
5680 game.quad[QUADSIZE-1][0] = '.'
5681 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5682 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5685 "Set the self-destruct password."
5686 if game.options & OPTION_PLAIN:
5689 proutn(_("Please type in a secret password- "))
5691 game.passwd = scanner.token
5692 if game.passwd != None:
5697 game.passwd += chr(ord('a')+randrange(26))
5699 # Code from sst.c begins here
5702 "SRSCAN": OPTION_TTY,
5703 "STATUS": OPTION_TTY,
5704 "REQUEST": OPTION_TTY,
5705 "LRSCAN": OPTION_TTY,
5718 "SENSORS": OPTION_PLANETS,
5719 "ORBIT": OPTION_PLANETS,
5720 "TRANSPORT": OPTION_PLANETS,
5721 "MINE": OPTION_PLANETS,
5722 "CRYSTALS": OPTION_PLANETS,
5723 "SHUTTLE": OPTION_PLANETS,
5724 "PLANETS": OPTION_PLANETS,
5729 "PROBE": OPTION_PROBE,
5731 "FREEZE": 0, # Synonym for SAVE
5737 "SOS": 0, # Synonym for MAYDAY
5738 "CALL": 0, # Synonym for MAYDAY
5744 "Generate a list of legal commands."
5745 prout(_("LEGAL COMMANDS ARE:"))
5747 for key in commands:
5748 if not commands[key] or (commands[key] & game.options):
5749 proutn("%-12s " % key)
5751 if emitted % 5 == 4:
5756 "Browse on-line help."
5757 key = scanner.next()
5760 setwnd(prompt_window)
5761 proutn(_("Help on what command? "))
5762 key = scanner.next()
5763 setwnd(message_window)
5766 if scanner.token in commands or scanner.token == "ABBREV":
5773 cmd = scanner.token.upper()
5775 fp = open(SSTDOC, "r")
5778 fp = open(DOC_NAME, "r")
5780 prout(_("Spock- \"Captain, that information is missing from the"))
5781 proutn(_(" computer. You need to find "))
5783 prout(_(" and put it in the"))
5784 proutn(_(" current directory or to "))
5787 # This used to continue: "You need to find SST.DOC and put
5788 # it in the current directory."
5791 linebuf = fp.readline()
5793 prout(_("Spock- \"Captain, there is no information on that command.\""))
5796 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5797 linebuf = linebuf[3:].strip()
5801 prout(_("Spock- \"Captain, I've found the following information:\""))
5803 while linebuf in fp:
5804 if "******" in linebuf:
5810 "Command-interpretation loop."
5812 setwnd(message_window)
5813 while True: # command loop
5815 while True: # get a command
5820 setwnd(prompt_window)
5823 if scanner.next() == "IHEOL":
5824 if game.options & OPTION_CURSES:
5827 elif scanner.token == "":
5831 setwnd(message_window)
5833 candidates = filter(lambda x: x.startswith(scanner.token.upper()),
5835 if len(candidates) == 1:
5838 elif candidates and not (game.options & OPTION_PLAIN):
5839 prout("Commands with prefix '%s': %s" % (scanner.token, " ".join(candidates)))
5843 if cmd == "SRSCAN": # srscan
5845 elif cmd == "STATUS": # status
5847 elif cmd == "REQUEST": # status request
5849 elif cmd == "LRSCAN": # long range scan
5850 lrscan(silent=False)
5851 elif cmd == "PHASERS": # phasers
5855 elif cmd == "TORPEDO": # photon torpedos
5859 elif cmd == "MOVE": # move under warp
5860 warp(course=None, involuntary=False)
5861 elif cmd == "SHIELDS": # shields
5862 doshield(shraise=False)
5865 game.shldchg = False
5866 elif cmd == "DOCK": # dock at starbase
5869 attack(torps_ok=False)
5870 elif cmd == "DAMAGES": # damage reports
5872 elif cmd == "CHART": # chart
5874 elif cmd == "IMPULSE": # impulse
5876 elif cmd == "REST": # rest
5880 elif cmd == "WARP": # warp
5882 elif cmd == "SCORE": # score
5884 elif cmd == "SENSORS": # sensors
5886 elif cmd == "ORBIT": # orbit
5890 elif cmd == "TRANSPORT": # transport "beam"
5892 elif cmd == "MINE": # mine
5896 elif cmd == "CRYSTALS": # crystals
5900 elif cmd == "SHUTTLE": # shuttle
5904 elif cmd == "PLANETS": # Planet list
5906 elif cmd == "REPORT": # Game Report
5908 elif cmd == "COMPUTER": # use COMPUTER!
5910 elif cmd == "COMMANDS":
5912 elif cmd == "EMEXIT": # Emergency exit
5913 clrscr() # Hide screen
5914 freeze(True) # forced save
5915 raise SysExit,1 # And quick exit
5916 elif cmd == "PROBE":
5917 probe() # Launch probe
5920 elif cmd == "ABANDON": # Abandon Ship
5922 elif cmd == "DESTRUCT": # Self Destruct
5924 elif cmd == "SAVE": # Save Game
5927 if game.skill > SKILL_GOOD:
5928 prout(_("WARNING--Saved games produce no plaques!"))
5929 elif cmd == "DEATHRAY": # Try a desparation measure
5933 elif cmd == "DEBUGCMD": # What do we want for debug???
5935 elif cmd == "MAYDAY": # Call for help
5940 game.alldone = True # quit the game
5945 break # Game has ended
5946 if game.optime != 0.0:
5949 break # Events did us in
5950 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
5953 if hitme and not game.justin:
5954 attack(torps_ok=True)
5957 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
5968 "Emit the name of an enemy or feature."
5969 if type == 'R': s = _("Romulan")
5970 elif type == 'K': s = _("Klingon")
5971 elif type == 'C': s = _("Commander")
5972 elif type == 'S': s = _("Super-commander")
5973 elif type == '*': s = _("Star")
5974 elif type == 'P': s = _("Planet")
5975 elif type == 'B': s = _("Starbase")
5976 elif type == ' ': s = _("Black hole")
5977 elif type == 'T': s = _("Tholian")
5978 elif type == '#': s = _("Tholian web")
5979 elif type == '?': s = _("Stranger")
5980 elif type == '@': s = _("Inhabited World")
5981 else: s = "Unknown??"
5984 def crmena(stars, enemy, loctype, w):
5985 "Emit the name of an enemy and his location."
5989 buf += cramen(enemy) + _(" at ")
5990 if loctype == "quadrant":
5991 buf += _("Quadrant ")
5992 elif loctype == "sector":
5997 "Emit our ship name."
5998 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6001 "Emit a line of stars"
6002 prouts("******************************************************")
6006 return -avrage*math.log(1e-7 + randreal())
6008 def randplace(size):
6009 "Choose a random location."
6011 w.i = randrange(size)
6012 w.j = randrange(size)
6022 # Get a token from the user
6025 # Fill the token quue if nothing here
6026 while not self.inqueue:
6028 if curwnd==prompt_window:
6030 setwnd(message_window)
6037 self.inqueue = line.lstrip().split() + ["\n"]
6038 # From here on in it's all looking at the queue
6039 self.token = self.inqueue.pop(0)
6040 if self.token == "\n":
6044 self.real = float(self.token)
6045 self.type = "IHREAL"
6050 self.token = self.token.lower()
6051 self.type = "IHALPHA"
6054 def append(self, tok):
6055 self.inqueue.append(tok)
6056 def push(self, tok):
6057 self.inqueue.insert(0, tok)
6061 # Demand input for next scan
6063 self.real = self.token = None
6065 # compares s to item and returns true if it matches to the length of s
6066 return s.startswith(self.token)
6068 # Round token value to nearest integer
6069 return int(round(scanner.real))
6073 if scanner.type != "IHREAL":
6076 s.i = scanner.int()-1
6078 if scanner.type != "IHREAL":
6081 s.j = scanner.int()-1
6084 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6087 "Yes-or-no confirmation."
6091 if scanner.token == 'y':
6093 if scanner.token == 'n':
6096 proutn(_("Please answer with \"y\" or \"n\": "))
6099 "Complain about unparseable input."
6102 prout(_("Beg your pardon, Captain?"))
6105 "Access to the internals for debugging."
6106 proutn("Reset levels? ")
6108 if game.energy < game.inenrg:
6109 game.energy = game.inenrg
6110 game.shield = game.inshld
6111 game.torps = game.intorps
6112 game.lsupres = game.inlsr
6113 proutn("Reset damage? ")
6115 for i in range(NDEVICES):
6116 if game.damage[i] > 0.0:
6117 game.damage[i] = 0.0
6118 proutn("Toggle debug flag? ")
6122 prout("Debug output ON")
6124 prout("Debug output OFF")
6125 proutn("Cause selective damage? ")
6127 for i in range(NDEVICES):
6128 proutn("Kill %s?" % device[i])
6130 key = scanner.next()
6131 if key == "IHALPHA" and scanner.sees("y"):
6132 game.damage[i] = 10.0
6133 proutn("Examine/change events? ")
6138 FSNOVA: "Supernova ",
6141 FBATTAK: "Base Attack ",
6142 FCDBAS: "Base Destroy ",
6143 FSCMOVE: "SC Move ",
6144 FSCDBAS: "SC Base Destroy ",
6145 FDSPROB: "Probe Move ",
6146 FDISTR: "Distress Call ",
6147 FENSLV: "Enslavement ",
6148 FREPRO: "Klingon Build ",
6150 for i in range(1, NEVENTS):
6153 proutn("%.2f" % (scheduled(i)-game.state.date))
6154 if i == FENSLV or i == FREPRO:
6156 proutn(" in %s" % ev.quadrant)
6161 key = scanner.next()
6165 elif key == "IHREAL":
6166 ev = schedule(i, scanner.real)
6167 if i == FENSLV or i == FREPRO:
6169 proutn("In quadrant- ")
6170 key = scanner.next()
6171 # "IHEOL" says to leave coordinates as they are
6174 prout("Event %d canceled, no x coordinate." % (i))
6177 w.i = int(round(scanner.real))
6178 key = scanner.next()
6180 prout("Event %d canceled, no y coordinate." % (i))
6183 w.j = int(round(scanner.real))
6186 proutn("Induce supernova here? ")
6188 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6191 if __name__ == '__main__':
6192 import getopt, socket
6194 global line, thing, game, idebug
6200 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6201 if os.getenv("TERM"):
6202 game.options |= OPTION_CURSES
6204 game.options |= OPTION_TTY
6205 seed = int(time.time())
6206 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:tx")
6207 for (switch, val) in options:
6210 replayfp = open(val, "r")
6212 sys.stderr.write("sst: can't open replay file %s\n" % val)
6215 line = replayfp.readline().strip()
6216 (leader, key, seed) = line.split()
6218 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6219 line = replayfp.readline().strip()
6220 arguments += line.split()[2:]
6222 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6224 game.options |= OPTION_TTY
6225 game.options &=~ OPTION_CURSES
6226 elif switch == '-s':
6228 elif switch == '-t':
6229 game.options |= OPTION_TTY
6230 game.options &=~ OPTION_CURSES
6231 elif switch == '-x':
6234 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6236 # where to save the input in case of bugs
6238 logfp = open("/usr/tmp/sst-input.log", "w")
6240 sys.stderr.write("sst: warning, can't open logfile\n")
6242 logfp.write("# seed %s\n" % seed)
6243 logfp.write("# options %s\n" % " ".join(arguments))
6244 logfp.write("# recorded by %s@%s on %s\n" % \
6245 (os.getenv("LOGNAME"),socket.gethostname(),time.ctime()))
6247 scanner = sstscanner()
6248 map(scanner.append, arguments)
6251 while True: # Play a game
6252 setwnd(fullscreen_window)
6258 game.alldone = False
6264 if game.tourn and game.alldone:
6265 proutn(_("Do you want your score recorded?"))
6271 proutn(_("Do you want to play again? "))
6275 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6279 except KeyboardInterrupt: