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