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, getpass
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
232 # Abstract out the event handling -- underlying data structures will change
233 # when we implement stateful events
234 def findevent(evtype): return game.future[evtype]
237 def __init__(self, type=None, loc=None, power=None):
239 self.location = coord()
242 self.power = power # enemy energy level
243 game.enemies.append(self)
245 motion = (loc != self.location)
246 if self.location.i is not None and self.location.j is not None:
249 game.quad[self.location.i][self.location.j] = '#'
251 game.quad[self.location.i][self.location.j] = '.'
253 self.location = copy.copy(loc)
254 game.quad[self.location.i][self.location.j] = self.type
255 self.kdist = self.kavgd = (game.sector - loc).distance()
257 self.location = coord()
258 self.kdist = self.kavgd = None
259 game.enemies.remove(self)
262 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
266 self.options = None # Game options
267 self.state = snapshot() # A snapshot structure
268 self.snapsht = snapshot() # Last snapshot taken for time-travel purposes
269 self.quad = None # contents of our quadrant
270 self.damage = [0.0] * NDEVICES # damage encountered
271 self.future = [] # future events
272 for i in range(NEVENTS):
273 self.future.append(event())
274 self.passwd = None; # Self Destruct password
276 self.quadrant = None # where we are in the large
277 self.sector = None # where we are in the small
278 self.tholian = None # Tholian enemy object
279 self.base = None # position of base in current quadrant
280 self.battle = None # base coordinates being attacked
281 self.plnet = None # location of planet in quadrant
282 self.gamewon = False # Finished!
283 self.ididit = False # action taken -- allows enemy to attack
284 self.alive = False # we are alive (not killed)
285 self.justin = False # just entered quadrant
286 self.shldup = False # shields are up
287 self.shldchg = False # shield is changing (affects efficiency)
288 self.iscate = False # super commander is here
289 self.ientesc = False # attempted escape from supercommander
290 self.resting = False # rest time
291 self.icraft = False # Kirk in Galileo
292 self.landed = False # party on planet (true), on ship (false)
293 self.alldone = False # game is now finished
294 self.neutz = False # Romulan Neutral Zone
295 self.isarmed = False # probe is armed
296 self.inorbit = False # orbiting a planet
297 self.imine = False # mining
298 self.icrystl = False # dilithium crystals aboard
299 self.iseenit = False # seen base attack report
300 self.thawed = False # thawed game
301 self.condition = None # "green", "yellow", "red", "docked", "dead"
302 self.iscraft = None # "onship", "offship", "removed"
303 self.skill = None # Player skill level
304 self.inkling = 0 # initial number of klingons
305 self.inbase = 0 # initial number of bases
306 self.incom = 0 # initial number of commanders
307 self.inscom = 0 # initial number of commanders
308 self.inrom = 0 # initial number of commanders
309 self.instar = 0 # initial stars
310 self.intorps = 0 # initial/max torpedoes
311 self.torps = 0 # number of torpedoes
312 self.ship = 0 # ship type -- 'E' is Enterprise
313 self.abandoned = 0 # count of crew abandoned in space
314 self.length = 0 # length of game
315 self.klhere = 0 # klingons here
316 self.casual = 0 # causalties
317 self.nhelp = 0 # calls for help
318 self.nkinks = 0 # count of energy-barrier crossings
319 self.iplnet = None # planet # in quadrant
320 self.inplan = 0 # initial planets
321 self.irhere = 0 # Romulans in quadrant
322 self.isatb = 0 # =1 if super commander is attacking base
323 self.tourn = None # tournament number
324 self.nprobes = 0 # number of probes available
325 self.inresor = 0.0 # initial resources
326 self.intime = 0.0 # initial time
327 self.inenrg = 0.0 # initial/max energy
328 self.inshld = 0.0 # initial/max shield
329 self.inlsr = 0.0 # initial life support resources
330 self.indate = 0.0 # initial date
331 self.energy = 0.0 # energy level
332 self.shield = 0.0 # shield level
333 self.warpfac = 0.0 # warp speed
334 self.wfacsq = 0.0 # squared warp factor
335 self.lsupres = 0.0 # life support reserves
336 self.optime = 0.0 # time taken by current operation
337 self.docfac = 0.0 # repair factor when docking (constant?)
338 self.damfac = 0.0 # damage factor
339 self.lastchart = 0.0 # time star chart was last updated
340 self.cryprob = 0.0 # probability that crystal will work
341 self.probe = None # object holding probe course info
342 self.height = 0.0 # height of orbit around planet
344 # Stas thinks this should be (C expression):
345 # game.state.remkl + len(game.state.kcmdr) > 0 ?
346 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
347 # He says the existing expression is prone to divide-by-zero errors
348 # after killing the last klingon when score is shown -- perhaps also
349 # if the only remaining klingon is SCOM.
350 game.state.remtime = game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr))
376 return random.random() < p
378 def randrange(*args):
379 return random.randrange(*args)
384 v *= args[0] # from [0, args[0])
386 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
389 # Code from ai.c begins here
392 "Would this quadrant welcome another Klingon?"
393 return iq.valid_quadrant() and \
394 not game.state.galaxy[iq.i][iq.j].supernova and \
395 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
397 def tryexit(enemy, look, irun):
398 "A bad guy attempts to bug out."
400 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
401 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
402 if not welcoming(iq):
404 if enemy.type == 'R':
405 return False; # Romulans cannot escape!
407 # avoid intruding on another commander's territory
408 if enemy.type == 'C':
409 if iq in game.state.kcmdr:
411 # refuse to leave if currently attacking starbase
412 if game.battle == game.quadrant:
414 # don't leave if over 1000 units of energy
415 if enemy.power > 1000.0:
417 # emit escape message and move out of quadrant.
418 # we know this if either short or long range sensors are working
419 if not damaged(DSRSENS) or not damaged(DLRSENS) or \
420 game.condition == "docked":
421 prout(crmena(True, enemy.type, "sector", enemy.location) + \
422 (_(" escapes to Quadrant %s (and regains strength).") % q))
423 # handle local matters related to escape
426 if game.condition != "docked":
428 # Handle global matters related to escape
429 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
430 game.state.galaxy[iq.i][iq.j].klingons += 1
435 schedule(FSCMOVE, 0.2777)
439 for cmdr in game.state.kcmdr:
440 if cmdr == game.quadrant:
441 game.state.kcmdr[n] = iq
443 return True; # success
445 # The bad-guy movement algorithm:
447 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
448 # If both are operating full strength, force is 1000. If both are damaged,
449 # force is -1000. Having shields down subtracts an additional 1000.
451 # 2. Enemy has forces equal to the energy of the attacker plus
452 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
453 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
455 # Attacker Initial energy levels (nominal):
456 # Klingon Romulan Commander Super-Commander
457 # Novice 400 700 1200
459 # Good 450 800 1300 1750
460 # Expert 475 850 1350 1875
461 # Emeritus 500 900 1400 2000
462 # VARIANCE 75 200 200 200
464 # Enemy vessels only move prior to their attack. In Novice - Good games
465 # only commanders move. In Expert games, all enemy vessels move if there
466 # is a commander present. In Emeritus games all enemy vessels move.
468 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
469 # forces are 1000 greater than Enterprise.
471 # Agressive action on average cuts the distance between the ship and
472 # the enemy to 1/4 the original.
474 # 4. At lower energy advantage, movement units are proportional to the
475 # advantage with a 650 advantage being to hold ground, 800 to move forward
476 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
478 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
479 # retreat, especially at high skill levels.
481 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
483 def movebaddy(enemy):
484 "Tactical movement for the bad guys."
485 next = coord(); look = coord()
487 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
488 if game.skill >= SKILL_EXPERT:
489 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
491 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
493 mdist = int(dist1 + 0.5); # Nearest integer distance
494 # If SC, check with spy to see if should hi-tail it
495 if enemy.type=='S' and \
496 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
500 # decide whether to advance, retreat, or hold position
501 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
503 forces += 1000; # Good for enemy if shield is down!
504 if not damaged(DPHASER) or not damaged(DPHOTON):
505 if damaged(DPHASER): # phasers damaged
508 forces -= 0.2*(game.energy - 2500.0)
509 if damaged(DPHOTON): # photon torpedoes damaged
512 forces -= 50.0*game.torps
514 # phasers and photon tubes both out!
517 if forces <= 1000.0 and game.condition != "docked": # Typical situation
518 motion = ((forces + randreal(200))/150.0) - 5.0
520 if forces > 1000.0: # Very strong -- move in for kill
521 motion = (1.0 - randreal())**2 * dist1 + 1.0
522 if game.condition=="docked" and (game.options & OPTION_BASE): # protected by base -- back off !
523 motion -= game.skill*(2.0-randreal()**2)
525 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
526 # don't move if no motion
529 # Limit motion according to skill
530 if abs(motion) > game.skill:
535 # calculate preferred number of steps
536 nsteps = abs(int(motion))
537 if motion > 0 and nsteps > mdist:
538 nsteps = mdist; # don't overshoot
539 if nsteps > QUADSIZE:
540 nsteps = QUADSIZE; # This shouldn't be necessary
542 nsteps = 1; # This shouldn't be necessary
544 proutn("NSTEPS = %d:" % nsteps)
545 # Compute preferred values of delta X and Y
546 m = game.sector - enemy.location
547 if 2.0 * abs(m.i) < abs(m.j):
549 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
551 m = (motion * m).sgn()
552 next = enemy.location
554 for ll in range(nsteps):
556 proutn(" %d" % (ll+1))
557 # Check if preferred position available
568 attempts = 0; # Settle mysterious hang problem
569 while attempts < 20 and not success:
571 if look.i < 0 or look.i >= QUADSIZE:
572 if motion < 0 and tryexit(enemy, look, irun):
574 if krawli == m.i or m.j == 0:
576 look.i = next.i + krawli
578 elif look.j < 0 or look.j >= QUADSIZE:
579 if motion < 0 and tryexit(enemy, look, irun):
581 if krawlj == m.j or m.i == 0:
583 look.j = next.j + krawlj
585 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
586 # See if enemy should ram ship
587 if game.quad[look.i][look.j] == game.ship and \
588 (enemy.type == 'C' or enemy.type == 'S'):
589 collision(rammed=True, enemy=enemy)
591 if krawli != m.i and m.j != 0:
592 look.i = next.i + krawli
594 elif krawlj != m.j and m.i != 0:
595 look.j = next.j + krawlj
598 break; # we have failed
610 if not damaged(DSRSENS) or game.condition == "docked":
611 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
612 if enemy.kdist < dist1:
613 proutn(_(" advances to "))
615 proutn(_(" retreats to "))
616 prout("Sector %s." % next)
619 "Sequence Klingon tactical movement."
622 # Figure out which Klingon is the commander (or Supercommander)
624 if game.quadrant in game.state.kcmdr:
625 for enemy in game.enemies:
626 if enemy.type == 'C':
628 if game.state.kscmdr==game.quadrant:
629 for enemy in game.enemies:
630 if enemy.type == 'S':
633 # If skill level is high, move other Klingons and Romulans too!
634 # Move these last so they can base their actions on what the
636 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
637 for enemy in game.enemies:
638 if enemy.type in ('K', 'R'):
640 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
642 def movescom(iq, avoid):
643 "Commander movement helper."
644 # Avoid quadrants with bases if we want to avoid Enterprise
645 if not welcoming(iq) or (avoid and iq in game.state.baseq):
647 if game.justin and not game.iscate:
650 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
651 game.state.kscmdr = iq
652 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
653 if game.state.kscmdr==game.quadrant:
654 # SC has scooted, Remove him from current quadrant
659 for enemy in game.enemies:
660 if enemy.type == 'S':
664 if game.condition != "docked":
666 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
667 # check for a helpful planet
668 for i in range(game.inplan):
669 if game.state.planets[i].quadrant == game.state.kscmdr and \
670 game.state.planets[i].crystals == "present":
672 game.state.planets[i].pclass = "destroyed"
673 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
676 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
677 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
678 prout(_(" by the Super-commander.\""))
680 return True; # looks good!
682 def supercommander():
683 "Move the Super Commander."
684 iq = coord(); sc = coord(); ibq = coord(); idelta = coord()
687 prout("== SUPERCOMMANDER")
688 # Decide on being active or passive
689 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 \
690 (game.state.date-game.indate) < 3.0)
691 if not game.iscate and avoid:
692 # compute move away from Enterprise
693 idelta = game.state.kscmdr-game.quadrant
694 if idelta.distance() > 2.0:
696 idelta.i = game.state.kscmdr.j-game.quadrant.j
697 idelta.j = game.quadrant.i-game.state.kscmdr.i
699 # compute distances to starbases
700 if not game.state.baseq:
704 sc = game.state.kscmdr
705 for base in game.state.baseq:
706 basetbl.append((i, (base - sc).distance()))
707 if game.state.baseq > 1:
708 basetbl.sort(lambda x, y: cmp(x[1]. y[1]))
709 # look for nearest base without a commander, no Enterprise, and
710 # without too many Klingons, and not already under attack.
711 ifindit = iwhichb = 0
712 for (i2, base) in enumerate(game.state.baseq):
713 i = basetbl[i2][0]; # bug in original had it not finding nearest
714 if base==game.quadrant or base==game.battle or not welcoming(base):
716 # if there is a commander, and no other base is appropriate,
717 # we will take the one with the commander
718 for cmdr in game.state.kcmdr:
719 if base == cmdr and ifindit != 2:
723 else: # no commander -- use this one
728 return # Nothing suitable -- wait until next time
729 ibq = game.state.baseq[iwhichb]
730 # decide how to move toward base
731 idelta = ibq - game.state.kscmdr
732 # Maximum movement is 1 quadrant in either or both axes
733 idelta = idelta.sgn()
734 # try moving in both x and y directions
735 # there was what looked like a bug in the Almy C code here,
736 # but it might be this translation is just wrong.
737 iq = game.state.kscmdr + idelta
738 if not movescom(iq, avoid):
739 # failed -- try some other maneuvers
740 if idelta.i==0 or idelta.j==0:
743 iq.j = game.state.kscmdr.j + 1
744 if not movescom(iq, avoid):
745 iq.j = game.state.kscmdr.j - 1
748 iq.i = game.state.kscmdr.i + 1
749 if not movescom(iq, avoid):
750 iq.i = game.state.kscmdr.i - 1
753 # try moving just in x or y
754 iq.j = game.state.kscmdr.j
755 if not movescom(iq, avoid):
756 iq.j = game.state.kscmdr.j + idelta.j
757 iq.i = game.state.kscmdr.i
760 if len(game.state.baseq) == 0:
763 for ibq in game.state.baseq:
764 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
767 return # no, don't attack base!
770 schedule(FSCDBAS, randreal(1.0, 3.0))
771 if is_scheduled(FCDBAS):
772 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
773 if not communicating():
777 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
779 prout(_(" reports that it is under attack from the Klingon Super-commander."))
780 proutn(_(" It can survive until stardate %d.\"") \
781 % int(scheduled(FSCDBAS)))
784 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
788 game.optime = 0.0; # actually finished
790 # Check for intelligence report
793 (not communicating()) or \
794 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
797 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
798 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
803 if not game.tholian or game.justin:
806 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
807 id.i = 0; id.j = QUADSIZE-1
808 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
809 id.i = QUADSIZE-1; id.j = QUADSIZE-1
810 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
811 id.i = QUADSIZE-1; id.j = 0
812 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
815 # something is wrong!
816 game.tholian.move(None)
817 prout("***Internal error: Tholian in a bad spot.")
819 # do nothing if we are blocked
820 if game.quad[id.i][id.j] not in ('.', '#'):
822 here = copy.copy(game.tholian.location)
823 delta = (id - game.tholian.location).sgn()
825 while here.i != id.i:
827 if game.quad[here.i][here.j]=='.':
828 game.tholian.move(here)
830 while here.j != id.j:
832 if game.quad[here.i][here.j]=='.':
833 game.tholian.move(here)
834 # check to see if all holes plugged
835 for i in range(QUADSIZE):
836 if game.quad[0][i]!='#' and game.quad[0][i]!='T':
838 if game.quad[QUADSIZE-1][i]!='#' and game.quad[QUADSIZE-1][i]!='T':
840 if game.quad[i][0]!='#' and game.quad[i][0]!='T':
842 if game.quad[i][QUADSIZE-1]!='#' and game.quad[i][QUADSIZE-1]!='T':
844 # All plugged up -- Tholian splits
845 game.quad[game.tholian.location.i][game.tholian.location.j]='#'
847 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
848 game.tholian.move(None)
851 # Code from battle.c begins here
853 def doshield(shraise):
854 "Change shield status."
862 if scanner.sees("transfer"):
866 prout(_("Shields damaged and down."))
868 if scanner.sees("up"):
870 elif scanner.sees("down"):
873 proutn(_("Do you wish to change shield energy? "))
875 proutn(_("Energy to transfer to shields- "))
877 elif damaged(DSHIELD):
878 prout(_("Shields damaged and down."))
881 proutn(_("Shields are up. Do you want them down? "))
888 proutn(_("Shields are down. Do you want them up? "))
894 if action == "SHUP": # raise shields
896 prout(_("Shields already up."))
900 if game.condition != "docked":
902 prout(_("Shields raised."))
905 prout(_("Shields raising uses up last of energy."))
910 elif action == "SHDN":
912 prout(_("Shields already down."))
916 prout(_("Shields lowered."))
919 elif action == "NRG":
920 while scanner.next() != "IHREAL":
922 proutn(_("Energy to transfer to shields- "))
924 if scanner.real == 0:
926 if scanner.real > game.energy:
927 prout(_("Insufficient ship energy."))
930 if game.shield+scanner.real >= game.inshld:
931 prout(_("Shield energy maximized."))
932 if game.shield+scanner.real > game.inshld:
933 prout(_("Excess energy requested returned to ship energy"))
934 game.energy -= game.inshld-game.shield
935 game.shield = game.inshld
937 if scanner.real < 0.0 and game.energy-scanner.real > game.inenrg:
938 # Prevent shield drain loophole
940 prout(_("Engineering to bridge--"))
941 prout(_(" Scott here. Power circuit problem, Captain."))
942 prout(_(" I can't drain the shields."))
945 if game.shield+scanner.real < 0:
946 prout(_("All shield energy transferred to ship."))
947 game.energy += game.shield
950 proutn(_("Scotty- \""))
952 prout(_("Transferring energy to shields.\""))
954 prout(_("Draining energy from shields.\""))
955 game.shield += scanner.real
956 game.energy -= scanner.real
960 "Choose a device to damage, at random."
961 # Quoth Eric Allman in the code of BSD-Trek:
962 # "Under certain conditions you can get a critical hit. This
963 # sort of hit damages devices. The probability that a given
964 # device is damaged depends on the device. Well protected
965 # devices (such as the computer, which is in the core of the
966 # ship and has considerable redundancy) almost never get
967 # damaged, whereas devices which are exposed (such as the
968 # warp engines) or which are particularly delicate (such as
969 # the transporter) have a much higher probability of being
972 # This is one place where OPTION_PLAIN does not restore the
973 # original behavior, which was equiprobable damage across
974 # all devices. If we wanted that, we'd return randrange(NDEVICES)
975 # and have done with it. Also, in the original game, DNAVYS
976 # and DCOMPTR were the same device.
978 # Instead, we use a table of weights similar to the one from BSD Trek.
979 # BSD doesn't have the shuttle, shield controller, death ray, or probes.
980 # We don't have a cloaking device. The shuttle got the allocation
981 # for the cloaking device, then we shaved a half-percent off
982 # everything to have some weight to give DSHCTRL/DDRAY/DDSP.
984 105, # DSRSENS: short range scanners 10.5%
985 105, # DLRSENS: long range scanners 10.5%
986 120, # DPHASER: phasers 12.0%
987 120, # DPHOTON: photon torpedoes 12.0%
988 25, # DLIFSUP: life support 2.5%
989 65, # DWARPEN: warp drive 6.5%
990 70, # DIMPULS: impulse engines 6.5%
991 145, # DSHIELD: deflector shields 14.5%
992 30, # DRADIO: subspace radio 3.0%
993 45, # DSHUTTL: shuttle 4.5%
994 15, # DCOMPTR: computer 1.5%
995 20, # NAVCOMP: navigation system 2.0%
996 75, # DTRANSP: transporter 7.5%
997 20, # DSHCTRL: high-speed shield controller 2.0%
998 10, # DDRAY: death ray 1.0%
999 30, # DDSP: deep-space probes 3.0%
1001 idx = randrange(1000) # weights must sum to 1000
1003 for (i, w) in enumerate(weights):
1007 return None; # we should never get here
1009 def collision(rammed, enemy):
1010 "Collision handling fot rammong events."
1011 prouts(_("***RED ALERT! RED ALERT!"))
1013 prout(_("***COLLISION IMMINENT."))
1017 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1019 proutn(_(" rammed by "))
1022 proutn(crmena(False, enemy.type, "sector", enemy.location))
1024 proutn(_(" (original position)"))
1026 deadkl(enemy.location, enemy.type, game.sector)
1027 proutn("***" + crmship() + " heavily damaged.")
1028 icas = randrange(10, 30)
1029 prout(_("***Sickbay reports %d casualties"), icas)
1031 game.state.crew -= icas
1032 # In the pre-SST2K version, all devices got equiprobably damaged,
1033 # which was silly. Instead, pick up to half the devices at
1034 # random according to our weighting table,
1035 ncrits = randrange(NDEVICES/2)
1036 for m in range(ncrits):
1038 if game.damage[dev] < 0:
1040 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1041 # Damage for at least time of travel!
1042 game.damage[dev] += game.optime + extradm
1044 prout(_("***Shields are down."))
1045 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1052 def torpedo(origin, bearing, dispersion, number, nburst):
1053 "Let a photon torpedo fly"
1054 if not damaged(DSRSENS) or game.condition=="docked":
1055 setwnd(srscan_window)
1057 setwnd(message_window)
1058 ac = bearing + 0.25*dispersion # dispersion is a random variable
1059 bullseye = (15.0 - bearing)*0.5235988
1060 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1061 bumpto = coord(0, 0)
1062 # Loop to move a single torpedo
1063 setwnd(message_window)
1064 for step in range(1, QUADSIZE*2):
1065 if not track.next(): break
1067 if not w.valid_sector():
1069 iquad=game.quad[w.i][w.j]
1070 tracktorpedo(origin, w, step, number, nburst, iquad)
1074 if not damaged(DSRSENS) or game.condition == "docked":
1075 skip(1); # start new line after text track
1076 if iquad in ('E', 'F'): # Hit our ship
1078 prout(_("Torpedo hits %s.") % crmshp())
1079 hit = 700.0 + randreal(100) - \
1080 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1081 newcnd(); # we're blown out of dock
1082 if game.landed or game.condition=="docked":
1083 return hit # Cheat if on a planet
1084 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1085 # is 143 degrees, which is almost exactly 4.8 clockface units
1086 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1088 bumpto = displacement.sector()
1089 if not bumpto.valid_sector():
1091 if game.quad[bumpto.i][bumpto.j]==' ':
1094 if game.quad[bumpto.i][bumpto.j]!='.':
1095 # can't move into object
1097 game.sector = bumpto
1099 game.quad[w.i][w.j]='.'
1100 game.quad[bumpto.i][bumpto.j]=iquad
1101 prout(_(" displaced by blast to Sector %s ") % bumpto)
1102 for enemy in game.enemies:
1103 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1104 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1106 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1108 if iquad in ('C', 'S') and withprob(0.05):
1109 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1110 prout(_(" torpedo neutralized."))
1112 for enemy in game.enemies:
1113 if w == enemy.location:
1115 kp = math.fabs(enemy.power)
1116 h1 = 700.0 + randrange(100) - \
1117 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1125 if enemy.power == 0:
1128 proutn(crmena(True, iquad, "sector", w))
1129 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1131 bumpto = displacement.sector()
1132 if not bumpto.valid_sector():
1133 prout(_(" damaged but not destroyed."))
1135 if game.quad[bumpto.i][bumpto.j] == ' ':
1136 prout(_(" buffeted into black hole."))
1137 deadkl(w, iquad, bumpto)
1138 if game.quad[bumpto.i][bumpto.j] != '.':
1139 prout(_(" damaged but not destroyed."))
1141 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1142 enemy.location = bumpto
1143 game.quad[w.i][w.j]='.'
1144 game.quad[bumpto.i][bumpto.j]=iquad
1145 for enemy in game.enemies:
1146 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1147 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1149 elif iquad == 'B': # Hit a base
1151 prout(_("***STARBASE DESTROYED.."))
1152 game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
1153 game.quad[w.i][w.j]='.'
1154 game.base.invalidate()
1155 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1
1156 game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1
1157 game.state.basekl += 1
1160 elif iquad == 'P': # Hit a planet
1161 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1162 game.state.nplankl += 1
1163 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1164 game.iplnet.pclass = "destroyed"
1166 game.plnet.invalidate()
1167 game.quad[w.i][w.j] = '.'
1169 # captain perishes on planet
1172 elif iquad == '@': # Hit an inhabited world -- very bad!
1173 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1174 game.state.nworldkl += 1
1175 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1176 game.iplnet.pclass = "destroyed"
1178 game.plnet.invalidate()
1179 game.quad[w.i][w.j] = '.'
1181 # captain perishes on planet
1183 prout(_("The torpedo destroyed an inhabited planet."))
1185 elif iquad == '*': # Hit a star
1189 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1191 elif iquad == '?': # Hit a thingy
1192 if not (game.options & OPTION_THINGY) or withprob(0.3):
1194 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1196 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1198 proutn(_("Mr. Spock-"))
1199 prouts(_(" \"Fascinating!\""))
1203 # Stas Sergeev added the possibility that
1204 # you can shove the Thingy and piss it off.
1205 # It then becomes an enemy and may fire at you.
1209 elif iquad == ' ': # Black hole
1211 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1213 elif iquad == '#': # hit the web
1215 prout(_("***Torpedo absorbed by Tholian web."))
1217 elif iquad == 'T': # Hit a Tholian
1218 h1 = 700.0 + randrange(100) - \
1219 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle))
1222 game.quad[w.i][w.j] = '.'
1227 proutn(crmena(True, 'T', "sector", w))
1229 prout(_(" survives photon blast."))
1231 prout(_(" disappears."))
1232 game.tholian.move(None)
1233 game.quad[w.i][w.j] = '#'
1238 proutn("Don't know how to handle torpedo collision with ")
1239 proutn(crmena(True, iquad, "sector", w))
1244 prout(_("Torpedo missed."))
1248 "Critical-hit resolution."
1249 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1251 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1252 proutn(_("***CRITICAL HIT--"))
1253 # Select devices and cause damage
1255 for loop1 in range(ncrit):
1258 # Cheat to prevent shuttle damage unless on ship
1259 if not (game.damage[j]<0.0 or (j==DSHUTTL and game.iscraft != "onship")):
1262 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1263 game.damage[j] += extradm
1265 for (i, j) in enumerate(cdam):
1267 if skipcount % 3 == 2 and i < len(cdam)-1:
1272 prout(_(" damaged."))
1273 if damaged(DSHIELD) and game.shldup:
1274 prout(_("***Shields knocked down."))
1277 def attack(torps_ok):
1278 # bad guy attacks us
1279 # torps_ok == False forces use of phasers in an attack
1280 # game could be over at this point, check
1283 attempt = False; ihurt = False;
1284 hitmax=0.0; hittot=0.0; chgfac=1.0
1287 prout("=== ATTACK!")
1288 # Tholian gets to move before attacking
1291 # if you have just entered the RNZ, you'll get a warning
1292 if game.neutz: # The one chance not to be attacked
1295 # commanders get a chance to tac-move towards you
1296 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:
1298 # if no enemies remain after movement, we're done
1299 if len(game.enemies)==0 or (len(game.enemies)==1 and thing == game.quadrant and not thing.angry):
1301 # set up partial hits if attack happens during shield status change
1302 pfac = 1.0/game.inshld
1304 chgfac = 0.25 + randreal(0.5)
1306 # message verbosity control
1307 if game.skill <= SKILL_FAIR:
1309 for enemy in game.enemies:
1311 continue; # too weak to attack
1312 # compute hit strength and diminish shield power
1314 # Increase chance of photon torpedos if docked or enemy energy is low
1315 if game.condition == "docked":
1317 if enemy.power < 500:
1319 if enemy.type=='T' or (enemy.type=='?' and not thing.angry):
1321 # different enemies have different probabilities of throwing a torp
1322 usephasers = not torps_ok or \
1323 (enemy.type == 'K' and r > 0.0005) or \
1324 (enemy.type=='C' and r > 0.015) or \
1325 (enemy.type=='R' and r > 0.3) or \
1326 (enemy.type=='S' and r > 0.07) or \
1327 (enemy.type=='?' and r > 0.05)
1328 if usephasers: # Enemy uses phasers
1329 if game.condition == "docked":
1330 continue; # Don't waste the effort!
1331 attempt = True; # Attempt to attack
1332 dustfac = randreal(0.8, 0.85)
1333 hit = enemy.power*math.pow(dustfac,enemy.kavgd)
1335 else: # Enemy uses photon torpedo
1336 # We should be able to make the bearing() method work here
1337 course = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1339 proutn(_("***TORPEDO INCOMING"))
1340 if not damaged(DSRSENS):
1341 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1344 dispersion = (randreal()+randreal())*0.5 - 0.5
1345 dispersion += 0.002*enemy.power*dispersion
1346 hit = torpedo(enemy.location, course, dispersion, number=1, nburst=1)
1347 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1348 finish(FWON); # Klingons did themselves in!
1349 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1350 return # Supernova or finished
1353 # incoming phaser or torpedo, shields may dissipate it
1354 if game.shldup or game.shldchg or game.condition=="docked":
1355 # shields will take hits
1356 propor = pfac * game.shield
1357 if game.condition =="docked":
1361 hitsh = propor*chgfac*hit+1.0
1363 if absorb > game.shield:
1364 absorb = game.shield
1365 game.shield -= absorb
1367 # taking a hit blasts us out of a starbase dock
1368 if game.condition == "docked":
1370 # but the shields may take care of it
1371 if propor > 0.1 and hit < 0.005*game.energy:
1373 # hit from this opponent got through shields, so take damage
1375 proutn(_("%d unit hit") % int(hit))
1376 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1377 proutn(_(" on the ") + crmshp())
1378 if not damaged(DSRSENS) and usephasers:
1379 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1381 # Decide if hit is critical
1387 if game.energy <= 0:
1388 # Returning home upon your shield, not with it...
1391 if not attempt and game.condition == "docked":
1392 prout(_("***Enemies decide against attacking your ship."))
1393 percent = 100.0*pfac*game.shield+0.5
1395 # Shields fully protect ship
1396 proutn(_("Enemy attack reduces shield strength to "))
1398 # Emit message if starship suffered hit(s)
1400 proutn(_("Energy left %2d shields ") % int(game.energy))
1403 elif not damaged(DSHIELD):
1406 proutn(_("damaged, "))
1407 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1408 # Check if anyone was hurt
1409 if hitmax >= 200 or hittot >= 500:
1410 icas = randrange(int(hittot * 0.015))
1413 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1414 prout(_(" in that last attack.\""))
1416 game.state.crew -= icas
1417 # After attack, reset average distance to enemies
1418 for enemy in game.enemies:
1419 enemy.kavgd = enemy.kdist
1420 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1423 def deadkl(w, type, mv):
1424 "Kill a Klingon, Tholian, Romulan, or Thingy."
1425 # Added mv to allow enemy to "move" before dying
1426 proutn(crmena(True, type, "sector", mv))
1427 # Decide what kind of enemy it is and update appropriately
1429 # Chalk up a Romulan
1430 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1432 game.state.nromrem -= 1
1441 # Killed some type of Klingon
1442 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1445 game.state.kcmdr.remove(game.quadrant)
1447 if game.state.kcmdr:
1448 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1449 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1452 game.state.remkl -= 1
1454 game.state.nscrem -= 1
1455 game.state.kscmdr.invalidate()
1460 # For each kind of enemy, finish message to player
1461 prout(_(" destroyed."))
1462 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1465 # Remove enemy ship from arrays describing local conditions
1466 for e in game.enemies:
1473 "Return None if target is invalid, otherwise return a course angle."
1474 if not w.valid_sector():
1478 # FIXME: C code this was translated from is wacky -- why the sign reversal?
1479 delta.j = (w.j - game.sector.j);
1480 delta.i = (game.sector.i - w.i);
1481 if delta == coord(0, 0):
1483 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1484 prout(_(" I recommend an immediate review of"))
1485 prout(_(" the Captain's psychological profile.\""))
1488 return delta.bearing()
1491 "Launch photon torpedo."
1494 if damaged(DPHOTON):
1495 prout(_("Photon tubes damaged."))
1499 prout(_("No torpedoes left."))
1502 # First, get torpedo count
1505 if scanner.token == "IHALPHA":
1508 elif scanner.token == "IHEOL" or not scanner.waiting():
1509 prout(_("%d torpedoes left.") % game.torps)
1511 proutn(_("Number of torpedoes to fire- "))
1512 continue # Go back around to get a number
1513 else: # key == "IHREAL"
1515 if n <= 0: # abort command
1520 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1523 scanner.chew() # User requested more torps than available
1524 continue # Go back around
1525 break # All is good, go to next stage
1529 key = scanner.next()
1530 if i==0 and key == "IHEOL":
1531 break; # no coordinate waiting, we will try prompting
1532 if i==1 and key == "IHEOL":
1533 # direct all torpedoes at one target
1535 target.append(target[0])
1536 course.append(course[0])
1539 scanner.push(scanner.token)
1540 target.append(scanner.getcoord())
1541 if target[-1] == None:
1543 course.append(targetcheck(target[-1]))
1544 if course[-1] == None:
1547 if len(target) == 0:
1548 # prompt for each one
1550 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1552 target.append(scanner.getcoord())
1553 if target[-1] == None:
1555 course.append(targetcheck(target[-1]))
1556 if course[-1] == None:
1559 # Loop for moving <n> torpedoes
1561 if game.condition != "docked":
1563 dispersion = (randreal()+randreal())*0.5 -0.5
1564 if math.fabs(dispersion) >= 0.47:
1566 dispersion *= randreal(1.2, 2.2)
1568 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1570 prouts(_("***TORPEDO MISFIRES."))
1573 prout(_(" Remainder of burst aborted."))
1575 prout(_("***Photon tubes damaged by misfire."))
1576 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1578 if game.shldup or game.condition == "docked":
1579 dispersion *= 1.0 + 0.0001*game.shield
1580 torpedo(game.sector, course[i], dispersion, number=i, nburst=n)
1581 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1583 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1587 "Check for phasers overheating."
1589 checkburn = (rpow-1500.0)*0.00038
1590 if withprob(checkburn):
1591 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1592 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1594 def checkshctrl(rpow):
1595 "Check shield control."
1598 prout(_("Shields lowered."))
1600 # Something bad has happened
1601 prouts(_("***RED ALERT! RED ALERT!"))
1603 hit = rpow*game.shield/game.inshld
1604 game.energy -= rpow+hit*0.8
1605 game.shield -= hit*0.2
1606 if game.energy <= 0.0:
1607 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1612 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1614 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1615 icas = randrange(int(hit*0.012))
1620 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1621 prout(_(" %d casualties so far.\"") % icas)
1623 game.state.crew -= icas
1625 prout(_("Phaser energy dispersed by shields."))
1626 prout(_("Enemy unaffected."))
1631 "Register a phaser hit on Klingons and Romulans."
1632 nenhr2 = len(game.enemies); kk=0
1635 for (k, wham) in enumerate(hits):
1638 dustfac = randreal(0.9, 1.0)
1639 hit = wham*math.pow(dustfac,game.enemies[kk].kdist)
1640 kpini = game.enemies[kk].power
1641 kp = math.fabs(kpini)
1642 if PHASEFAC*hit < kp:
1644 if game.enemies[kk].power < 0:
1645 game.enemies[kk].power -= -kp
1647 game.enemies[kk].power -= kp
1648 kpow = game.enemies[kk].power
1649 w = game.enemies[kk].location
1651 if not damaged(DSRSENS):
1653 proutn(_("%d unit hit on ") % int(hit))
1655 proutn(_("Very small hit on "))
1656 ienm = game.quad[w.i][w.j]
1659 proutn(crmena(False, ienm, "sector", w))
1663 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1667 kk -= 1 # don't do the increment
1669 else: # decide whether or not to emasculate klingon
1670 if kpow>0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1671 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1672 prout(_(" has just lost its firepower.\""))
1673 game.enemies[kk].power = -kpow
1678 "Fire phasers at bad guys."
1680 kz = 0; k = 1; irec=0 # Cheating inhibitor
1681 ifast = False; no = False; itarg = True; msgflag = True; rpow=0
1685 # SR sensors and Computer are needed for automode
1686 if damaged(DSRSENS) or damaged(DCOMPTR):
1688 if game.condition == "docked":
1689 prout(_("Phasers can't be fired through base shields."))
1692 if damaged(DPHASER):
1693 prout(_("Phaser control damaged."))
1697 if damaged(DSHCTRL):
1698 prout(_("High speed shield control damaged."))
1701 if game.energy <= 200.0:
1702 prout(_("Insufficient energy to activate high-speed shield control."))
1705 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1707 # Original code so convoluted, I re-did it all
1708 # (That was Tom Almy talking about the C code, I think -- ESR)
1709 while automode=="NOTSET":
1711 if key == "IHALPHA":
1712 if scanner.sees("manual"):
1713 if len(game.enemies)==0:
1714 prout(_("There is no enemy present to select."))
1717 automode="AUTOMATIC"
1720 key = scanner.next()
1721 elif scanner.sees("automatic"):
1722 if (not itarg) and len(game.enemies) != 0:
1723 automode = "FORCEMAN"
1725 if len(game.enemies)==0:
1726 prout(_("Energy will be expended into space."))
1727 automode = "AUTOMATIC"
1728 key = scanner.next()
1729 elif scanner.sees("no"):
1734 elif key == "IHREAL":
1735 if len(game.enemies)==0:
1736 prout(_("Energy will be expended into space."))
1737 automode = "AUTOMATIC"
1739 automode = "FORCEMAN"
1741 automode = "AUTOMATIC"
1744 if len(game.enemies)==0:
1745 prout(_("Energy will be expended into space."))
1746 automode = "AUTOMATIC"
1748 automode = "FORCEMAN"
1750 proutn(_("Manual or automatic? "))
1755 if automode == "AUTOMATIC":
1756 if key == "IHALPHA" and scanner.sees("no"):
1758 key = scanner.next()
1759 if key != "IHREAL" and len(game.enemies) != 0:
1760 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1765 for i in range(len(game.enemies)):
1766 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1768 proutn(_("%d units required. ") % irec)
1770 proutn(_("Units to fire= "))
1771 key = scanner.next()
1776 proutn(_("Energy available= %.2f") % avail)
1779 if not rpow > avail:
1786 if key == "IHALPHA" and scanner.sees("no"):
1789 game.energy -= 200; # Go and do it!
1790 if checkshctrl(rpow):
1795 if len(game.enemies):
1798 for i in range(len(game.enemies)):
1802 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))
1803 over = randreal(1.01, 1.06) * hits[i]
1805 powrem -= hits[i] + over
1806 if powrem <= 0 and temp < hits[i]:
1815 if extra > 0 and not game.alldone:
1817 proutn(_("*** Tholian web absorbs "))
1818 if len(game.enemies)>0:
1819 proutn(_("excess "))
1820 prout(_("phaser energy."))
1822 prout(_("%d expended on empty space.") % int(extra))
1823 elif automode == "FORCEMAN":
1826 if damaged(DCOMPTR):
1827 prout(_("Battle computer damaged, manual fire only."))
1830 prouts(_("---WORKING---"))
1832 prout(_("Short-range-sensors-damaged"))
1833 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1834 prout(_("Manual-fire-must-be-used"))
1836 elif automode == "MANUAL":
1838 for k in range(len(game.enemies)):
1839 aim = game.enemies[k].location
1840 ienm = game.quad[aim.i][aim.j]
1842 proutn(_("Energy available= %.2f") % (avail-0.006))
1846 if damaged(DSRSENS) and \
1847 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1848 prout(cramen(ienm) + _(" can't be located without short range scan."))
1851 hits[k] = 0; # prevent overflow -- thanks to Alexei Voitenko
1856 if itarg and k > kz:
1857 irec=(abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9,game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1860 if not damaged(DCOMPTR):
1865 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1866 key = scanner.next()
1867 if key == "IHALPHA" and scanner.sees("no"):
1869 key = scanner.next()
1871 if key == "IHALPHA":
1875 if k==1: # Let me say I'm baffled by this
1878 if scanner.real < 0:
1882 hits[k] = scanner.real
1883 rpow += scanner.real
1884 # If total requested is too much, inform and start over
1886 prout(_("Available energy exceeded -- try again."))
1889 key = scanner.next(); # scan for next value
1892 # zero energy -- abort
1895 if key == "IHALPHA" and scanner.sees("no"):
1900 game.energy -= 200.0
1901 if checkshctrl(rpow):
1905 # Say shield raised or malfunction, if necessary
1912 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1913 prouts(_(" CLICK CLICK POP . . ."))
1914 prout(_(" No response, sir!"))
1917 prout(_("Shields raised."))
1922 # Code from events,c begins here.
1924 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1925 # event of each type active at any given time. Mostly these means we can
1926 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1927 # BSD Trek, from which we swiped the idea, can have up to 5.
1929 def unschedule(evtype):
1930 "Remove an event from the schedule."
1931 game.future[evtype].date = FOREVER
1932 return game.future[evtype]
1934 def is_scheduled(evtype):
1935 "Is an event of specified type scheduled."
1936 return game.future[evtype].date != FOREVER
1938 def scheduled(evtype):
1939 "When will this event happen?"
1940 return game.future[evtype].date
1942 def schedule(evtype, offset):
1943 "Schedule an event of specified type."
1944 game.future[evtype].date = game.state.date + offset
1945 return game.future[evtype]
1947 def postpone(evtype, offset):
1948 "Postpone a scheduled event."
1949 game.future[evtype].date += offset
1952 "Rest period is interrupted by event."
1955 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
1957 game.resting = False
1963 "Run through the event queue looking for things to do."
1965 fintim = game.state.date + game.optime; yank=0
1966 ictbeam = False; istract = False
1967 w = coord(); hold = coord()
1968 ev = event(); ev2 = event()
1970 def tractorbeam(yank):
1971 "Tractor-beaming cases merge here."
1973 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
1975 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
1976 # If Kirk & Co. screwing around on planet, handle
1977 atover(True) # atover(true) is Grab
1980 if game.icraft: # Caught in Galileo?
1983 # Check to see if shuttle is aboard
1984 if game.iscraft == "offship":
1987 prout(_("Galileo, left on the planet surface, is captured"))
1988 prout(_("by aliens and made into a flying McDonald's."))
1989 game.damage[DSHUTTL] = -10
1990 game.iscraft = "removed"
1992 prout(_("Galileo, left on the planet surface, is well hidden."))
1994 game.quadrant = game.state.kscmdr
1996 game.quadrant = game.state.kcmdr[i]
1997 game.sector = randplace(QUADSIZE)
1998 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
1999 % (game.quadrant, game.sector))
2001 prout(_("(Remainder of rest/repair period cancelled.)"))
2002 game.resting = False
2004 if not damaged(DSHIELD) and game.shield > 0:
2005 doshield(shraise=True) # raise shields
2006 game.shldchg = False
2008 prout(_("(Shields not currently useable.)"))
2010 # Adjust finish time to time of tractor beaming
2011 fintim = game.state.date+game.optime
2012 attack(torps_ok=False)
2013 if not game.state.kcmdr:
2016 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2019 "Code merges here for any commander destroying a starbase."
2020 # Not perfect, but will have to do
2021 # Handle case where base is in same quadrant as starship
2022 if game.battle == game.quadrant:
2023 game.state.chart[game.battle.i][game.battle.j].starbase = False
2024 game.quad[game.base.i][game.base.j] = '.'
2025 game.base.invalidate()
2028 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2029 elif game.state.baseq and communicating():
2030 # Get word via subspace radio
2033 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2034 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2036 prout(_("the Klingon Super-Commander"))
2038 prout(_("a Klingon Commander"))
2039 game.state.chart[game.battle.i][game.battle.j].starbase = False
2040 # Remove Starbase from galaxy
2041 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2042 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2044 # reinstate a commander's base attack
2048 game.battle.invalidate()
2050 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2051 for i in range(1, NEVENTS):
2052 if i == FSNOVA: proutn("=== Supernova ")
2053 elif i == FTBEAM: proutn("=== T Beam ")
2054 elif i == FSNAP: proutn("=== Snapshot ")
2055 elif i == FBATTAK: proutn("=== Base Attack ")
2056 elif i == FCDBAS: proutn("=== Base Destroy ")
2057 elif i == FSCMOVE: proutn("=== SC Move ")
2058 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2059 elif i == FDSPROB: proutn("=== Probe Move ")
2060 elif i == FDISTR: proutn("=== Distress Call ")
2061 elif i == FENSLV: proutn("=== Enslavement ")
2062 elif i == FREPRO: proutn("=== Klingon Build ")
2064 prout("%.2f" % (scheduled(i)))
2067 radio_was_broken = damaged(DRADIO)
2070 # Select earliest extraneous event, evcode==0 if no events
2075 for l in range(1, NEVENTS):
2076 if game.future[l].date < datemin:
2079 prout("== Event %d fires" % evcode)
2080 datemin = game.future[l].date
2081 xtime = datemin-game.state.date
2082 game.state.date = datemin
2083 # Decrement Federation resources and recompute remaining time
2084 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2086 if game.state.remtime <=0:
2089 # Any crew left alive?
2090 if game.state.crew <=0:
2093 # Is life support adequate?
2094 if damaged(DLIFSUP) and game.condition != "docked":
2095 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2098 game.lsupres -= xtime
2099 if game.damage[DLIFSUP] <= xtime:
2100 game.lsupres = game.inlsr
2103 if game.condition == "docked":
2104 repair /= game.docfac
2105 # Don't fix Deathray here
2106 for l in range(NDEVICES):
2107 if game.damage[l] > 0.0 and l != DDRAY:
2108 if game.damage[l]-repair > 0.0:
2109 game.damage[l] -= repair
2111 game.damage[l] = 0.0
2112 # If radio repaired, update star chart and attack reports
2113 if radio_was_broken and not damaged(DRADIO):
2114 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2115 prout(_(" surveillance reports are coming in."))
2117 if not game.iseenit:
2121 prout(_(" The star chart is now up to date.\""))
2123 # Cause extraneous event EVCODE to occur
2124 game.optime -= xtime
2125 if evcode == FSNOVA: # Supernova
2128 schedule(FSNOVA, expran(0.5*game.intime))
2129 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2131 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2132 if game.state.nscrem == 0 or \
2133 ictbeam or istract or \
2134 game.condition=="docked" or game.isatb==1 or game.iscate:
2136 if game.ientesc or \
2137 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2138 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2139 (damaged(DSHIELD) and \
2140 (game.energy < 2500 or damaged(DPHASER)) and \
2141 (game.torps < 5 or damaged(DPHOTON))):
2143 istract = ictbeam = True
2144 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2147 elif evcode == FTBEAM: # Tractor beam
2148 if not game.state.kcmdr:
2151 i = randrange(len(game.state.kcmdr))
2152 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2153 if istract or game.condition == "docked" or yank == 0:
2154 # Drats! Have to reschedule
2156 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2160 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2161 game.snapsht = copy.deepcopy(game.state)
2162 game.state.snap = True
2163 schedule(FSNAP, expran(0.5 * game.intime))
2164 elif evcode == FBATTAK: # Commander attacks starbase
2165 if not game.state.kcmdr or not game.state.baseq:
2171 for ibq in game.state.baseq:
2172 for cmdr in game.state.kcmdr:
2173 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2176 # no match found -- try later
2177 schedule(FBATTAK, expran(0.3*game.intime))
2182 # commander + starbase combination found -- launch attack
2184 schedule(FCDBAS, randreal(1.0, 4.0))
2185 if game.isatb: # extra time if SC already attacking
2186 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2187 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2188 game.iseenit = False
2189 if not communicating():
2190 continue # No warning :-(
2194 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2195 prout(_(" reports that it is under attack and that it can"))
2196 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2199 elif evcode == FSCDBAS: # Supercommander destroys base
2202 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2203 continue # WAS RETURN!
2205 game.battle = game.state.kscmdr
2207 elif evcode == FCDBAS: # Commander succeeds in destroying base
2210 if not game.state.baseq() \
2211 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2212 game.battle.invalidate()
2214 # find the lucky pair
2215 for cmdr in game.state.kcmdr:
2216 if cmdr == game.battle:
2219 # No action to take after all
2222 elif evcode == FSCMOVE: # Supercommander moves
2223 schedule(FSCMOVE, 0.2777)
2224 if not game.ientesc and not istract and game.isatb != 1 and \
2225 (not game.iscate or not game.justin):
2227 elif evcode == FDSPROB: # Move deep space probe
2228 schedule(FDSPROB, 0.01)
2229 if not game.probe.next():
2230 if not game.probe.quadrant().valid_quadrant() or \
2231 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2232 # Left galaxy or ran into supernova
2236 proutn(_("Lt. Uhura- \"The deep space probe "))
2237 if not game.probe.quadrant().valid_quadrant():
2238 prout(_("has left the galaxy.\""))
2240 prout(_("is no longer transmitting.\""))
2246 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2247 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2249 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2250 chp.klingons = pdest.klingons
2251 chp.starbase = pdest.starbase
2252 chp.stars = pdest.stars
2253 pdest.charted = True
2254 game.probe.moves -= 1 # One less to travel
2255 if game.probe.arrived() and game.isarmed and pdest.stars:
2256 supernova(game.probe) # fire in the hole!
2258 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2260 elif evcode == FDISTR: # inhabited system issues distress call
2262 # try a whole bunch of times to find something suitable
2263 for i in range(100):
2264 # need a quadrant which is not the current one,
2265 # which has some stars which are inhabited and
2266 # not already under attack, which is not
2267 # supernova'ed, and which has some Klingons in it
2268 w = randplace(GALSIZE)
2269 q = game.state.galaxy[w.i][w.j]
2270 if not (game.quadrant == w or q.planet == None or \
2271 not q.planet.inhabited or \
2272 q.supernova or q.status!="secure" or q.klingons<=0):
2275 # can't seem to find one; ignore this call
2277 prout("=== Couldn't find location for distress event.")
2279 # got one!! Schedule its enslavement
2280 ev = schedule(FENSLV, expran(game.intime))
2282 q.status = "distressed"
2283 # tell the captain about it if we can
2285 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2287 prout(_("by a Klingon invasion fleet."))
2290 elif evcode == FENSLV: # starsystem is enslaved
2291 ev = unschedule(FENSLV)
2292 # see if current distress call still active
2293 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2297 q.status = "enslaved"
2299 # play stork and schedule the first baby
2300 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2301 ev2.quadrant = ev.quadrant
2303 # report the disaster if we can
2305 prout(_("Uhura- We've lost contact with starsystem %s") % \
2307 prout(_("in Quadrant %s.\n") % ev.quadrant)
2308 elif evcode == FREPRO: # Klingon reproduces
2309 # If we ever switch to a real event queue, we'll need to
2310 # explicitly retrieve and restore the x and y.
2311 ev = schedule(FREPRO, expran(1.0 * game.intime))
2312 # see if current distress call still active
2313 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2317 if game.state.remkl >=MAXKLGAME:
2318 continue # full right now
2319 # reproduce one Klingon
2322 if game.klhere >= MAXKLQUAD:
2324 # this quadrant not ok, pick an adjacent one
2325 for m.i in range(w.i - 1, w.i + 2):
2326 for m.j in range(w.j - 1, w.j + 2):
2327 if not m.valid_quadrant():
2329 q = game.state.galaxy[m.i][m.j]
2330 # check for this quad ok (not full & no snova)
2331 if q.klingons >= MAXKLQUAD or q.supernova:
2335 continue # search for eligible quadrant failed
2339 game.state.remkl += 1
2341 if game.quadrant == w:
2343 game.enemies.append(newkling())
2344 # recompute time left
2347 if game.quadrant == w:
2348 prout(_("Spock- sensors indicate the Klingons have"))
2349 prout(_("launched a warship from %s.") % q.planet)
2351 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2352 if q.planet != None:
2353 proutn(_("near %s") % q.planet)
2354 prout(_("in Quadrant %s.") % w)
2360 key = scanner.next()
2363 proutn(_("How long? "))
2368 origTime = delay = scanner.real
2371 if delay >= game.state.remtime or len(game.enemies) != 0:
2372 proutn(_("Are you sure? "))
2375 # Alternate resting periods (events) with attacks
2379 game.resting = False
2380 if not game.resting:
2381 prout(_("%d stardates left.") % int(game.state.remtime))
2383 temp = game.optime = delay
2384 if len(game.enemies):
2385 rtime = randreal(1.0, 2.0)
2389 if game.optime < delay:
2390 attack(torps_ok=False)
2398 # Repair Deathray if long rest at starbase
2399 if origTime-delay >= 9.99 and game.condition == "docked":
2400 game.damage[DDRAY] = 0.0
2401 # leave if quadrant supernovas
2402 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2404 game.resting = False
2409 course = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2410 newc = coord(); neighbor = coord(); bump = coord(0, 0)
2412 # Wow! We've supernova'ed
2413 supernova(game.quadrant)
2415 # handle initial nova
2416 game.quad[nov.i][nov.j] = '.'
2417 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2418 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2419 game.state.starkl += 1
2420 # Set up queue to recursively trigger adjacent stars
2426 for offset.i in range(-1, 1+1):
2427 for offset.j in range(-1, 1+1):
2428 if offset.j==0 and offset.i==0:
2430 neighbor = start + offset
2431 if not neighbor.valid_sector():
2433 iquad = game.quad[neighbor.i][neighbor.j]
2434 # Empty space ends reaction
2435 if iquad in ('.', '?', ' ', 'T', '#'):
2437 elif iquad == '*': # Affect another star
2439 # This star supernovas
2440 supernova(game.quadrant)
2443 hits.append(neighbor)
2444 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2445 game.state.starkl += 1
2446 proutn(crmena(True, '*', "sector", neighbor))
2448 game.quad[neighbor.i][neighbor.j] = '.'
2450 elif iquad in ('P', '@'): # Destroy planet
2451 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2453 game.state.nplankl += 1
2455 game.state.worldkl += 1
2456 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2457 game.iplnet.pclass = "destroyed"
2459 game.plnet.invalidate()
2463 game.quad[neighbor.i][neighbor.j] = '.'
2464 elif iquad == 'B': # Destroy base
2465 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2466 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2467 game.base.invalidate()
2468 game.state.basekl += 1
2470 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2471 game.quad[neighbor.i][neighbor.j] = '.'
2472 elif iquad in ('E', 'F'): # Buffet ship
2473 prout(_("***Starship buffeted by nova."))
2475 if game.shield >= 2000.0:
2476 game.shield -= 2000.0
2478 diff = 2000.0 - game.shield
2482 prout(_("***Shields knocked out."))
2483 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2485 game.energy -= 2000.0
2486 if game.energy <= 0:
2489 # add in course nova contributes to kicking starship
2490 bump += (game.sector-hits[mm]).sgn()
2491 elif iquad == 'K': # kill klingon
2492 deadkl(neighbor, iquad, neighbor)
2493 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2494 for ll in range(len(game.enemies)):
2495 if game.enemies[ll].location == neighbor:
2497 game.enemies[ll].power -= 800.0 # If firepower is lost, die
2498 if game.enemies[ll].power <= 0.0:
2499 deadkl(neighbor, iquad, neighbor)
2501 newc = neighbor + neighbor - hits[mm]
2502 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2503 if not newc.valid_sector():
2504 # can't leave quadrant
2507 iquad1 = game.quad[newc.i][newc.j]
2509 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2511 deadkl(neighbor, iquad, newc)
2514 # can't move into something else
2517 proutn(_(", buffeted to Sector %s") % newc)
2518 game.quad[neighbor.i][neighbor.j] = '.'
2519 game.quad[newc.i][newc.j] = iquad
2520 game.enemies[ll].move(newc)
2521 # Starship affected by nova -- kick it away.
2523 direc = course[3*(bump.i+1)+bump.j+2]
2528 course = course(bearing=direc, distance=dist)
2529 game.optime = course.time(warp=4)
2531 prout(_("Force of nova displaces starship."))
2532 imove(course, noattack=True)
2533 game.optime = course.time(warp=4)
2537 "Star goes supernova."
2542 # Scheduled supernova -- select star at random.
2545 for nq.i in range(GALSIZE):
2546 for nq.j in range(GALSIZE):
2547 stars += game.state.galaxy[nq.i][nq.j].stars
2549 return # nothing to supernova exists
2550 num = randrange(stars) + 1
2551 for nq.i in range(GALSIZE):
2552 for nq.j in range(GALSIZE):
2553 num -= game.state.galaxy[nq.i][nq.j].stars
2559 proutn("=== Super nova here?")
2562 if not nq == game.quadrant or game.justin:
2563 # it isn't here, or we just entered (treat as enroute)
2566 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2567 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2570 # we are in the quadrant!
2571 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2572 for ns.i in range(QUADSIZE):
2573 for ns.j in range(QUADSIZE):
2574 if game.quad[ns.i][ns.j]=='*':
2581 prouts(_("***RED ALERT! RED ALERT!"))
2583 prout(_("***Incipient supernova detected at Sector %s") % ns)
2584 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2585 proutn(_("Emergency override attempts t"))
2586 prouts("***************")
2590 # destroy any Klingons in supernovaed quadrant
2591 kldead = game.state.galaxy[nq.i][nq.j].klingons
2592 game.state.galaxy[nq.i][nq.j].klingons = 0
2593 if nq == game.state.kscmdr:
2594 # did in the Supercommander!
2595 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2599 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2600 comkills = len(game.state.kcmdr) - len(survivors)
2601 game.state.kcmdr = survivors
2603 if not game.state.kcmdr:
2605 game.state.remkl -= kldead
2606 # destroy Romulans and planets in supernovaed quadrant
2607 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2608 game.state.galaxy[nq.i][nq.j].romulans = 0
2609 game.state.nromrem -= nrmdead
2611 for loop in range(game.inplan):
2612 if game.state.planets[loop].quadrant == nq:
2613 game.state.planets[loop].pclass = "destroyed"
2615 # Destroy any base in supernovaed quadrant
2616 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2617 # If starship caused supernova, tally up destruction
2619 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2620 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2621 game.state.nplankl += npdead
2622 # mark supernova in galaxy and in star chart
2623 if game.quadrant == nq or communicating():
2624 game.state.galaxy[nq.i][nq.j].supernova = True
2625 # If supernova destroys last Klingons give special message
2626 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2629 prout(_("Lucky you!"))
2630 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2633 # if some Klingons remain, continue or die in supernova
2638 # Code from finish.c ends here.
2641 "Self-destruct maneuver. Finish with a BANG!"
2643 if damaged(DCOMPTR):
2644 prout(_("Computer damaged; cannot execute destruct sequence."))
2646 prouts(_("---WORKING---")); skip(1)
2647 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2648 prouts(" 10"); skip(1)
2649 prouts(" 9"); skip(1)
2650 prouts(" 8"); skip(1)
2651 prouts(" 7"); skip(1)
2652 prouts(" 6"); skip(1)
2654 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2656 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2658 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2662 if game.passwd != scanner.token:
2663 prouts(_("PASSWORD-REJECTED;"))
2665 prouts(_("CONTINUITY-EFFECTED"))
2668 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2669 prouts(" 5"); skip(1)
2670 prouts(" 4"); skip(1)
2671 prouts(" 3"); skip(1)
2672 prouts(" 2"); skip(1)
2673 prouts(" 1"); skip(1)
2675 prouts(_("GOODBYE-CRUEL-WORLD"))
2683 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2687 if len(game.enemies) != 0:
2688 whammo = 25.0 * game.energy
2690 while l <= len(game.enemies):
2691 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2692 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2697 "Compute our rate of kils over time."
2698 elapsed = game.state.date - game.indate
2699 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2702 starting = (game.inkling + game.incom + game.inscom)
2703 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2704 return (starting - remaining)/elapsed
2708 badpt = 5.0*game.state.starkl + \
2710 10.0*game.state.nplankl + \
2711 300*game.state.nworldkl + \
2713 100.0*game.state.basekl +\
2715 if game.ship == 'F':
2717 elif game.ship == None:
2722 # end the game, with appropriate notfications
2726 prout(_("It is stardate %.1f.") % game.state.date)
2728 if ifin == FWON: # Game has been won
2729 if game.state.nromrem != 0:
2730 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2733 prout(_("You have smashed the Klingon invasion fleet and saved"))
2734 prout(_("the Federation."))
2739 badpt = 0.0 # Close enough!
2740 # killsPerDate >= RateMax
2741 if game.state.date-game.indate < 5.0 or \
2742 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2744 prout(_("In fact, you have done so well that Starfleet Command"))
2745 if game.skill == SKILL_NOVICE:
2746 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2747 elif game.skill == SKILL_FAIR:
2748 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2749 elif game.skill == SKILL_GOOD:
2750 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2751 elif game.skill == SKILL_EXPERT:
2752 prout(_("promotes you to Commodore Emeritus."))
2754 prout(_("Now that you think you're really good, try playing"))
2755 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2756 elif game.skill == SKILL_EMERITUS:
2758 proutn(_("Computer- "))
2759 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2761 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2763 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2765 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2767 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2769 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2771 prout(_("Now you can retire and write your own Star Trek game!"))
2773 elif game.skill >= SKILL_EXPERT:
2774 if game.thawed and not idebug:
2775 prout(_("You cannot get a citation, so..."))
2777 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2781 # Only grant long life if alive (original didn't!)
2783 prout(_("LIVE LONG AND PROSPER."))
2788 elif ifin == FDEPLETE: # Federation Resources Depleted
2789 prout(_("Your time has run out and the Federation has been"))
2790 prout(_("conquered. Your starship is now Klingon property,"))
2791 prout(_("and you are put on trial as a war criminal. On the"))
2792 proutn(_("basis of your record, you are "))
2793 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2794 prout(_("acquitted."))
2796 prout(_("LIVE LONG AND PROSPER."))
2798 prout(_("found guilty and"))
2799 prout(_("sentenced to death by slow torture."))
2803 elif ifin == FLIFESUP:
2804 prout(_("Your life support reserves have run out, and"))
2805 prout(_("you die of thirst, starvation, and asphyxiation."))
2806 prout(_("Your starship is a derelict in space."))
2808 prout(_("Your energy supply is exhausted."))
2810 prout(_("Your starship is a derelict in space."))
2811 elif ifin == FBATTLE:
2812 prout(_("The %s has been destroyed in battle.") % crmshp())
2814 prout(_("Dulce et decorum est pro patria mori."))
2816 prout(_("You have made three attempts to cross the negative energy"))
2817 prout(_("barrier which surrounds the galaxy."))
2819 prout(_("Your navigation is abominable."))
2822 prout(_("Your starship has been destroyed by a nova."))
2823 prout(_("That was a great shot."))
2825 elif ifin == FSNOVAED:
2826 prout(_("The %s has been fried by a supernova.") % crmshp())
2827 prout(_("...Not even cinders remain..."))
2828 elif ifin == FABANDN:
2829 prout(_("You have been captured by the Klingons. If you still"))
2830 prout(_("had a starbase to be returned to, you would have been"))
2831 prout(_("repatriated and given another chance. Since you have"))
2832 prout(_("no starbases, you will be mercilessly tortured to death."))
2833 elif ifin == FDILITHIUM:
2834 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2835 elif ifin == FMATERIALIZE:
2836 prout(_("Starbase was unable to re-materialize your starship."))
2837 prout(_("Sic transit gloria mundi"))
2838 elif ifin == FPHASER:
2839 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2841 prout(_("You and your landing party have been"))
2842 prout(_("converted to energy, disipating through space."))
2843 elif ifin == FMINING:
2844 prout(_("You are left with your landing party on"))
2845 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2847 prout(_("They are very fond of \"Captain Kirk\" soup."))
2849 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2850 elif ifin == FDPLANET:
2851 prout(_("You and your mining party perish."))
2853 prout(_("That was a great shot."))
2856 prout(_("The Galileo is instantly annihilated by the supernova."))
2857 prout(_("You and your mining party are atomized."))
2859 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2860 prout(_("joins the Romulans, wreaking terror on the Federation."))
2861 elif ifin == FPNOVA:
2862 prout(_("You and your mining party are atomized."))
2864 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2865 prout(_("joins the Romulans, wreaking terror on the Federation."))
2866 elif ifin == FSTRACTOR:
2867 prout(_("The shuttle craft Galileo is also caught,"))
2868 prout(_("and breaks up under the strain."))
2870 prout(_("Your debris is scattered for millions of miles."))
2871 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2873 prout(_("The mutants attack and kill Spock."))
2874 prout(_("Your ship is captured by Klingons, and"))
2875 prout(_("your crew is put on display in a Klingon zoo."))
2876 elif ifin == FTRIBBLE:
2877 prout(_("Tribbles consume all remaining water,"))
2878 prout(_("food, and oxygen on your ship."))
2880 prout(_("You die of thirst, starvation, and asphyxiation."))
2881 prout(_("Your starship is a derelict in space."))
2883 prout(_("Your ship is drawn to the center of the black hole."))
2884 prout(_("You are crushed into extremely dense matter."))
2886 prout(_("Your last crew member has died."))
2887 if game.ship == 'F':
2889 elif game.ship == 'E':
2892 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2893 goodies = game.state.remres/game.inresor
2894 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2895 if goodies/baddies >= randreal(1.0, 1.5):
2896 prout(_("As a result of your actions, a treaty with the Klingon"))
2897 prout(_("Empire has been signed. The terms of the treaty are"))
2898 if goodies/baddies >= randreal(3.0):
2899 prout(_("favorable to the Federation."))
2901 prout(_("Congratulations!"))
2903 prout(_("highly unfavorable to the Federation."))
2905 prout(_("The Federation will be destroyed."))
2907 prout(_("Since you took the last Klingon with you, you are a"))
2908 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2909 prout(_("statue in your memory. Rest in peace, and try not"))
2910 prout(_("to think about pigeons."))
2915 "Compute player's score."
2916 timused = game.state.date - game.indate
2918 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2920 perdate = killrate()
2921 ithperd = 500*perdate + 0.5
2924 iwon = 100*game.skill
2925 if game.ship == 'E':
2927 elif game.ship == 'F':
2931 if not game.gamewon:
2932 game.state.nromrem = 0 # None captured if no win
2933 iscore = 10*(game.inkling - game.state.remkl) \
2934 + 50*(game.incom - len(game.state.kcmdr)) \
2936 + 20*(game.inrom - game.state.nromrem) \
2937 + 200*(game.inscom - game.state.nscrem) \
2938 - game.state.nromrem \
2943 prout(_("Your score --"))
2944 if game.inrom - game.state.nromrem:
2945 prout(_("%6d Romulans destroyed %5d") %
2946 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
2947 if game.state.nromrem:
2948 prout(_("%6d Romulans captured %5d") %
2949 (game.state.nromrem, game.state.nromrem))
2950 if game.inkling - game.state.remkl:
2951 prout(_("%6d ordinary Klingons destroyed %5d") %
2952 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
2953 if game.incom - len(game.state.kcmdr):
2954 prout(_("%6d Klingon commanders destroyed %5d") %
2955 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
2956 if game.inscom - game.state.nscrem:
2957 prout(_("%6d Super-Commander destroyed %5d") %
2958 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
2960 prout(_("%6.2f Klingons per stardate %5d") %
2962 if game.state.starkl:
2963 prout(_("%6d stars destroyed by your action %5d") %
2964 (game.state.starkl, -5*game.state.starkl))
2965 if game.state.nplankl:
2966 prout(_("%6d planets destroyed by your action %5d") %
2967 (game.state.nplankl, -10*game.state.nplankl))
2968 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
2969 prout(_("%6d inhabited planets destroyed by your action %5d") %
2970 (game.state.nplankl, -300*game.state.nworldkl))
2971 if game.state.basekl:
2972 prout(_("%6d bases destroyed by your action %5d") %
2973 (game.state.basekl, -100*game.state.basekl))
2975 prout(_("%6d calls for help from starbase %5d") %
2976 (game.nhelp, -45*game.nhelp))
2978 prout(_("%6d casualties incurred %5d") %
2979 (game.casual, -game.casual))
2981 prout(_("%6d crew abandoned in space %5d") %
2982 (game.abandoned, -3*game.abandoned))
2984 prout(_("%6d ship(s) lost or destroyed %5d") %
2985 (klship, -100*klship))
2987 prout(_("Penalty for getting yourself killed -200"))
2989 proutn(_("Bonus for winning "))
2990 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
2991 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
2992 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
2993 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
2994 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
2995 prout(" %5d" % iwon)
2997 prout(_("TOTAL SCORE %5d") % iscore)
3000 "Emit winner's commemmorative plaque."
3003 proutn(_("File or device name for your plaque: "))
3006 fp = open(winner, "w")
3009 prout(_("Invalid name."))
3011 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3013 # The 38 below must be 64 for 132-column paper
3014 nskip = 38 - len(winner)/2
3015 fp.write("\n\n\n\n")
3016 # --------DRAW ENTERPRISE PICTURE.
3017 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3018 fp.write(" EEE E : : : E\n" )
3019 fp.write(" EE EEE E : : NCC-1701 : E\n")
3020 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3021 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3022 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3023 fp.write(" EEEEEEE EEEEE E E E E\n")
3024 fp.write(" EEE E E E E\n")
3025 fp.write(" E E E E\n")
3026 fp.write(" EEEEEEEEEEEEE E E\n")
3027 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3028 fp.write(" :E : EEEE E\n")
3029 fp.write(" .-E -:----- E\n")
3030 fp.write(" :E : E\n")
3031 fp.write(" EE : EEEEEEEE\n")
3032 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3034 fp.write(_(" U. S. S. ENTERPRISE\n"))
3035 fp.write("\n\n\n\n")
3036 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3038 fp.write(_(" Starfleet Command bestows to you\n"))
3040 fp.write("%*s%s\n\n" % (nskip, "", winner))
3041 fp.write(_(" the rank of\n\n"))
3042 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3044 if game.skill == SKILL_EXPERT:
3045 fp.write(_(" Expert level\n\n"))
3046 elif game.skill == SKILL_EMERITUS:
3047 fp.write(_("Emeritus level\n\n"))
3049 fp.write(_(" Cheat level\n\n"))
3050 timestring = time.ctime()
3051 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3052 (timestring+4, timestring+20, timestring+11))
3053 fp.write(_(" Your score: %d\n\n") % iscore)
3054 fp.write(_(" Klingons per stardate: %.2f\n") % perdate)
3057 # Code from io.c begins here
3059 rows = linecount = 0 # for paging
3062 fullscreen_window = None
3063 srscan_window = None
3064 report_window = None
3065 status_window = None
3066 lrscan_window = None
3067 message_window = None
3068 prompt_window = None
3073 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3074 gettext.textdomain("sst")
3075 if not (game.options & OPTION_CURSES):
3076 ln_env = os.getenv("LINES")
3082 stdscr = curses.initscr()
3086 global fullscreen_window, srscan_window, report_window, status_window
3087 global lrscan_window, message_window, prompt_window
3088 (rows, columns) = stdscr.getmaxyx()
3089 fullscreen_window = stdscr
3090 srscan_window = curses.newwin(12, 25, 0, 0)
3091 report_window = curses.newwin(11, 0, 1, 25)
3092 status_window = curses.newwin(10, 0, 1, 39)
3093 lrscan_window = curses.newwin(5, 0, 0, 64)
3094 message_window = curses.newwin(0, 0, 12, 0)
3095 prompt_window = curses.newwin(1, 0, rows-2, 0)
3096 message_window.scrollok(True)
3097 setwnd(fullscreen_window)
3101 if game.options & OPTION_CURSES:
3102 stdscr.keypad(False)
3108 "Wait for user action -- OK to do nothing if on a TTY"
3109 if game.options & OPTION_CURSES:
3114 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3118 if game.skill > SKILL_FAIR:
3119 prompt = _("[CONTINUE?]")
3121 prompt = _("[PRESS ENTER TO CONTINUE]")
3123 if game.options & OPTION_CURSES:
3125 setwnd(prompt_window)
3126 prompt_window.clear()
3127 prompt_window.addstr(prompt)
3128 prompt_window.getstr()
3129 prompt_window.clear()
3130 prompt_window.refresh()
3131 setwnd(message_window)
3134 sys.stdout.write('\n')
3137 for j in range(rows):
3138 sys.stdout.write('\n')
3142 "Skip i lines. Pause game if this would cause a scrolling event."
3143 for dummy in range(i):
3144 if game.options & OPTION_CURSES:
3145 (y, x) = curwnd.getyx()
3146 (my, mx) = curwnd.getmaxyx()
3147 if curwnd == message_window and y >= my - 3:
3153 except curses.error:
3158 if rows and linecount >= rows:
3161 sys.stdout.write('\n')
3164 "Utter a line with no following line feed."
3165 if game.options & OPTION_CURSES:
3169 sys.stdout.write(line)
3179 if not replayfp or replayfp.closed: # Don't slow down replays
3182 if game.options & OPTION_CURSES:
3186 if not replayfp or replayfp.closed:
3190 "Get a line of input."
3191 if game.options & OPTION_CURSES:
3192 line = curwnd.getstr() + "\n"
3195 if replayfp and not replayfp.closed:
3197 line = replayfp.readline()
3200 prout("*** Replay finished")
3203 elif line[0] != "#":
3206 line = raw_input() + "\n"
3212 "Change windows -- OK for this to be a no-op in tty mode."
3214 if game.options & OPTION_CURSES:
3216 curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window)
3219 "Clear to end of line -- can be a no-op in tty mode"
3220 if game.options & OPTION_CURSES:
3225 "Clear screen -- can be a no-op in tty mode."
3227 if game.options & OPTION_CURSES:
3234 # Things past this point have policy implications.
3238 "Hook to be called after moving to redraw maps."
3239 if game.options & OPTION_CURSES:
3242 setwnd(srscan_window)
3246 setwnd(status_window)
3247 status_window.clear()
3248 status_window.move(0, 0)
3249 setwnd(report_window)
3250 report_window.clear()
3251 report_window.move(0, 0)
3253 setwnd(lrscan_window)
3254 lrscan_window.clear()
3255 lrscan_window.move(0, 0)
3256 lrscan(silent=False)
3258 def put_srscan_sym(w, sym):
3259 "Emit symbol for short-range scan."
3260 srscan_window.move(w.i+1, w.j*2+2)
3261 srscan_window.addch(sym)
3262 srscan_window.refresh()
3265 "Enemy fall down, go boom."
3266 if game.options & OPTION_CURSES:
3268 setwnd(srscan_window)
3269 srscan_window.attron(curses.A_REVERSE)
3270 put_srscan_sym(w, game.quad[w.i][w.j])
3274 srscan_window.attroff(curses.A_REVERSE)
3275 put_srscan_sym(w, game.quad[w.i][w.j])
3276 curses.delay_output(500)
3277 setwnd(message_window)
3280 "Sound and visual effects for teleportation."
3281 if game.options & OPTION_CURSES:
3283 setwnd(message_window)
3285 prouts(" . . . . . ")
3286 if game.options & OPTION_CURSES:
3287 #curses.delay_output(1000)
3291 def tracktorpedo(origin, w, step, i, n, iquad):
3292 "Torpedo-track animation."
3293 if not game.options & OPTION_CURSES:
3297 proutn(_("Track for torpedo number %d- ") % (i+1))
3300 proutn(_("Torpedo track- "))
3301 elif step==4 or step==9:
3305 if not damaged(DSRSENS) or game.condition=="docked":
3306 if i != 0 and step == 1:
3309 if (iquad=='.') or (iquad==' '):
3310 put_srscan_sym(w, '+')
3314 put_srscan_sym(w, iquad)
3316 curwnd.attron(curses.A_REVERSE)
3317 put_srscan_sym(w, iquad)
3321 curwnd.attroff(curses.A_REVERSE)
3322 put_srscan_sym(w, iquad)
3327 "Display the current galaxy chart."
3328 if game.options & OPTION_CURSES:
3329 setwnd(message_window)
3330 message_window.clear()
3332 if game.options & OPTION_TTY:
3337 def prstat(txt, data):
3339 if game.options & OPTION_CURSES:
3341 setwnd(status_window)
3343 proutn(" " * (NSYM - len(txt)))
3346 if game.options & OPTION_CURSES:
3347 setwnd(report_window)
3349 # Code from moving.c begins here
3351 def imove(course=None, noattack=False):
3352 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3355 def newquadrant(noattack):
3356 # Leaving quadrant -- allow final enemy attack
3357 # Don't do it if being pushed by Nova
3358 if len(game.enemies) != 0 and not noattack:
3360 for enemy in game.enemies:
3361 finald = (w - enemy.location).distance()
3362 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3363 # Stas Sergeev added the condition
3364 # that attacks only happen if Klingons
3365 # are present and your skill is good.
3366 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3367 attack(torps_ok=False)
3370 # check for edge of galaxy
3374 if course.final.i < 0:
3375 course.final.i = -course.final.i
3377 if course.final.j < 0:
3378 course.final.j = -course.final.j
3380 if course.final.i >= GALSIZE*QUADSIZE:
3381 course.final.i = (GALSIZE*QUADSIZE*2) - course.final.i
3383 if course.final.j >= GALSIZE*QUADSIZE:
3384 course.final.j = (GALSIZE*QUADSIZE*2) - course.final.j
3392 if game.nkinks == 3:
3393 # Three strikes -- you're out!
3397 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3398 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3399 prout(_("YOU WILL BE DESTROYED."))
3400 # Compute final position in new quadrant
3401 if trbeam: # Don't bother if we are to be beamed
3403 game.quadrant = course.final.quadrant()
3404 game.sector = course.final.sector()
3406 prout(_("Entering Quadrant %s.") % game.quadrant)
3407 game.quad[game.sector.i][game.sector.j] = game.ship
3409 if game.skill>SKILL_NOVICE:
3410 attack(torps_ok=False)
3412 def check_collision(h):
3413 iquad = game.quad[h.i][h.j]
3415 # object encountered in flight path
3416 stopegy = 50.0*course.distance/game.optime
3417 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3418 for enemy in game.enemies:
3419 if enemy.location == game.sector:
3421 collision(rammed=False, enemy=enemy)
3425 prouts(_("***RED ALERT! RED ALERT!"))
3427 proutn("***" + crmshp())
3428 proutn(_(" pulled into black hole at Sector %s") % h)
3429 # Getting pulled into a black hole was certain
3430 # death in Almy's original. Stas Sergeev added a
3431 # possibility that you'll get timewarped instead.
3433 for m in range(NDEVICES):
3434 if game.damage[m]>0:
3436 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3437 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3447 prout(_(" encounters Tholian web at %s;") % h)
3449 prout(_(" blocked by object at %s;") % h)
3450 proutn(_("Emergency stop required "))
3451 prout(_("%2d units of energy.") % int(stopegy))
3452 game.energy -= stopegy
3453 if game.energy <= 0:
3460 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3461 game.inorbit = False
3462 # If tractor beam is to occur, don't move full distance
3463 if game.state.date+game.optime >= scheduled(FTBEAM):
3465 game.condition = "red"
3466 course.distance = course.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3467 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3469 game.quad[game.sector.i][game.sector.j] = '.'
3470 for m in range(course.moves):
3473 if course.origin.quadrant() != course.location.quadrant():
3474 newquadrant(noattack)
3476 elif check_collision(w):
3477 print "Collision detected"
3481 # We're in destination quadrant -- compute new average enemy distances
3482 game.quad[game.sector.i][game.sector.j] = game.ship
3484 for enemy in game.enemies:
3485 finald = (w-enemy.location).distance()
3486 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3487 enemy.kdist = finald
3488 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
3489 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3490 attack(torps_ok=False)
3491 for enemy in game.enemies:
3492 enemy.kavgd = enemy.kdist
3495 setwnd(message_window)
3499 "Dock our ship at a starbase."
3501 if game.condition == "docked" and verbose:
3502 prout(_("Already docked."))
3505 prout(_("You must first leave standard orbit."))
3507 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3508 prout(crmshp() + _(" not adjacent to base."))
3510 game.condition = "docked"
3514 if game.energy < game.inenrg:
3515 game.energy = game.inenrg
3516 game.shield = game.inshld
3517 game.torps = game.intorps
3518 game.lsupres = game.inlsr
3519 game.state.crew = FULLCREW
3520 if not damaged(DRADIO) and \
3521 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3522 # get attack report from base
3523 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3527 def cartesian(loc1=None, loc2=None):
3529 return game.quadrant * QUADSIZE + game.sector
3531 return game.quadrant * QUADSIZE + loc1
3533 return loc1 * QUADSIZE + loc2
3535 def getcourse(isprobe):
3536 "Get a course and distance from the user."
3538 dquad = copy.copy(game.quadrant)
3539 navmode = "unspecified"
3543 if game.landed and not isprobe:
3544 prout(_("Dummy! You can't leave standard orbit until you"))
3545 proutn(_("are back aboard the ship."))
3548 while navmode == "unspecified":
3549 if damaged(DNAVSYS):
3551 prout(_("Computer damaged; manual navigation only"))
3553 prout(_("Computer damaged; manual movement only"))
3558 key = scanner.next()
3560 proutn(_("Manual or automatic- "))
3563 elif key == "IHALPHA":
3564 if scanner.sees("manual"):
3566 key = scanner.next()
3568 elif scanner.sees("automatic"):
3569 navmode = "automatic"
3570 key = scanner.next()
3578 prout(_("(Manual navigation assumed.)"))
3580 prout(_("(Manual movement assumed.)"))
3584 if navmode == "automatic":
3585 while key == "IHEOL":
3587 proutn(_("Target quadrant or quadrant§or- "))
3589 proutn(_("Destination sector or quadrant§or- "))
3592 key = scanner.next()
3596 xi = int(round(scanner.real))-1
3597 key = scanner.next()
3601 xj = int(round(scanner.real))-1
3602 key = scanner.next()
3604 # both quadrant and sector specified
3605 xk = int(round(scanner.real))-1
3606 key = scanner.next()
3610 xl = int(round(scanner.real))-1
3616 # only one pair of numbers was specified
3618 # only quadrant specified -- go to center of dest quad
3621 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3623 # only sector specified
3627 if not dquad.valid_quadrant() or not dsect.valid_sector():
3634 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3636 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3637 # the actual deltas get computed here
3638 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3639 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3641 while key == "IHEOL":
3642 proutn(_("X and Y displacements- "))
3645 key = scanner.next()
3650 delta.j = scanner.real
3651 key = scanner.next()
3655 delta.i = scanner.real
3656 # Check for zero movement
3657 if delta.i == 0 and delta.j == 0:
3660 if itemp == "verbose" and not isprobe:
3662 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3664 return course(bearing=delta.bearing(), distance=delta.distance())
3667 def __init__(self, bearing, distance, origin=None):
3668 self.distance = distance
3669 self.bearing = bearing
3671 self.origin = cartesian(game.quadrant, game.sector)
3673 self.origin = origin
3674 # The bearing() code we inherited from FORTRAN is actually computing
3675 # clockface directions!
3676 if self.bearing < 0.0:
3677 self.bearing += 12.0
3678 self.angle = ((15.0 - self.bearing) * 0.5235988)
3680 self.origin = cartesian(game.quadrant, game.sector)
3682 self.origin = cartesian(game.quadrant, origin)
3683 self.increment = coord(-math.sin(self.angle), math.cos(self.angle))
3684 bigger = max(abs(self.increment.i), abs(self.increment.j))
3685 self.increment /= bigger
3686 self.moves = int(round(10*self.distance*bigger))
3688 self.final = (self.location + self.moves*self.increment).roundtogrid()
3690 self.location = self.origin
3693 return self.location.roundtogrid() == self.final
3695 "Next step on course."
3697 self.nextlocation = self.location + self.increment
3698 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3699 self.location = self.nextlocation
3702 return self.location.quadrant()
3704 return self.location.sector()
3705 def power(self, warp):
3706 return self.distance*(warp**3)*(game.shldup+1)
3707 def time(self, warp):
3708 return 10.0*self.distance/warp**2
3711 "Move under impulse power."
3713 if damaged(DIMPULS):
3716 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3718 if game.energy > 30.0:
3720 course = getcourse(isprobe=False)
3723 power = 20.0 + 100.0*course.distance
3726 if power >= game.energy:
3727 # Insufficient power for trip
3729 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3730 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3731 if game.energy > 30:
3732 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3733 int(0.01 * (game.energy-20.0)-0.05))
3734 prout(_(" quadrants.\""))
3736 prout(_("quadrant. They are, therefore, useless.\""))
3739 # Make sure enough time is left for the trip
3740 game.optime = course.dist/0.095
3741 if game.optime >= game.state.remtime:
3742 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3743 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3744 proutn(_("we dare spend the time?\" "))
3747 # Activate impulse engines and pay the cost
3748 imove(course, noattack=False)
3752 power = 20.0 + 100.0*course.dist
3753 game.energy -= power
3754 game.optime = course.dist/0.095
3755 if game.energy <= 0:
3759 def warp(course, involuntary):
3760 "ove under warp drive."
3761 blooey = False; twarp = False
3762 if not involuntary: # Not WARPX entry
3764 if game.damage[DWARPEN] > 10.0:
3767 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3769 if damaged(DWARPEN) and game.warpfac > 4.0:
3772 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3773 prout(_(" is repaired, I can only give you warp 4.\""))
3775 # Read in course and distance
3778 course = getcourse(isprobe=False)
3781 # Make sure starship has enough energy for the trip
3782 # Note: this formula is slightly different from the C version,
3783 # and lets you skate a bit closer to the edge.
3784 if course.power(game.warpfac) >= game.energy:
3785 # Insufficient power for trip
3788 prout(_("Engineering to bridge--"))
3789 if not game.shldup or 0.5*power > game.energy:
3790 iwarp = (game.energy/(course.dist+0.05)) ** 0.333333333
3792 prout(_("We can't do it, Captain. We don't have enough energy."))
3794 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3797 prout(_("if you'll lower the shields."))
3801 prout(_("We haven't the energy to go that far with the shields up."))
3803 # Make sure enough time is left for the trip
3804 game.optime = course.time(game.warpfac)
3805 if game.optime >= 0.8*game.state.remtime:
3807 prout(_("First Officer Spock- \"Captain, I compute that such"))
3808 proutn(_(" a trip would require approximately %2.0f") %
3809 (100.0*game.optime/game.state.remtime))
3810 prout(_(" percent of our"))
3811 proutn(_(" remaining time. Are you sure this is wise?\" "))
3817 if game.warpfac > 6.0:
3818 # Decide if engine damage will occur
3819 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3820 prob = course.distance*(6.0-game.warpfac)**2/66.666666666
3821 if prob > randreal():
3823 course.distance = randreal(course.distance)
3824 # Decide if time warp will occur
3825 if 0.5*course.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3827 if idebug and game.warpfac==10 and not twarp:
3829 proutn("=== Force time warp? ")
3833 # If time warp or engine damage, check path
3834 # If it is obstructed, don't do warp or damage
3835 for m in range(course.moves):
3838 if not w.valid_sector():
3840 if game.quad[w.i][w.j] != '.':
3844 # Activate Warp Engines and pay the cost
3845 imove(course, noattack=False)
3848 game.energy -= course.power(game.warpfac)
3849 if game.energy <= 0:
3851 game.optime = course.time(game.warpfac)
3855 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
3857 prout(_("Engineering to bridge--"))
3858 prout(_(" Scott here. The warp engines are damaged."))
3859 prout(_(" We'll have to reduce speed to warp 4."))
3864 "Change the warp factor."
3870 proutn(_("Warp factor- "))
3875 if game.damage[DWARPEN] > 10.0:
3876 prout(_("Warp engines inoperative."))
3878 if damaged(DWARPEN) and scanner.real > 4.0:
3879 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
3880 prout(_(" but right now we can only go warp 4.\""))
3882 if scanner.real > 10.0:
3883 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
3885 if scanner.real < 1.0:
3886 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
3888 oldfac = game.warpfac
3889 game.warpfac = scanner.real
3890 if game.warpfac <= oldfac or game.warpfac <= 6.0:
3891 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
3894 if game.warpfac < 8.00:
3895 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
3897 if game.warpfac == 10.0:
3898 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
3900 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
3904 "Cope with being tossed out of quadrant by supernova or yanked by beam."
3906 # is captain on planet?
3908 if damaged(DTRANSP):
3911 prout(_("Scotty rushes to the transporter controls."))
3913 prout(_("But with the shields up it's hopeless."))
3915 prouts(_("His desperate attempt to rescue you . . ."))
3920 prout(_("SUCCEEDS!"))
3923 proutn(_("The crystals mined were "))
3931 # Check to see if captain in shuttle craft
3936 # Inform captain of attempt to reach safety
3940 prouts(_("***RED ALERT! RED ALERT!"))
3942 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
3943 prouts(_(" a supernova."))
3945 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
3946 prout(_("safely out of quadrant."))
3947 if not damaged(DRADIO):
3948 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
3949 # Try to use warp engines
3950 if damaged(DWARPEN):
3952 prout(_("Warp engines damaged."))
3955 game.warpfac = randreal(6.0, 8.0)
3956 prout(_("Warp factor set to %d") % int(game.warpfac))
3957 power = 0.75*game.energy
3958 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
3959 dist = max(dist, randreal(math.sqrt(2)))
3960 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
3961 game.optime = bugout.time(game.warpfac)
3963 game.inorbit = False
3964 warp(bugout, involuntary=True)
3966 # This is bad news, we didn't leave quadrant.
3970 prout(_("Insufficient energy to leave quadrant."))
3973 # Repeat if another snova
3974 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3976 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
3977 finish(FWON) # Snova killed remaining enemy.
3980 "Let's do the time warp again."
3981 prout(_("***TIME WARP ENTERED."))
3982 if game.state.snap and withprob(0.5):
3984 prout(_("You are traveling backwards in time %d stardates.") %
3985 int(game.state.date-game.snapsht.date))
3986 game.state = game.snapsht
3987 game.state.snap = False
3988 if len(game.state.kcmdr):
3989 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
3990 schedule(FBATTAK, expran(0.3*game.intime))
3991 schedule(FSNOVA, expran(0.5*game.intime))
3992 # next snapshot will be sooner
3993 schedule(FSNAP, expran(0.25*game.state.remtime))
3995 if game.state.nscrem:
3996 schedule(FSCMOVE, 0.2777)
4000 game.battle.invalidate()
4001 # Make sure Galileo is consistant -- Snapshot may have been taken
4002 # when on planet, which would give us two Galileos!
4004 for l in range(game.inplan):
4005 if game.state.planets[l].known == "shuttle_down":
4007 if game.iscraft == "onship" and game.ship=='E':
4008 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4009 game.iscraft = "offship"
4010 # Likewise, if in the original time the Galileo was abandoned, but
4011 # was on ship earlier, it would have vanished -- let's restore it.
4012 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4013 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4014 game.iscraft = "onship"
4015 # There used to be code to do the actual reconstrction here,
4016 # but the starchart is now part of the snapshotted galaxy state.
4017 prout(_("Spock has reconstructed a correct star chart from memory"))
4019 # Go forward in time
4020 game.optime = -0.5*game.intime*math.log(randreal())
4021 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4022 # cheat to make sure no tractor beams occur during time warp
4023 postpone(FTBEAM, game.optime)
4024 game.damage[DRADIO] += game.optime
4026 events() # Stas Sergeev added this -- do pending events
4029 "Launch deep-space probe."
4030 # New code to launch a deep space probe
4031 if game.nprobes == 0:
4034 if game.ship == 'E':
4035 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4037 prout(_("Ye Faerie Queene has no deep space probes."))
4042 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4044 if is_scheduled(FDSPROB):
4047 if damaged(DRADIO) and game.condition != "docked":
4048 prout(_("Spock- \"Records show the previous probe has not yet"))
4049 prout(_(" reached its destination.\""))
4051 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4053 key = scanner.next()
4055 if game.nprobes == 1:
4056 prout(_("1 probe left."))
4058 prout(_("%d probes left") % game.nprobes)
4059 proutn(_("Are you sure you want to fire a probe? "))
4062 game.isarmed = False
4063 if key == "IHALPHA" and scanner.token == "armed":
4065 key = scanner.next()
4066 elif key == "IHEOL":
4067 proutn(_("Arm NOVAMAX warhead? "))
4069 elif key == "IHREAL": # first element of course
4070 scanner.push(scanner.token)
4072 game.probe = getcourse(isprobe=True)
4076 schedule(FDSPROB, 0.01) # Time to move one sector
4077 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4082 "Yell for help from nearest starbase."
4083 # There's more than one way to move in this game!
4085 # Test for conditions which prevent calling for help
4086 if game.condition == "docked":
4087 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4090 prout(_("Subspace radio damaged."))
4092 if not game.state.baseq:
4093 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4096 prout(_("You must be aboard the %s.") % crmshp())
4098 # OK -- call for help from nearest starbase
4101 # There's one in this quadrant
4102 ddist = (game.base - game.sector).distance()
4105 for ibq in game.state.baseq:
4106 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4109 # Since starbase not in quadrant, set up new quadrant
4112 # dematerialize starship
4113 game.quad[game.sector.i][game.sector.j]='.'
4114 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4115 % (game.quadrant, crmshp()))
4116 game.sector.invalidate()
4117 for m in range(1, 5+1):
4118 w = game.base.scatter()
4119 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4120 # found one -- finish up
4123 if not game.sector.is_valid():
4124 prout(_("You have been lost in space..."))
4125 finish(FMATERIALIZE)
4127 # Give starbase three chances to rematerialize starship
4128 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4129 for m in range(1, 3+1):
4130 if m == 1: proutn(_("1st"))
4131 elif m == 2: proutn(_("2nd"))
4132 elif m == 3: proutn(_("3rd"))
4133 proutn(_(" attempt to re-materialize ") + crmshp())
4134 game.quad[ix][iy]=('-','o','O')[m-1]
4136 if randreal() > probf:
4139 curses.delay_output(500)
4141 game.quad[ix][iy]='?'
4144 setwnd(message_window)
4145 finish(FMATERIALIZE)
4147 game.quad[ix][iy]=game.ship
4148 prout(_("succeeds."))
4151 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4156 if game.condition=="docked":
4158 prout(_("You cannot abandon Ye Faerie Queene."))
4161 # Must take shuttle craft to exit
4162 if game.damage[DSHUTTL]==-1:
4163 prout(_("Ye Faerie Queene has no shuttle craft."))
4165 if game.damage[DSHUTTL]<0:
4166 prout(_("Shuttle craft now serving Big Macs."))
4168 if game.damage[DSHUTTL]>0:
4169 prout(_("Shuttle craft damaged."))
4172 prout(_("You must be aboard the ship."))
4174 if game.iscraft != "onship":
4175 prout(_("Shuttle craft not currently available."))
4177 # Emit abandon ship messages
4179 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4181 prouts(_("***ALL HANDS ABANDON SHIP!"))
4183 prout(_("Captain and crew escape in shuttle craft."))
4184 if not game.state.baseq:
4185 # Oops! no place to go...
4188 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4190 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4191 prout(_("Remainder of ship's complement beam down"))
4192 prout(_("to nearest habitable planet."))
4193 elif q.planet != None and not damaged(DTRANSP):
4194 prout(_("Remainder of ship's complement beam down to %s.") %
4197 prout(_("Entire crew of %d left to die in outer space.") %
4199 game.casual += game.state.crew
4200 game.abandoned += game.state.crew
4201 # If at least one base left, give 'em the Faerie Queene
4203 game.icrystl = False # crystals are lost
4204 game.nprobes = 0 # No probes
4205 prout(_("You are captured by Klingons and released to"))
4206 prout(_("the Federation in a prisoner-of-war exchange."))
4207 nb = randrange(len(game.state.baseq))
4208 # Set up quadrant and position FQ adjacient to base
4209 if not game.quadrant == game.state.baseq[nb]:
4210 game.quadrant = game.state.baseq[nb]
4211 game.sector.i = game.sector.j = 5
4214 # position next to base by trial and error
4215 game.quad[game.sector.i][game.sector.j] = '.'
4216 for l in range(QUADSIZE):
4217 game.sector = game.base.scatter()
4218 if game.sector.valid_sector() and \
4219 game.quad[game.sector.i][game.sector.j] == '.':
4222 break # found a spot
4223 game.sector.i=QUADSIZE/2
4224 game.sector.j=QUADSIZE/2
4226 # Get new commission
4227 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4228 game.state.crew = FULLCREW
4229 prout(_("Starfleet puts you in command of another ship,"))
4230 prout(_("the Faerie Queene, which is antiquated but,"))
4231 prout(_("still useable."))
4233 prout(_("The dilithium crystals have been moved."))
4235 game.iscraft = "offship" # Galileo disappears
4237 game.condition="docked"
4238 for l in range(NDEVICES):
4239 game.damage[l] = 0.0
4240 game.damage[DSHUTTL] = -1
4241 game.energy = game.inenrg = 3000.0
4242 game.shield = game.inshld = 1250.0
4243 game.torps = game.intorps = 6
4244 game.lsupres=game.inlsr=3.0
4249 # Code from planets.c begins here.
4252 "Abort a lengthy operation if an event interrupts it."
4255 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4260 "Report on (uninhabited) planets in the galaxy."
4264 prout(_("Spock- \"Planet report follows, Captain.\""))
4266 for i in range(game.inplan):
4267 if game.state.planets[i].pclass == "destroyed":
4269 if (game.state.planets[i].known != "unknown" \
4270 and not game.state.planets[i].inhabited) \
4273 if idebug and game.state.planets[i].known=="unknown":
4274 proutn("(Unknown) ")
4275 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4276 proutn(_(" class "))
4277 proutn(game.state.planets[i].pclass)
4279 if game.state.planets[i].crystals != present:
4281 prout(_("dilithium crystals present."))
4282 if game.state.planets[i].known=="shuttle_down":
4283 prout(_(" Shuttle Craft Galileo on surface."))
4285 prout(_("No information available."))
4288 "Enter standard orbit."
4292 prout(_("Already in standard orbit."))
4294 if damaged(DWARPEN) and damaged(DIMPULS):
4295 prout(_("Both warp and impulse engines damaged."))
4297 if not game.plnet.is_valid():
4298 prout("There is no planet in this sector.")
4300 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4301 prout(crmshp() + _(" not adjacent to planet."))
4304 game.optime = randreal(0.02, 0.05)
4305 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4309 game.height = randreal(1400, 8600)
4310 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4315 "Examine planets in this quadrant."
4316 if damaged(DSRSENS):
4317 if game.options & OPTION_TTY:
4318 prout(_("Short range sensors damaged."))
4320 if game.iplnet == None:
4321 if game.options & OPTION_TTY:
4322 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4324 if game.iplnet.known == "unknown":
4325 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4327 prout(_(" Planet at Sector %s is of class %s.") %
4328 (game.plnet, game.iplnet.pclass))
4329 if game.iplnet.known=="shuttle_down":
4330 prout(_(" Sensors show Galileo still on surface."))
4331 proutn(_(" Readings indicate"))
4332 if game.iplnet.crystals != "present":
4334 prout(_(" dilithium crystals present.\""))
4335 if game.iplnet.known == "unknown":
4336 game.iplnet.known = "known"
4337 elif game.iplnet.inhabited:
4338 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4339 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4342 "Use the transporter."
4346 if damaged(DTRANSP):
4347 prout(_("Transporter damaged."))
4348 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4350 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4354 if not game.inorbit:
4355 prout(crmshp() + _(" not in standard orbit."))
4358 prout(_("Impossible to transport through shields."))
4360 if game.iplnet.known=="unknown":
4361 prout(_("Spock- \"Captain, we have no information on this planet"))
4362 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4363 prout(_(" you may not go down.\""))
4365 if not game.landed and game.iplnet.crystals=="absent":
4366 prout(_("Spock- \"Captain, I fail to see the logic in"))
4367 prout(_(" exploring a planet with no dilithium crystals."))
4368 proutn(_(" Are you sure this is wise?\" "))
4372 if not (game.options & OPTION_PLAIN):
4373 nrgneed = 50 * game.skill + game.height / 100.0
4374 if nrgneed > game.energy:
4375 prout(_("Engineering to bridge--"))
4376 prout(_(" Captain, we don't have enough energy for transportation."))
4378 if not game.landed and nrgneed * 2 > game.energy:
4379 prout(_("Engineering to bridge--"))
4380 prout(_(" Captain, we have enough energy only to transport you down to"))
4381 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4382 if game.iplnet.known == "shuttle_down":
4383 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4384 proutn(_(" Are you sure this is wise?\" "))
4389 # Coming from planet
4390 if game.iplnet.known=="shuttle_down":
4391 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4395 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4396 prout(_("Landing party assembled, ready to beam up."))
4398 prout(_("Kirk whips out communicator..."))
4399 prouts(_("BEEP BEEP BEEP"))
4401 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4404 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4406 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4408 prout(_("Kirk- \"Energize.\""))
4411 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4414 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4416 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4419 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4420 game.landed = not game.landed
4421 game.energy -= nrgneed
4423 prout(_("Transport complete."))
4424 if game.landed and game.iplnet.known=="shuttle_down":
4425 prout(_("The shuttle craft Galileo is here!"))
4426 if not game.landed and game.imine:
4433 "Strip-mine a world for dilithium."
4437 prout(_("Mining party not on planet."))
4439 if game.iplnet.crystals == "mined":
4440 prout(_("This planet has already been strip-mined for dilithium."))
4442 elif game.iplnet.crystals == "absent":
4443 prout(_("No dilithium crystals on this planet."))
4446 prout(_("You've already mined enough crystals for this trip."))
4448 if game.icrystl and game.cryprob == 0.05:
4449 prout(_("With all those fresh crystals aboard the ") + crmshp())
4450 prout(_("there's no reason to mine more at this time."))
4452 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4455 prout(_("Mining operation complete."))
4456 game.iplnet.crystals = "mined"
4457 game.imine = game.ididit = True
4460 "Use dilithium crystals."
4464 if not game.icrystl:
4465 prout(_("No dilithium crystals available."))
4467 if game.energy >= 1000:
4468 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4469 prout(_(" except when Condition Yellow exists."))
4471 prout(_("Spock- \"Captain, I must warn you that loading"))
4472 prout(_(" raw dilithium crystals into the ship's power"))
4473 prout(_(" system may risk a severe explosion."))
4474 proutn(_(" Are you sure this is wise?\" "))
4479 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4480 prout(_(" Mr. Spock and I will try it.\""))
4482 prout(_("Spock- \"Crystals in place, Sir."))
4483 prout(_(" Ready to activate circuit.\""))
4485 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4487 if with(game.cryprob):
4488 prouts(_(" \"Activating now! - - No good! It's***"))
4490 prouts(_("***RED ALERT! RED A*L********************************"))
4493 prouts(_("****************** KA-BOOM!!!! *******************"))
4497 game.energy += randreal(5000.0, 5500.0)
4498 prouts(_(" \"Activating now! - - "))
4499 prout(_("The instruments"))
4500 prout(_(" are going crazy, but I think it's"))
4501 prout(_(" going to work!! Congratulations, Sir!\""))
4506 "Use shuttlecraft for planetary jaunt."
4509 if damaged(DSHUTTL):
4510 if game.damage[DSHUTTL] == -1.0:
4511 if game.inorbit and game.iplnet.known == "shuttle_down":
4512 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4514 prout(_("Ye Faerie Queene had no shuttle craft."))
4515 elif game.damage[DSHUTTL] > 0:
4516 prout(_("The Galileo is damaged."))
4517 else: # game.damage[DSHUTTL] < 0
4518 prout(_("Shuttle craft is now serving Big Macs."))
4520 if not game.inorbit:
4521 prout(crmshp() + _(" not in standard orbit."))
4523 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4524 prout(_("Shuttle craft not currently available."))
4526 if not game.landed and game.iplnet.known=="shuttle_down":
4527 prout(_("You will have to beam down to retrieve the shuttle craft."))
4529 if game.shldup or game.condition == "docked":
4530 prout(_("Shuttle craft cannot pass through shields."))
4532 if game.iplnet.known=="unknown":
4533 prout(_("Spock- \"Captain, we have no information on this planet"))
4534 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4535 prout(_(" you may not fly down.\""))
4537 game.optime = 3.0e-5*game.height
4538 if game.optime >= 0.8*game.state.remtime:
4539 prout(_("First Officer Spock- \"Captain, I compute that such"))
4540 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4541 int(100*game.optime/game.state.remtime))
4542 prout(_("remaining time."))
4543 proutn(_("Are you sure this is wise?\" "))
4549 if game.iscraft == "onship":
4551 if not damaged(DTRANSP):
4552 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4556 proutn(_("Shuttle crew"))
4558 proutn(_("Rescue party"))
4559 prout(_(" boards Galileo and swoops toward planet surface."))
4560 game.iscraft = "offship"
4564 game.iplnet.known="shuttle_down"
4565 prout(_("Trip complete."))
4568 # Ready to go back to ship
4569 prout(_("You and your mining party board the"))
4570 prout(_("shuttle craft for the trip back to the Enterprise."))
4572 prouts(_("The short hop begins . . ."))
4574 game.iplnet.known="known"
4580 game.iscraft = "onship"
4586 prout(_("Trip complete."))
4589 # Kirk on ship and so is Galileo
4590 prout(_("Mining party assembles in the hangar deck,"))
4591 prout(_("ready to board the shuttle craft \"Galileo\"."))
4593 prouts(_("The hangar doors open; the trip begins."))
4596 game.iscraft = "offship"
4599 game.iplnet.known = "shuttle_down"
4602 prout(_("Trip complete."))
4606 "Use the big zapper."
4610 if game.ship != 'E':
4611 prout(_("Ye Faerie Queene has no death ray."))
4613 if len(game.enemies)==0:
4614 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4617 prout(_("Death Ray is damaged."))
4619 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4620 prout(_(" is highly unpredictible. Considering the alternatives,"))
4621 proutn(_(" are you sure this is wise?\" "))
4624 prout(_("Spock- \"Acknowledged.\""))
4627 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4629 prout(_("Crew scrambles in emergency preparation."))
4630 prout(_("Spock and Scotty ready the death ray and"))
4631 prout(_("prepare to channel all ship's power to the device."))
4633 prout(_("Spock- \"Preparations complete, sir.\""))
4634 prout(_("Kirk- \"Engage!\""))
4636 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4639 if game.options & OPTION_PLAIN:
4643 prouts(_("Sulu- \"Captain! It's working!\""))
4645 while len(game.enemies) > 0:
4646 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4647 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4648 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4650 if (game.options & OPTION_PLAIN) == 0:
4651 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4653 prout(_(" is still operational.\""))
4655 prout(_(" has been rendered nonfunctional.\""))
4656 game.damage[DDRAY] = 39.95
4658 r = randreal() # Pick failure method
4660 prouts(_("Sulu- \"Captain! It's working!\""))
4662 prouts(_("***RED ALERT! RED ALERT!"))
4664 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4666 prouts(_("***RED ALERT! RED A*L********************************"))
4669 prouts(_("****************** KA-BOOM!!!! *******************"))
4674 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4676 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4678 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4679 prout(_(" have apparently been transformed into strange mutations."))
4680 prout(_(" Vulcans do not seem to be affected."))
4682 prout(_("Kirk- \"Raauch! Raauch!\""))
4687 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4689 proutn(_("Spock- \"I believe the word is"))
4690 prouts(_(" *ASTONISHING*"))
4691 prout(_(" Mr. Sulu."))
4692 for i in range(QUADSIZE):
4693 for j in range(QUADSIZE):
4694 if game.quad[i][j] == '.':
4695 game.quad[i][j] = '?'
4696 prout(_(" Captain, our quadrant is now infested with"))
4697 prouts(_(" - - - - - - *THINGS*."))
4699 prout(_(" I have no logical explanation.\""))
4701 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4703 prout(_("Scotty- \"There are so many tribbles down here"))
4704 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4708 # Code from reports.c begins here
4710 def attackreport(curt):
4711 "eport status of bases under attack."
4713 if is_scheduled(FCDBAS):
4714 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4715 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4716 elif game.isatb == 1:
4717 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4718 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4720 prout(_("No Starbase is currently under attack."))
4722 if is_scheduled(FCDBAS):
4723 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4725 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4729 # report on general game status
4731 s1 = "" and game.thawed and _("thawed ")
4732 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4733 s3 = (None, _("novice"). _("fair"),
4734 _("good"), _("expert"), _("emeritus"))[game.skill]
4735 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4736 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4737 prout(_("No plaque is allowed."))
4739 prout(_("This is tournament game %d.") % game.tourn)
4740 prout(_("Your secret password is \"%s\"") % game.passwd)
4741 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4742 (game.inkling + game.incom + game.inscom)))
4743 if game.incom - len(game.state.kcmdr):
4744 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4745 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4746 prout(_(", but no Commanders."))
4749 if game.skill > SKILL_FAIR:
4750 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4751 if len(game.state.baseq) != game.inbase:
4753 if game.inbase-len(game.state.baseq)==1:
4754 proutn(_("has been 1 base"))
4756 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4757 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4759 prout(_("There are %d bases.") % game.inbase)
4760 if communicating() or game.iseenit:
4761 # Don't report this if not seen and
4762 # either the radio is dead or not at base!
4766 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4768 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4769 if game.ship == 'E':
4770 proutn(_("You have "))
4772 proutn("%d" % (game.nprobes))
4775 proutn(_(" deep space probe"))
4779 if communicating() and is_scheduled(FDSPROB):
4781 proutn(_("An armed deep space probe is in "))
4783 proutn(_("A deep space probe is in "))
4784 prout("Quadrant %s." % game.probec)
4786 if game.cryprob <= .05:
4787 prout(_("Dilithium crystals aboard ship... not yet used."))
4791 while game.cryprob > ai:
4794 prout(_("Dilithium crystals have been used %d time%s.") % \
4795 (i, (_("s"), "")[i==1]))
4799 "Long-range sensor scan."
4800 if damaged(DLRSENS):
4801 # Now allow base's sensors if docked
4802 if game.condition != "docked":
4804 prout(_("LONG-RANGE SENSORS DAMAGED."))
4807 prout(_("Starbase's long-range scan"))
4809 prout(_("Long-range scan"))
4810 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4813 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4814 if not coord(x, y).valid_quadrant():
4818 if not damaged(DRADIO):
4819 game.state.galaxy[x][y].charted = True
4820 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4821 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4822 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4823 if not silent and game.state.galaxy[x][y].supernova:
4826 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4833 for i in range(NDEVICES):
4836 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4837 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4839 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4840 game.damage[i]+0.05,
4841 game.docfac*game.damage[i]+0.005))
4843 prout(_("All devices functional."))
4846 "Update the chart in the Enterprise's computer from galaxy data."
4847 game.lastchart = game.state.date
4848 for i in range(GALSIZE):
4849 for j in range(GALSIZE):
4850 if game.state.galaxy[i][j].charted:
4851 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
4852 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
4853 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
4856 "Display the star chart."
4858 if (game.options & OPTION_AUTOSCAN):
4860 if not damaged(DRADIO):
4862 if game.lastchart < game.state.date and game.condition == "docked":
4863 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
4865 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
4866 if game.state.date > game.lastchart:
4867 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
4868 prout(" 1 2 3 4 5 6 7 8")
4869 for i in range(GALSIZE):
4870 proutn("%d |" % (i+1))
4871 for j in range(GALSIZE):
4872 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4876 if game.state.galaxy[i][j].supernova:
4878 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
4880 elif game.state.galaxy[i][j].charted:
4881 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
4885 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4893 def sectscan(goodScan, i, j):
4894 "Light up an individual dot in a sector."
4895 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
4896 proutn("%c " % game.quad[i][j])
4901 "Emit status report lines"
4902 if not req or req == 1:
4903 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
4904 % (game.state.date, game.state.remtime))
4905 if not req or req == 2:
4906 if game.condition != "docked":
4908 prstat(_("Condition"), _("%s, %i DAMAGES") % \
4909 (game.condition.upper(), sum(map(lambda x: x > 0, game.damage))))
4910 if not req or req == 3:
4911 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
4912 if not req or req == 4:
4913 if damaged(DLIFSUP):
4914 if game.condition == "docked":
4915 s = _("DAMAGED, Base provides")
4917 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
4920 prstat(_("Life Support"), s)
4921 if not req or req == 5:
4922 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
4923 if not req or req == 6:
4925 if game.icrystl and (game.options & OPTION_SHOWME):
4926 extra = _(" (have crystals)")
4927 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
4928 if not req or req == 7:
4929 prstat(_("Torpedoes"), "%d" % (game.torps))
4930 if not req or req == 8:
4931 if damaged(DSHIELD):
4937 data = _(" %d%% %.1f units") \
4938 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
4939 prstat(_("Shields"), s+data)
4940 if not req or req == 9:
4941 prstat(_("Klingons Left"), "%d" \
4942 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
4943 if not req or req == 10:
4944 if game.options & OPTION_WORLDS:
4945 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
4946 if plnet and plnet.inhabited:
4947 prstat(_("Major system"), plnet.name)
4949 prout(_("Sector is uninhabited"))
4950 elif not req or req == 11:
4951 attackreport(not req)
4954 "Request specified status data, a historical relic from slow TTYs."
4955 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
4956 while scanner.next() == "IHEOL":
4957 proutn(_("Information desired? "))
4959 if scanner.token in requests:
4960 status(requests.index(scanner.token))
4962 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
4963 prout((" date, condition, position, lsupport, warpfactor,"))
4964 prout((" energy, torpedoes, shields, klingons, system, time."))
4969 if damaged(DSRSENS):
4970 # Allow base's sensors if docked
4971 if game.condition != "docked":
4972 prout(_(" S.R. SENSORS DAMAGED!"))
4975 prout(_(" [Using Base's sensors]"))
4977 prout(_(" Short-range scan"))
4978 if goodScan and not damaged(DRADIO):
4979 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
4980 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
4981 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
4982 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4983 prout(" 1 2 3 4 5 6 7 8 9 10")
4984 if game.condition != "docked":
4986 for i in range(QUADSIZE):
4987 proutn("%2d " % (i+1))
4988 for j in range(QUADSIZE):
4989 sectscan(goodScan, i, j)
4993 "Use computer to get estimated time of arrival for a warp jump."
4994 w1 = coord(); w2 = coord()
4996 if damaged(DCOMPTR):
4997 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5000 if scanner.next() != "IHREAL":
5003 proutn(_("Destination quadrant and/or sector? "))
5004 if scanner.next()!="IHREAL":
5007 w1.j = int(scanner.real-0.5)
5008 if scanner.next() != "IHREAL":
5011 w1.i = int(scanner.real-0.5)
5012 if scanner.next() == "IHREAL":
5013 w2.j = int(scanner.real-0.5)
5014 if scanner.next() != "IHREAL":
5017 w2.i = int(scanner.real-0.5)
5019 if game.quadrant.j>w1.i:
5023 if game.quadrant.i>w1.j:
5027 if not w1.valid_quadrant() or not w2.valid_sector():
5030 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5031 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5034 prout(_("Answer \"no\" if you don't know the value:"))
5037 proutn(_("Time or arrival date? "))
5038 if scanner.next()=="IHREAL":
5039 ttime = scanner.real
5040 if ttime > game.state.date:
5041 ttime -= game.state.date # Actually a star date
5042 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5043 if ttime <= 1e-10 or twarp > 10:
5044 prout(_("We'll never make it, sir."))
5051 proutn(_("Warp factor? "))
5052 if scanner.next()== "IHREAL":
5054 twarp = scanner.real
5055 if twarp<1.0 or twarp > 10.0:
5059 prout(_("Captain, certainly you can give me one of these."))
5062 ttime = (10.0*dist)/twarp**2
5063 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5064 if tpower >= game.energy:
5065 prout(_("Insufficient energy, sir."))
5066 if not game.shldup or tpower > game.energy*2.0:
5069 proutn(_("New warp factor to try? "))
5070 if scanner.next() == "IHREAL":
5072 twarp = scanner.real
5073 if twarp<1.0 or twarp > 10.0:
5081 prout(_("But if you lower your shields,"))
5082 proutn(_("remaining"))
5085 proutn(_("Remaining"))
5086 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5088 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5090 prout(_("Any warp speed is adequate."))
5092 prout(_("Minimum warp needed is %.2f,") % (twarp))
5093 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5094 if game.state.remtime < ttime:
5095 prout(_("Unfortunately, the Federation will be destroyed by then."))
5097 prout(_("You'll be taking risks at that speed, Captain"))
5098 if (game.isatb==1 and game.state.kscmdr == w1 and \
5099 scheduled(FSCDBAS)< ttime+game.state.date) or \
5100 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5101 prout(_("The starbase there will be destroyed by then."))
5102 proutn(_("New warp factor to try? "))
5103 if scanner.next() == "IHREAL":
5105 twarp = scanner.real
5106 if twarp<1.0 or twarp > 10.0:
5114 # Code from setup.c begins here
5117 "Issue a historically correct banner."
5119 prout(_("-SUPER- STAR TREK"))
5121 # From the FORTRAN original
5122 # prout(_("Latest update-21 Sept 78"))
5128 scanner.push("emsave.trk")
5129 key = scanner.next()
5131 proutn(_("File name: "))
5132 key = scanner.next()
5133 if key != "IHALPHA":
5137 if '.' not in scanner.token:
5138 scanner.token += ".trk"
5140 fp = open(scanner.token, "wb")
5142 prout(_("Can't freeze game as file %s") % scanner.token)
5144 cPickle.dump(game, fp)
5148 "Retrieve saved game."
5149 game.passwd[0] = '\0'
5150 key = scanner.next()
5152 proutn(_("File name: "))
5153 key = scanner.next()
5154 if key != "IHALPHA":
5158 if '.' not in scanner.token:
5159 scanner.token += ".trk"
5161 fp = open(scanner.token, "rb")
5163 prout(_("Can't thaw game in %s") % scanner.token)
5165 game = cPickle.load(fp)
5169 # I used <http://www.memory-alpha.org> to find planets
5170 # with references in ST:TOS. Eath and the Alpha Centauri
5171 # Colony have been omitted.
5173 # Some planets marked Class G and P here will be displayed as class M
5174 # because of the way planets are generated. This is a known bug.
5177 _("Andoria (Fesoan)"), # several episodes
5178 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5179 _("Vulcan (T'Khasi)"), # many episodes
5180 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5181 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5182 _("Ardana"), # TOS: "The Cloud Minders"
5183 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5184 _("Gideon"), # TOS: "The Mark of Gideon"
5185 _("Aldebaran III"), # TOS: "The Deadly Years"
5186 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5187 _("Altair IV"), # TOS: "Amok Time
5188 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5189 _("Benecia"), # TOS: "The Conscience of the King"
5190 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5191 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5192 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5193 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5194 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5195 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5196 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5197 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5198 _("Ingraham B"), # TOS: "Operation: Annihilate"
5199 _("Janus IV"), # TOS: "The Devil in the Dark"
5200 _("Makus III"), # TOS: "The Galileo Seven"
5201 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5202 _("Omega IV"), # TOS: "The Omega Glory"
5203 _("Regulus V"), # TOS: "Amok Time
5204 _("Deneva"), # TOS: "Operation -- Annihilate!"
5205 # Worlds from BSD Trek
5206 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5207 _("Beta III"), # TOS: "The Return of the Archons"
5208 _("Triacus"), # TOS: "And the Children Shall Lead",
5209 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5211 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5212 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5213 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5214 # _("Izar"), # TOS: "Whom Gods Destroy"
5215 # _("Tiburon"), # TOS: "The Way to Eden"
5216 # _("Merak II"), # TOS: "The Cloud Minders"
5217 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5218 # _("Iotia"), # TOS: "A Piece of the Action"
5222 _("S. R. Sensors"), \
5223 _("L. R. Sensors"), \
5225 _("Photon Tubes"), \
5226 _("Life Support"), \
5227 _("Warp Engines"), \
5228 _("Impulse Engines"), \
5230 _("Subspace Radio"), \
5231 _("Shuttle Craft"), \
5233 _("Navigation System"), \
5235 _("Shield Control"), \
5241 "Prepare to play, set up cosmos."
5243 # Decide how many of everything
5245 return # frozen game
5246 # Prepare the Enterprise
5247 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5249 game.state.crew = FULLCREW
5250 game.energy = game.inenrg = 5000.0
5251 game.shield = game.inshld = 2500.0
5254 game.quadrant = randplace(GALSIZE)
5255 game.sector = randplace(QUADSIZE)
5256 game.torps = game.intorps = 10
5257 game.nprobes = randrange(2, 5)
5259 for i in range(NDEVICES):
5260 game.damage[i] = 0.0
5261 # Set up assorted game parameters
5262 game.battle = coord()
5263 game.state.date = game.indate = 100.0 * randreal(20, 51)
5264 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5265 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5266 game.isatb = game.state.nplankl = 0
5267 game.state.starkl = game.state.basekl = 0
5268 game.iscraft = "onship"
5272 # Starchart is functional but we've never seen it
5273 game.lastchart = FOREVER
5274 # Put stars in the galaxy
5276 for i in range(GALSIZE):
5277 for j in range(GALSIZE):
5278 k = randrange(1, QUADSIZE**2/10+1)
5280 game.state.galaxy[i][j].stars = k
5281 # Locate star bases in galaxy
5282 for i in range(game.inbase):
5285 w = randplace(GALSIZE)
5286 if not game.state.galaxy[w.i][w.j].starbase:
5289 # C version: for (j = i-1; j > 0; j--)
5290 # so it did them in the opposite order.
5291 for j in range(1, i):
5292 # Improved placement algorithm to spread out bases
5293 distq = (w - game.state.baseq[j]).distance()
5294 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5297 prout("=== Abandoning base #%d at %s" % (i, w))
5299 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5301 prout("=== Saving base #%d, close to #%d" % (i, j))
5304 game.state.baseq.append(w)
5305 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5306 # Position ordinary Klingon Battle Cruisers
5308 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5309 if klumper > MAXKLQUAD:
5313 klump = (1.0 - r*r)*klumper
5318 w = randplace(GALSIZE)
5319 if not game.state.galaxy[w.i][w.j].supernova and \
5320 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5322 game.state.galaxy[w.i][w.j].klingons += int(klump)
5325 # Position Klingon Commander Ships
5326 for i in range(game.incom):
5328 w = randplace(GALSIZE)
5329 if not welcoming(w) or w in game.state.kcmdr:
5331 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5333 game.state.galaxy[w.i][w.j].klingons += 1
5334 game.state.kcmdr.append(w)
5335 # Locate planets in galaxy
5336 for i in range(game.inplan):
5338 w = randplace(GALSIZE)
5339 if game.state.galaxy[w.i][w.j].planet == None:
5343 new.crystals = "absent"
5344 if (game.options & OPTION_WORLDS) and i < NINHAB:
5345 new.pclass = "M" # All inhabited planets are class M
5346 new.crystals = "absent"
5348 new.name = systnames[i]
5349 new.inhabited = True
5351 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5353 new.crystals = "present"
5354 new.known = "unknown"
5355 new.inhabited = False
5356 game.state.galaxy[w.i][w.j].planet = new
5357 game.state.planets.append(new)
5359 for i in range(game.state.nromrem):
5360 w = randplace(GALSIZE)
5361 game.state.galaxy[w.i][w.j].romulans += 1
5362 # Place the Super-Commander if needed
5363 if game.state.nscrem > 0:
5365 w = randplace(GALSIZE)
5368 game.state.kscmdr = w
5369 game.state.galaxy[w.i][w.j].klingons += 1
5370 # Initialize times for extraneous events
5371 schedule(FSNOVA, expran(0.5 * game.intime))
5372 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5373 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5374 schedule(FBATTAK, expran(0.3*game.intime))
5376 if game.state.nscrem:
5377 schedule(FSCMOVE, 0.2777)
5382 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5383 schedule(FDISTR, expran(1.0 + game.intime))
5388 # Place thing (in tournament game, we don't want one!)
5389 # New in SST2K: never place the Thing near a starbase.
5390 # This makes sense and avoids a special case in the old code.
5392 if game.tourn is None:
5394 thing = randplace(GALSIZE)
5395 if thing not in game.state.baseq:
5398 game.state.snap = False
5399 if game.skill == SKILL_NOVICE:
5400 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5401 prout(_("a deadly Klingon invasion force. As captain of the United"))
5402 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5403 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5404 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5405 prout(_("your mission. As you proceed you may be given more time."))
5407 prout(_("You will have %d supporting starbases.") % (game.inbase))
5408 proutn(_("Starbase locations- "))
5410 prout(_("Stardate %d.") % int(game.state.date))
5412 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5413 prout(_("An unknown number of Romulans."))
5414 if game.state.nscrem:
5415 prout(_("And one (GULP) Super-Commander."))
5416 prout(_("%d stardates.") % int(game.intime))
5417 proutn(_("%d starbases in ") % game.inbase)
5418 for i in range(game.inbase):
5419 proutn(`game.state.baseq[i]`)
5422 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5423 proutn(_(" Sector %s") % game.sector)
5425 prout(_("Good Luck!"))
5426 if game.state.nscrem:
5427 prout(_(" YOU'LL NEED IT."))
5430 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5432 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5433 attack(torps_ok=False)
5436 "Choose your game type."
5441 game.skill = SKILL_NONE
5443 if not scanner.inqueue: # Can start with command line options
5444 proutn(_("Would you like a regular, tournament, or saved game? "))
5446 if scanner.sees("tournament"):
5447 while scanner.next() == "IHEOL":
5448 proutn(_("Type in tournament number-"))
5449 if scanner.real == 0:
5451 continue # We don't want a blank entry
5452 game.tourn = int(round(scanner.real))
5453 random.seed(scanner.real)
5455 logfp.write("# random.seed(%d)\n" % scanner.real)
5457 if scanner.sees("saved") or scanner.sees("frozen"):
5461 if game.passwd == None:
5463 if not game.alldone:
5464 game.thawed = True # No plaque if not finished
5468 if scanner.sees("regular"):
5470 proutn(_("What is \"%s\"?") % scanner.token)
5472 while game.length==0 or game.skill==SKILL_NONE:
5473 if scanner.next() == "IHALPHA":
5474 if scanner.sees("short"):
5476 elif scanner.sees("medium"):
5478 elif scanner.sees("long"):
5480 elif scanner.sees("novice"):
5481 game.skill = SKILL_NOVICE
5482 elif scanner.sees("fair"):
5483 game.skill = SKILL_FAIR
5484 elif scanner.sees("good"):
5485 game.skill = SKILL_GOOD
5486 elif scanner.sees("expert"):
5487 game.skill = SKILL_EXPERT
5488 elif scanner.sees("emeritus"):
5489 game.skill = SKILL_EMERITUS
5491 proutn(_("What is \""))
5492 proutn(scanner.token)
5497 proutn(_("Would you like a Short, Medium, or Long game? "))
5498 elif game.skill == SKILL_NONE:
5499 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5500 # Choose game options -- added by ESR for SST2K
5501 if scanner.next() != "IHALPHA":
5503 proutn(_("Choose your game style (or just press enter): "))
5505 if scanner.sees("plain"):
5506 # Approximates the UT FORTRAN version.
5507 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5508 game.options |= OPTION_PLAIN
5509 elif scanner.sees("almy"):
5510 # Approximates Tom Almy's version.
5511 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5512 game.options |= OPTION_ALMY
5513 elif scanner.sees("fancy") or scanner.sees("\n"):
5515 elif len(scanner.token):
5516 proutn(_("What is \"%s\"?") % scanner.token)
5518 if game.passwd == "debug":
5520 prout("=== Debug mode enabled.")
5521 # Use parameters to generate initial values of things
5522 game.damfac = 0.5 * game.skill
5523 game.inbase = randrange(BASEMIN, BASEMAX+1)
5525 if game.options & OPTION_PLANETS:
5526 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5527 if game.options & OPTION_WORLDS:
5528 game.inplan += int(NINHAB)
5529 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5530 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5531 game.state.remtime = 7.0 * game.length
5532 game.intime = game.state.remtime
5533 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5534 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5535 game.state.remres = (game.inkling+4*game.incom)*game.intime
5536 game.inresor = game.state.remres
5537 if game.inkling > 50:
5538 game.state.inbase += 1
5541 def dropin(iquad=None):
5542 "Drop a feature on a random dot in the current quadrant."
5544 w = randplace(QUADSIZE)
5545 if game.quad[w.i][w.j] == '.':
5547 if iquad is not None:
5548 game.quad[w.i][w.j] = iquad
5552 "Update our alert status."
5553 game.condition = "green"
5554 if game.energy < 1000.0:
5555 game.condition = "yellow"
5556 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5557 game.condition = "red"
5559 game.condition="dead"
5562 "Drop new Klingon into current quadrant."
5563 return enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5566 "Set up a new state of quadrant, for when we enter or re-enter it."
5569 game.neutz = game.inorbit = game.landed = False
5570 game.ientesc = game.iseenit = False
5571 # Create a blank quadrant
5572 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5574 # Attempt to escape Super-commander, so tbeam back!
5577 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5578 # cope with supernova
5581 game.klhere = q.klingons
5582 game.irhere = q.romulans
5584 game.quad[game.sector.i][game.sector.j] = game.ship
5587 # Position ordinary Klingons
5588 for i in range(game.klhere):
5590 # If we need a commander, promote a Klingon
5591 for cmdr in game.state.kcmdr:
5592 if cmdr == game.quadrant:
5593 e = game.enemies[game.klhere-1]
5594 game.quad[e.location.i][e.location.j] = 'C'
5595 e.power = randreal(950,1350) + 50.0*game.skill
5597 # If we need a super-commander, promote a Klingon
5598 if game.quadrant == game.state.kscmdr:
5600 game.quad[e.location.i][e.location.j] = 'S'
5601 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5602 game.iscate = (game.state.remkl > 1)
5603 # Put in Romulans if needed
5604 for i in range(q.romulans):
5605 enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5606 # If quadrant needs a starbase, put it in
5608 game.base = dropin('B')
5609 # If quadrant needs a planet, put it in
5611 game.iplnet = q.planet
5612 if not q.planet.inhabited:
5613 game.plnet = dropin('P')
5615 game.plnet = dropin('@')
5616 # Check for condition
5619 if game.irhere > 0 and game.klhere == 0:
5621 if not damaged(DRADIO):
5623 prout(_("LT. Uhura- \"Captain, an urgent message."))
5624 prout(_(" I'll put it on audio.\" CLICK"))
5626 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5627 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5628 # Put in THING if needed
5629 if thing == game.quadrant:
5630 enemy(type='?', loc=dropin(),
5631 power=randreal(6000,6500.0)+250.0*game.skill)
5632 if not damaged(DSRSENS):
5634 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5635 prout(_(" Please examine your short-range scan.\""))
5636 # Decide if quadrant needs a Tholian; lighten up if skill is low
5637 if game.options & OPTION_THOLIAN:
5638 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5639 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5640 (game.skill > SKILL_GOOD and withprob(0.08)):
5643 w.i = withprob(0.5) * (QUADSIZE-1)
5644 w.j = withprob(0.5) * (QUADSIZE-1)
5645 if game.quad[w.i][w.j] == '.':
5647 game.tholian = enemy(type='T', loc=w,
5648 power=randrange(100, 500) + 25.0*game.skill)
5649 # Reserve unoccupied corners
5650 if game.quad[0][0]=='.':
5651 game.quad[0][0] = 'X'
5652 if game.quad[0][QUADSIZE-1]=='.':
5653 game.quad[0][QUADSIZE-1] = 'X'
5654 if game.quad[QUADSIZE-1][0]=='.':
5655 game.quad[QUADSIZE-1][0] = 'X'
5656 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5657 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5658 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
5659 # And finally the stars
5660 for i in range(q.stars):
5662 # Put in a few black holes
5663 for i in range(1, 3+1):
5666 # Take out X's in corners if Tholian present
5668 if game.quad[0][0]=='X':
5669 game.quad[0][0] = '.'
5670 if game.quad[0][QUADSIZE-1]=='X':
5671 game.quad[0][QUADSIZE-1] = '.'
5672 if game.quad[QUADSIZE-1][0]=='X':
5673 game.quad[QUADSIZE-1][0] = '.'
5674 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5675 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5678 "Set the self-destruct password."
5679 if game.options & OPTION_PLAIN:
5682 proutn(_("Please type in a secret password- "))
5684 game.passwd = scanner.token
5685 if game.passwd != None:
5690 game.passwd += chr(ord('a')+randrange(26))
5692 # Code from sst.c begins here
5695 "SRSCAN": OPTION_TTY,
5696 "STATUS": OPTION_TTY,
5697 "REQUEST": OPTION_TTY,
5698 "LRSCAN": OPTION_TTY,
5711 "SENSORS": OPTION_PLANETS,
5712 "ORBIT": OPTION_PLANETS,
5713 "TRANSPORT": OPTION_PLANETS,
5714 "MINE": OPTION_PLANETS,
5715 "CRYSTALS": OPTION_PLANETS,
5716 "SHUTTLE": OPTION_PLANETS,
5717 "PLANETS": OPTION_PLANETS,
5722 "PROBE": OPTION_PROBE,
5724 "FREEZE": 0, # Synonym for SAVE
5730 "SOS": 0, # Synonym for MAYDAY
5731 "CALL": 0, # Synonym for MAYDAY
5737 "Generate a list of legal commands."
5738 prout(_("LEGAL COMMANDS ARE:"))
5740 for key in commands:
5741 if not commands[key] or (commands[key] & game.options):
5742 proutn("%-12s " % key)
5744 if emitted % 5 == 4:
5749 "Browse on-line help."
5750 key = scanner.next()
5753 setwnd(prompt_window)
5754 proutn(_("Help on what command? "))
5755 key = scanner.next()
5756 setwnd(message_window)
5759 if scanner.token in commands or scanner.token == "ABBREV":
5766 cmd = scanner.token.upper()
5768 fp = open(SSTDOC, "r")
5771 fp = open(DOC_NAME, "r")
5773 prout(_("Spock- \"Captain, that information is missing from the"))
5774 proutn(_(" computer. You need to find "))
5776 prout(_(" and put it in the"))
5777 proutn(_(" current directory or to "))
5780 # This used to continue: "You need to find SST.DOC and put
5781 # it in the current directory."
5784 linebuf = fp.readline()
5786 prout(_("Spock- \"Captain, there is no information on that command.\""))
5789 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5790 linebuf = linebuf[3:].strip()
5794 prout(_("Spock- \"Captain, I've found the following information:\""))
5796 while linebuf in fp:
5797 if "******" in linebuf:
5803 "Command-interpretation loop."
5805 setwnd(message_window)
5806 while True: # command loop
5808 while True: # get a command
5813 setwnd(prompt_window)
5816 if scanner.next() == "IHEOL":
5817 if game.options & OPTION_CURSES:
5820 elif scanner.token == "":
5824 setwnd(message_window)
5826 candidates = filter(lambda x: x.startswith(scanner.token.upper()),
5828 if len(candidates) == 1:
5831 elif candidates and not (game.options & OPTION_PLAIN):
5832 prout("Commands with prefix '%s': %s" % (scanner.token, " ".join(candidates)))
5836 if cmd == "SRSCAN": # srscan
5838 elif cmd == "STATUS": # status
5840 elif cmd == "REQUEST": # status request
5842 elif cmd == "LRSCAN": # long range scan
5843 lrscan(silent=False)
5844 elif cmd == "PHASERS": # phasers
5848 elif cmd == "TORPEDO": # photon torpedos
5852 elif cmd == "MOVE": # move under warp
5853 warp(course=None, involuntary=False)
5854 elif cmd == "SHIELDS": # shields
5855 doshield(shraise=False)
5858 game.shldchg = False
5859 elif cmd == "DOCK": # dock at starbase
5862 attack(torps_ok=False)
5863 elif cmd == "DAMAGES": # damage reports
5865 elif cmd == "CHART": # chart
5867 elif cmd == "IMPULSE": # impulse
5869 elif cmd == "REST": # rest
5873 elif cmd == "WARP": # warp
5875 elif cmd == "SCORE": # score
5877 elif cmd == "SENSORS": # sensors
5879 elif cmd == "ORBIT": # orbit
5883 elif cmd == "TRANSPORT": # transport "beam"
5885 elif cmd == "MINE": # mine
5889 elif cmd == "CRYSTALS": # crystals
5893 elif cmd == "SHUTTLE": # shuttle
5897 elif cmd == "PLANETS": # Planet list
5899 elif cmd == "REPORT": # Game Report
5901 elif cmd == "COMPUTER": # use COMPUTER!
5903 elif cmd == "COMMANDS":
5905 elif cmd == "EMEXIT": # Emergency exit
5906 clrscr() # Hide screen
5907 freeze(True) # forced save
5908 raise SysExit,1 # And quick exit
5909 elif cmd == "PROBE":
5910 probe() # Launch probe
5913 elif cmd == "ABANDON": # Abandon Ship
5915 elif cmd == "DESTRUCT": # Self Destruct
5917 elif cmd == "SAVE": # Save Game
5920 if game.skill > SKILL_GOOD:
5921 prout(_("WARNING--Saved games produce no plaques!"))
5922 elif cmd == "DEATHRAY": # Try a desparation measure
5926 elif cmd == "DEBUGCMD": # What do we want for debug???
5928 elif cmd == "MAYDAY": # Call for help
5933 game.alldone = True # quit the game
5938 break # Game has ended
5939 if game.optime != 0.0:
5942 break # Events did us in
5943 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
5946 if hitme and not game.justin:
5947 attack(torps_ok=True)
5950 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
5961 "Emit the name of an enemy or feature."
5962 if type == 'R': s = _("Romulan")
5963 elif type == 'K': s = _("Klingon")
5964 elif type == 'C': s = _("Commander")
5965 elif type == 'S': s = _("Super-commander")
5966 elif type == '*': s = _("Star")
5967 elif type == 'P': s = _("Planet")
5968 elif type == 'B': s = _("Starbase")
5969 elif type == ' ': s = _("Black hole")
5970 elif type == 'T': s = _("Tholian")
5971 elif type == '#': s = _("Tholian web")
5972 elif type == '?': s = _("Stranger")
5973 elif type == '@': s = _("Inhabited World")
5974 else: s = "Unknown??"
5977 def crmena(stars, enemy, loctype, w):
5978 "Emit the name of an enemy and his location."
5982 buf += cramen(enemy) + _(" at ")
5983 if loctype == "quadrant":
5984 buf += _("Quadrant ")
5985 elif loctype == "sector":
5990 "Emit our ship name."
5991 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
5994 "Emit a line of stars"
5995 prouts("******************************************************")
5999 return -avrage*math.log(1e-7 + randreal())
6001 def randplace(size):
6002 "Choose a random location."
6004 w.i = randrange(size)
6005 w.j = randrange(size)
6015 # Get a token from the user
6018 # Fill the token quue if nothing here
6019 while not self.inqueue:
6021 if curwnd==prompt_window:
6023 setwnd(message_window)
6030 self.inqueue = line.lstrip().split() + ["\n"]
6031 # From here on in it's all looking at the queue
6032 self.token = self.inqueue.pop(0)
6033 if self.token == "\n":
6037 self.real = float(self.token)
6038 self.type = "IHREAL"
6043 self.token = self.token.lower()
6044 self.type = "IHALPHA"
6047 def append(self, tok):
6048 self.inqueue.append(tok)
6049 def push(self, tok):
6050 self.inqueue.insert(0, tok)
6054 # Demand input for next scan
6056 self.real = self.token = None
6058 # compares s to item and returns true if it matches to the length of s
6059 return s.startswith(self.token)
6061 # Round token value to nearest integer
6062 return int(round(scanner.real))
6066 if scanner.type != "IHREAL":
6069 s.i = scanner.int()-1
6071 if scanner.type != "IHREAL":
6074 s.j = scanner.int()-1
6077 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6080 "Yes-or-no confirmation."
6084 if scanner.token == 'y':
6086 if scanner.token == 'n':
6089 proutn(_("Please answer with \"y\" or \"n\": "))
6092 "Complain about unparseable input."
6095 prout(_("Beg your pardon, Captain?"))
6098 "Access to the internals for debugging."
6099 proutn("Reset levels? ")
6101 if game.energy < game.inenrg:
6102 game.energy = game.inenrg
6103 game.shield = game.inshld
6104 game.torps = game.intorps
6105 game.lsupres = game.inlsr
6106 proutn("Reset damage? ")
6108 for i in range(NDEVICES):
6109 if game.damage[i] > 0.0:
6110 game.damage[i] = 0.0
6111 proutn("Toggle debug flag? ")
6115 prout("Debug output ON")
6117 prout("Debug output OFF")
6118 proutn("Cause selective damage? ")
6120 for i in range(NDEVICES):
6121 proutn("Kill %s?" % device[i])
6123 key = scanner.next()
6124 if key == "IHALPHA" and scanner.sees("y"):
6125 game.damage[i] = 10.0
6126 proutn("Examine/change events? ")
6131 FSNOVA: "Supernova ",
6134 FBATTAK: "Base Attack ",
6135 FCDBAS: "Base Destroy ",
6136 FSCMOVE: "SC Move ",
6137 FSCDBAS: "SC Base Destroy ",
6138 FDSPROB: "Probe Move ",
6139 FDISTR: "Distress Call ",
6140 FENSLV: "Enslavement ",
6141 FREPRO: "Klingon Build ",
6143 for i in range(1, NEVENTS):
6146 proutn("%.2f" % (scheduled(i)-game.state.date))
6147 if i == FENSLV or i == FREPRO:
6149 proutn(" in %s" % ev.quadrant)
6154 key = scanner.next()
6158 elif key == "IHREAL":
6159 ev = schedule(i, scanner.real)
6160 if i == FENSLV or i == FREPRO:
6162 proutn("In quadrant- ")
6163 key = scanner.next()
6164 # "IHEOL" says to leave coordinates as they are
6167 prout("Event %d canceled, no x coordinate." % (i))
6170 w.i = int(round(scanner.real))
6171 key = scanner.next()
6173 prout("Event %d canceled, no y coordinate." % (i))
6176 w.j = int(round(scanner.real))
6179 proutn("Induce supernova here? ")
6181 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6184 if __name__ == '__main__':
6185 import getopt, socket
6187 global line, thing, game, idebug
6193 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6194 if os.getenv("TERM"):
6195 game.options |= OPTION_CURSES
6197 game.options |= OPTION_TTY
6198 seed = int(time.time())
6199 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:tx")
6200 for (switch, val) in options:
6203 replayfp = open(val, "r")
6205 sys.stderr.write("sst: can't open replay file %s\n" % val)
6208 line = replayfp.readline().strip()
6209 (leader, key, seed) = line.split()
6211 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6212 line = replayfp.readline().strip()
6213 arguments += line.split()[2:]
6215 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6217 game.options |= OPTION_TTY
6218 game.options &=~ OPTION_CURSES
6219 elif switch == '-s':
6221 elif switch == '-t':
6222 game.options |= OPTION_TTY
6223 game.options &=~ OPTION_CURSES
6224 elif switch == '-x':
6227 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6229 # where to save the input in case of bugs
6231 logfp = open("/usr/tmp/sst-input.log", "w")
6233 sys.stderr.write("sst: warning, can't open logfile\n")
6235 logfp.write("# seed %s\n" % seed)
6236 logfp.write("# options %s\n" % " ".join(arguments))
6237 logfp.write("# recorded by %s@%s on %s\n" % \
6238 (getpass.getuser(),socket.gethostname(),time.ctime()))
6240 scanner = sstscanner()
6241 map(scanner.append, arguments)
6244 while True: # Play a game
6245 setwnd(fullscreen_window)
6251 game.alldone = False
6257 if game.tourn and game.alldone:
6258 proutn(_("Do you want your score recorded?"))
6264 proutn(_("Do you want to play again? "))
6268 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6272 except KeyboardInterrupt: