3 sst.py -- Super Star Trek 2K
5 SST2K is a Python translation of a C translation of a FORTRAN
6 original dating back to 1973. Beautiful Python it is not, but it
7 works. Translation by Eric S. Raymond; original game by David Matuszek
8 and Paul Reynolds, with modifications by Don Smith, Tom Almy,
9 Stas Sergeev, and Eric S. Raymond.
11 See the doc/HACKING file in the distribution for designers notes and advice
12 on how to modify (and how not to modify!) this code.
14 import os, sys, math, curses, time, readline, cPickle, random, copy, gettext, getpass
18 docpath = (".", "../doc", "/usr/share/doc/sst")
20 def _(str): return gettext.gettext(str)
22 GALSIZE = 8 # Galaxy size in quadrants
23 NINHAB = (GALSIZE * GALSIZE / 2) # Number of inhabited worlds
24 MAXUNINHAB = 10 # Maximum uninhabited worlds
25 QUADSIZE = 10 # Quadrant size in sectors
26 BASEMIN = 2 # Minimum starbases
27 BASEMAX = (GALSIZE * GALSIZE / 12) # Maximum starbases
28 MAXKLGAME = 127 # Maximum Klingons per game
29 MAXKLQUAD = 9 # Maximum Klingons per quadrant
30 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
31 FOREVER = 1e30 # Time for the indefinite future
32 MAXBURST = 3 # Max # of torps you can launch in one turn
33 MINCMDR = 10 # Minimum number of Klingon commanders
34 DOCKFAC = 0.25 # Repair faster when docked
35 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
55 class TrekError(Exception):
58 class JumpOut(Exception):
62 def __init__(self, x=None, y=None):
65 def valid_quadrant(self):
66 return self.i>=0 and self.i<GALSIZE and self.j>=0 and self.j<GALSIZE
67 def valid_sector(self):
68 return self.i>=0 and self.i<QUADSIZE and self.j>=0 and self.j<QUADSIZE
70 self.i = self.j = None
72 return self.i != None and self.j != None
73 def __eq__(self, other):
74 return other != None and self.i == other.i and self.j == other.j
75 def __ne__(self, other):
76 return other == None or self.i != other.i or self.j != other.j
77 def __add__(self, other):
78 return coord(self.i+other.i, self.j+other.j)
79 def __sub__(self, other):
80 return coord(self.i-other.i, self.j-other.j)
81 def __mul__(self, other):
82 return coord(self.i*other, self.j*other)
83 def __rmul__(self, other):
84 return coord(self.i*other, self.j*other)
85 def __div__(self, other):
86 return coord(self.i/other, self.j/other)
87 def __mod__(self, other):
88 return coord(self.i % other, self.j % other)
89 def __rdiv__(self, other):
90 return coord(self.i/other, self.j/other)
91 def roundtogrid(self):
92 return coord(int(round(self.i)), int(round(self.j)))
93 def distance(self, other=None):
94 if not other: other = coord(0, 0)
95 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
97 return 1.90985*math.atan2(self.j, self.i)
103 s.i = self.i / abs(self.i)
107 s.j = self.j / abs(self.j)
110 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
111 return self.roundtogrid() / QUADSIZE
113 return self.roundtogrid() % QUADSIZE
116 s.i = self.i + randrange(-1, 2)
117 s.j = self.j + randrange(-1, 2)
120 if self.i == None or self.j == None:
122 return "%s - %s" % (self.i+1, self.j+1)
127 self.name = None # string-valued if inhabited
128 self.quadrant = coord() # quadrant located
129 self.pclass = None # could be ""M", "N", "O", or "destroyed"
130 self.crystals = "absent"# could be "mined", "present", "absent"
131 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
132 self.inhabited = False # is it inhabites?
140 self.starbase = False
143 self.supernova = False
145 self.status = "secure" # Could be "secure", "distressed", "enslaved"
153 def fill2d(size, fillfun):
154 "Fill an empty list in 2D."
156 for i in range(size):
158 for j in range(size):
159 lst[i].append(fillfun(i, j))
164 self.snap = False # snapshot taken
165 self.crew = 0 # crew complement
166 self.remkl = 0 # remaining klingons
167 self.nscrem = 0 # remaining super commanders
168 self.starkl = 0 # destroyed stars
169 self.basekl = 0 # destroyed bases
170 self.nromrem = 0 # Romulans remaining
171 self.nplankl = 0 # destroyed uninhabited planets
172 self.nworldkl = 0 # destroyed inhabited planets
173 self.planets = [] # Planet information
174 self.date = 0.0 # stardate
175 self.remres = 0 # remaining resources
176 self.remtime = 0 # remaining time
177 self.baseq = [] # Base quadrant coordinates
178 self.kcmdr = [] # Commander quadrant coordinates
179 self.kscmdr = coord() # Supercommander quadrant coordinates
181 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: quadrant())
183 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: page())
187 self.date = None # A real number
188 self.quadrant = None # A coord structure
191 OPTION_ALL = 0xffffffff
192 OPTION_TTY = 0x00000001 # old interface
193 OPTION_CURSES = 0x00000002 # new interface
194 OPTION_IOMODES = 0x00000003 # cover both interfaces
195 OPTION_PLANETS = 0x00000004 # planets and mining
196 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
197 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
198 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
199 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
200 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
201 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
202 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
203 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
204 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
205 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
206 OPTION_PLAIN = 0x01000000 # user chose plain game
207 OPTION_ALMY = 0x02000000 # user chose Almy variant
208 OPTION_COLOR = 0x04000000 # enable color display (experimental, ESR, 2010)
227 NDEVICES= 16 # Number of devices
236 def damaged(dev): return (game.damage[dev] != 0.0)
237 def communicating(): return not damaged(DRADIO) or game.condition=="docked"
239 # Define future events
240 FSPY = 0 # Spy event happens always (no future[] entry)
241 # can cause SC to tractor beam Enterprise
242 FSNOVA = 1 # Supernova
243 FTBEAM = 2 # Commander tractor beams Enterprise
244 FSNAP = 3 # Snapshot for time warp
245 FBATTAK = 4 # Commander attacks base
246 FCDBAS = 5 # Commander destroys base
247 FSCMOVE = 6 # Supercommander moves (might attack base)
248 FSCDBAS = 7 # Supercommander destroys base
249 FDSPROB = 8 # Move deep space probe
250 FDISTR = 9 # Emit distress call from an inhabited world
251 FENSLV = 10 # Inhabited word is enslaved */
252 FREPRO = 11 # Klingons build a ship in an enslaved system
255 # Abstract out the event handling -- underlying data structures will change
256 # when we implement stateful events
257 def findevent(evtype): return game.future[evtype]
260 def __init__(self, type=None, loc=None, power=None):
262 self.location = coord()
265 self.power = power # enemy energy level
266 game.enemies.append(self)
268 motion = (loc != self.location)
269 if self.location.i is not None and self.location.j is not None:
272 game.quad[self.location.i][self.location.j] = '#'
274 game.quad[self.location.i][self.location.j] = '.'
276 self.location = copy.copy(loc)
277 game.quad[self.location.i][self.location.j] = self.type
278 self.kdist = self.kavgd = (game.sector - loc).distance()
280 self.location = coord()
281 self.kdist = self.kavgd = None
282 game.enemies.remove(self)
285 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
289 self.options = None # Game options
290 self.state = snapshot() # A snapshot structure
291 self.snapsht = snapshot() # Last snapshot taken for time-travel purposes
292 self.quad = None # contents of our quadrant
293 self.damage = [0.0] * NDEVICES # damage encountered
294 self.future = [] # future events
295 for i_unused in range(NEVENTS):
296 self.future.append(event())
297 self.passwd = None; # Self Destruct password
299 self.quadrant = None # where we are in the large
300 self.sector = None # where we are in the small
301 self.tholian = None # Tholian enemy object
302 self.base = None # position of base in current quadrant
303 self.battle = None # base coordinates being attacked
304 self.plnet = None # location of planet in quadrant
305 self.gamewon = False # Finished!
306 self.ididit = False # action taken -- allows enemy to attack
307 self.alive = False # we are alive (not killed)
308 self.justin = False # just entered quadrant
309 self.shldup = False # shields are up
310 self.shldchg = False # shield is changing (affects efficiency)
311 self.iscate = False # super commander is here
312 self.ientesc = False # attempted escape from supercommander
313 self.resting = False # rest time
314 self.icraft = False # Kirk in Galileo
315 self.landed = False # party on planet (true), on ship (false)
316 self.alldone = False # game is now finished
317 self.neutz = False # Romulan Neutral Zone
318 self.isarmed = False # probe is armed
319 self.inorbit = False # orbiting a planet
320 self.imine = False # mining
321 self.icrystl = False # dilithium crystals aboard
322 self.iseenit = False # seen base attack report
323 self.thawed = False # thawed game
324 self.condition = None # "green", "yellow", "red", "docked", "dead"
325 self.iscraft = None # "onship", "offship", "removed"
326 self.skill = None # Player skill level
327 self.inkling = 0 # initial number of klingons
328 self.inbase = 0 # initial number of bases
329 self.incom = 0 # initial number of commanders
330 self.inscom = 0 # initial number of commanders
331 self.inrom = 0 # initial number of commanders
332 self.instar = 0 # initial stars
333 self.intorps = 0 # initial/max torpedoes
334 self.torps = 0 # number of torpedoes
335 self.ship = 0 # ship type -- 'E' is Enterprise
336 self.abandoned = 0 # count of crew abandoned in space
337 self.length = 0 # length of game
338 self.klhere = 0 # klingons here
339 self.casual = 0 # causalties
340 self.nhelp = 0 # calls for help
341 self.nkinks = 0 # count of energy-barrier crossings
342 self.iplnet = None # planet # in quadrant
343 self.inplan = 0 # initial planets
344 self.irhere = 0 # Romulans in quadrant
345 self.isatb = 0 # =2 if super commander is attacking base
346 self.tourn = None # tournament number
347 self.nprobes = 0 # number of probes available
348 self.inresor = 0.0 # initial resources
349 self.intime = 0.0 # initial time
350 self.inenrg = 0.0 # initial/max energy
351 self.inshld = 0.0 # initial/max shield
352 self.inlsr = 0.0 # initial life support resources
353 self.indate = 0.0 # initial date
354 self.energy = 0.0 # energy level
355 self.shield = 0.0 # shield level
356 self.warpfac = 0.0 # warp speed
357 self.lsupres = 0.0 # life support reserves
358 self.optime = 0.0 # time taken by current operation
359 self.damfac = 0.0 # damage factor
360 self.lastchart = 0.0 # time star chart was last updated
361 self.cryprob = 0.0 # probability that crystal will work
362 self.probe = None # object holding probe course info
363 self.height = 0.0 # height of orbit around planet
364 self.idebug = False # Debugging instrumentation enabled?
366 # Stas thinks this should be (C expression):
367 # game.state.remkl + len(game.state.kcmdr) > 0 ?
368 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
369 # He says the existing expression is prone to divide-by-zero errors
370 # after killing the last klingon when score is shown -- perhaps also
371 # if the only remaining klingon is SCOM.
372 game.state.remtime = game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr))
398 return random.random() < p
400 def randrange(*args):
401 return random.randrange(*args)
406 v *= args[0] # from [0, args[0])
408 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
411 # Code from ai.c begins here
414 "Would this quadrant welcome another Klingon?"
415 return iq.valid_quadrant() and \
416 not game.state.galaxy[iq.i][iq.j].supernova and \
417 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
419 def tryexit(enemy, look, irun):
420 "A bad guy attempts to bug out."
422 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
423 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
424 if not welcoming(iq):
426 if enemy.type == 'R':
427 return False; # Romulans cannot escape!
429 # avoid intruding on another commander's territory
430 if enemy.type == 'C':
431 if iq in game.state.kcmdr:
433 # refuse to leave if currently attacking starbase
434 if game.battle == game.quadrant:
436 # don't leave if over 1000 units of energy
437 if enemy.power > 1000.0:
439 # emit escape message and move out of quadrant.
440 # we know this if either short or long range sensors are working
441 if not damaged(DSRSENS) or not damaged(DLRSENS) or \
442 game.condition == "docked":
443 prout(crmena(True, enemy.type, "sector", enemy.location) + \
444 (_(" escapes to Quadrant %s (and regains strength).") % iq))
445 # handle local matters related to escape
448 if game.condition != "docked":
450 # Handle global matters related to escape
451 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
452 game.state.galaxy[iq.i][iq.j].klingons += 1
457 schedule(FSCMOVE, 0.2777)
461 for cmdr in game.state.kcmdr:
462 if cmdr == game.quadrant:
463 game.state.kcmdr.append(iq)
465 return True; # success
467 # The bad-guy movement algorithm:
469 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
470 # If both are operating full strength, force is 1000. If both are damaged,
471 # force is -1000. Having shields down subtracts an additional 1000.
473 # 2. Enemy has forces equal to the energy of the attacker plus
474 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
475 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
477 # Attacker Initial energy levels (nominal):
478 # Klingon Romulan Commander Super-Commander
479 # Novice 400 700 1200
481 # Good 450 800 1300 1750
482 # Expert 475 850 1350 1875
483 # Emeritus 500 900 1400 2000
484 # VARIANCE 75 200 200 200
486 # Enemy vessels only move prior to their attack. In Novice - Good games
487 # only commanders move. In Expert games, all enemy vessels move if there
488 # is a commander present. In Emeritus games all enemy vessels move.
490 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
491 # forces are 1000 greater than Enterprise.
493 # Agressive action on average cuts the distance between the ship and
494 # the enemy to 1/4 the original.
496 # 4. At lower energy advantage, movement units are proportional to the
497 # advantage with a 650 advantage being to hold ground, 800 to move forward
498 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
500 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
501 # retreat, especially at high skill levels.
503 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
505 def movebaddy(enemy):
506 "Tactical movement for the bad guys."
507 goto = coord(); look = coord()
509 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
510 if game.skill >= SKILL_EXPERT:
511 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
513 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
515 mdist = int(dist1 + 0.5); # Nearest integer distance
516 # If SC, check with spy to see if should hi-tail it
517 if enemy.type=='S' and \
518 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
522 # decide whether to advance, retreat, or hold position
523 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
525 forces += 1000; # Good for enemy if shield is down!
526 if not damaged(DPHASER) or not damaged(DPHOTON):
527 if damaged(DPHASER): # phasers damaged
530 forces -= 0.2*(game.energy - 2500.0)
531 if damaged(DPHOTON): # photon torpedoes damaged
534 forces -= 50.0*game.torps
536 # phasers and photon tubes both out!
539 if forces <= 1000.0 and game.condition != "docked": # Typical situation
540 motion = ((forces + randreal(200))/150.0) - 5.0
542 if forces > 1000.0: # Very strong -- move in for kill
543 motion = (1.0 - randreal())**2 * dist1 + 1.0
544 if game.condition=="docked" and (game.options & OPTION_BASE): # protected by base -- back off !
545 motion -= game.skill*(2.0-randreal()**2)
547 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
548 # don't move if no motion
551 # Limit motion according to skill
552 if abs(motion) > game.skill:
557 # calculate preferred number of steps
558 nsteps = abs(int(motion))
559 if motion > 0 and nsteps > mdist:
560 nsteps = mdist; # don't overshoot
561 if nsteps > QUADSIZE:
562 nsteps = QUADSIZE; # This shouldn't be necessary
564 nsteps = 1; # This shouldn't be necessary
566 proutn("NSTEPS = %d:" % nsteps)
567 # Compute preferred values of delta X and Y
568 m = game.sector - enemy.location
569 if 2.0 * abs(m.i) < abs(m.j):
571 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
573 m = (motion * m).sgn()
574 goto = enemy.location
576 for ll in range(nsteps):
578 proutn(" %d" % (ll+1))
579 # Check if preferred position available
590 attempts = 0; # Settle mysterious hang problem
591 while attempts < 20 and not success:
593 if look.i < 0 or look.i >= QUADSIZE:
594 if motion < 0 and tryexit(enemy, look, irun):
596 if krawli == m.i or m.j == 0:
598 look.i = goto.i + krawli
600 elif look.j < 0 or look.j >= QUADSIZE:
601 if motion < 0 and tryexit(enemy, look, irun):
603 if krawlj == m.j or m.i == 0:
605 look.j = goto.j + krawlj
607 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
608 # See if enemy should ram ship
609 if game.quad[look.i][look.j] == game.ship and \
610 (enemy.type == 'C' or enemy.type == 'S'):
611 collision(rammed=True, enemy=enemy)
613 if krawli != m.i and m.j != 0:
614 look.i = goto.i + krawli
616 elif krawlj != m.j and m.i != 0:
617 look.j = goto.j + krawlj
620 break; # we have failed
632 if not damaged(DSRSENS) or game.condition == "docked":
633 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
634 if enemy.kdist < dist1:
635 proutn(_(" advances to "))
637 proutn(_(" retreats to "))
638 prout("Sector %s." % goto)
641 "Sequence Klingon tactical movement."
644 # Figure out which Klingon is the commander (or Supercommander)
646 if game.quadrant in game.state.kcmdr:
647 for enemy in game.enemies:
648 if enemy.type == 'C':
650 if game.state.kscmdr==game.quadrant:
651 for enemy in game.enemies:
652 if enemy.type == 'S':
655 # If skill level is high, move other Klingons and Romulans too!
656 # Move these last so they can base their actions on what the
658 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
659 for enemy in game.enemies:
660 if enemy.type in ('K', 'R'):
662 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
664 def movescom(iq, avoid):
665 "Commander movement helper."
666 # Avoid quadrants with bases if we want to avoid Enterprise
667 if not welcoming(iq) or (avoid and iq in game.state.baseq):
669 if game.justin and not game.iscate:
672 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
673 game.state.kscmdr = iq
674 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
675 if game.state.kscmdr==game.quadrant:
676 # SC has scooted, remove him from current quadrant
681 for enemy in game.enemies:
682 if enemy.type == 'S':
686 if game.condition != "docked":
688 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
689 # check for a helpful planet
690 for i in range(game.inplan):
691 if game.state.planets[i].quadrant == game.state.kscmdr and \
692 game.state.planets[i].crystals == "present":
694 game.state.planets[i].pclass = "destroyed"
695 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
698 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
699 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
700 prout(_(" by the Super-commander.\""))
702 return True; # looks good!
704 def supercommander():
705 "Move the Super Commander."
706 iq = coord(); sc = coord(); ibq = coord(); idelta = coord()
709 prout("== SUPERCOMMANDER")
710 # Decide on being active or passive
711 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 \
712 (game.state.date-game.indate) < 3.0)
713 if not game.iscate and avoid:
714 # compute move away from Enterprise
715 idelta = game.state.kscmdr-game.quadrant
716 if idelta.distance() > 2.0:
718 idelta.i = game.state.kscmdr.j-game.quadrant.j
719 idelta.j = game.quadrant.i-game.state.kscmdr.i
721 # compute distances to starbases
722 if not game.state.baseq:
726 sc = game.state.kscmdr
727 for base in game.state.baseq:
728 basetbl.append((i, (base - sc).distance()))
729 if game.state.baseq > 1:
730 basetbl.sort(lambda x, y: cmp(x[1], y[1]))
731 # look for nearest base without a commander, no Enterprise, and
732 # without too many Klingons, and not already under attack.
733 ifindit = iwhichb = 0
734 for (i2, base) in enumerate(game.state.baseq):
735 i = basetbl[i2][0]; # bug in original had it not finding nearest
736 if base==game.quadrant or base==game.battle or not welcoming(base):
738 # if there is a commander, and no other base is appropriate,
739 # we will take the one with the commander
740 for cmdr in game.state.kcmdr:
741 if base == cmdr and ifindit != 2:
745 else: # no commander -- use this one
750 return # Nothing suitable -- wait until next time
751 ibq = game.state.baseq[iwhichb]
752 # decide how to move toward base
753 idelta = ibq - game.state.kscmdr
754 # Maximum movement is 1 quadrant in either or both axes
755 idelta = idelta.sgn()
756 # try moving in both x and y directions
757 # there was what looked like a bug in the Almy C code here,
758 # but it might be this translation is just wrong.
759 iq = game.state.kscmdr + idelta
760 if not movescom(iq, avoid):
761 # failed -- try some other maneuvers
762 if idelta.i==0 or idelta.j==0:
765 iq.j = game.state.kscmdr.j + 1
766 if not movescom(iq, avoid):
767 iq.j = game.state.kscmdr.j - 1
770 iq.i = game.state.kscmdr.i + 1
771 if not movescom(iq, avoid):
772 iq.i = game.state.kscmdr.i - 1
775 # try moving just in x or y
776 iq.j = game.state.kscmdr.j
777 if not movescom(iq, avoid):
778 iq.j = game.state.kscmdr.j + idelta.j
779 iq.i = game.state.kscmdr.i
782 if len(game.state.baseq) == 0:
785 for ibq in game.state.baseq:
786 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
789 return # no, don't attack base!
792 schedule(FSCDBAS, randreal(1.0, 3.0))
793 if is_scheduled(FCDBAS):
794 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
795 if not communicating():
799 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
801 prout(_(" reports that it is under attack from the Klingon Super-commander."))
802 proutn(_(" It can survive until stardate %d.\"") \
803 % int(scheduled(FSCDBAS)))
806 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
810 game.optime = 0.0; # actually finished
812 # Check for intelligence report
813 if not game.idebug and \
815 (not communicating()) or \
816 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
819 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
820 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
825 if not game.tholian or game.justin:
828 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
829 tid.i = 0; tid.j = QUADSIZE-1
830 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
831 tid.i = QUADSIZE-1; tid.j = QUADSIZE-1
832 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
833 tid.i = QUADSIZE-1; tid.j = 0
834 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
837 # something is wrong!
838 game.tholian.move(None)
839 prout("***Internal error: Tholian in a bad spot.")
841 # do nothing if we are blocked
842 if game.quad[tid.i][tid.j] not in ('.', '#'):
844 here = copy.copy(game.tholian.location)
845 delta = (tid - game.tholian.location).sgn()
847 while here.i != tid.i:
849 if game.quad[here.i][here.j]=='.':
850 game.tholian.move(here)
852 while here.j != tid.j:
854 if game.quad[here.i][here.j]=='.':
855 game.tholian.move(here)
856 # check to see if all holes plugged
857 for i in range(QUADSIZE):
858 if game.quad[0][i]!='#' and game.quad[0][i]!='T':
860 if game.quad[QUADSIZE-1][i]!='#' and game.quad[QUADSIZE-1][i]!='T':
862 if game.quad[i][0]!='#' and game.quad[i][0]!='T':
864 if game.quad[i][QUADSIZE-1]!='#' and game.quad[i][QUADSIZE-1]!='T':
866 # All plugged up -- Tholian splits
867 game.quad[game.tholian.location.i][game.tholian.location.j]='#'
869 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
870 game.tholian.move(None)
873 # Code from battle.c begins here
875 def doshield(shraise):
876 "Change shield status."
884 if scanner.sees("transfer"):
888 prout(_("Shields damaged and down."))
890 if scanner.sees("up"):
892 elif scanner.sees("down"):
895 proutn(_("Do you wish to change shield energy? "))
898 elif damaged(DSHIELD):
899 prout(_("Shields damaged and down."))
902 proutn(_("Shields are up. Do you want them down? "))
909 proutn(_("Shields are down. Do you want them up? "))
915 if action == "SHUP": # raise shields
917 prout(_("Shields already up."))
921 if game.condition != "docked":
923 prout(_("Shields raised."))
926 prout(_("Shields raising uses up last of energy."))
931 elif action == "SHDN":
933 prout(_("Shields already down."))
937 prout(_("Shields lowered."))
940 elif action == "NRG":
941 while scanner.next() != "IHREAL":
943 proutn(_("Energy to transfer to shields- "))
948 if nrg > game.energy:
949 prout(_("Insufficient ship energy."))
952 if game.shield+nrg >= game.inshld:
953 prout(_("Shield energy maximized."))
954 if game.shield+nrg > game.inshld:
955 prout(_("Excess energy requested returned to ship energy"))
956 game.energy -= game.inshld-game.shield
957 game.shield = game.inshld
959 if nrg < 0.0 and game.energy-nrg > game.inenrg:
960 # Prevent shield drain loophole
962 prout(_("Engineering to bridge--"))
963 prout(_(" Scott here. Power circuit problem, Captain."))
964 prout(_(" I can't drain the shields."))
967 if game.shield+nrg < 0:
968 prout(_("All shield energy transferred to ship."))
969 game.energy += game.shield
972 proutn(_("Scotty- \""))
974 prout(_("Transferring energy to shields.\""))
976 prout(_("Draining energy from shields.\""))
982 "Choose a device to damage, at random."
984 105, # DSRSENS: short range scanners 10.5%
985 105, # DLRSENS: long range scanners 10.5%
986 120, # DPHASER: phasers 12.0%
987 120, # DPHOTON: photon torpedoes 12.0%
988 25, # DLIFSUP: life support 2.5%
989 65, # DWARPEN: warp drive 6.5%
990 70, # DIMPULS: impulse engines 6.5%
991 145, # DSHIELD: deflector shields 14.5%
992 30, # DRADIO: subspace radio 3.0%
993 45, # DSHUTTL: shuttle 4.5%
994 15, # DCOMPTR: computer 1.5%
995 20, # NAVCOMP: navigation system 2.0%
996 75, # DTRANSP: transporter 7.5%
997 20, # DSHCTRL: high-speed shield controller 2.0%
998 10, # DDRAY: death ray 1.0%
999 30, # DDSP: deep-space probes 3.0%
1001 assert(sum(weights) == 1000)
1002 idx = randrange(1000)
1004 for (i, w) in enumerate(weights):
1008 return None; # we should never get here
1010 def collision(rammed, enemy):
1011 "Collision handling fot rammong events."
1012 prouts(_("***RED ALERT! RED ALERT!"))
1014 prout(_("***COLLISION IMMINENT."))
1018 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1020 proutn(_(" rammed by "))
1023 proutn(crmena(False, enemy.type, "sector", enemy.location))
1025 proutn(_(" (original position)"))
1027 deadkl(enemy.location, enemy.type, game.sector)
1028 proutn("***" + crmshp() + " heavily damaged.")
1029 icas = randrange(10, 30)
1030 prout(_("***Sickbay reports %d casualties") % icas)
1032 game.state.crew -= icas
1033 # In the pre-SST2K version, all devices got equiprobably damaged,
1034 # which was silly. Instead, pick up to half the devices at
1035 # random according to our weighting table,
1036 ncrits = randrange(NDEVICES/2)
1040 if game.damage[dev] < 0:
1042 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1043 # Damage for at least time of travel!
1044 game.damage[dev] += game.optime + extradm
1046 prout(_("***Shields are down."))
1047 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1054 def torpedo(origin, bearing, dispersion, number, nburst):
1055 "Let a photon torpedo fly"
1056 if not damaged(DSRSENS) or game.condition=="docked":
1057 setwnd(srscan_window)
1059 setwnd(message_window)
1060 ac = bearing + 0.25*dispersion # dispersion is a random variable
1061 bullseye = (15.0 - bearing)*0.5235988
1062 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1063 bumpto = coord(0, 0)
1064 # Loop to move a single torpedo
1065 setwnd(message_window)
1066 for step in range(1, QUADSIZE*2):
1067 if not track.next(): break
1069 if not w.valid_sector():
1071 iquad=game.quad[w.i][w.j]
1072 tracktorpedo(origin, w, step, number, nburst, iquad)
1076 if not damaged(DSRSENS) or game.condition == "docked":
1077 skip(1); # start new line after text track
1078 if iquad in ('E', 'F'): # Hit our ship
1080 prout(_("Torpedo hits %s.") % crmshp())
1081 hit = 700.0 + randreal(100) - \
1082 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1083 newcnd(); # we're blown out of dock
1084 if game.landed or game.condition=="docked":
1085 return hit # Cheat if on a planet
1086 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1087 # is 143 degrees, which is almost exactly 4.8 clockface units
1088 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1090 bumpto = displacement.sector()
1091 if not bumpto.valid_sector():
1093 if game.quad[bumpto.i][bumpto.j]==' ':
1096 if game.quad[bumpto.i][bumpto.j]!='.':
1097 # can't move into object
1099 game.sector = bumpto
1101 game.quad[w.i][w.j]='.'
1102 game.quad[bumpto.i][bumpto.j]=iquad
1103 prout(_(" displaced by blast to Sector %s ") % bumpto)
1104 for enemy in game.enemies:
1105 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1106 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1108 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1110 if iquad in ('C', 'S') and withprob(0.05):
1111 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1112 prout(_(" torpedo neutralized."))
1114 for enemy in game.enemies:
1115 if w == enemy.location:
1117 kp = math.fabs(enemy.power)
1118 h1 = 700.0 + randrange(100) - \
1119 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1127 if enemy.power == 0:
1130 proutn(crmena(True, iquad, "sector", w))
1131 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1133 bumpto = displacement.sector()
1134 if not bumpto.valid_sector():
1135 prout(_(" damaged but not destroyed."))
1137 if game.quad[bumpto.i][bumpto.j] == ' ':
1138 prout(_(" buffeted into black hole."))
1139 deadkl(w, iquad, bumpto)
1140 if game.quad[bumpto.i][bumpto.j] != '.':
1141 prout(_(" damaged but not destroyed."))
1143 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1144 enemy.location = bumpto
1145 game.quad[w.i][w.j]='.'
1146 game.quad[bumpto.i][bumpto.j]=iquad
1147 for enemy in game.enemies:
1148 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1149 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1151 elif iquad == 'B': # Hit a base
1153 prout(_("***STARBASE DESTROYED.."))
1154 game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
1155 game.quad[w.i][w.j]='.'
1156 game.base.invalidate()
1157 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1
1158 game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1
1159 game.state.basekl += 1
1162 elif iquad == 'P': # Hit a planet
1163 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1164 game.state.nplankl += 1
1165 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1166 game.iplnet.pclass = "destroyed"
1168 game.plnet.invalidate()
1169 game.quad[w.i][w.j] = '.'
1171 # captain perishes on planet
1174 elif iquad == '@': # Hit an inhabited world -- very bad!
1175 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1176 game.state.nworldkl += 1
1177 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1178 game.iplnet.pclass = "destroyed"
1180 game.plnet.invalidate()
1181 game.quad[w.i][w.j] = '.'
1183 # captain perishes on planet
1185 prout(_("The torpedo destroyed an inhabited planet."))
1187 elif iquad == '*': # Hit a star
1191 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1193 elif iquad == '?': # Hit a thingy
1194 if not (game.options & OPTION_THINGY) or withprob(0.3):
1196 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1198 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1200 proutn(_("Mr. Spock-"))
1201 prouts(_(" \"Fascinating!\""))
1205 # Stas Sergeev added the possibility that
1206 # you can shove the Thingy and piss it off.
1207 # It then becomes an enemy and may fire at you.
1210 elif iquad == ' ': # Black hole
1212 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1214 elif iquad == '#': # hit the web
1216 prout(_("***Torpedo absorbed by Tholian web."))
1218 elif iquad == 'T': # Hit a Tholian
1219 h1 = 700.0 + randrange(100) - \
1220 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle))
1223 game.quad[w.i][w.j] = '.'
1228 proutn(crmena(True, 'T', "sector", w))
1230 prout(_(" survives photon blast."))
1232 prout(_(" disappears."))
1233 game.tholian.move(None)
1234 game.quad[w.i][w.j] = '#'
1239 proutn("Don't know how to handle torpedo collision with ")
1240 proutn(crmena(True, iquad, "sector", w))
1245 prout(_("Torpedo missed."))
1249 "Critical-hit resolution."
1250 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1252 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1253 proutn(_("***CRITICAL HIT--"))
1254 # Select devices and cause damage
1260 # Cheat to prevent shuttle damage unless on ship
1261 if not (game.damage[j]<0.0 or (j==DSHUTTL and game.iscraft != "onship")):
1264 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1265 game.damage[j] += extradm
1267 for (i, j) in enumerate(cdam):
1269 if skipcount % 3 == 2 and i < len(cdam)-1:
1274 prout(_(" damaged."))
1275 if damaged(DSHIELD) and game.shldup:
1276 prout(_("***Shields knocked down."))
1279 def attack(torps_ok):
1280 # bad guy attacks us
1281 # torps_ok == False forces use of phasers in an attack
1282 # game could be over at this point, check
1285 attempt = False; ihurt = False;
1286 hitmax=0.0; hittot=0.0; chgfac=1.0
1289 prout("=== ATTACK!")
1290 # Tholian gets to move before attacking
1293 # if you have just entered the RNZ, you'll get a warning
1294 if game.neutz: # The one chance not to be attacked
1297 # commanders get a chance to tac-move towards you
1298 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:
1300 # if no enemies remain after movement, we're done
1301 if len(game.enemies)==0 or (len(game.enemies)==1 and thing == game.quadrant and not thing.angry):
1303 # set up partial hits if attack happens during shield status change
1304 pfac = 1.0/game.inshld
1306 chgfac = 0.25 + randreal(0.5)
1308 # message verbosity control
1309 if game.skill <= SKILL_FAIR:
1311 for enemy in game.enemies:
1313 continue; # too weak to attack
1314 # compute hit strength and diminish shield power
1316 # Increase chance of photon torpedos if docked or enemy energy is low
1317 if game.condition == "docked":
1319 if enemy.power < 500:
1321 if enemy.type=='T' or (enemy.type=='?' and not thing.angry):
1323 # different enemies have different probabilities of throwing a torp
1324 usephasers = not torps_ok or \
1325 (enemy.type == 'K' and r > 0.0005) or \
1326 (enemy.type=='C' and r > 0.015) or \
1327 (enemy.type=='R' and r > 0.3) or \
1328 (enemy.type=='S' and r > 0.07) or \
1329 (enemy.type=='?' and r > 0.05)
1330 if usephasers: # Enemy uses phasers
1331 if game.condition == "docked":
1332 continue; # Don't waste the effort!
1333 attempt = True; # Attempt to attack
1334 dustfac = randreal(0.8, 0.85)
1335 hit = enemy.power*math.pow(dustfac,enemy.kavgd)
1337 else: # Enemy uses photon torpedo
1338 # We should be able to make the bearing() method work here
1339 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1341 proutn(_("***TORPEDO INCOMING"))
1342 if not damaged(DSRSENS):
1343 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1346 dispersion = (randreal()+randreal())*0.5 - 0.5
1347 dispersion += 0.002*enemy.power*dispersion
1348 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1349 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1350 finish(FWON); # Klingons did themselves in!
1351 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1352 return # Supernova or finished
1355 # incoming phaser or torpedo, shields may dissipate it
1356 if game.shldup or game.shldchg or game.condition=="docked":
1357 # shields will take hits
1358 propor = pfac * game.shield
1359 if game.condition =="docked":
1363 hitsh = propor*chgfac*hit+1.0
1365 if absorb > game.shield:
1366 absorb = game.shield
1367 game.shield -= absorb
1369 # taking a hit blasts us out of a starbase dock
1370 if game.condition == "docked":
1372 # but the shields may take care of it
1373 if propor > 0.1 and hit < 0.005*game.energy:
1375 # hit from this opponent got through shields, so take damage
1377 proutn(_("%d unit hit") % int(hit))
1378 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1379 proutn(_(" on the ") + crmshp())
1380 if not damaged(DSRSENS) and usephasers:
1381 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1383 # Decide if hit is critical
1389 if game.energy <= 0:
1390 # Returning home upon your shield, not with it...
1393 if not attempt and game.condition == "docked":
1394 prout(_("***Enemies decide against attacking your ship."))
1395 percent = 100.0*pfac*game.shield+0.5
1397 # Shields fully protect ship
1398 proutn(_("Enemy attack reduces shield strength to "))
1400 # Emit message if starship suffered hit(s)
1402 proutn(_("Energy left %2d shields ") % int(game.energy))
1405 elif not damaged(DSHIELD):
1408 proutn(_("damaged, "))
1409 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1410 # Check if anyone was hurt
1411 if hitmax >= 200 or hittot >= 500:
1412 icas = randrange(int(hittot * 0.015))
1415 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1416 prout(_(" in that last attack.\""))
1418 game.state.crew -= icas
1419 # After attack, reset average distance to enemies
1420 for enemy in game.enemies:
1421 enemy.kavgd = enemy.kdist
1422 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1425 def deadkl(w, type, mv):
1426 "Kill a Klingon, Tholian, Romulan, or Thingy."
1427 # Added mv to allow enemy to "move" before dying
1428 proutn(crmena(True, type, "sector", mv))
1429 # Decide what kind of enemy it is and update appropriately
1431 # Chalk up a Romulan
1432 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1434 game.state.nromrem -= 1
1443 # Killed some type of Klingon
1444 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1447 game.state.kcmdr.remove(game.quadrant)
1449 if game.state.kcmdr:
1450 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1451 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1454 game.state.remkl -= 1
1456 game.state.nscrem -= 1
1457 game.state.kscmdr.invalidate()
1462 # For each kind of enemy, finish message to player
1463 prout(_(" destroyed."))
1464 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1467 # Remove enemy ship from arrays describing local conditions
1468 for e in game.enemies:
1475 "Return None if target is invalid, otherwise return a course angle."
1476 if not w.valid_sector():
1480 # FIXME: C code this was translated from is wacky -- why the sign reversal?
1481 delta.j = (w.j - game.sector.j);
1482 delta.i = (game.sector.i - w.i);
1483 if delta == coord(0, 0):
1485 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1486 prout(_(" I recommend an immediate review of"))
1487 prout(_(" the Captain's psychological profile.\""))
1490 return delta.bearing()
1493 "Launch photon torpedo salvo."
1496 if damaged(DPHOTON):
1497 prout(_("Photon tubes damaged."))
1501 prout(_("No torpedoes left."))
1504 # First, get torpedo count
1507 if scanner.token == "IHALPHA":
1510 elif scanner.token == "IHEOL" or not scanner.waiting():
1511 prout(_("%d torpedoes left.") % game.torps)
1513 proutn(_("Number of torpedoes to fire- "))
1514 continue # Go back around to get a number
1515 else: # key == "IHREAL"
1517 if n <= 0: # abort command
1522 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1525 scanner.chew() # User requested more torps than available
1526 continue # Go back around
1527 break # All is good, go to next stage
1531 key = scanner.next()
1532 if i==0 and key == "IHEOL":
1533 break; # no coordinate waiting, we will try prompting
1534 if i==1 and key == "IHEOL":
1535 # direct all torpedoes at one target
1537 target.append(target[0])
1538 tcourse.append(tcourse[0])
1541 scanner.push(scanner.token)
1542 target.append(scanner.getcoord())
1543 if target[-1] == None:
1545 tcourse.append(targetcheck(target[-1]))
1546 if tcourse[-1] == None:
1549 if len(target) == 0:
1550 # prompt for each one
1552 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1554 target.append(scanner.getcoord())
1555 if target[-1] == None:
1557 tcourse.append(targetcheck(target[-1]))
1558 if tcourse[-1] == None:
1561 # Loop for moving <n> torpedoes
1563 if game.condition != "docked":
1565 dispersion = (randreal()+randreal())*0.5 -0.5
1566 if math.fabs(dispersion) >= 0.47:
1568 dispersion *= randreal(1.2, 2.2)
1570 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1572 prouts(_("***TORPEDO MISFIRES."))
1575 prout(_(" Remainder of burst aborted."))
1577 prout(_("***Photon tubes damaged by misfire."))
1578 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1580 if game.shldup or game.condition == "docked":
1581 dispersion *= 1.0 + 0.0001*game.shield
1582 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1583 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1585 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1589 "Check for phasers overheating."
1591 checkburn = (rpow-1500.0)*0.00038
1592 if withprob(checkburn):
1593 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1594 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1596 def checkshctrl(rpow):
1597 "Check shield control."
1600 prout(_("Shields lowered."))
1602 # Something bad has happened
1603 prouts(_("***RED ALERT! RED ALERT!"))
1605 hit = rpow*game.shield/game.inshld
1606 game.energy -= rpow+hit*0.8
1607 game.shield -= hit*0.2
1608 if game.energy <= 0.0:
1609 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1614 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1616 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1617 icas = randrange(int(hit*0.012))
1622 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1623 prout(_(" %d casualties so far.\"") % icas)
1625 game.state.crew -= icas
1627 prout(_("Phaser energy dispersed by shields."))
1628 prout(_("Enemy unaffected."))
1633 "Register a phaser hit on Klingons and Romulans."
1637 for (k, wham) in enumerate(hits):
1640 dustfac = randreal(0.9, 1.0)
1641 hit = wham*math.pow(dustfac,game.enemies[kk].kdist)
1642 kpini = game.enemies[kk].power
1643 kp = math.fabs(kpini)
1644 if PHASEFAC*hit < kp:
1646 if game.enemies[kk].power < 0:
1647 game.enemies[kk].power -= -kp
1649 game.enemies[kk].power -= kp
1650 kpow = game.enemies[kk].power
1651 w = game.enemies[kk].location
1653 if not damaged(DSRSENS):
1655 proutn(_("%d unit hit on ") % int(hit))
1657 proutn(_("Very small hit on "))
1658 ienm = game.quad[w.i][w.j]
1661 proutn(crmena(False, ienm, "sector", w))
1665 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1669 kk -= 1 # don't do the increment
1671 else: # decide whether or not to emasculate klingon
1672 if kpow>0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1673 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1674 prout(_(" has just lost its firepower.\""))
1675 game.enemies[kk].power = -kpow
1680 "Fire phasers at bad guys."
1682 kz = 0; k = 1; irec=0 # Cheating inhibitor
1683 ifast = False; no = False; itarg = True; msgflag = True; rpow=0
1687 # SR sensors and Computer are needed for automode
1688 if damaged(DSRSENS) or damaged(DCOMPTR):
1690 if game.condition == "docked":
1691 prout(_("Phasers can't be fired through base shields."))
1694 if damaged(DPHASER):
1695 prout(_("Phaser control damaged."))
1699 if damaged(DSHCTRL):
1700 prout(_("High speed shield control damaged."))
1703 if game.energy <= 200.0:
1704 prout(_("Insufficient energy to activate high-speed shield control."))
1707 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1709 # Original code so convoluted, I re-did it all
1710 # (That was Tom Almy talking about the C code, I think -- ESR)
1711 while automode=="NOTSET":
1713 if key == "IHALPHA":
1714 if scanner.sees("manual"):
1715 if len(game.enemies)==0:
1716 prout(_("There is no enemy present to select."))
1719 automode="AUTOMATIC"
1722 key = scanner.next()
1723 elif scanner.sees("automatic"):
1724 if (not itarg) and len(game.enemies) != 0:
1725 automode = "FORCEMAN"
1727 if len(game.enemies)==0:
1728 prout(_("Energy will be expended into space."))
1729 automode = "AUTOMATIC"
1730 key = scanner.next()
1731 elif scanner.sees("no"):
1736 elif key == "IHREAL":
1737 if len(game.enemies)==0:
1738 prout(_("Energy will be expended into space."))
1739 automode = "AUTOMATIC"
1741 automode = "FORCEMAN"
1743 automode = "AUTOMATIC"
1746 if len(game.enemies)==0:
1747 prout(_("Energy will be expended into space."))
1748 automode = "AUTOMATIC"
1750 automode = "FORCEMAN"
1752 proutn(_("Manual or automatic? "))
1757 if automode == "AUTOMATIC":
1758 if key == "IHALPHA" and scanner.sees("no"):
1760 key = scanner.next()
1761 if key != "IHREAL" and len(game.enemies) != 0:
1762 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1767 for i in range(len(game.enemies)):
1768 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1770 proutn(_("%d units required. ") % irec)
1772 proutn(_("Units to fire= "))
1773 key = scanner.next()
1778 proutn(_("Energy available= %.2f") % avail)
1781 if not rpow > avail:
1788 if key == "IHALPHA" and scanner.sees("no"):
1791 game.energy -= 200; # Go and do it!
1792 if checkshctrl(rpow):
1797 if len(game.enemies):
1800 for i in range(len(game.enemies)):
1804 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))
1805 over = randreal(1.01, 1.06) * hits[i]
1807 powrem -= hits[i] + over
1808 if powrem <= 0 and temp < hits[i]:
1817 if extra > 0 and not game.alldone:
1819 proutn(_("*** Tholian web absorbs "))
1820 if len(game.enemies)>0:
1821 proutn(_("excess "))
1822 prout(_("phaser energy."))
1824 prout(_("%d expended on empty space.") % int(extra))
1825 elif automode == "FORCEMAN":
1828 if damaged(DCOMPTR):
1829 prout(_("Battle computer damaged, manual fire only."))
1832 prouts(_("---WORKING---"))
1834 prout(_("Short-range-sensors-damaged"))
1835 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1836 prout(_("Manual-fire-must-be-used"))
1838 elif automode == "MANUAL":
1840 for k in range(len(game.enemies)):
1841 aim = game.enemies[k].location
1842 ienm = game.quad[aim.i][aim.j]
1844 proutn(_("Energy available= %.2f") % (avail-0.006))
1848 if damaged(DSRSENS) and \
1849 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1850 prout(cramen(ienm) + _(" can't be located without short range scan."))
1853 hits[k] = 0; # prevent overflow -- thanks to Alexei Voitenko
1858 if itarg and k > kz:
1859 irec=(abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9,game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1862 if not damaged(DCOMPTR):
1867 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1868 key = scanner.next()
1869 if key == "IHALPHA" and scanner.sees("no"):
1871 key = scanner.next()
1873 if key == "IHALPHA":
1877 if k==1: # Let me say I'm baffled by this
1880 if scanner.real < 0:
1884 hits[k] = scanner.real
1885 rpow += scanner.real
1886 # If total requested is too much, inform and start over
1888 prout(_("Available energy exceeded -- try again."))
1891 key = scanner.next(); # scan for next value
1894 # zero energy -- abort
1897 if key == "IHALPHA" and scanner.sees("no"):
1902 game.energy -= 200.0
1903 if checkshctrl(rpow):
1907 # Say shield raised or malfunction, if necessary
1914 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1915 prouts(_(" CLICK CLICK POP . . ."))
1916 prout(_(" No response, sir!"))
1919 prout(_("Shields raised."))
1924 # Code from events,c begins here.
1926 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1927 # event of each type active at any given time. Mostly these means we can
1928 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1929 # BSD Trek, from which we swiped the idea, can have up to 5.
1931 def unschedule(evtype):
1932 "Remove an event from the schedule."
1933 game.future[evtype].date = FOREVER
1934 return game.future[evtype]
1936 def is_scheduled(evtype):
1937 "Is an event of specified type scheduled."
1938 return game.future[evtype].date != FOREVER
1940 def scheduled(evtype):
1941 "When will this event happen?"
1942 return game.future[evtype].date
1944 def schedule(evtype, offset):
1945 "Schedule an event of specified type."
1946 game.future[evtype].date = game.state.date + offset
1947 return game.future[evtype]
1949 def postpone(evtype, offset):
1950 "Postpone a scheduled event."
1951 game.future[evtype].date += offset
1954 "Rest period is interrupted by event."
1957 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
1959 game.resting = False
1965 "Run through the event queue looking for things to do."
1967 fintim = game.state.date + game.optime; yank=0
1968 ictbeam = False; istract = False
1969 w = coord(); hold = coord()
1970 ev = event(); ev2 = event()
1972 def tractorbeam(yank):
1973 "Tractor-beaming cases merge here."
1975 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
1977 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
1978 # If Kirk & Co. screwing around on planet, handle
1979 atover(True) # atover(true) is Grab
1982 if game.icraft: # Caught in Galileo?
1985 # Check to see if shuttle is aboard
1986 if game.iscraft == "offship":
1989 prout(_("Galileo, left on the planet surface, is captured"))
1990 prout(_("by aliens and made into a flying McDonald's."))
1991 game.damage[DSHUTTL] = -10
1992 game.iscraft = "removed"
1994 prout(_("Galileo, left on the planet surface, is well hidden."))
1996 game.quadrant = game.state.kscmdr
1998 game.quadrant = game.state.kcmdr[i]
1999 game.sector = randplace(QUADSIZE)
2000 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2001 % (game.quadrant, game.sector))
2003 prout(_("(Remainder of rest/repair period cancelled.)"))
2004 game.resting = False
2006 if not damaged(DSHIELD) and game.shield > 0:
2007 doshield(shraise=True) # raise shields
2008 game.shldchg = False
2010 prout(_("(Shields not currently useable.)"))
2012 # Adjust finish time to time of tractor beaming
2013 fintim = game.state.date+game.optime
2014 attack(torps_ok=False)
2015 if not game.state.kcmdr:
2018 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2021 "Code merges here for any commander destroying a starbase."
2022 # Not perfect, but will have to do
2023 # Handle case where base is in same quadrant as starship
2024 if game.battle == game.quadrant:
2025 game.state.chart[game.battle.i][game.battle.j].starbase = False
2026 game.quad[game.base.i][game.base.j] = '.'
2027 game.base.invalidate()
2030 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2031 elif game.state.baseq and communicating():
2032 # Get word via subspace radio
2035 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2036 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2038 prout(_("the Klingon Super-Commander"))
2040 prout(_("a Klingon Commander"))
2041 game.state.chart[game.battle.i][game.battle.j].starbase = False
2042 # Remove Starbase from galaxy
2043 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2044 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2046 # reinstate a commander's base attack
2050 game.battle.invalidate()
2052 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2053 for i in range(1, NEVENTS):
2054 if i == FSNOVA: proutn("=== Supernova ")
2055 elif i == FTBEAM: proutn("=== T Beam ")
2056 elif i == FSNAP: proutn("=== Snapshot ")
2057 elif i == FBATTAK: proutn("=== Base Attack ")
2058 elif i == FCDBAS: proutn("=== Base Destroy ")
2059 elif i == FSCMOVE: proutn("=== SC Move ")
2060 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2061 elif i == FDSPROB: proutn("=== Probe Move ")
2062 elif i == FDISTR: proutn("=== Distress Call ")
2063 elif i == FENSLV: proutn("=== Enslavement ")
2064 elif i == FREPRO: proutn("=== Klingon Build ")
2066 prout("%.2f" % (scheduled(i)))
2069 radio_was_broken = damaged(DRADIO)
2072 # Select earliest extraneous event, evcode==0 if no events
2077 for l in range(1, NEVENTS):
2078 if game.future[l].date < datemin:
2081 prout("== Event %d fires" % evcode)
2082 datemin = game.future[l].date
2083 xtime = datemin-game.state.date
2084 game.state.date = datemin
2085 # Decrement Federation resources and recompute remaining time
2086 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2088 if game.state.remtime <=0:
2091 # Any crew left alive?
2092 if game.state.crew <=0:
2095 # Is life support adequate?
2096 if damaged(DLIFSUP) and game.condition != "docked":
2097 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2100 game.lsupres -= xtime
2101 if game.damage[DLIFSUP] <= xtime:
2102 game.lsupres = game.inlsr
2105 if game.condition == "docked":
2107 # Don't fix Deathray here
2108 for l in range(NDEVICES):
2109 if game.damage[l] > 0.0 and l != DDRAY:
2110 if game.damage[l]-repair > 0.0:
2111 game.damage[l] -= repair
2113 game.damage[l] = 0.0
2114 # If radio repaired, update star chart and attack reports
2115 if radio_was_broken and not damaged(DRADIO):
2116 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2117 prout(_(" surveillance reports are coming in."))
2119 if not game.iseenit:
2123 prout(_(" The star chart is now up to date.\""))
2125 # Cause extraneous event EVCODE to occur
2126 game.optime -= xtime
2127 if evcode == FSNOVA: # Supernova
2130 schedule(FSNOVA, expran(0.5*game.intime))
2131 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2133 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2134 if game.state.nscrem == 0 or \
2135 ictbeam or istract or \
2136 game.condition=="docked" or game.isatb==1 or game.iscate:
2138 if game.ientesc or \
2139 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2140 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2141 (damaged(DSHIELD) and \
2142 (game.energy < 2500 or damaged(DPHASER)) and \
2143 (game.torps < 5 or damaged(DPHOTON))):
2145 istract = ictbeam = True
2146 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2149 elif evcode == FTBEAM: # Tractor beam
2150 if not game.state.kcmdr:
2153 i = randrange(len(game.state.kcmdr))
2154 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2155 if istract or game.condition == "docked" or yank == 0:
2156 # Drats! Have to reschedule
2158 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2162 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2163 game.snapsht = copy.deepcopy(game.state)
2164 game.state.snap = True
2165 schedule(FSNAP, expran(0.5 * game.intime))
2166 elif evcode == FBATTAK: # Commander attacks starbase
2167 if not game.state.kcmdr or not game.state.baseq:
2173 for ibq in game.state.baseq:
2174 for cmdr in game.state.kcmdr:
2175 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2178 # no match found -- try later
2179 schedule(FBATTAK, expran(0.3*game.intime))
2184 # commander + starbase combination found -- launch attack
2186 schedule(FCDBAS, randreal(1.0, 4.0))
2187 if game.isatb: # extra time if SC already attacking
2188 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2189 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2190 game.iseenit = False
2191 if not communicating():
2192 continue # No warning :-(
2196 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2197 prout(_(" reports that it is under attack and that it can"))
2198 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2201 elif evcode == FSCDBAS: # Supercommander destroys base
2204 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2205 continue # WAS RETURN!
2207 game.battle = game.state.kscmdr
2209 elif evcode == FCDBAS: # Commander succeeds in destroying base
2212 if not game.state.baseq() \
2213 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2214 game.battle.invalidate()
2216 # find the lucky pair
2217 for cmdr in game.state.kcmdr:
2218 if cmdr == game.battle:
2221 # No action to take after all
2224 elif evcode == FSCMOVE: # Supercommander moves
2225 schedule(FSCMOVE, 0.2777)
2226 if not game.ientesc and not istract and game.isatb != 1 and \
2227 (not game.iscate or not game.justin):
2229 elif evcode == FDSPROB: # Move deep space probe
2230 schedule(FDSPROB, 0.01)
2231 if not game.probe.next():
2232 if not game.probe.quadrant().valid_quadrant() or \
2233 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2234 # Left galaxy or ran into supernova
2238 proutn(_("Lt. Uhura- \"The deep space probe "))
2239 if not game.probe.quadrant().valid_quadrant():
2240 prout(_("has left the galaxy.\""))
2242 prout(_("is no longer transmitting.\""))
2248 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2249 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2251 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2252 chp.klingons = pdest.klingons
2253 chp.starbase = pdest.starbase
2254 chp.stars = pdest.stars
2255 pdest.charted = True
2256 game.probe.moves -= 1 # One less to travel
2257 if game.probe.arrived() and game.isarmed and pdest.stars:
2258 supernova(game.probe) # fire in the hole!
2260 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2262 elif evcode == FDISTR: # inhabited system issues distress call
2264 # try a whole bunch of times to find something suitable
2265 for i in range(100):
2266 # need a quadrant which is not the current one,
2267 # which has some stars which are inhabited and
2268 # not already under attack, which is not
2269 # supernova'ed, and which has some Klingons in it
2270 w = randplace(GALSIZE)
2271 q = game.state.galaxy[w.i][w.j]
2272 if not (game.quadrant == w or q.planet == None or \
2273 not q.planet.inhabited or \
2274 q.supernova or q.status!="secure" or q.klingons<=0):
2277 # can't seem to find one; ignore this call
2279 prout("=== Couldn't find location for distress event.")
2281 # got one!! Schedule its enslavement
2282 ev = schedule(FENSLV, expran(game.intime))
2284 q.status = "distressed"
2285 # tell the captain about it if we can
2287 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2289 prout(_("by a Klingon invasion fleet."))
2292 elif evcode == FENSLV: # starsystem is enslaved
2293 ev = unschedule(FENSLV)
2294 # see if current distress call still active
2295 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2299 q.status = "enslaved"
2301 # play stork and schedule the first baby
2302 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2303 ev2.quadrant = ev.quadrant
2305 # report the disaster if we can
2307 prout(_("Uhura- We've lost contact with starsystem %s") % \
2309 prout(_("in Quadrant %s.\n") % ev.quadrant)
2310 elif evcode == FREPRO: # Klingon reproduces
2311 # If we ever switch to a real event queue, we'll need to
2312 # explicitly retrieve and restore the x and y.
2313 ev = schedule(FREPRO, expran(1.0 * game.intime))
2314 # see if current distress call still active
2315 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2319 if game.state.remkl >=MAXKLGAME:
2320 continue # full right now
2321 # reproduce one Klingon
2324 if game.klhere >= MAXKLQUAD:
2326 # this quadrant not ok, pick an adjacent one
2327 for m.i in range(w.i - 1, w.i + 2):
2328 for m.j in range(w.j - 1, w.j + 2):
2329 if not m.valid_quadrant():
2331 q = game.state.galaxy[m.i][m.j]
2332 # check for this quad ok (not full & no snova)
2333 if q.klingons >= MAXKLQUAD or q.supernova:
2337 continue # search for eligible quadrant failed
2341 game.state.remkl += 1
2343 if game.quadrant == w:
2345 game.enemies.append(newkling())
2346 # recompute time left
2349 if game.quadrant == w:
2350 prout(_("Spock- sensors indicate the Klingons have"))
2351 prout(_("launched a warship from %s.") % q.planet)
2353 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2354 if q.planet != None:
2355 proutn(_("near %s ") % q.planet)
2356 prout(_("in Quadrant %s.") % w)
2362 key = scanner.next()
2365 proutn(_("How long? "))
2370 origTime = delay = scanner.real
2373 if delay >= game.state.remtime or len(game.enemies) != 0:
2374 proutn(_("Are you sure? "))
2377 # Alternate resting periods (events) with attacks
2381 game.resting = False
2382 if not game.resting:
2383 prout(_("%d stardates left.") % int(game.state.remtime))
2385 temp = game.optime = delay
2386 if len(game.enemies):
2387 rtime = randreal(1.0, 2.0)
2391 if game.optime < delay:
2392 attack(torps_ok=False)
2400 # Repair Deathray if long rest at starbase
2401 if origTime-delay >= 9.99 and game.condition == "docked":
2402 game.damage[DDRAY] = 0.0
2403 # leave if quadrant supernovas
2404 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2406 game.resting = False
2411 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2412 newc = coord(); neighbor = coord(); bump = coord(0, 0)
2414 # Wow! We've supernova'ed
2415 supernova(game.quadrant)
2417 # handle initial nova
2418 game.quad[nov.i][nov.j] = '.'
2419 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2420 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2421 game.state.starkl += 1
2422 # Set up queue to recursively trigger adjacent stars
2428 for offset.i in range(-1, 1+1):
2429 for offset.j in range(-1, 1+1):
2430 if offset.j==0 and offset.i==0:
2432 neighbor = start + offset
2433 if not neighbor.valid_sector():
2435 iquad = game.quad[neighbor.i][neighbor.j]
2436 # Empty space ends reaction
2437 if iquad in ('.', '?', ' ', 'T', '#'):
2439 elif iquad == '*': # Affect another star
2441 # This star supernovas
2442 supernova(game.quadrant)
2445 hits.append(neighbor)
2446 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2447 game.state.starkl += 1
2448 proutn(crmena(True, '*', "sector", neighbor))
2450 game.quad[neighbor.i][neighbor.j] = '.'
2452 elif iquad in ('P', '@'): # Destroy planet
2453 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2455 game.state.nplankl += 1
2457 game.state.worldkl += 1
2458 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2459 game.iplnet.pclass = "destroyed"
2461 game.plnet.invalidate()
2465 game.quad[neighbor.i][neighbor.j] = '.'
2466 elif iquad == 'B': # Destroy base
2467 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2468 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2469 game.base.invalidate()
2470 game.state.basekl += 1
2472 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2473 game.quad[neighbor.i][neighbor.j] = '.'
2474 elif iquad in ('E', 'F'): # Buffet ship
2475 prout(_("***Starship buffeted by nova."))
2477 if game.shield >= 2000.0:
2478 game.shield -= 2000.0
2480 diff = 2000.0 - game.shield
2484 prout(_("***Shields knocked out."))
2485 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2487 game.energy -= 2000.0
2488 if game.energy <= 0:
2491 # add in course nova contributes to kicking starship
2492 bump += (game.sector-hits[mm]).sgn()
2493 elif iquad == 'K': # kill klingon
2494 deadkl(neighbor, iquad, neighbor)
2495 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2496 for ll in range(len(game.enemies)):
2497 if game.enemies[ll].location == neighbor:
2499 game.enemies[ll].power -= 800.0 # If firepower is lost, die
2500 if game.enemies[ll].power <= 0.0:
2501 deadkl(neighbor, iquad, neighbor)
2503 newc = neighbor + neighbor - hits[mm]
2504 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2505 if not newc.valid_sector():
2506 # can't leave quadrant
2509 iquad1 = game.quad[newc.i][newc.j]
2511 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2513 deadkl(neighbor, iquad, newc)
2516 # can't move into something else
2519 proutn(_(", buffeted to Sector %s") % newc)
2520 game.quad[neighbor.i][neighbor.j] = '.'
2521 game.quad[newc.i][newc.j] = iquad
2522 game.enemies[ll].move(newc)
2523 # Starship affected by nova -- kick it away.
2525 direc = ncourse[3*(bump.i+1)+bump.j+2]
2530 scourse = course(bearing=direc, distance=dist)
2531 game.optime = course.time(warp=4)
2533 prout(_("Force of nova displaces starship."))
2534 imove(scourse, noattack=True)
2535 game.optime = scourse.time(warp=4)
2539 "Star goes supernova."
2544 # Scheduled supernova -- select star at random.
2547 for nq.i in range(GALSIZE):
2548 for nq.j in range(GALSIZE):
2549 stars += game.state.galaxy[nq.i][nq.j].stars
2551 return # nothing to supernova exists
2552 num = randrange(stars) + 1
2553 for nq.i in range(GALSIZE):
2554 for nq.j in range(GALSIZE):
2555 num -= game.state.galaxy[nq.i][nq.j].stars
2561 proutn("=== Super nova here?")
2564 if not nq == game.quadrant or game.justin:
2565 # it isn't here, or we just entered (treat as enroute)
2568 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2569 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2572 # we are in the quadrant!
2573 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2574 for ns.i in range(QUADSIZE):
2575 for ns.j in range(QUADSIZE):
2576 if game.quad[ns.i][ns.j]=='*':
2583 prouts(_("***RED ALERT! RED ALERT!"))
2585 prout(_("***Incipient supernova detected at Sector %s") % ns)
2586 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2587 proutn(_("Emergency override attempts t"))
2588 prouts("***************")
2592 # destroy any Klingons in supernovaed quadrant
2593 kldead = game.state.galaxy[nq.i][nq.j].klingons
2594 game.state.galaxy[nq.i][nq.j].klingons = 0
2595 if nq == game.state.kscmdr:
2596 # did in the Supercommander!
2597 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2601 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2602 comkills = len(game.state.kcmdr) - len(survivors)
2603 game.state.kcmdr = survivors
2605 if not game.state.kcmdr:
2607 game.state.remkl -= kldead
2608 # destroy Romulans and planets in supernovaed quadrant
2609 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2610 game.state.galaxy[nq.i][nq.j].romulans = 0
2611 game.state.nromrem -= nrmdead
2613 for loop in range(game.inplan):
2614 if game.state.planets[loop].quadrant == nq:
2615 game.state.planets[loop].pclass = "destroyed"
2617 # Destroy any base in supernovaed quadrant
2618 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2619 # If starship caused supernova, tally up destruction
2621 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2622 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2623 game.state.nplankl += npdead
2624 # mark supernova in galaxy and in star chart
2625 if game.quadrant == nq or communicating():
2626 game.state.galaxy[nq.i][nq.j].supernova = True
2627 # If supernova destroys last Klingons give special message
2628 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2631 prout(_("Lucky you!"))
2632 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2635 # if some Klingons remain, continue or die in supernova
2640 # Code from finish.c ends here.
2643 "Self-destruct maneuver. Finish with a BANG!"
2645 if damaged(DCOMPTR):
2646 prout(_("Computer damaged; cannot execute destruct sequence."))
2648 prouts(_("---WORKING---")); skip(1)
2649 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2650 prouts(" 10"); skip(1)
2651 prouts(" 9"); skip(1)
2652 prouts(" 8"); skip(1)
2653 prouts(" 7"); skip(1)
2654 prouts(" 6"); skip(1)
2656 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2658 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2660 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2664 if game.passwd != scanner.token:
2665 prouts(_("PASSWORD-REJECTED;"))
2667 prouts(_("CONTINUITY-EFFECTED"))
2670 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2671 prouts(" 5"); skip(1)
2672 prouts(" 4"); skip(1)
2673 prouts(" 3"); skip(1)
2674 prouts(" 2"); skip(1)
2675 prouts(" 1"); skip(1)
2677 prouts(_("GOODBYE-CRUEL-WORLD"))
2685 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2689 if len(game.enemies) != 0:
2690 whammo = 25.0 * game.energy
2692 while l <= len(game.enemies):
2693 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2694 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2699 "Compute our rate of kils over time."
2700 elapsed = game.state.date - game.indate
2701 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2704 starting = (game.inkling + game.incom + game.inscom)
2705 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2706 return (starting - remaining)/elapsed
2710 badpt = 5.0*game.state.starkl + \
2712 10.0*game.state.nplankl + \
2713 300*game.state.nworldkl + \
2715 100.0*game.state.basekl +\
2717 if game.ship == 'F':
2719 elif game.ship == None:
2724 # end the game, with appropriate notfications
2728 prout(_("It is stardate %.1f.") % game.state.date)
2730 if ifin == FWON: # Game has been won
2731 if game.state.nromrem != 0:
2732 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2735 prout(_("You have smashed the Klingon invasion fleet and saved"))
2736 prout(_("the Federation."))
2741 badpt = 0.0 # Close enough!
2742 # killsPerDate >= RateMax
2743 if game.state.date-game.indate < 5.0 or \
2744 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2746 prout(_("In fact, you have done so well that Starfleet Command"))
2747 if game.skill == SKILL_NOVICE:
2748 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2749 elif game.skill == SKILL_FAIR:
2750 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2751 elif game.skill == SKILL_GOOD:
2752 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2753 elif game.skill == SKILL_EXPERT:
2754 prout(_("promotes you to Commodore Emeritus."))
2756 prout(_("Now that you think you're really good, try playing"))
2757 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2758 elif game.skill == SKILL_EMERITUS:
2760 proutn(_("Computer- "))
2761 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2763 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2765 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2767 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2769 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2771 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2773 prout(_("Now you can retire and write your own Star Trek game!"))
2775 elif game.skill >= SKILL_EXPERT:
2776 if game.thawed and not game.idebug:
2777 prout(_("You cannot get a citation, so..."))
2779 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2783 # Only grant long life if alive (original didn't!)
2785 prout(_("LIVE LONG AND PROSPER."))
2790 elif ifin == FDEPLETE: # Federation Resources Depleted
2791 prout(_("Your time has run out and the Federation has been"))
2792 prout(_("conquered. Your starship is now Klingon property,"))
2793 prout(_("and you are put on trial as a war criminal. On the"))
2794 proutn(_("basis of your record, you are "))
2795 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2796 prout(_("acquitted."))
2798 prout(_("LIVE LONG AND PROSPER."))
2800 prout(_("found guilty and"))
2801 prout(_("sentenced to death by slow torture."))
2805 elif ifin == FLIFESUP:
2806 prout(_("Your life support reserves have run out, and"))
2807 prout(_("you die of thirst, starvation, and asphyxiation."))
2808 prout(_("Your starship is a derelict in space."))
2810 prout(_("Your energy supply is exhausted."))
2812 prout(_("Your starship is a derelict in space."))
2813 elif ifin == FBATTLE:
2814 prout(_("The %s has been destroyed in battle.") % crmshp())
2816 prout(_("Dulce et decorum est pro patria mori."))
2818 prout(_("You have made three attempts to cross the negative energy"))
2819 prout(_("barrier which surrounds the galaxy."))
2821 prout(_("Your navigation is abominable."))
2824 prout(_("Your starship has been destroyed by a nova."))
2825 prout(_("That was a great shot."))
2827 elif ifin == FSNOVAED:
2828 prout(_("The %s has been fried by a supernova.") % crmshp())
2829 prout(_("...Not even cinders remain..."))
2830 elif ifin == FABANDN:
2831 prout(_("You have been captured by the Klingons. If you still"))
2832 prout(_("had a starbase to be returned to, you would have been"))
2833 prout(_("repatriated and given another chance. Since you have"))
2834 prout(_("no starbases, you will be mercilessly tortured to death."))
2835 elif ifin == FDILITHIUM:
2836 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2837 elif ifin == FMATERIALIZE:
2838 prout(_("Starbase was unable to re-materialize your starship."))
2839 prout(_("Sic transit gloria mundi"))
2840 elif ifin == FPHASER:
2841 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2843 prout(_("You and your landing party have been"))
2844 prout(_("converted to energy, disipating through space."))
2845 elif ifin == FMINING:
2846 prout(_("You are left with your landing party on"))
2847 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2849 prout(_("They are very fond of \"Captain Kirk\" soup."))
2851 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2852 elif ifin == FDPLANET:
2853 prout(_("You and your mining party perish."))
2855 prout(_("That was a great shot."))
2858 prout(_("The Galileo is instantly annihilated by the supernova."))
2859 prout(_("You and your mining party are atomized."))
2861 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2862 prout(_("joins the Romulans, wreaking terror on the Federation."))
2863 elif ifin == FPNOVA:
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 == FSTRACTOR:
2869 prout(_("The shuttle craft Galileo is also caught,"))
2870 prout(_("and breaks up under the strain."))
2872 prout(_("Your debris is scattered for millions of miles."))
2873 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2875 prout(_("The mutants attack and kill Spock."))
2876 prout(_("Your ship is captured by Klingons, and"))
2877 prout(_("your crew is put on display in a Klingon zoo."))
2878 elif ifin == FTRIBBLE:
2879 prout(_("Tribbles consume all remaining water,"))
2880 prout(_("food, and oxygen on your ship."))
2882 prout(_("You die of thirst, starvation, and asphyxiation."))
2883 prout(_("Your starship is a derelict in space."))
2885 prout(_("Your ship is drawn to the center of the black hole."))
2886 prout(_("You are crushed into extremely dense matter."))
2888 prout(_("Your last crew member has died."))
2889 if game.ship == 'F':
2891 elif game.ship == 'E':
2894 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2895 goodies = game.state.remres/game.inresor
2896 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2897 if goodies/baddies >= randreal(1.0, 1.5):
2898 prout(_("As a result of your actions, a treaty with the Klingon"))
2899 prout(_("Empire has been signed. The terms of the treaty are"))
2900 if goodies/baddies >= randreal(3.0):
2901 prout(_("favorable to the Federation."))
2903 prout(_("Congratulations!"))
2905 prout(_("highly unfavorable to the Federation."))
2907 prout(_("The Federation will be destroyed."))
2909 prout(_("Since you took the last Klingon with you, you are a"))
2910 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2911 prout(_("statue in your memory. Rest in peace, and try not"))
2912 prout(_("to think about pigeons."))
2917 "Compute player's score."
2918 timused = game.state.date - game.indate
2920 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2922 perdate = killrate()
2923 ithperd = 500*perdate + 0.5
2926 iwon = 100*game.skill
2927 if game.ship == 'E':
2929 elif game.ship == 'F':
2933 iscore = 10*(game.inkling - game.state.remkl) \
2934 + 50*(game.incom - len(game.state.kcmdr)) \
2936 + 20*(game.inrom - game.state.nromrem) \
2937 + 200*(game.inscom - game.state.nscrem) \
2938 - game.state.nromrem \
2943 prout(_("Your score --"))
2944 if game.inrom - game.state.nromrem:
2945 prout(_("%6d Romulans destroyed %5d") %
2946 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
2947 if game.state.nromrem and game.gamewon:
2948 prout(_("%6d Romulans captured %5d") %
2949 (game.state.nromrem, game.state.nromrem))
2950 if game.inkling - game.state.remkl:
2951 prout(_("%6d ordinary Klingons destroyed %5d") %
2952 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
2953 if game.incom - len(game.state.kcmdr):
2954 prout(_("%6d Klingon commanders destroyed %5d") %
2955 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
2956 if game.inscom - game.state.nscrem:
2957 prout(_("%6d Super-Commander destroyed %5d") %
2958 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
2960 prout(_("%6.2f Klingons per stardate %5d") %
2962 if game.state.starkl:
2963 prout(_("%6d stars destroyed by your action %5d") %
2964 (game.state.starkl, -5*game.state.starkl))
2965 if game.state.nplankl:
2966 prout(_("%6d planets destroyed by your action %5d") %
2967 (game.state.nplankl, -10*game.state.nplankl))
2968 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
2969 prout(_("%6d inhabited planets destroyed by your action %5d") %
2970 (game.state.nworldkl, -300*game.state.nworldkl))
2971 if game.state.basekl:
2972 prout(_("%6d bases destroyed by your action %5d") %
2973 (game.state.basekl, -100*game.state.basekl))
2975 prout(_("%6d calls for help from starbase %5d") %
2976 (game.nhelp, -45*game.nhelp))
2978 prout(_("%6d casualties incurred %5d") %
2979 (game.casual, -game.casual))
2981 prout(_("%6d crew abandoned in space %5d") %
2982 (game.abandoned, -3*game.abandoned))
2984 prout(_("%6d ship(s) lost or destroyed %5d") %
2985 (klship, -100*klship))
2987 prout(_("Penalty for getting yourself killed -200"))
2989 proutn(_("Bonus for winning "))
2990 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
2991 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
2992 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
2993 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
2994 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
2995 prout(" %5d" % iwon)
2997 prout(_("TOTAL SCORE %5d") % iscore)
3000 "Emit winner's commemmorative plaque."
3003 proutn(_("File or device name for your plaque: "))
3006 fp = open(winner, "w")
3009 prout(_("Invalid name."))
3011 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3013 # The 38 below must be 64 for 132-column paper
3014 nskip = 38 - len(winner)/2
3015 fp.write("\n\n\n\n")
3016 # --------DRAW ENTERPRISE PICTURE.
3017 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3018 fp.write(" EEE E : : : E\n" )
3019 fp.write(" EE EEE E : : NCC-1701 : E\n")
3020 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3021 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3022 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3023 fp.write(" EEEEEEE EEEEE E E E E\n")
3024 fp.write(" EEE E E E E\n")
3025 fp.write(" E E E E\n")
3026 fp.write(" EEEEEEEEEEEEE E E\n")
3027 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3028 fp.write(" :E : EEEE E\n")
3029 fp.write(" .-E -:----- E\n")
3030 fp.write(" :E : E\n")
3031 fp.write(" EE : EEEEEEEE\n")
3032 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3034 fp.write(_(" U. S. S. ENTERPRISE\n"))
3035 fp.write("\n\n\n\n")
3036 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3038 fp.write(_(" Starfleet Command bestows to you\n"))
3040 fp.write("%*s%s\n\n" % (nskip, "", winner))
3041 fp.write(_(" the rank of\n\n"))
3042 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3044 if game.skill == SKILL_EXPERT:
3045 fp.write(_(" Expert level\n\n"))
3046 elif game.skill == SKILL_EMERITUS:
3047 fp.write(_("Emeritus level\n\n"))
3049 fp.write(_(" Cheat level\n\n"))
3050 timestring = time.ctime()
3051 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3052 (timestring+4, timestring+20, timestring+11))
3053 fp.write(_(" Your score: %d\n\n") % iscore)
3054 fp.write(_(" Klingons per stardate: %.2f\n") % perdate)
3057 # Code from io.c begins here
3059 rows = linecount = 0 # for paging
3062 fullscreen_window = None
3063 srscan_window = None
3064 report_window = None
3065 status_window = None
3066 lrscan_window = None
3067 message_window = None
3068 prompt_window = None
3073 "for some recent versions of python2, the following enables UTF8"
3074 "for the older ones we probably need to set C locale, and the python3"
3075 "has no problems at all"
3076 if sys.version_info[0] < 3:
3078 locale.setlocale(locale.LC_ALL, "")
3079 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3080 gettext.textdomain("sst")
3081 if not (game.options & OPTION_CURSES):
3082 ln_env = os.getenv("LINES")
3088 stdscr = curses.initscr()
3092 if game.options & OPTION_COLOR:
3093 curses.start_color();
3094 curses.use_default_colors()
3095 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1);
3096 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1);
3097 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1);
3098 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1);
3099 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1);
3100 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1);
3101 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1);
3102 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1);
3103 global fullscreen_window, srscan_window, report_window, status_window
3104 global lrscan_window, message_window, prompt_window
3105 (rows, columns) = stdscr.getmaxyx()
3106 fullscreen_window = stdscr
3107 srscan_window = curses.newwin(12, 25, 0, 0)
3108 report_window = curses.newwin(11, 0, 1, 25)
3109 status_window = curses.newwin(10, 0, 1, 39)
3110 lrscan_window = curses.newwin(5, 0, 0, 64)
3111 message_window = curses.newwin(0, 0, 12, 0)
3112 prompt_window = curses.newwin(1, 0, rows-2, 0)
3113 message_window.scrollok(True)
3114 setwnd(fullscreen_window)
3118 if game.options & OPTION_CURSES:
3119 stdscr.keypad(False)
3125 "Wait for user action -- OK to do nothing if on a TTY"
3126 if game.options & OPTION_CURSES:
3131 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3135 if game.skill > SKILL_FAIR:
3136 prompt = _("[CONTINUE?]")
3138 prompt = _("[PRESS ENTER TO CONTINUE]")
3140 if game.options & OPTION_CURSES:
3142 setwnd(prompt_window)
3143 prompt_window.clear()
3144 prompt_window.addstr(prompt)
3145 prompt_window.getstr()
3146 prompt_window.clear()
3147 prompt_window.refresh()
3148 setwnd(message_window)
3151 sys.stdout.write('\n')
3154 for j_unused in range(rows):
3155 sys.stdout.write('\n')
3159 "Skip i lines. Pause game if this would cause a scrolling event."
3160 for dummy in range(i):
3161 if game.options & OPTION_CURSES:
3162 (y, x) = curwnd.getyx()
3163 (my, mx) = curwnd.getmaxyx()
3164 if curwnd == message_window and y >= my - 2:
3170 except curses.error:
3175 if rows and linecount >= rows:
3178 sys.stdout.write('\n')
3181 "Utter a line with no following line feed."
3182 if game.options & OPTION_CURSES:
3186 sys.stdout.write(line)
3196 if not replayfp or replayfp.closed: # Don't slow down replays
3199 if game.options & OPTION_CURSES:
3203 if not replayfp or replayfp.closed:
3207 "Get a line of input."
3208 if game.options & OPTION_CURSES:
3209 line = curwnd.getstr() + "\n"
3212 if replayfp and not replayfp.closed:
3214 line = replayfp.readline()
3217 prout("*** Replay finished")
3220 elif line[0] != "#":
3223 line = raw_input() + "\n"
3229 "Change windows -- OK for this to be a no-op in tty mode."
3231 if game.options & OPTION_CURSES:
3233 curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window)
3236 "Clear to end of line -- can be a no-op in tty mode"
3237 if game.options & OPTION_CURSES:
3242 "Clear screen -- can be a no-op in tty mode."
3244 if game.options & OPTION_CURSES:
3250 def textcolor(color=DEFAULT):
3251 if game.options & OPTION_COLOR:
3252 if color == DEFAULT:
3254 elif color == BLACK:
3255 curwnd.attron(curses.color_pair(curses.COLOR_BLACK));
3257 curwnd.attron(curses.color_pair(curses.COLOR_BLUE));
3258 elif color == GREEN:
3259 curwnd.attron(curses.color_pair(curses.COLOR_GREEN));
3261 curwnd.attron(curses.color_pair(curses.COLOR_CYAN));
3263 curwnd.attron(curses.color_pair(curses.COLOR_RED));
3264 elif color == MAGENTA:
3265 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA));
3266 elif color == BROWN:
3267 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW));
3268 elif color == LIGHTGRAY:
3269 curwnd.attron(curses.color_pair(curses.COLOR_WHITE));
3270 elif color == DARKGRAY:
3271 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD);
3272 elif color == LIGHTBLUE:
3273 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD);
3274 elif color == LIGHTGREEN:
3275 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD);
3276 elif color == LIGHTCYAN:
3277 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD);
3278 elif color == LIGHTRED:
3279 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD);
3280 elif color == LIGHTMAGENTA:
3281 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD);
3282 elif color == YELLOW:
3283 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD);
3284 elif color == WHITE:
3285 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD);
3288 if game.options & OPTION_COLOR:
3289 curwnd.attron(curses.A_REVERSE)
3292 # Things past this point have policy implications.
3296 "Hook to be called after moving to redraw maps."
3297 if game.options & OPTION_CURSES:
3300 setwnd(srscan_window)
3304 setwnd(status_window)
3305 status_window.clear()
3306 status_window.move(0, 0)
3307 setwnd(report_window)
3308 report_window.clear()
3309 report_window.move(0, 0)
3311 setwnd(lrscan_window)
3312 lrscan_window.clear()
3313 lrscan_window.move(0, 0)
3314 lrscan(silent=False)
3316 def put_srscan_sym(w, sym):
3317 "Emit symbol for short-range scan."
3318 srscan_window.move(w.i+1, w.j*2+2)
3319 srscan_window.addch(sym)
3320 srscan_window.refresh()
3323 "Enemy fall down, go boom."
3324 if game.options & OPTION_CURSES:
3326 setwnd(srscan_window)
3327 srscan_window.attron(curses.A_REVERSE)
3328 put_srscan_sym(w, game.quad[w.i][w.j])
3332 srscan_window.attroff(curses.A_REVERSE)
3333 put_srscan_sym(w, game.quad[w.i][w.j])
3334 curses.delay_output(500)
3335 setwnd(message_window)
3338 "Sound and visual effects for teleportation."
3339 if game.options & OPTION_CURSES:
3341 setwnd(message_window)
3343 prouts(" . . . . . ")
3344 if game.options & OPTION_CURSES:
3345 #curses.delay_output(1000)
3349 def tracktorpedo(origin, w, step, i, n, iquad):
3350 "Torpedo-track animation."
3351 if not game.options & OPTION_CURSES:
3355 proutn(_("Track for torpedo number %d- ") % (i+1))
3358 proutn(_("Torpedo track- "))
3359 elif step==4 or step==9:
3363 if not damaged(DSRSENS) or game.condition=="docked":
3364 if i != 0 and step == 1:
3367 if (iquad=='.') or (iquad==' '):
3368 put_srscan_sym(w, '+')
3372 put_srscan_sym(w, iquad)
3374 curwnd.attron(curses.A_REVERSE)
3375 put_srscan_sym(w, iquad)
3379 curwnd.attroff(curses.A_REVERSE)
3380 put_srscan_sym(w, iquad)
3385 "Display the current galaxy chart."
3386 if game.options & OPTION_CURSES:
3387 setwnd(message_window)
3388 message_window.clear()
3390 if game.options & OPTION_TTY:
3395 def prstat(txt, data):
3397 if game.options & OPTION_CURSES:
3399 setwnd(status_window)
3401 proutn(" " * (NSYM - len(txt)))
3404 if game.options & OPTION_CURSES:
3405 setwnd(report_window)
3407 # Code from moving.c begins here
3409 def imove(course=None, noattack=False):
3410 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3413 def newquadrant(noattack):
3414 # Leaving quadrant -- allow final enemy attack
3415 # Don't do it if being pushed by Nova
3416 if len(game.enemies) != 0 and not noattack:
3418 for enemy in game.enemies:
3419 finald = (w - enemy.location).distance()
3420 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3421 # Stas Sergeev added the condition
3422 # that attacks only happen if Klingons
3423 # are present and your skill is good.
3424 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3425 attack(torps_ok=False)
3428 # check for edge of galaxy
3432 if course.final.i < 0:
3433 course.final.i = -course.final.i
3435 if course.final.j < 0:
3436 course.final.j = -course.final.j
3438 if course.final.i >= GALSIZE*QUADSIZE:
3439 course.final.i = (GALSIZE*QUADSIZE*2) - course.final.i
3441 if course.final.j >= GALSIZE*QUADSIZE:
3442 course.final.j = (GALSIZE*QUADSIZE*2) - course.final.j
3450 if game.nkinks == 3:
3451 # Three strikes -- you're out!
3455 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3456 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3457 prout(_("YOU WILL BE DESTROYED."))
3458 # Compute final position in new quadrant
3459 if trbeam: # Don't bother if we are to be beamed
3461 game.quadrant = course.final.quadrant()
3462 game.sector = course.final.sector()
3464 prout(_("Entering Quadrant %s.") % game.quadrant)
3465 game.quad[game.sector.i][game.sector.j] = game.ship
3467 if game.skill>SKILL_NOVICE:
3468 attack(torps_ok=False)
3470 def check_collision(h):
3471 iquad = game.quad[h.i][h.j]
3473 # object encountered in flight path
3474 stopegy = 50.0*course.distance/game.optime
3475 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3476 for enemy in game.enemies:
3477 if enemy.location == game.sector:
3479 collision(rammed=False, enemy=enemy)
3483 prouts(_("***RED ALERT! RED ALERT!"))
3485 proutn("***" + crmshp())
3486 proutn(_(" pulled into black hole at Sector %s") % h)
3487 # Getting pulled into a black hole was certain
3488 # death in Almy's original. Stas Sergeev added a
3489 # possibility that you'll get timewarped instead.
3491 for m in range(NDEVICES):
3492 if game.damage[m]>0:
3494 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3495 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3505 prout(_(" encounters Tholian web at %s;") % h)
3507 prout(_(" blocked by object at %s;") % h)
3508 proutn(_("Emergency stop required "))
3509 prout(_("%2d units of energy.") % int(stopegy))
3510 game.energy -= stopegy
3511 if game.energy <= 0:
3518 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3519 game.inorbit = False
3520 # If tractor beam is to occur, don't move full distance
3521 if game.state.date+game.optime >= scheduled(FTBEAM):
3523 game.condition = "red"
3524 course.distance = course.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3525 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3527 game.quad[game.sector.i][game.sector.j] = '.'
3528 for m in range(course.moves):
3531 if course.origin.quadrant() != course.location.quadrant():
3532 newquadrant(noattack)
3534 elif check_collision(w):
3535 print "Collision detected"
3539 # We're in destination quadrant -- compute new average enemy distances
3540 game.quad[game.sector.i][game.sector.j] = game.ship
3542 for enemy in game.enemies:
3543 finald = (w-enemy.location).distance()
3544 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3545 enemy.kdist = finald
3546 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
3547 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3548 attack(torps_ok=False)
3549 for enemy in game.enemies:
3550 enemy.kavgd = enemy.kdist
3553 setwnd(message_window)
3557 "Dock our ship at a starbase."
3559 if game.condition == "docked" and verbose:
3560 prout(_("Already docked."))
3563 prout(_("You must first leave standard orbit."))
3565 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3566 prout(crmshp() + _(" not adjacent to base."))
3568 game.condition = "docked"
3572 if game.energy < game.inenrg:
3573 game.energy = game.inenrg
3574 game.shield = game.inshld
3575 game.torps = game.intorps
3576 game.lsupres = game.inlsr
3577 game.state.crew = FULLCREW
3578 if not damaged(DRADIO) and \
3579 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3580 # get attack report from base
3581 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3585 def cartesian(loc1=None, loc2=None):
3587 return game.quadrant * QUADSIZE + game.sector
3589 return game.quadrant * QUADSIZE + loc1
3591 return loc1 * QUADSIZE + loc2
3593 def getcourse(isprobe):
3594 "Get a course and distance from the user."
3596 dquad = copy.copy(game.quadrant)
3597 navmode = "unspecified"
3601 if game.landed and not isprobe:
3602 prout(_("Dummy! You can't leave standard orbit until you"))
3603 proutn(_("are back aboard the ship."))
3606 while navmode == "unspecified":
3607 if damaged(DNAVSYS):
3609 prout(_("Computer damaged; manual navigation only"))
3611 prout(_("Computer damaged; manual movement only"))
3616 key = scanner.next()
3618 proutn(_("Manual or automatic- "))
3621 elif key == "IHALPHA":
3622 if scanner.sees("manual"):
3624 key = scanner.next()
3626 elif scanner.sees("automatic"):
3627 navmode = "automatic"
3628 key = scanner.next()
3636 prout(_("(Manual navigation assumed.)"))
3638 prout(_("(Manual movement assumed.)"))
3642 if navmode == "automatic":
3643 while key == "IHEOL":
3645 proutn(_("Target quadrant or quadrant§or- "))
3647 proutn(_("Destination sector or quadrant§or- "))
3650 key = scanner.next()
3654 xi = int(round(scanner.real))-1
3655 key = scanner.next()
3659 xj = int(round(scanner.real))-1
3660 key = scanner.next()
3662 # both quadrant and sector specified
3663 xk = int(round(scanner.real))-1
3664 key = scanner.next()
3668 xl = int(round(scanner.real))-1
3674 # only one pair of numbers was specified
3676 # only quadrant specified -- go to center of dest quad
3679 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3681 # only sector specified
3685 if not dquad.valid_quadrant() or not dsect.valid_sector():
3692 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3694 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3695 # the actual deltas get computed here
3696 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3697 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3699 while key == "IHEOL":
3700 proutn(_("X and Y displacements- "))
3703 key = scanner.next()
3708 delta.j = scanner.real
3709 key = scanner.next()
3713 delta.i = scanner.real
3714 # Check for zero movement
3715 if delta.i == 0 and delta.j == 0:
3718 if itemp == "verbose" and not isprobe:
3720 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3722 return course(bearing=delta.bearing(), distance=delta.distance())
3725 def __init__(self, bearing, distance, origin=None):
3726 self.distance = distance
3727 self.bearing = bearing
3729 self.origin = cartesian(game.quadrant, game.sector)
3731 self.origin = origin
3732 # The bearing() code we inherited from FORTRAN is actually computing
3733 # clockface directions!
3734 if self.bearing < 0.0:
3735 self.bearing += 12.0
3736 self.angle = ((15.0 - self.bearing) * 0.5235988)
3738 self.origin = cartesian(game.quadrant, game.sector)
3740 self.origin = cartesian(game.quadrant, origin)
3741 self.increment = coord(-math.sin(self.angle), math.cos(self.angle))
3742 bigger = max(abs(self.increment.i), abs(self.increment.j))
3743 self.increment /= bigger
3744 self.moves = int(round(10*self.distance*bigger))
3746 self.final = (self.location + self.moves*self.increment).roundtogrid()
3748 self.location = self.origin
3751 return self.location.roundtogrid() == self.final
3753 "Next step on course."
3755 self.nextlocation = self.location + self.increment
3756 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3757 self.location = self.nextlocation
3760 return self.location.quadrant()
3762 return self.location.sector()
3763 def power(self, warp):
3764 return self.distance*(warp**3)*(game.shldup+1)
3765 def time(self, warp):
3766 return 10.0*self.distance/warp**2
3769 "Move under impulse power."
3771 if damaged(DIMPULS):
3774 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3776 if game.energy > 30.0:
3778 course = getcourse(isprobe=False)
3781 power = 20.0 + 100.0*course.distance
3784 if power >= game.energy:
3785 # Insufficient power for trip
3787 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3788 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3789 if game.energy > 30:
3790 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3791 int(0.01 * (game.energy-20.0)-0.05))
3792 prout(_(" quadrants.\""))
3794 prout(_("quadrant. They are, therefore, useless.\""))
3797 # Make sure enough time is left for the trip
3798 game.optime = course.dist/0.095
3799 if game.optime >= game.state.remtime:
3800 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3801 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3802 proutn(_("we dare spend the time?\" "))
3805 # Activate impulse engines and pay the cost
3806 imove(course, noattack=False)
3810 power = 20.0 + 100.0*course.dist
3811 game.energy -= power
3812 game.optime = course.dist/0.095
3813 if game.energy <= 0:
3817 def warp(course, involuntary):
3818 "ove under warp drive."
3819 blooey = False; twarp = False
3820 if not involuntary: # Not WARPX entry
3822 if game.damage[DWARPEN] > 10.0:
3825 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3827 if damaged(DWARPEN) and game.warpfac > 4.0:
3830 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3831 prout(_(" is repaired, I can only give you warp 4.\""))
3833 # Read in course and distance
3836 course = getcourse(isprobe=False)
3839 # Make sure starship has enough energy for the trip
3840 # Note: this formula is slightly different from the C version,
3841 # and lets you skate a bit closer to the edge.
3842 if course.power(game.warpfac) >= game.energy:
3843 # Insufficient power for trip
3846 prout(_("Engineering to bridge--"))
3847 if not game.shldup or 0.5*course.power(game.warpfac) > game.energy:
3848 iwarp = (game.energy/(course.dist+0.05)) ** 0.333333333
3850 prout(_("We can't do it, Captain. We don't have enough energy."))
3852 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3855 prout(_("if you'll lower the shields."))
3859 prout(_("We haven't the energy to go that far with the shields up."))
3861 # Make sure enough time is left for the trip
3862 game.optime = course.time(game.warpfac)
3863 if game.optime >= 0.8*game.state.remtime:
3865 prout(_("First Officer Spock- \"Captain, I compute that such"))
3866 proutn(_(" a trip would require approximately %2.0f") %
3867 (100.0*game.optime/game.state.remtime))
3868 prout(_(" percent of our"))
3869 proutn(_(" remaining time. Are you sure this is wise?\" "))
3875 if game.warpfac > 6.0:
3876 # Decide if engine damage will occur
3877 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3878 prob = course.distance*(6.0-game.warpfac)**2/66.666666666
3879 if prob > randreal():
3881 course.distance = randreal(course.distance)
3882 # Decide if time warp will occur
3883 if 0.5*course.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3885 if game.idebug and game.warpfac==10 and not twarp:
3887 proutn("=== Force time warp? ")
3891 # If time warp or engine damage, check path
3892 # If it is obstructed, don't do warp or damage
3893 for m_unused in range(course.moves):
3896 if not w.valid_sector():
3898 if game.quad[w.i][w.j] != '.':
3902 # Activate Warp Engines and pay the cost
3903 imove(course, noattack=False)
3906 game.energy -= course.power(game.warpfac)
3907 if game.energy <= 0:
3909 game.optime = course.time(game.warpfac)
3913 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
3915 prout(_("Engineering to bridge--"))
3916 prout(_(" Scott here. The warp engines are damaged."))
3917 prout(_(" We'll have to reduce speed to warp 4."))
3922 "Change the warp factor."
3928 proutn(_("Warp factor- "))
3932 if game.damage[DWARPEN] > 10.0:
3933 prout(_("Warp engines inoperative."))
3935 if damaged(DWARPEN) and scanner.real > 4.0:
3936 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
3937 prout(_(" but right now we can only go warp 4.\""))
3939 if scanner.real > 10.0:
3940 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
3942 if scanner.real < 1.0:
3943 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
3945 oldfac = game.warpfac
3946 game.warpfac = scanner.real
3947 if game.warpfac <= oldfac or game.warpfac <= 6.0:
3948 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
3951 if game.warpfac < 8.00:
3952 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
3954 if game.warpfac == 10.0:
3955 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
3957 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
3961 "Cope with being tossed out of quadrant by supernova or yanked by beam."
3963 # is captain on planet?
3965 if damaged(DTRANSP):
3968 prout(_("Scotty rushes to the transporter controls."))
3970 prout(_("But with the shields up it's hopeless."))
3972 prouts(_("His desperate attempt to rescue you . . ."))
3977 prout(_("SUCCEEDS!"))
3980 proutn(_("The crystals mined were "))
3988 # Check to see if captain in shuttle craft
3993 # Inform captain of attempt to reach safety
3997 prouts(_("***RED ALERT! RED ALERT!"))
3999 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4000 prouts(_(" a supernova."))
4002 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4003 prout(_("safely out of quadrant."))
4004 if not damaged(DRADIO):
4005 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4006 # Try to use warp engines
4007 if damaged(DWARPEN):
4009 prout(_("Warp engines damaged."))
4012 game.warpfac = randreal(6.0, 8.0)
4013 prout(_("Warp factor set to %d") % int(game.warpfac))
4014 power = 0.75*game.energy
4015 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4016 dist = max(dist, randreal(math.sqrt(2)))
4017 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4018 game.optime = bugout.time(game.warpfac)
4020 game.inorbit = False
4021 warp(bugout, involuntary=True)
4023 # This is bad news, we didn't leave quadrant.
4027 prout(_("Insufficient energy to leave quadrant."))
4030 # Repeat if another snova
4031 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4033 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4034 finish(FWON) # Snova killed remaining enemy.
4037 "Let's do the time warp again."
4038 prout(_("***TIME WARP ENTERED."))
4039 if game.state.snap and withprob(0.5):
4041 prout(_("You are traveling backwards in time %d stardates.") %
4042 int(game.state.date-game.snapsht.date))
4043 game.state = game.snapsht
4044 game.state.snap = False
4045 if len(game.state.kcmdr):
4046 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4047 schedule(FBATTAK, expran(0.3*game.intime))
4048 schedule(FSNOVA, expran(0.5*game.intime))
4049 # next snapshot will be sooner
4050 schedule(FSNAP, expran(0.25*game.state.remtime))
4052 if game.state.nscrem:
4053 schedule(FSCMOVE, 0.2777)
4057 game.battle.invalidate()
4058 # Make sure Galileo is consistant -- Snapshot may have been taken
4059 # when on planet, which would give us two Galileos!
4061 for l in range(game.inplan):
4062 if game.state.planets[l].known == "shuttle_down":
4064 if game.iscraft == "onship" and game.ship=='E':
4065 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4066 game.iscraft = "offship"
4067 # Likewise, if in the original time the Galileo was abandoned, but
4068 # was on ship earlier, it would have vanished -- let's restore it.
4069 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4070 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4071 game.iscraft = "onship"
4072 # There used to be code to do the actual reconstrction here,
4073 # but the starchart is now part of the snapshotted galaxy state.
4074 prout(_("Spock has reconstructed a correct star chart from memory"))
4076 # Go forward in time
4077 game.optime = expran(0.5*game.intime)
4078 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4079 # cheat to make sure no tractor beams occur during time warp
4080 postpone(FTBEAM, game.optime)
4081 game.damage[DRADIO] += game.optime
4083 events() # Stas Sergeev added this -- do pending events
4086 "Launch deep-space probe."
4087 # New code to launch a deep space probe
4088 if game.nprobes == 0:
4091 if game.ship == 'E':
4092 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4094 prout(_("Ye Faerie Queene has no deep space probes."))
4099 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4101 if is_scheduled(FDSPROB):
4104 if damaged(DRADIO) and game.condition != "docked":
4105 prout(_("Spock- \"Records show the previous probe has not yet"))
4106 prout(_(" reached its destination.\""))
4108 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4110 key = scanner.next()
4112 if game.nprobes == 1:
4113 prout(_("1 probe left."))
4115 prout(_("%d probes left") % game.nprobes)
4116 proutn(_("Are you sure you want to fire a probe? "))
4119 game.isarmed = False
4120 if key == "IHALPHA" and scanner.token == "armed":
4122 key = scanner.next()
4123 elif key == "IHEOL":
4124 proutn(_("Arm NOVAMAX warhead? "))
4126 elif key == "IHREAL": # first element of course
4127 scanner.push(scanner.token)
4129 game.probe = getcourse(isprobe=True)
4133 schedule(FDSPROB, 0.01) # Time to move one sector
4134 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4139 "Yell for help from nearest starbase."
4140 # There's more than one way to move in this game!
4142 # Test for conditions which prevent calling for help
4143 if game.condition == "docked":
4144 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4147 prout(_("Subspace radio damaged."))
4149 if not game.state.baseq:
4150 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4153 prout(_("You must be aboard the %s.") % crmshp())
4155 # OK -- call for help from nearest starbase
4158 # There's one in this quadrant
4159 ddist = (game.base - game.sector).distance()
4162 for ibq in game.state.baseq:
4163 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4166 # Since starbase not in quadrant, set up new quadrant
4169 # dematerialize starship
4170 game.quad[game.sector.i][game.sector.j]='.'
4171 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4172 % (game.quadrant, crmshp()))
4173 game.sector.invalidate()
4174 for m in range(1, 5+1):
4175 w = game.base.scatter()
4176 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4177 # found one -- finish up
4180 if not game.sector.is_valid():
4181 prout(_("You have been lost in space..."))
4182 finish(FMATERIALIZE)
4184 # Give starbase three chances to rematerialize starship
4185 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4186 for m in range(1, 3+1):
4187 if m == 1: proutn(_("1st"))
4188 elif m == 2: proutn(_("2nd"))
4189 elif m == 3: proutn(_("3rd"))
4190 proutn(_(" attempt to re-materialize ") + crmshp())
4191 game.quad[ix][iy]=('-','o','O')[m-1]
4194 if randreal() > probf:
4198 curses.delay_output(500)
4200 game.quad[ix][iy]='?'
4203 setwnd(message_window)
4204 finish(FMATERIALIZE)
4206 game.quad[ix][iy]=game.ship
4208 prout(_("succeeds."))
4212 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4217 if game.condition=="docked":
4219 prout(_("You cannot abandon Ye Faerie Queene."))
4222 # Must take shuttle craft to exit
4223 if game.damage[DSHUTTL]==-1:
4224 prout(_("Ye Faerie Queene has no shuttle craft."))
4226 if game.damage[DSHUTTL]<0:
4227 prout(_("Shuttle craft now serving Big Macs."))
4229 if game.damage[DSHUTTL]>0:
4230 prout(_("Shuttle craft damaged."))
4233 prout(_("You must be aboard the ship."))
4235 if game.iscraft != "onship":
4236 prout(_("Shuttle craft not currently available."))
4238 # Emit abandon ship messages
4240 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4242 prouts(_("***ALL HANDS ABANDON SHIP!"))
4244 prout(_("Captain and crew escape in shuttle craft."))
4245 if not game.state.baseq:
4246 # Oops! no place to go...
4249 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4251 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4252 prout(_("Remainder of ship's complement beam down"))
4253 prout(_("to nearest habitable planet."))
4254 elif q.planet != None and not damaged(DTRANSP):
4255 prout(_("Remainder of ship's complement beam down to %s.") %
4258 prout(_("Entire crew of %d left to die in outer space.") %
4260 game.casual += game.state.crew
4261 game.abandoned += game.state.crew
4262 # If at least one base left, give 'em the Faerie Queene
4264 game.icrystl = False # crystals are lost
4265 game.nprobes = 0 # No probes
4266 prout(_("You are captured by Klingons and released to"))
4267 prout(_("the Federation in a prisoner-of-war exchange."))
4268 nb = randrange(len(game.state.baseq))
4269 # Set up quadrant and position FQ adjacient to base
4270 if not game.quadrant == game.state.baseq[nb]:
4271 game.quadrant = game.state.baseq[nb]
4272 game.sector.i = game.sector.j = 5
4275 # position next to base by trial and error
4276 game.quad[game.sector.i][game.sector.j] = '.'
4277 for l in range(QUADSIZE):
4278 game.sector = game.base.scatter()
4279 if game.sector.valid_sector() and \
4280 game.quad[game.sector.i][game.sector.j] == '.':
4283 break # found a spot
4284 game.sector.i=QUADSIZE/2
4285 game.sector.j=QUADSIZE/2
4287 # Get new commission
4288 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4289 game.state.crew = FULLCREW
4290 prout(_("Starfleet puts you in command of another ship,"))
4291 prout(_("the Faerie Queene, which is antiquated but,"))
4292 prout(_("still useable."))
4294 prout(_("The dilithium crystals have been moved."))
4296 game.iscraft = "offship" # Galileo disappears
4298 game.condition="docked"
4299 for l in range(NDEVICES):
4300 game.damage[l] = 0.0
4301 game.damage[DSHUTTL] = -1
4302 game.energy = game.inenrg = 3000.0
4303 game.shield = game.inshld = 1250.0
4304 game.torps = game.intorps = 6
4305 game.lsupres=game.inlsr=3.0
4310 # Code from planets.c begins here.
4313 "Abort a lengthy operation if an event interrupts it."
4316 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4321 "Report on (uninhabited) planets in the galaxy."
4325 prout(_("Spock- \"Planet report follows, Captain.\""))
4327 for i in range(game.inplan):
4328 if game.state.planets[i].pclass == "destroyed":
4330 if (game.state.planets[i].known != "unknown" \
4331 and not game.state.planets[i].inhabited) \
4334 if game.idebug and game.state.planets[i].known=="unknown":
4335 proutn("(Unknown) ")
4336 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4337 proutn(_(" class "))
4338 proutn(game.state.planets[i].pclass)
4340 if game.state.planets[i].crystals != "present":
4342 prout(_("dilithium crystals present."))
4343 if game.state.planets[i].known=="shuttle_down":
4344 prout(_(" Shuttle Craft Galileo on surface."))
4346 prout(_("No information available."))
4349 "Enter standard orbit."
4353 prout(_("Already in standard orbit."))
4355 if damaged(DWARPEN) and damaged(DIMPULS):
4356 prout(_("Both warp and impulse engines damaged."))
4358 if not game.plnet.is_valid():
4359 prout("There is no planet in this sector.")
4361 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4362 prout(crmshp() + _(" not adjacent to planet."))
4365 game.optime = randreal(0.02, 0.05)
4366 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4370 game.height = randreal(1400, 8600)
4371 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4376 "Examine planets in this quadrant."
4377 if damaged(DSRSENS):
4378 if game.options & OPTION_TTY:
4379 prout(_("Short range sensors damaged."))
4381 if game.iplnet == None:
4382 if game.options & OPTION_TTY:
4383 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4385 if game.iplnet.known == "unknown":
4386 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4388 prout(_(" Planet at Sector %s is of class %s.") %
4389 (game.plnet, game.iplnet.pclass))
4390 if game.iplnet.known=="shuttle_down":
4391 prout(_(" Sensors show Galileo still on surface."))
4392 proutn(_(" Readings indicate"))
4393 if game.iplnet.crystals != "present":
4395 prout(_(" dilithium crystals present.\""))
4396 if game.iplnet.known == "unknown":
4397 game.iplnet.known = "known"
4398 elif game.iplnet.inhabited:
4399 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4400 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4403 "Use the transporter."
4407 if damaged(DTRANSP):
4408 prout(_("Transporter damaged."))
4409 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4411 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4415 if not game.inorbit:
4416 prout(crmshp() + _(" not in standard orbit."))
4419 prout(_("Impossible to transport through shields."))
4421 if game.iplnet.known=="unknown":
4422 prout(_("Spock- \"Captain, we have no information on this planet"))
4423 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4424 prout(_(" you may not go down.\""))
4426 if not game.landed and game.iplnet.crystals=="absent":
4427 prout(_("Spock- \"Captain, I fail to see the logic in"))
4428 prout(_(" exploring a planet with no dilithium crystals."))
4429 proutn(_(" Are you sure this is wise?\" "))
4433 if not (game.options & OPTION_PLAIN):
4434 nrgneed = 50 * game.skill + game.height / 100.0
4435 if nrgneed > game.energy:
4436 prout(_("Engineering to bridge--"))
4437 prout(_(" Captain, we don't have enough energy for transportation."))
4439 if not game.landed and nrgneed * 2 > game.energy:
4440 prout(_("Engineering to bridge--"))
4441 prout(_(" Captain, we have enough energy only to transport you down to"))
4442 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4443 if game.iplnet.known == "shuttle_down":
4444 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4445 proutn(_(" Are you sure this is wise?\" "))
4450 # Coming from planet
4451 if game.iplnet.known=="shuttle_down":
4452 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4456 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4457 prout(_("Landing party assembled, ready to beam up."))
4459 prout(_("Kirk whips out communicator..."))
4460 prouts(_("BEEP BEEP BEEP"))
4462 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4465 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4467 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4469 prout(_("Kirk- \"Energize.\""))
4472 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4475 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4477 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4480 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4481 game.landed = not game.landed
4482 game.energy -= nrgneed
4484 prout(_("Transport complete."))
4485 if game.landed and game.iplnet.known=="shuttle_down":
4486 prout(_("The shuttle craft Galileo is here!"))
4487 if not game.landed and game.imine:
4494 "Strip-mine a world for dilithium."
4498 prout(_("Mining party not on planet."))
4500 if game.iplnet.crystals == "mined":
4501 prout(_("This planet has already been strip-mined for dilithium."))
4503 elif game.iplnet.crystals == "absent":
4504 prout(_("No dilithium crystals on this planet."))
4507 prout(_("You've already mined enough crystals for this trip."))
4509 if game.icrystl and game.cryprob == 0.05:
4510 prout(_("With all those fresh crystals aboard the ") + crmshp())
4511 prout(_("there's no reason to mine more at this time."))
4513 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4516 prout(_("Mining operation complete."))
4517 game.iplnet.crystals = "mined"
4518 game.imine = game.ididit = True
4521 "Use dilithium crystals."
4525 if not game.icrystl:
4526 prout(_("No dilithium crystals available."))
4528 if game.energy >= 1000:
4529 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4530 prout(_(" except when Condition Yellow exists."))
4532 prout(_("Spock- \"Captain, I must warn you that loading"))
4533 prout(_(" raw dilithium crystals into the ship's power"))
4534 prout(_(" system may risk a severe explosion."))
4535 proutn(_(" Are you sure this is wise?\" "))
4540 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4541 prout(_(" Mr. Spock and I will try it.\""))
4543 prout(_("Spock- \"Crystals in place, Sir."))
4544 prout(_(" Ready to activate circuit.\""))
4546 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4548 if withprob(game.cryprob):
4549 prouts(_(" \"Activating now! - - No good! It's***"))
4551 prouts(_("***RED ALERT! RED A*L********************************"))
4554 prouts(_("****************** KA-BOOM!!!! *******************"))
4558 game.energy += randreal(5000.0, 5500.0)
4559 prouts(_(" \"Activating now! - - "))
4560 prout(_("The instruments"))
4561 prout(_(" are going crazy, but I think it's"))
4562 prout(_(" going to work!! Congratulations, Sir!\""))
4567 "Use shuttlecraft for planetary jaunt."
4570 if damaged(DSHUTTL):
4571 if game.damage[DSHUTTL] == -1.0:
4572 if game.inorbit and game.iplnet.known == "shuttle_down":
4573 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4575 prout(_("Ye Faerie Queene had no shuttle craft."))
4576 elif game.damage[DSHUTTL] > 0:
4577 prout(_("The Galileo is damaged."))
4578 else: # game.damage[DSHUTTL] < 0
4579 prout(_("Shuttle craft is now serving Big Macs."))
4581 if not game.inorbit:
4582 prout(crmshp() + _(" not in standard orbit."))
4584 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4585 prout(_("Shuttle craft not currently available."))
4587 if not game.landed and game.iplnet.known=="shuttle_down":
4588 prout(_("You will have to beam down to retrieve the shuttle craft."))
4590 if game.shldup or game.condition == "docked":
4591 prout(_("Shuttle craft cannot pass through shields."))
4593 if game.iplnet.known=="unknown":
4594 prout(_("Spock- \"Captain, we have no information on this planet"))
4595 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4596 prout(_(" you may not fly down.\""))
4598 game.optime = 3.0e-5*game.height
4599 if game.optime >= 0.8*game.state.remtime:
4600 prout(_("First Officer Spock- \"Captain, I compute that such"))
4601 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4602 int(100*game.optime/game.state.remtime))
4603 prout(_("remaining time."))
4604 proutn(_("Are you sure this is wise?\" "))
4610 if game.iscraft == "onship":
4612 if not damaged(DTRANSP):
4613 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4617 proutn(_("Shuttle crew"))
4619 proutn(_("Rescue party"))
4620 prout(_(" boards Galileo and swoops toward planet surface."))
4621 game.iscraft = "offship"
4625 game.iplnet.known="shuttle_down"
4626 prout(_("Trip complete."))
4629 # Ready to go back to ship
4630 prout(_("You and your mining party board the"))
4631 prout(_("shuttle craft for the trip back to the Enterprise."))
4633 prouts(_("The short hop begins . . ."))
4635 game.iplnet.known="known"
4641 game.iscraft = "onship"
4647 prout(_("Trip complete."))
4650 # Kirk on ship and so is Galileo
4651 prout(_("Mining party assembles in the hangar deck,"))
4652 prout(_("ready to board the shuttle craft \"Galileo\"."))
4654 prouts(_("The hangar doors open; the trip begins."))
4657 game.iscraft = "offship"
4660 game.iplnet.known = "shuttle_down"
4663 prout(_("Trip complete."))
4667 "Use the big zapper."
4671 if game.ship != 'E':
4672 prout(_("Ye Faerie Queene has no death ray."))
4674 if len(game.enemies)==0:
4675 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4678 prout(_("Death Ray is damaged."))
4680 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4681 prout(_(" is highly unpredictible. Considering the alternatives,"))
4682 proutn(_(" are you sure this is wise?\" "))
4685 prout(_("Spock- \"Acknowledged.\""))
4688 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4690 prout(_("Crew scrambles in emergency preparation."))
4691 prout(_("Spock and Scotty ready the death ray and"))
4692 prout(_("prepare to channel all ship's power to the device."))
4694 prout(_("Spock- \"Preparations complete, sir.\""))
4695 prout(_("Kirk- \"Engage!\""))
4697 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4700 if game.options & OPTION_PLAIN:
4704 prouts(_("Sulu- \"Captain! It's working!\""))
4706 while len(game.enemies) > 0:
4707 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4708 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4709 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4711 if (game.options & OPTION_PLAIN) == 0:
4712 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4714 prout(_(" is still operational.\""))
4716 prout(_(" has been rendered nonfunctional.\""))
4717 game.damage[DDRAY] = 39.95
4719 r = randreal() # Pick failure method
4721 prouts(_("Sulu- \"Captain! It's working!\""))
4723 prouts(_("***RED ALERT! RED ALERT!"))
4725 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4727 prouts(_("***RED ALERT! RED A*L********************************"))
4730 prouts(_("****************** KA-BOOM!!!! *******************"))
4735 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4737 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4739 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4740 prout(_(" have apparently been transformed into strange mutations."))
4741 prout(_(" Vulcans do not seem to be affected."))
4743 prout(_("Kirk- \"Raauch! Raauch!\""))
4747 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4749 proutn(_("Spock- \"I believe the word is"))
4750 prouts(_(" *ASTONISHING*"))
4751 prout(_(" Mr. Sulu."))
4752 for i in range(QUADSIZE):
4753 for j in range(QUADSIZE):
4754 if game.quad[i][j] == '.':
4755 game.quad[i][j] = '?'
4756 prout(_(" Captain, our quadrant is now infested with"))
4757 prouts(_(" - - - - - - *THINGS*."))
4759 prout(_(" I have no logical explanation.\""))
4761 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4763 prout(_("Scotty- \"There are so many tribbles down here"))
4764 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4768 # Code from reports.c begins here
4770 def attackreport(curt):
4771 "eport status of bases under attack."
4773 if is_scheduled(FCDBAS):
4774 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4775 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4776 elif game.isatb == 1:
4777 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4778 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4780 prout(_("No Starbase is currently under attack."))
4782 if is_scheduled(FCDBAS):
4783 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4785 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4789 # report on general game status
4791 s1 = "" and game.thawed and _("thawed ")
4792 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4793 s3 = (None, _("novice"), _("fair"),
4794 _("good"), _("expert"), _("emeritus"))[game.skill]
4795 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4796 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4797 prout(_("No plaque is allowed."))
4799 prout(_("This is tournament game %d.") % game.tourn)
4800 prout(_("Your secret password is \"%s\"") % game.passwd)
4801 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4802 (game.inkling + game.incom + game.inscom)))
4803 if game.incom - len(game.state.kcmdr):
4804 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4805 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4806 prout(_(", but no Commanders."))
4809 if game.skill > SKILL_FAIR:
4810 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4811 if len(game.state.baseq) != game.inbase:
4813 if game.inbase-len(game.state.baseq)==1:
4814 proutn(_("has been 1 base"))
4816 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4817 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4819 prout(_("There are %d bases.") % game.inbase)
4820 if communicating() or game.iseenit:
4821 # Don't report this if not seen and
4822 # either the radio is dead or not at base!
4826 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4828 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4829 if game.ship == 'E':
4830 proutn(_("You have "))
4832 proutn("%d" % (game.nprobes))
4835 proutn(_(" deep space probe"))
4839 if communicating() and is_scheduled(FDSPROB):
4841 proutn(_("An armed deep space probe is in "))
4843 proutn(_("A deep space probe is in "))
4844 prout("Quadrant %s." % game.probec)
4846 if game.cryprob <= .05:
4847 prout(_("Dilithium crystals aboard ship... not yet used."))
4851 while game.cryprob > ai:
4854 prout(_("Dilithium crystals have been used %d time%s.") % \
4855 (i, (_("s"), "")[i==1]))
4859 "Long-range sensor scan."
4860 if damaged(DLRSENS):
4861 # Now allow base's sensors if docked
4862 if game.condition != "docked":
4864 prout(_("LONG-RANGE SENSORS DAMAGED."))
4867 prout(_("Starbase's long-range scan"))
4869 prout(_("Long-range scan"))
4870 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4873 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4874 if not coord(x, y).valid_quadrant():
4878 if not damaged(DRADIO):
4879 game.state.galaxy[x][y].charted = True
4880 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4881 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4882 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4883 if not silent and game.state.galaxy[x][y].supernova:
4886 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4894 for i in range(NDEVICES):
4897 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4898 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4900 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4901 game.damage[i]+0.05,
4902 DOCKFAC*game.damage[i]+0.005))
4904 prout(_("All devices functional."))
4907 "Update the chart in the Enterprise's computer from galaxy data."
4908 game.lastchart = game.state.date
4909 for i in range(GALSIZE):
4910 for j in range(GALSIZE):
4911 if game.state.galaxy[i][j].charted:
4912 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
4913 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
4914 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
4917 "Display the star chart."
4919 if (game.options & OPTION_AUTOSCAN):
4921 if not damaged(DRADIO):
4923 if game.lastchart < game.state.date and game.condition == "docked":
4924 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
4926 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
4927 if game.state.date > game.lastchart:
4928 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
4929 prout(" 1 2 3 4 5 6 7 8")
4930 for i in range(GALSIZE):
4931 proutn("%d |" % (i+1))
4932 for j in range(GALSIZE):
4933 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4937 if game.state.galaxy[i][j].supernova:
4939 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
4941 elif game.state.galaxy[i][j].charted:
4942 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
4946 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4954 def sectscan(goodScan, i, j):
4955 "Light up an individual dot in a sector."
4956 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
4957 textcolor({"green":GREEN,
4961 "dead":BROWN}[game.condition])
4962 if game.quad[i][j] != game.ship:
4964 proutn("%c " % game.quad[i][j])
4970 "Emit status report lines"
4971 if not req or req == 1:
4972 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
4973 % (game.state.date, game.state.remtime))
4974 if not req or req == 2:
4975 if game.condition != "docked":
4977 prstat(_("Condition"), _("%s, %i DAMAGES") % \
4978 (game.condition.upper(), sum(map(lambda x: x > 0, game.damage))))
4979 if not req or req == 3:
4980 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
4981 if not req or req == 4:
4982 if damaged(DLIFSUP):
4983 if game.condition == "docked":
4984 s = _("DAMAGED, Base provides")
4986 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
4989 prstat(_("Life Support"), s)
4990 if not req or req == 5:
4991 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
4992 if not req or req == 6:
4994 if game.icrystl and (game.options & OPTION_SHOWME):
4995 extra = _(" (have crystals)")
4996 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
4997 if not req or req == 7:
4998 prstat(_("Torpedoes"), "%d" % (game.torps))
4999 if not req or req == 8:
5000 if damaged(DSHIELD):
5006 data = _(" %d%% %.1f units") \
5007 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5008 prstat(_("Shields"), s+data)
5009 if not req or req == 9:
5010 prstat(_("Klingons Left"), "%d" \
5011 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5012 if not req or req == 10:
5013 if game.options & OPTION_WORLDS:
5014 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5015 if plnet and plnet.inhabited:
5016 prstat(_("Major system"), plnet.name)
5018 prout(_("Sector is uninhabited"))
5019 elif not req or req == 11:
5020 attackreport(not req)
5023 "Request specified status data, a historical relic from slow TTYs."
5024 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5025 while scanner.next() == "IHEOL":
5026 proutn(_("Information desired? "))
5028 if scanner.token in requests:
5029 status(requests.index(scanner.token))
5031 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5032 prout((" date, condition, position, lsupport, warpfactor,"))
5033 prout((" energy, torpedoes, shields, klingons, system, time."))
5038 if damaged(DSRSENS):
5039 # Allow base's sensors if docked
5040 if game.condition != "docked":
5041 prout(_(" S.R. SENSORS DAMAGED!"))
5044 prout(_(" [Using Base's sensors]"))
5046 prout(_(" Short-range scan"))
5047 if goodScan and not damaged(DRADIO):
5048 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5049 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5050 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5051 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5052 prout(" 1 2 3 4 5 6 7 8 9 10")
5053 if game.condition != "docked":
5055 for i in range(QUADSIZE):
5056 proutn("%2d " % (i+1))
5057 for j in range(QUADSIZE):
5058 sectscan(goodScan, i, j)
5062 "Use computer to get estimated time of arrival for a warp jump."
5063 w1 = coord(); w2 = coord()
5065 if damaged(DCOMPTR):
5066 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5069 if scanner.next() != "IHREAL":
5072 proutn(_("Destination quadrant and/or sector? "))
5073 if scanner.next()!="IHREAL":
5076 w1.j = int(scanner.real-0.5)
5077 if scanner.next() != "IHREAL":
5080 w1.i = int(scanner.real-0.5)
5081 if scanner.next() == "IHREAL":
5082 w2.j = int(scanner.real-0.5)
5083 if scanner.next() != "IHREAL":
5086 w2.i = int(scanner.real-0.5)
5088 if game.quadrant.j>w1.i:
5092 if game.quadrant.i>w1.j:
5096 if not w1.valid_quadrant() or not w2.valid_sector():
5099 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5100 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5103 prout(_("Answer \"no\" if you don't know the value:"))
5106 proutn(_("Time or arrival date? "))
5107 if scanner.next()=="IHREAL":
5108 ttime = scanner.real
5109 if ttime > game.state.date:
5110 ttime -= game.state.date # Actually a star date
5111 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5112 if ttime <= 1e-10 or twarp > 10:
5113 prout(_("We'll never make it, sir."))
5120 proutn(_("Warp factor? "))
5121 if scanner.next()== "IHREAL":
5123 twarp = scanner.real
5124 if twarp<1.0 or twarp > 10.0:
5128 prout(_("Captain, certainly you can give me one of these."))
5131 ttime = (10.0*dist)/twarp**2
5132 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5133 if tpower >= game.energy:
5134 prout(_("Insufficient energy, sir."))
5135 if not game.shldup or tpower > game.energy*2.0:
5138 proutn(_("New warp factor to try? "))
5139 if scanner.next() == "IHREAL":
5141 twarp = scanner.real
5142 if twarp<1.0 or twarp > 10.0:
5150 prout(_("But if you lower your shields,"))
5151 proutn(_("remaining"))
5154 proutn(_("Remaining"))
5155 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5157 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5159 prout(_("Any warp speed is adequate."))
5161 prout(_("Minimum warp needed is %.2f,") % (twarp))
5162 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5163 if game.state.remtime < ttime:
5164 prout(_("Unfortunately, the Federation will be destroyed by then."))
5166 prout(_("You'll be taking risks at that speed, Captain"))
5167 if (game.isatb==1 and game.state.kscmdr == w1 and \
5168 scheduled(FSCDBAS)< ttime+game.state.date) or \
5169 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5170 prout(_("The starbase there will be destroyed by then."))
5171 proutn(_("New warp factor to try? "))
5172 if scanner.next() == "IHREAL":
5174 twarp = scanner.real
5175 if twarp<1.0 or twarp > 10.0:
5183 # Code from setup.c begins here
5186 "Issue a historically correct banner."
5188 prout(_("-SUPER- STAR TREK"))
5190 # From the FORTRAN original
5191 # prout(_("Latest update-21 Sept 78"))
5197 scanner.push("emsave.trk")
5198 key = scanner.next()
5200 proutn(_("File name: "))
5201 key = scanner.next()
5202 if key != "IHALPHA":
5206 if '.' not in scanner.token:
5207 scanner.token += ".trk"
5209 fp = open(scanner.token, "wb")
5211 prout(_("Can't freeze game as file %s") % scanner.token)
5213 cPickle.dump(game, fp)
5217 "Retrieve saved game."
5218 game.passwd[0] = '\0'
5219 key = scanner.next()
5221 proutn(_("File name: "))
5222 key = scanner.next()
5223 if key != "IHALPHA":
5227 if '.' not in scanner.token:
5228 scanner.token += ".trk"
5230 fp = open(scanner.token, "rb")
5232 prout(_("Can't thaw game in %s") % scanner.token)
5234 game = cPickle.load(fp)
5238 # I used <http://www.memory-alpha.org> to find planets
5239 # with references in ST:TOS. Earth and the Alpha Centauri
5240 # Colony have been omitted.
5242 # Some planets marked Class G and P here will be displayed as class M
5243 # because of the way planets are generated. This is a known bug.
5246 _("Andoria (Fesoan)"), # several episodes
5247 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5248 _("Vulcan (T'Khasi)"), # many episodes
5249 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5250 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5251 _("Ardana"), # TOS: "The Cloud Minders"
5252 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5253 _("Gideon"), # TOS: "The Mark of Gideon"
5254 _("Aldebaran III"), # TOS: "The Deadly Years"
5255 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5256 _("Altair IV"), # TOS: "Amok Time
5257 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5258 _("Benecia"), # TOS: "The Conscience of the King"
5259 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5260 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5261 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5262 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5263 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5264 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5265 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5266 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5267 _("Ingraham B"), # TOS: "Operation: Annihilate"
5268 _("Janus IV"), # TOS: "The Devil in the Dark"
5269 _("Makus III"), # TOS: "The Galileo Seven"
5270 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5271 _("Omega IV"), # TOS: "The Omega Glory"
5272 _("Regulus V"), # TOS: "Amok Time
5273 _("Deneva"), # TOS: "Operation -- Annihilate!"
5274 # Worlds from BSD Trek
5275 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5276 _("Beta III"), # TOS: "The Return of the Archons"
5277 _("Triacus"), # TOS: "And the Children Shall Lead",
5278 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5280 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5281 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5282 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5283 # _("Izar"), # TOS: "Whom Gods Destroy"
5284 # _("Tiburon"), # TOS: "The Way to Eden"
5285 # _("Merak II"), # TOS: "The Cloud Minders"
5286 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5287 # _("Iotia"), # TOS: "A Piece of the Action"
5291 _("S. R. Sensors"), \
5292 _("L. R. Sensors"), \
5294 _("Photon Tubes"), \
5295 _("Life Support"), \
5296 _("Warp Engines"), \
5297 _("Impulse Engines"), \
5299 _("Subspace Radio"), \
5300 _("Shuttle Craft"), \
5302 _("Navigation System"), \
5304 _("Shield Control"), \
5310 "Prepare to play, set up cosmos."
5312 # Decide how many of everything
5314 return # frozen game
5315 # Prepare the Enterprise
5316 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5318 game.state.crew = FULLCREW
5319 game.energy = game.inenrg = 5000.0
5320 game.shield = game.inshld = 2500.0
5323 game.quadrant = randplace(GALSIZE)
5324 game.sector = randplace(QUADSIZE)
5325 game.torps = game.intorps = 10
5326 game.nprobes = randrange(2, 5)
5328 for i in range(NDEVICES):
5329 game.damage[i] = 0.0
5330 # Set up assorted game parameters
5331 game.battle = coord()
5332 game.state.date = game.indate = 100.0 * randreal(20, 51)
5333 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5334 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5335 game.isatb = game.state.nplankl = 0
5336 game.state.starkl = game.state.basekl = 0
5337 game.iscraft = "onship"
5340 # Starchart is functional but we've never seen it
5341 game.lastchart = FOREVER
5342 # Put stars in the galaxy
5344 for i in range(GALSIZE):
5345 for j in range(GALSIZE):
5346 k = randrange(1, QUADSIZE**2/10+1)
5348 game.state.galaxy[i][j].stars = k
5349 # Locate star bases in galaxy
5350 for i in range(game.inbase):
5353 w = randplace(GALSIZE)
5354 if not game.state.galaxy[w.i][w.j].starbase:
5357 # C version: for (j = i-1; j > 0; j--)
5358 # so it did them in the opposite order.
5359 for j in range(1, i):
5360 # Improved placement algorithm to spread out bases
5361 distq = (w - game.state.baseq[j]).distance()
5362 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5365 prout("=== Abandoning base #%d at %s" % (i, w))
5367 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5369 prout("=== Saving base #%d, close to #%d" % (i, j))
5372 game.state.baseq.append(w)
5373 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5374 # Position ordinary Klingon Battle Cruisers
5376 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5377 if klumper > MAXKLQUAD:
5381 klump = (1.0 - r*r)*klumper
5386 w = randplace(GALSIZE)
5387 if not game.state.galaxy[w.i][w.j].supernova and \
5388 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5390 game.state.galaxy[w.i][w.j].klingons += int(klump)
5393 # Position Klingon Commander Ships
5394 for i in range(game.incom):
5396 w = randplace(GALSIZE)
5397 if not welcoming(w) or w in game.state.kcmdr:
5399 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5401 game.state.galaxy[w.i][w.j].klingons += 1
5402 game.state.kcmdr.append(w)
5403 # Locate planets in galaxy
5404 for i in range(game.inplan):
5406 w = randplace(GALSIZE)
5407 if game.state.galaxy[w.i][w.j].planet == None:
5411 new.crystals = "absent"
5412 if (game.options & OPTION_WORLDS) and i < NINHAB:
5413 new.pclass = "M" # All inhabited planets are class M
5414 new.crystals = "absent"
5416 new.name = systnames[i]
5417 new.inhabited = True
5419 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5421 new.crystals = "present"
5422 new.known = "unknown"
5423 new.inhabited = False
5424 game.state.galaxy[w.i][w.j].planet = new
5425 game.state.planets.append(new)
5427 for i in range(game.state.nromrem):
5428 w = randplace(GALSIZE)
5429 game.state.galaxy[w.i][w.j].romulans += 1
5430 # Place the Super-Commander if needed
5431 if game.state.nscrem > 0:
5433 w = randplace(GALSIZE)
5436 game.state.kscmdr = w
5437 game.state.galaxy[w.i][w.j].klingons += 1
5438 # Initialize times for extraneous events
5439 schedule(FSNOVA, expran(0.5 * game.intime))
5440 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5441 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5442 schedule(FBATTAK, expran(0.3*game.intime))
5444 if game.state.nscrem:
5445 schedule(FSCMOVE, 0.2777)
5450 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5451 schedule(FDISTR, expran(1.0 + game.intime))
5456 # Place thing (in tournament game, we don't want one!)
5457 # New in SST2K: never place the Thing near a starbase.
5458 # This makes sense and avoids a special case in the old code.
5460 if game.tourn is None:
5462 thing = randplace(GALSIZE)
5463 if thing not in game.state.baseq:
5466 game.state.snap = False
5467 if game.skill == SKILL_NOVICE:
5468 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5469 prout(_("a deadly Klingon invasion force. As captain of the United"))
5470 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5471 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5472 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5473 prout(_("your mission. As you proceed you may be given more time."))
5475 prout(_("You will have %d supporting starbases.") % (game.inbase))
5476 proutn(_("Starbase locations- "))
5478 prout(_("Stardate %d.") % int(game.state.date))
5480 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5481 prout(_("An unknown number of Romulans."))
5482 if game.state.nscrem:
5483 prout(_("And one (GULP) Super-Commander."))
5484 prout(_("%d stardates.") % int(game.intime))
5485 proutn(_("%d starbases in ") % game.inbase)
5486 for i in range(game.inbase):
5487 proutn(`game.state.baseq[i]`)
5490 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5491 proutn(_(" Sector %s") % game.sector)
5493 prout(_("Good Luck!"))
5494 if game.state.nscrem:
5495 prout(_(" YOU'LL NEED IT."))
5498 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5500 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5501 attack(torps_ok=False)
5504 "Choose your game type."
5506 game.tourn = game.length = 0
5508 game.skill = SKILL_NONE
5509 if not scanner.inqueue: # Can start with command line options
5510 proutn(_("Would you like a regular, tournament, or saved game? "))
5512 if scanner.sees("tournament"):
5513 while scanner.next() == "IHEOL":
5514 proutn(_("Type in tournament number-"))
5515 if scanner.real == 0:
5517 continue # We don't want a blank entry
5518 game.tourn = int(round(scanner.real))
5519 random.seed(scanner.real)
5521 logfp.write("# random.seed(%d)\n" % scanner.real)
5523 if scanner.sees("saved") or scanner.sees("frozen"):
5527 if game.passwd == None:
5529 if not game.alldone:
5530 game.thawed = True # No plaque if not finished
5534 if scanner.sees("regular"):
5536 proutn(_("What is \"%s\"?") % scanner.token)
5538 while game.length==0 or game.skill==SKILL_NONE:
5539 if scanner.next() == "IHALPHA":
5540 if scanner.sees("short"):
5542 elif scanner.sees("medium"):
5544 elif scanner.sees("long"):
5546 elif scanner.sees("novice"):
5547 game.skill = SKILL_NOVICE
5548 elif scanner.sees("fair"):
5549 game.skill = SKILL_FAIR
5550 elif scanner.sees("good"):
5551 game.skill = SKILL_GOOD
5552 elif scanner.sees("expert"):
5553 game.skill = SKILL_EXPERT
5554 elif scanner.sees("emeritus"):
5555 game.skill = SKILL_EMERITUS
5557 proutn(_("What is \""))
5558 proutn(scanner.token)
5563 proutn(_("Would you like a Short, Medium, or Long game? "))
5564 elif game.skill == SKILL_NONE:
5565 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5566 # Choose game options -- added by ESR for SST2K
5567 if scanner.next() != "IHALPHA":
5569 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5571 if scanner.sees("plain"):
5572 # Approximates the UT FORTRAN version.
5573 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5574 game.options |= OPTION_PLAIN
5575 elif scanner.sees("almy"):
5576 # Approximates Tom Almy's version.
5577 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5578 game.options |= OPTION_ALMY
5579 elif scanner.sees("fancy") or scanner.sees("\n"):
5581 elif len(scanner.token):
5582 proutn(_("What is \"%s\"?") % scanner.token)
5583 game.options &=~ OPTION_COLOR
5585 if game.passwd == "debug":
5587 prout("=== Debug mode enabled.")
5588 # Use parameters to generate initial values of things
5589 game.damfac = 0.5 * game.skill
5590 game.inbase = randrange(BASEMIN, BASEMAX+1)
5592 if game.options & OPTION_PLANETS:
5593 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5594 if game.options & OPTION_WORLDS:
5595 game.inplan += int(NINHAB)
5596 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5597 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5598 game.state.remtime = 7.0 * game.length
5599 game.intime = game.state.remtime
5600 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5601 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5602 game.state.remres = (game.inkling+4*game.incom)*game.intime
5603 game.inresor = game.state.remres
5604 if game.inkling > 50:
5605 game.state.inbase += 1
5608 def dropin(iquad=None):
5609 "Drop a feature on a random dot in the current quadrant."
5611 w = randplace(QUADSIZE)
5612 if game.quad[w.i][w.j] == '.':
5614 if iquad is not None:
5615 game.quad[w.i][w.j] = iquad
5619 "Update our alert status."
5620 game.condition = "green"
5621 if game.energy < 1000.0:
5622 game.condition = "yellow"
5623 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5624 game.condition = "red"
5626 game.condition="dead"
5629 "Drop new Klingon into current quadrant."
5630 return enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5633 "Set up a new state of quadrant, for when we enter or re-enter it."
5636 game.neutz = game.inorbit = game.landed = False
5637 game.ientesc = game.iseenit = False
5638 # Create a blank quadrant
5639 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5641 # Attempt to escape Super-commander, so tbeam back!
5644 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5645 # cope with supernova
5648 game.klhere = q.klingons
5649 game.irhere = q.romulans
5651 game.quad[game.sector.i][game.sector.j] = game.ship
5654 # Position ordinary Klingons
5655 for i in range(game.klhere):
5657 # If we need a commander, promote a Klingon
5658 for cmdr in game.state.kcmdr:
5659 if cmdr == game.quadrant:
5660 e = game.enemies[game.klhere-1]
5661 game.quad[e.location.i][e.location.j] = 'C'
5662 e.power = randreal(950,1350) + 50.0*game.skill
5664 # If we need a super-commander, promote a Klingon
5665 if game.quadrant == game.state.kscmdr:
5667 game.quad[e.location.i][e.location.j] = 'S'
5668 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5669 game.iscate = (game.state.remkl > 1)
5670 # Put in Romulans if needed
5671 for i in range(q.romulans):
5672 enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5673 # If quadrant needs a starbase, put it in
5675 game.base = dropin('B')
5676 # If quadrant needs a planet, put it in
5678 game.iplnet = q.planet
5679 if not q.planet.inhabited:
5680 game.plnet = dropin('P')
5682 game.plnet = dropin('@')
5683 # Check for condition
5686 if game.irhere > 0 and game.klhere == 0:
5688 if not damaged(DRADIO):
5690 prout(_("LT. Uhura- \"Captain, an urgent message."))
5691 prout(_(" I'll put it on audio.\" CLICK"))
5693 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5694 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5695 # Put in THING if needed
5696 if thing == game.quadrant:
5697 enemy(type='?', loc=dropin(),
5698 power=randreal(6000,6500.0)+250.0*game.skill)
5699 if not damaged(DSRSENS):
5701 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5702 prout(_(" Please examine your short-range scan.\""))
5703 # Decide if quadrant needs a Tholian; lighten up if skill is low
5704 if game.options & OPTION_THOLIAN:
5705 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5706 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5707 (game.skill > SKILL_GOOD and withprob(0.08)):
5710 w.i = withprob(0.5) * (QUADSIZE-1)
5711 w.j = withprob(0.5) * (QUADSIZE-1)
5712 if game.quad[w.i][w.j] == '.':
5714 game.tholian = enemy(type='T', loc=w,
5715 power=randrange(100, 500) + 25.0*game.skill)
5716 # Reserve unoccupied corners
5717 if game.quad[0][0]=='.':
5718 game.quad[0][0] = 'X'
5719 if game.quad[0][QUADSIZE-1]=='.':
5720 game.quad[0][QUADSIZE-1] = 'X'
5721 if game.quad[QUADSIZE-1][0]=='.':
5722 game.quad[QUADSIZE-1][0] = 'X'
5723 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5724 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5725 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
5726 # And finally the stars
5727 for i in range(q.stars):
5729 # Put in a few black holes
5730 for i in range(1, 3+1):
5733 # Take out X's in corners if Tholian present
5735 if game.quad[0][0]=='X':
5736 game.quad[0][0] = '.'
5737 if game.quad[0][QUADSIZE-1]=='X':
5738 game.quad[0][QUADSIZE-1] = '.'
5739 if game.quad[QUADSIZE-1][0]=='X':
5740 game.quad[QUADSIZE-1][0] = '.'
5741 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5742 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5745 "Set the self-destruct password."
5746 if game.options & OPTION_PLAIN:
5749 proutn(_("Please type in a secret password- "))
5751 game.passwd = scanner.token
5752 if game.passwd != None:
5756 for i_unused in range(3):
5757 game.passwd += chr(ord('a')+randrange(26))
5759 # Code from sst.c begins here
5762 "SRSCAN": OPTION_TTY,
5763 "STATUS": OPTION_TTY,
5764 "REQUEST": OPTION_TTY,
5765 "LRSCAN": OPTION_TTY,
5778 "SENSORS": OPTION_PLANETS,
5779 "ORBIT": OPTION_PLANETS,
5780 "TRANSPORT": OPTION_PLANETS,
5781 "MINE": OPTION_PLANETS,
5782 "CRYSTALS": OPTION_PLANETS,
5783 "SHUTTLE": OPTION_PLANETS,
5784 "PLANETS": OPTION_PLANETS,
5789 "PROBE": OPTION_PROBE,
5791 "FREEZE": 0, # Synonym for SAVE
5797 "SOS": 0, # Synonym for MAYDAY
5798 "CALL": 0, # Synonym for MAYDAY
5804 "Generate a list of legal commands."
5805 prout(_("LEGAL COMMANDS ARE:"))
5807 for key in commands:
5808 if not commands[key] or (commands[key] & game.options):
5809 proutn("%-12s " % key)
5811 if emitted % 5 == 4:
5816 "Browse on-line help."
5817 key = scanner.next()
5820 setwnd(prompt_window)
5821 proutn(_("Help on what command? "))
5822 key = scanner.next()
5823 setwnd(message_window)
5826 if scanner.token.upper() in commands or scanner.token == "ABBREV":
5833 cmd = scanner.token.upper()
5834 for directory in docpath:
5836 fp = open(os.path.join(directory, "sst.doc"), "r")
5841 prout(_("Spock- \"Captain, that information is missing from the"))
5842 prout(_(" computer. You need to find sst.doc and put it somewhere"))
5843 proutn(_(" in these directories: %s") % ":".join(docpath))
5845 # This used to continue: "You need to find SST.DOC and put
5846 # it in the current directory."
5849 linebuf = fp.readline()
5851 prout(_("Spock- \"Captain, there is no information on that command.\""))
5854 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5855 linebuf = linebuf[3:].strip()
5856 if cmd.upper() == linebuf:
5859 prout(_("Spock- \"Captain, I've found the following information:\""))
5862 linebuf = fp.readline()
5863 if "******" in linebuf:
5869 "Command-interpretation loop."
5871 setwnd(message_window)
5872 while True: # command loop
5874 while True: # get a command
5876 game.optime = game.justin = False
5878 setwnd(prompt_window)
5881 if scanner.next() == "IHEOL":
5882 if game.options & OPTION_CURSES:
5885 elif scanner.token == "":
5889 setwnd(message_window)
5891 candidates = filter(lambda x: x.startswith(scanner.token.upper()),
5893 if len(candidates) == 1:
5896 elif candidates and not (game.options & OPTION_PLAIN):
5897 prout("Commands with prefix '%s': %s" % (scanner.token, " ".join(candidates)))
5901 if cmd == "SRSCAN": # srscan
5903 elif cmd == "STATUS": # status
5905 elif cmd == "REQUEST": # status request
5907 elif cmd == "LRSCAN": # long range scan
5908 lrscan(silent=False)
5909 elif cmd == "PHASERS": # phasers
5913 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
5917 elif cmd == "MOVE": # move under warp
5918 warp(course=None, involuntary=False)
5919 elif cmd == "SHIELDS": # shields
5920 doshield(shraise=False)
5923 game.shldchg = False
5924 elif cmd == "DOCK": # dock at starbase
5927 attack(torps_ok=False)
5928 elif cmd == "DAMAGES": # damage reports
5930 elif cmd == "CHART": # chart
5932 elif cmd == "IMPULSE": # impulse
5934 elif cmd == "REST": # rest
5938 elif cmd == "WARP": # warp
5940 elif cmd == "SCORE": # score
5942 elif cmd == "SENSORS": # sensors
5944 elif cmd == "ORBIT": # orbit
5948 elif cmd == "TRANSPORT": # transport "beam"
5950 elif cmd == "MINE": # mine
5954 elif cmd == "CRYSTALS": # crystals
5958 elif cmd == "SHUTTLE": # shuttle
5962 elif cmd == "PLANETS": # Planet list
5964 elif cmd == "REPORT": # Game Report
5966 elif cmd == "COMPUTER": # use COMPUTER!
5968 elif cmd == "COMMANDS":
5970 elif cmd == "EMEXIT": # Emergency exit
5971 clrscr() # Hide screen
5972 freeze(True) # forced save
5973 raise SystemExit,1 # And quick exit
5974 elif cmd == "PROBE":
5975 probe() # Launch probe
5978 elif cmd == "ABANDON": # Abandon Ship
5980 elif cmd == "DESTRUCT": # Self Destruct
5982 elif cmd == "SAVE": # Save Game
5985 if game.skill > SKILL_GOOD:
5986 prout(_("WARNING--Saved games produce no plaques!"))
5987 elif cmd == "DEATHRAY": # Try a desparation measure
5991 elif cmd == "DEBUGCMD": # What do we want for debug???
5993 elif cmd == "MAYDAY": # Call for help
5998 game.alldone = True # quit the game
6003 break # Game has ended
6004 if game.optime != 0.0:
6007 break # Events did us in
6008 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6011 if hitme and not game.justin:
6012 attack(torps_ok=True)
6015 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6026 "Emit the name of an enemy or feature."
6027 if type == 'R': s = _("Romulan")
6028 elif type == 'K': s = _("Klingon")
6029 elif type == 'C': s = _("Commander")
6030 elif type == 'S': s = _("Super-commander")
6031 elif type == '*': s = _("Star")
6032 elif type == 'P': s = _("Planet")
6033 elif type == 'B': s = _("Starbase")
6034 elif type == ' ': s = _("Black hole")
6035 elif type == 'T': s = _("Tholian")
6036 elif type == '#': s = _("Tholian web")
6037 elif type == '?': s = _("Stranger")
6038 elif type == '@': s = _("Inhabited World")
6039 else: s = "Unknown??"
6042 def crmena(stars, enemy, loctype, w):
6043 "Emit the name of an enemy and his location."
6047 buf += cramen(enemy) + _(" at ")
6048 if loctype == "quadrant":
6049 buf += _("Quadrant ")
6050 elif loctype == "sector":
6055 "Emit our ship name."
6056 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6059 "Emit a line of stars"
6060 prouts("******************************************************")
6064 return -avrage*math.log(1e-7 + randreal())
6066 def randplace(size):
6067 "Choose a random location."
6069 w.i = randrange(size)
6070 w.j = randrange(size)
6080 # Get a token from the user
6083 # Fill the token quue if nothing here
6084 while not self.inqueue:
6086 if curwnd==prompt_window:
6088 setwnd(message_window)
6095 self.inqueue = line.lstrip().split() + ["\n"]
6096 # From here on in it's all looking at the queue
6097 self.token = self.inqueue.pop(0)
6098 if self.token == "\n":
6102 self.real = float(self.token)
6103 self.type = "IHREAL"
6108 self.token = self.token.lower()
6109 self.type = "IHALPHA"
6112 def append(self, tok):
6113 self.inqueue.append(tok)
6114 def push(self, tok):
6115 self.inqueue.insert(0, tok)
6119 # Demand input for next scan
6121 self.real = self.token = None
6123 # compares s to item and returns true if it matches to the length of s
6124 return s.startswith(self.token)
6126 # Round token value to nearest integer
6127 return int(round(scanner.real))
6131 if scanner.type != "IHREAL":
6134 s.i = scanner.int()-1
6136 if scanner.type != "IHREAL":
6139 s.j = scanner.int()-1
6142 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6145 "Yes-or-no confirmation."
6149 if scanner.token == 'y':
6151 if scanner.token == 'n':
6154 proutn(_("Please answer with \"y\" or \"n\": "))
6157 "Complain about unparseable input."
6160 prout(_("Beg your pardon, Captain?"))
6163 "Access to the internals for debugging."
6164 proutn("Reset levels? ")
6166 if game.energy < game.inenrg:
6167 game.energy = game.inenrg
6168 game.shield = game.inshld
6169 game.torps = game.intorps
6170 game.lsupres = game.inlsr
6171 proutn("Reset damage? ")
6173 for i in range(NDEVICES):
6174 if game.damage[i] > 0.0:
6175 game.damage[i] = 0.0
6176 proutn("Toggle debug flag? ")
6178 game.idebug = not game.idebug
6180 prout("Debug output ON")
6182 prout("Debug output OFF")
6183 proutn("Cause selective damage? ")
6185 for i in range(NDEVICES):
6186 proutn("Kill %s?" % device[i])
6188 key = scanner.next()
6189 if key == "IHALPHA" and scanner.sees("y"):
6190 game.damage[i] = 10.0
6191 proutn("Examine/change events? ")
6196 FSNOVA: "Supernova ",
6199 FBATTAK: "Base Attack ",
6200 FCDBAS: "Base Destroy ",
6201 FSCMOVE: "SC Move ",
6202 FSCDBAS: "SC Base Destroy ",
6203 FDSPROB: "Probe Move ",
6204 FDISTR: "Distress Call ",
6205 FENSLV: "Enslavement ",
6206 FREPRO: "Klingon Build ",
6208 for i in range(1, NEVENTS):
6211 proutn("%.2f" % (scheduled(i)-game.state.date))
6212 if i == FENSLV or i == FREPRO:
6214 proutn(" in %s" % ev.quadrant)
6219 key = scanner.next()
6223 elif key == "IHREAL":
6224 ev = schedule(i, scanner.real)
6225 if i == FENSLV or i == FREPRO:
6227 proutn("In quadrant- ")
6228 key = scanner.next()
6229 # "IHEOL" says to leave coordinates as they are
6232 prout("Event %d canceled, no x coordinate." % (i))
6235 w.i = int(round(scanner.real))
6236 key = scanner.next()
6238 prout("Event %d canceled, no y coordinate." % (i))
6241 w.j = int(round(scanner.real))
6244 proutn("Induce supernova here? ")
6246 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6249 if __name__ == '__main__':
6250 import getopt, socket
6252 global line, thing, game
6257 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6258 if os.getenv("TERM"):
6259 game.options |= OPTION_CURSES
6261 game.options |= OPTION_TTY
6262 seed = int(time.time())
6263 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6264 for (switch, val) in options:
6267 replayfp = open(val, "r")
6269 sys.stderr.write("sst: can't open replay file %s\n" % val)
6272 line = replayfp.readline().strip()
6273 (leader, key, seed) = line.split()
6275 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6276 line = replayfp.readline().strip()
6277 arguments += line.split()[2:]
6279 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6281 game.options |= OPTION_TTY
6282 game.options &=~ OPTION_CURSES
6283 elif switch == '-s':
6285 elif switch == '-t':
6286 game.options |= OPTION_TTY
6287 game.options &=~ OPTION_CURSES
6288 elif switch == '-x':
6290 elif switch == '-V':
6291 print "SST2K", version
6294 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6296 # where to save the input in case of bugs
6297 if "TMPDIR" in os.environ:
6298 tmpdir = os.environ['TMPDIR']
6302 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6304 sys.stderr.write("sst: warning, can't open logfile\n")
6307 logfp.write("# seed %s\n" % seed)
6308 logfp.write("# options %s\n" % " ".join(arguments))
6309 logfp.write("# recorded by %s@%s on %s\n" % \
6310 (getpass.getuser(),socket.gethostname(),time.ctime()))
6312 scanner = sstscanner()
6313 map(scanner.append, arguments)
6316 while True: # Play a game
6317 setwnd(fullscreen_window)
6323 game.alldone = False
6329 if game.tourn and game.alldone:
6330 proutn(_("Do you want your score recorded?"))
6336 proutn(_("Do you want to play again? "))
6340 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6344 except KeyboardInterrupt: