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")
21 return gettext.gettext(st)
23 GALSIZE = 8 # Galaxy size in quadrants
24 NINHAB = (GALSIZE * GALSIZE / 2) # Number of inhabited worlds
25 MAXUNINHAB = 10 # Maximum uninhabited worlds
26 QUADSIZE = 10 # Quadrant size in sectors
27 BASEMIN = 2 # Minimum starbases
28 BASEMAX = (GALSIZE * GALSIZE / 12) # Maximum starbases
29 MAXKLGAME = 127 # Maximum Klingons per game
30 MAXKLQUAD = 9 # Maximum Klingons per quadrant
31 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
32 FOREVER = 1e30 # Time for the indefinite future
33 MAXBURST = 3 # Max # of torps you can launch in one turn
34 MINCMDR = 10 # Minimum number of Klingon commanders
35 DOCKFAC = 0.25 # Repair faster when docked
36 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
56 class TrekError(Exception):
59 class JumpOut(Exception):
63 def __init__(self, x=None, y=None):
66 def valid_quadrant(self):
67 return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
68 def valid_sector(self):
69 return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
71 self.i = self.j = None
73 return self.i != None and self.j != None
74 def __eq__(self, other):
75 return other != None and self.i == other.i and self.j == other.j
76 def __ne__(self, other):
77 return other == None or self.i != other.i or self.j != other.j
78 def __add__(self, other):
79 return Coord(self.i+other.i, self.j+other.j)
80 def __sub__(self, other):
81 return Coord(self.i-other.i, self.j-other.j)
82 def __mul__(self, other):
83 return Coord(self.i*other, self.j*other)
84 def __rmul__(self, other):
85 return Coord(self.i*other, self.j*other)
86 def __div__(self, other):
87 return Coord(self.i/other, self.j/other)
88 def __mod__(self, other):
89 return Coord(self.i % other, self.j % other)
90 def __rdiv__(self, other):
91 return Coord(self.i/other, self.j/other)
92 def roundtogrid(self):
93 return Coord(int(round(self.i)), int(round(self.j)))
94 def distance(self, other=None):
97 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
99 return 1.90985*math.atan2(self.j, self.i)
105 s.i = self.i / abs(self.i)
109 s.j = self.j / abs(self.j)
112 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
113 return self.roundtogrid() / QUADSIZE
115 return self.roundtogrid() % QUADSIZE
118 s.i = self.i + randrange(-1, 2)
119 s.j = self.j + randrange(-1, 2)
122 if self.i == None or self.j == None:
124 return "%s - %s" % (self.i+1, self.j+1)
128 "Do not anger the Space Thingy!"
137 self.name = None # string-valued if inhabited
138 self.quadrant = Coord() # quadrant located
139 self.pclass = None # could be ""M", "N", "O", or "destroyed"
140 self.crystals = "absent"# could be "mined", "present", "absent"
141 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
142 self.inhabited = False # is it inhabites?
150 self.starbase = False
153 self.supernova = False
155 self.status = "secure" # Could be "secure", "distressed", "enslaved"
163 def fill2d(size, fillfun):
164 "Fill an empty list in 2D."
166 for i in range(size):
168 for j in range(size):
169 lst[i].append(fillfun(i, j))
174 self.snap = False # snapshot taken
175 self.crew = 0 # crew complement
176 self.remkl = 0 # remaining klingons
177 self.nscrem = 0 # remaining super commanders
178 self.starkl = 0 # destroyed stars
179 self.basekl = 0 # destroyed bases
180 self.nromrem = 0 # Romulans remaining
181 self.nplankl = 0 # destroyed uninhabited planets
182 self.nworldkl = 0 # destroyed inhabited planets
183 self.planets = [] # Planet information
184 self.date = 0.0 # stardate
185 self.remres = 0 # remaining resources
186 self.remtime = 0 # remaining time
187 self.baseq = [] # Base quadrant coordinates
188 self.kcmdr = [] # Commander quadrant coordinates
189 self.kscmdr = Coord() # Supercommander quadrant coordinates
191 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
193 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
197 self.date = None # A real number
198 self.quadrant = None # A coord structure
201 OPTION_ALL = 0xffffffff
202 OPTION_TTY = 0x00000001 # old interface
203 OPTION_CURSES = 0x00000002 # new interface
204 OPTION_IOMODES = 0x00000003 # cover both interfaces
205 OPTION_PLANETS = 0x00000004 # planets and mining
206 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
207 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
208 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
209 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
210 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
211 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
212 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
213 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
214 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
215 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
216 OPTION_PLAIN = 0x01000000 # user chose plain game
217 OPTION_ALMY = 0x02000000 # user chose Almy variant
218 OPTION_COLOR = 0x04000000 # enable color display (experimental, ESR, 2010)
237 NDEVICES = 16 # Number of devices
247 return (game.damage[dev] != 0.0)
249 return not damaged(DRADIO) or game.condition=="docked"
251 # Define future events
252 FSPY = 0 # Spy event happens always (no future[] entry)
253 # can cause SC to tractor beam Enterprise
254 FSNOVA = 1 # Supernova
255 FTBEAM = 2 # Commander tractor beams Enterprise
256 FSNAP = 3 # Snapshot for time warp
257 FBATTAK = 4 # Commander attacks base
258 FCDBAS = 5 # Commander destroys base
259 FSCMOVE = 6 # Supercommander moves (might attack base)
260 FSCDBAS = 7 # Supercommander destroys base
261 FDSPROB = 8 # Move deep space probe
262 FDISTR = 9 # Emit distress call from an inhabited world
263 FENSLV = 10 # Inhabited word is enslaved */
264 FREPRO = 11 # Klingons build a ship in an enslaved system
267 # Abstract out the event handling -- underlying data structures will change
268 # when we implement stateful events
269 def findevent(evtype):
270 return game.future[evtype]
273 def __init__(self, etype=None, loc=None, power=None):
275 self.location = Coord()
280 self.power = power # enemy energy level
281 game.enemies.append(self)
283 motion = (loc != self.location)
284 if self.location.i is not None and self.location.j is not None:
287 game.quad[self.location.i][self.location.j] = '#'
289 game.quad[self.location.i][self.location.j] = '.'
291 self.location = copy.copy(loc)
292 game.quad[self.location.i][self.location.j] = self.type
293 self.kdist = self.kavgd = (game.sector - loc).distance()
295 self.location = Coord()
296 self.kdist = self.kavgd = None
297 game.enemies.remove(self)
300 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
304 self.options = None # Game options
305 self.state = Snapshot() # A snapshot structure
306 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
307 self.quad = None # contents of our quadrant
308 self.damage = [0.0] * NDEVICES # damage encountered
309 self.future = [] # future events
313 self.future.append(Event())
314 self.passwd = None # Self Destruct password
316 self.quadrant = None # where we are in the large
317 self.sector = None # where we are in the small
318 self.tholian = None # Tholian enemy object
319 self.base = None # position of base in current quadrant
320 self.battle = None # base coordinates being attacked
321 self.plnet = None # location of planet in quadrant
322 self.gamewon = False # Finished!
323 self.ididit = False # action taken -- allows enemy to attack
324 self.alive = False # we are alive (not killed)
325 self.justin = False # just entered quadrant
326 self.shldup = False # shields are up
327 self.shldchg = False # shield is changing (affects efficiency)
328 self.iscate = False # super commander is here
329 self.ientesc = False # attempted escape from supercommander
330 self.resting = False # rest time
331 self.icraft = False # Kirk in Galileo
332 self.landed = False # party on planet (true), on ship (false)
333 self.alldone = False # game is now finished
334 self.neutz = False # Romulan Neutral Zone
335 self.isarmed = False # probe is armed
336 self.inorbit = False # orbiting a planet
337 self.imine = False # mining
338 self.icrystl = False # dilithium crystals aboard
339 self.iseenit = False # seen base attack report
340 self.thawed = False # thawed game
341 self.condition = None # "green", "yellow", "red", "docked", "dead"
342 self.iscraft = None # "onship", "offship", "removed"
343 self.skill = None # Player skill level
344 self.inkling = 0 # initial number of klingons
345 self.inbase = 0 # initial number of bases
346 self.incom = 0 # initial number of commanders
347 self.inscom = 0 # initial number of commanders
348 self.inrom = 0 # initial number of commanders
349 self.instar = 0 # initial stars
350 self.intorps = 0 # initial/max torpedoes
351 self.torps = 0 # number of torpedoes
352 self.ship = 0 # ship type -- 'E' is Enterprise
353 self.abandoned = 0 # count of crew abandoned in space
354 self.length = 0 # length of game
355 self.klhere = 0 # klingons here
356 self.casual = 0 # causalties
357 self.nhelp = 0 # calls for help
358 self.nkinks = 0 # count of energy-barrier crossings
359 self.iplnet = None # planet # in quadrant
360 self.inplan = 0 # initial planets
361 self.irhere = 0 # Romulans in quadrant
362 self.isatb = 0 # =2 if super commander is attacking base
363 self.tourn = None # tournament number
364 self.nprobes = 0 # number of probes available
365 self.inresor = 0.0 # initial resources
366 self.intime = 0.0 # initial time
367 self.inenrg = 0.0 # initial/max energy
368 self.inshld = 0.0 # initial/max shield
369 self.inlsr = 0.0 # initial life support resources
370 self.indate = 0.0 # initial date
371 self.energy = 0.0 # energy level
372 self.shield = 0.0 # shield level
373 self.warpfac = 0.0 # warp speed
374 self.lsupres = 0.0 # life support reserves
375 self.optime = 0.0 # time taken by current operation
376 self.damfac = 0.0 # damage factor
377 self.lastchart = 0.0 # time star chart was last updated
378 self.cryprob = 0.0 # probability that crystal will work
379 self.probe = None # object holding probe course info
380 self.height = 0.0 # height of orbit around planet
381 self.score = 0.0 # overall score
382 self.perdate = 0.0 # rate of kills
383 self.idebug = False # Debugging instrumentation enabled?
384 self.statekscmdr = None # No SuperCommander coordinates yet.
386 # Stas thinks this should be (C expression):
387 # game.state.remkl + len(game.state.kcmdr) > 0 ?
388 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
389 # He says the existing expression is prone to divide-by-zero errors
390 # after killing the last klingon when score is shown -- perhaps also
391 # if the only remaining klingon is SCOM.
392 self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.state.kcmdr))
418 return random.random() < p
420 def randrange(*args):
421 return random.randrange(*args)
426 v *= args[0] # from [0, args[0])
428 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
431 # Code from ai.c begins here
434 "Would this quadrant welcome another Klingon?"
435 return iq.valid_quadrant() and \
436 not game.state.galaxy[iq.i][iq.j].supernova and \
437 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
439 def tryexit(enemy, look, irun):
440 "A bad guy attempts to bug out."
442 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
443 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
444 if not welcoming(iq):
446 if enemy.type == 'R':
447 return False # Romulans cannot escape!
449 # avoid intruding on another commander's territory
450 if enemy.type == 'C':
451 if iq in game.state.kcmdr:
453 # refuse to leave if currently attacking starbase
454 if game.battle == game.quadrant:
456 # don't leave if over 1000 units of energy
457 if enemy.power > 1000.0:
459 # emit escape message and move out of quadrant.
460 # we know this if either short or long range sensors are working
461 if not damaged(DSRSENS) or not damaged(DLRSENS) or \
462 game.condition == "docked":
463 prout(crmena(True, enemy.type, "sector", enemy.location) + \
464 (_(" escapes to Quadrant %s (and regains strength).") % iq))
465 # handle local matters related to escape
468 if game.condition != "docked":
470 # Handle global matters related to escape
471 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
472 game.state.galaxy[iq.i][iq.j].klingons += 1
473 if enemy.type == 'S':
477 schedule(FSCMOVE, 0.2777)
479 game.state.kscmdr = iq
481 for cmdr in game.state.kcmdr:
482 if cmdr == game.quadrant:
483 game.state.kcmdr.append(iq)
485 return True # success
487 # The bad-guy movement algorithm:
489 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
490 # If both are operating full strength, force is 1000. If both are damaged,
491 # force is -1000. Having shields down subtracts an additional 1000.
493 # 2. Enemy has forces equal to the energy of the attacker plus
494 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
495 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
497 # Attacker Initial energy levels (nominal):
498 # Klingon Romulan Commander Super-Commander
499 # Novice 400 700 1200
501 # Good 450 800 1300 1750
502 # Expert 475 850 1350 1875
503 # Emeritus 500 900 1400 2000
504 # VARIANCE 75 200 200 200
506 # Enemy vessels only move prior to their attack. In Novice - Good games
507 # only commanders move. In Expert games, all enemy vessels move if there
508 # is a commander present. In Emeritus games all enemy vessels move.
510 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
511 # forces are 1000 greater than Enterprise.
513 # Agressive action on average cuts the distance between the ship and
514 # the enemy to 1/4 the original.
516 # 4. At lower energy advantage, movement units are proportional to the
517 # advantage with a 650 advantage being to hold ground, 800 to move forward
518 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
520 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
521 # retreat, especially at high skill levels.
523 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
525 def movebaddy(enemy):
526 "Tactical movement for the bad guys."
530 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
531 if game.skill >= SKILL_EXPERT:
532 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
534 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
535 old_dist = enemy.kdist
536 mdist = int(old_dist + 0.5) # Nearest integer distance
537 # If SC, check with spy to see if should hi-tail it
538 if enemy.type == 'S' and \
539 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
543 # decide whether to advance, retreat, or hold position
544 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
546 forces += 1000 # Good for enemy if shield is down!
547 if not damaged(DPHASER) or not damaged(DPHOTON):
548 if damaged(DPHASER): # phasers damaged
551 forces -= 0.2*(game.energy - 2500.0)
552 if damaged(DPHOTON): # photon torpedoes damaged
555 forces -= 50.0*game.torps
557 # phasers and photon tubes both out!
560 if forces <= 1000.0 and game.condition != "docked": # Typical situation
561 motion = ((forces + randreal(200))/150.0) - 5.0
563 if forces > 1000.0: # Very strong -- move in for kill
564 motion = (1.0 - randreal())**2 * old_dist + 1.0
565 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
566 motion -= game.skill*(2.0-randreal()**2)
568 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
569 # don't move if no motion
572 # Limit motion according to skill
573 if abs(motion) > game.skill:
578 # calculate preferred number of steps
579 nsteps = abs(int(motion))
580 if motion > 0 and nsteps > mdist:
581 nsteps = mdist # don't overshoot
582 if nsteps > QUADSIZE:
583 nsteps = QUADSIZE # This shouldn't be necessary
585 nsteps = 1 # This shouldn't be necessary
587 proutn("NSTEPS = %d:" % nsteps)
588 # Compute preferred values of delta X and Y
589 m = game.sector - enemy.location
590 if 2.0 * abs(m.i) < abs(m.j):
592 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
594 m = (motion * m).sgn()
595 goto = enemy.location
597 for ll in range(nsteps):
599 proutn(" %d" % (ll+1))
600 # Check if preferred position available
611 attempts = 0 # Settle mysterious hang problem
612 while attempts < 20 and not success:
614 if look.i < 0 or look.i >= QUADSIZE:
615 if motion < 0 and tryexit(enemy, look, irun):
617 if krawli == m.i or m.j == 0:
619 look.i = goto.i + krawli
621 elif look.j < 0 or look.j >= QUADSIZE:
622 if motion < 0 and tryexit(enemy, look, irun):
624 if krawlj == m.j or m.i == 0:
626 look.j = goto.j + krawlj
628 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
629 # See if enemy should ram ship
630 if game.quad[look.i][look.j] == game.ship and \
631 (enemy.type == 'C' or enemy.type == 'S'):
632 collision(rammed=True, enemy=enemy)
634 if krawli != m.i and m.j != 0:
635 look.i = goto.i + krawli
637 elif krawlj != m.j and m.i != 0:
638 look.j = goto.j + krawlj
641 break # we have failed
652 return (enemy, old_dist, goto)
655 "Sequence Klingon tactical movement."
658 # Figure out which Klingon is the commander (or Supercommander)
661 if game.quadrant in game.state.kcmdr:
662 for enemy in game.enemies:
663 if enemy.type == 'C':
664 tacmoves.append(movebaddy(enemy))
665 if game.state.kscmdr == game.quadrant:
666 for enemy in game.enemies:
667 if enemy.type == 'S':
668 tacmoves.append(movebaddy(enemy))
670 # If skill level is high, move other Klingons and Romulans too!
671 # Move these last so they can base their actions on what the
673 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
674 for enemy in game.enemies:
675 if enemy.type in ('K', 'R'):
676 tacmoves.append(movebaddy(enemy))
679 def movescom(iq, avoid):
680 "Commander movement helper."
681 # Avoid quadrants with bases if we want to avoid Enterprise
682 if not welcoming(iq) or (avoid and iq in game.state.baseq):
684 if game.justin and not game.iscate:
687 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
688 game.state.kscmdr = iq
689 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
690 if game.state.kscmdr == game.quadrant:
691 # SC has scooted, remove him from current quadrant
696 for enemy in game.enemies:
697 if enemy.type == 'S':
700 if game.condition != "docked":
703 # check for a helpful planet
704 for i in range(game.inplan):
705 if game.state.planets[i].quadrant == game.state.kscmdr and \
706 game.state.planets[i].crystals == "present":
708 game.state.planets[i].pclass = "destroyed"
709 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
712 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
713 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
714 prout(_(" by the Super-commander.\""))
716 return True # looks good!
718 def supercommander():
719 "Move the Super Commander."
726 prout("== SUPERCOMMANDER")
727 # Decide on being active or passive
728 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 \
729 (game.state.date-game.indate) < 3.0)
730 if not game.iscate and avoid:
731 # compute move away from Enterprise
732 idelta = game.state.kscmdr-game.quadrant
733 if idelta.distance() > 2.0:
735 idelta.i = game.state.kscmdr.j-game.quadrant.j
736 idelta.j = game.quadrant.i-game.state.kscmdr.i
738 # compute distances to starbases
739 if not game.state.baseq:
743 sc = game.state.kscmdr
744 for (i, base) in enumerate(game.state.baseq):
745 basetbl.append((i, (base - sc).distance()))
746 if game.state.baseq > 1:
747 basetbl.sort(lambda x, y: cmp(x[1], y[1]))
748 # look for nearest base without a commander, no Enterprise, and
749 # without too many Klingons, and not already under attack.
750 ifindit = iwhichb = 0
751 for (i2, base) in enumerate(game.state.baseq):
752 i = basetbl[i2][0] # bug in original had it not finding nearest
753 if base == game.quadrant or base == game.battle or not welcoming(base):
755 # if there is a commander, and no other base is appropriate,
756 # we will take the one with the commander
757 for cmdr in game.state.kcmdr:
758 if base == cmdr and ifindit != 2:
762 else: # no commander -- use this one
767 return # Nothing suitable -- wait until next time
768 ibq = game.state.baseq[iwhichb]
769 # decide how to move toward base
770 idelta = ibq - game.state.kscmdr
771 # Maximum movement is 1 quadrant in either or both axes
772 idelta = idelta.sgn()
773 # try moving in both x and y directions
774 # there was what looked like a bug in the Almy C code here,
775 # but it might be this translation is just wrong.
776 iq = game.state.kscmdr + idelta
777 if not movescom(iq, avoid):
778 # failed -- try some other maneuvers
779 if idelta.i == 0 or idelta.j == 0:
782 iq.j = game.state.kscmdr.j + 1
783 if not movescom(iq, avoid):
784 iq.j = game.state.kscmdr.j - 1
787 iq.i = game.state.kscmdr.i + 1
788 if not movescom(iq, avoid):
789 iq.i = game.state.kscmdr.i - 1
792 # try moving just in x or y
793 iq.j = game.state.kscmdr.j
794 if not movescom(iq, avoid):
795 iq.j = game.state.kscmdr.j + idelta.j
796 iq.i = game.state.kscmdr.i
799 if len(game.state.baseq) == 0:
802 for ibq in game.state.baseq:
803 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
806 return # no, don't attack base!
809 schedule(FSCDBAS, randreal(1.0, 3.0))
810 if is_scheduled(FCDBAS):
811 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
812 if not communicating():
816 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
818 prout(_(" reports that it is under attack from the Klingon Super-commander."))
819 proutn(_(" It can survive until stardate %d.\"") \
820 % int(scheduled(FSCDBAS)))
823 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
827 game.optime = 0.0 # actually finished
829 # Check for intelligence report
830 if not game.idebug and \
832 (not communicating()) or \
833 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
836 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
837 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
842 if not game.tholian or game.justin:
845 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
848 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
851 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
854 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
858 # something is wrong!
859 game.tholian.move(None)
860 prout("***Internal error: Tholian in a bad spot.")
862 # do nothing if we are blocked
863 if game.quad[tid.i][tid.j] not in ('.', '#'):
865 here = copy.copy(game.tholian.location)
866 delta = (tid - game.tholian.location).sgn()
868 while here.i != tid.i:
870 if game.quad[here.i][here.j] == '.':
871 game.tholian.move(here)
873 while here.j != tid.j:
875 if game.quad[here.i][here.j] == '.':
876 game.tholian.move(here)
877 # check to see if all holes plugged
878 for i in range(QUADSIZE):
879 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
881 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
883 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
885 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
887 # All plugged up -- Tholian splits
888 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
890 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
891 game.tholian.move(None)
894 # Code from battle.c begins here
896 def doshield(shraise):
897 "Change shield status."
905 if scanner.sees("transfer"):
909 prout(_("Shields damaged and down."))
911 if scanner.sees("up"):
913 elif scanner.sees("down"):
916 proutn(_("Do you wish to change shield energy? "))
919 elif damaged(DSHIELD):
920 prout(_("Shields damaged and down."))
923 proutn(_("Shields are up. Do you want them down? "))
930 proutn(_("Shields are down. Do you want them up? "))
936 if action == "SHUP": # raise shields
938 prout(_("Shields already up."))
942 if game.condition != "docked":
944 prout(_("Shields raised."))
947 prout(_("Shields raising uses up last of energy."))
952 elif action == "SHDN":
954 prout(_("Shields already down."))
958 prout(_("Shields lowered."))
961 elif action == "NRG":
962 while scanner.next() != "IHREAL":
964 proutn(_("Energy to transfer to shields- "))
969 if nrg > game.energy:
970 prout(_("Insufficient ship energy."))
973 if game.shield+nrg >= game.inshld:
974 prout(_("Shield energy maximized."))
975 if game.shield+nrg > game.inshld:
976 prout(_("Excess energy requested returned to ship energy"))
977 game.energy -= game.inshld-game.shield
978 game.shield = game.inshld
980 if nrg < 0.0 and game.energy-nrg > game.inenrg:
981 # Prevent shield drain loophole
983 prout(_("Engineering to bridge--"))
984 prout(_(" Scott here. Power circuit problem, Captain."))
985 prout(_(" I can't drain the shields."))
988 if game.shield+nrg < 0:
989 prout(_("All shield energy transferred to ship."))
990 game.energy += game.shield
993 proutn(_("Scotty- \""))
995 prout(_("Transferring energy to shields.\""))
997 prout(_("Draining energy from shields.\""))
1003 "Choose a device to damage, at random."
1005 105, # DSRSENS: short range scanners 10.5%
1006 105, # DLRSENS: long range scanners 10.5%
1007 120, # DPHASER: phasers 12.0%
1008 120, # DPHOTON: photon torpedoes 12.0%
1009 25, # DLIFSUP: life support 2.5%
1010 65, # DWARPEN: warp drive 6.5%
1011 70, # DIMPULS: impulse engines 6.5%
1012 145, # DSHIELD: deflector shields 14.5%
1013 30, # DRADIO: subspace radio 3.0%
1014 45, # DSHUTTL: shuttle 4.5%
1015 15, # DCOMPTR: computer 1.5%
1016 20, # NAVCOMP: navigation system 2.0%
1017 75, # DTRANSP: transporter 7.5%
1018 20, # DSHCTRL: high-speed shield controller 2.0%
1019 10, # DDRAY: death ray 1.0%
1020 30, # DDSP: deep-space probes 3.0%
1022 assert(sum(weights) == 1000)
1023 idx = randrange(1000)
1025 for (i, w) in enumerate(weights):
1029 return None # we should never get here
1031 def collision(rammed, enemy):
1032 "Collision handling fot rammong events."
1033 prouts(_("***RED ALERT! RED ALERT!"))
1035 prout(_("***COLLISION IMMINENT."))
1039 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1041 proutn(_(" rammed by "))
1044 proutn(crmena(False, enemy.type, "sector", enemy.location))
1046 proutn(_(" (original position)"))
1048 deadkl(enemy.location, enemy.type, game.sector)
1049 proutn("***" + crmshp() + " heavily damaged.")
1050 icas = randrange(10, 30)
1051 prout(_("***Sickbay reports %d casualties") % icas)
1053 game.state.crew -= icas
1054 # In the pre-SST2K version, all devices got equiprobably damaged,
1055 # which was silly. Instead, pick up to half the devices at
1056 # random according to our weighting table,
1057 ncrits = randrange(NDEVICES/2)
1061 if game.damage[dev] < 0:
1063 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1064 # Damage for at least time of travel!
1065 game.damage[dev] += game.optime + extradm
1067 prout(_("***Shields are down."))
1068 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1075 def torpedo(origin, bearing, dispersion, number, nburst):
1076 "Let a photon torpedo fly"
1077 if not damaged(DSRSENS) or game.condition == "docked":
1078 setwnd(srscan_window)
1080 setwnd(message_window)
1081 ac = bearing + 0.25*dispersion # dispersion is a random variable
1082 bullseye = (15.0 - bearing)*0.5235988
1083 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1084 bumpto = Coord(0, 0)
1085 # Loop to move a single torpedo
1086 setwnd(message_window)
1087 for step in range(1, QUADSIZE*2):
1088 if not track.next():
1091 if not w.valid_sector():
1093 iquad = game.quad[w.i][w.j]
1094 tracktorpedo(w, step, number, nburst, iquad)
1098 setwnd(message_window)
1099 if not damaged(DSRSENS) or game.condition == "docked":
1100 skip(1) # start new line after text track
1101 if iquad in ('E', 'F'): # Hit our ship
1103 prout(_("Torpedo hits %s.") % crmshp())
1104 hit = 700.0 + randreal(100) - \
1105 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1106 newcnd() # we're blown out of dock
1107 if game.landed or game.condition == "docked":
1108 return hit # Cheat if on a planet
1109 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1110 # is 143 degrees, which is almost exactly 4.8 clockface units
1111 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1113 bumpto = displacement.sector()
1114 if not bumpto.valid_sector():
1116 if game.quad[bumpto.i][bumpto.j] == ' ':
1119 if game.quad[bumpto.i][bumpto.j] != '.':
1120 # can't move into object
1122 game.sector = bumpto
1124 game.quad[w.i][w.j] = '.'
1125 game.quad[bumpto.i][bumpto.j] = iquad
1126 prout(_(" displaced by blast to Sector %s ") % bumpto)
1127 for enemy in game.enemies:
1128 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1131 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1133 if iquad in ('C', 'S') and withprob(0.05):
1134 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1135 prout(_(" torpedo neutralized."))
1137 for enemy in game.enemies:
1138 if w == enemy.location:
1139 kp = math.fabs(enemy.power)
1140 h1 = 700.0 + randrange(100) - \
1141 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1149 if enemy.power == 0:
1152 proutn(crmena(True, iquad, "sector", w))
1153 displacement = course(track.bearing+randreal(-2.4, 2.4), distance=2**0.5)
1155 bumpto = displacement.sector()
1156 if not bumpto.valid_sector():
1157 prout(_(" damaged but not destroyed."))
1159 if game.quad[bumpto.i][bumpto.j] == ' ':
1160 prout(_(" buffeted into black hole."))
1161 deadkl(w, iquad, bumpto)
1162 if game.quad[bumpto.i][bumpto.j] != '.':
1163 prout(_(" damaged but not destroyed."))
1165 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1166 enemy.location = bumpto
1167 game.quad[w.i][w.j] = '.'
1168 game.quad[bumpto.i][bumpto.j] = iquad
1169 for enemy in game.enemies:
1170 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1174 prout("Internal error, no enemy where expected!")
1177 elif iquad == 'B': # Hit a base
1179 prout(_("***STARBASE DESTROYED.."))
1180 game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
1181 game.quad[w.i][w.j] = '.'
1182 game.base.invalidate()
1183 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1
1184 game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1
1185 game.state.basekl += 1
1188 elif iquad == 'P': # Hit a planet
1189 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1190 game.state.nplankl += 1
1191 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1192 game.iplnet.pclass = "destroyed"
1194 game.plnet.invalidate()
1195 game.quad[w.i][w.j] = '.'
1197 # captain perishes on planet
1200 elif iquad == '@': # Hit an inhabited world -- very bad!
1201 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1202 game.state.nworldkl += 1
1203 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1204 game.iplnet.pclass = "destroyed"
1206 game.plnet.invalidate()
1207 game.quad[w.i][w.j] = '.'
1209 # captain perishes on planet
1211 prout(_("The torpedo destroyed an inhabited planet."))
1213 elif iquad == '*': # Hit a star
1217 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1219 elif iquad == '?': # Hit a thingy
1220 if not (game.options & OPTION_THINGY) or withprob(0.3):
1222 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1224 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1226 proutn(_("Mr. Spock-"))
1227 prouts(_(" \"Fascinating!\""))
1231 # Stas Sergeev added the possibility that
1232 # you can shove the Thingy and piss it off.
1233 # It then becomes an enemy and may fire at you.
1236 elif iquad == ' ': # Black hole
1238 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1240 elif iquad == '#': # hit the web
1242 prout(_("***Torpedo absorbed by Tholian web."))
1244 elif iquad == 'T': # Hit a Tholian
1245 h1 = 700.0 + randrange(100) - \
1246 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1249 game.quad[w.i][w.j] = '.'
1254 proutn(crmena(True, 'T', "sector", w))
1256 prout(_(" survives photon blast."))
1258 prout(_(" disappears."))
1259 game.tholian.move(None)
1260 game.quad[w.i][w.j] = '#'
1265 proutn("Don't know how to handle torpedo collision with ")
1266 proutn(crmena(True, iquad, "sector", w))
1271 setwnd(message_window)
1272 prout(_("Torpedo missed."))
1276 "Critical-hit resolution."
1277 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1279 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1280 proutn(_("***CRITICAL HIT--"))
1281 # Select devices and cause damage
1286 # Cheat to prevent shuttle damage unless on ship
1287 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship")):
1290 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1291 game.damage[j] += extradm
1294 for (i, j) in enumerate(cdam):
1296 if skipcount % 3 == 2 and i < len(cdam)-1:
1301 prout(_(" damaged."))
1302 if damaged(DSHIELD) and game.shldup:
1303 prout(_("***Shields knocked down."))
1306 def attack(torps_ok):
1307 # bad guy attacks us
1308 # torps_ok == False forces use of phasers in an attack
1309 # game could be over at this point, check
1319 prout("=== ATTACK!")
1320 # Tholian gets to move before attacking
1323 # if you have just entered the RNZ, you'll get a warning
1324 if game.neutz: # The one chance not to be attacked
1327 # commanders get a chance to tac-move towards you
1328 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:
1329 for (enemy, old_dist, goto) in moveklings():
1330 if enemy.move(goto):
1331 if not damaged(DSRSENS) or game.condition == "docked":
1332 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
1333 if enemy.kdist < old_dist:
1334 proutn(_(" advances to "))
1336 proutn(_(" retreats to "))
1337 prout("Sector %s." % goto)
1339 # if no enemies remain after movement, we're done
1340 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing == game.quadrant and not thing.angered):
1342 # set up partial hits if attack happens during shield status change
1343 pfac = 1.0/game.inshld
1345 chgfac = 0.25 + randreal(0.5)
1347 # message verbosity control
1348 if game.skill <= SKILL_FAIR:
1350 for enemy in game.enemies:
1352 continue # too weak to attack
1353 # compute hit strength and diminish shield power
1355 # Increase chance of photon torpedos if docked or enemy energy is low
1356 if game.condition == "docked":
1358 if enemy.power < 500:
1360 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1362 # different enemies have different probabilities of throwing a torp
1363 usephasers = not torps_ok or \
1364 (enemy.type == 'K' and r > 0.0005) or \
1365 (enemy.type == 'C' and r > 0.015) or \
1366 (enemy.type == 'R' and r > 0.3) or \
1367 (enemy.type == 'S' and r > 0.07) or \
1368 (enemy.type == '?' and r > 0.05)
1369 if usephasers: # Enemy uses phasers
1370 if game.condition == "docked":
1371 continue # Don't waste the effort!
1372 attempt = True # Attempt to attack
1373 dustfac = randreal(0.8, 0.85)
1374 hit = enemy.power*math.pow(dustfac, enemy.kavgd)
1376 else: # Enemy uses photon torpedo
1377 # We should be able to make the bearing() method work here
1378 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1380 proutn(_("***TORPEDO INCOMING"))
1381 if not damaged(DSRSENS):
1382 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1385 dispersion = (randreal()+randreal())*0.5 - 0.5
1386 dispersion += 0.002*enemy.power*dispersion
1387 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1388 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1389 finish(FWON) # Klingons did themselves in!
1390 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1391 return # Supernova or finished
1394 # incoming phaser or torpedo, shields may dissipate it
1395 if game.shldup or game.shldchg or game.condition == "docked":
1396 # shields will take hits
1397 propor = pfac * game.shield
1398 if game.condition == "docked":
1402 hitsh = propor*chgfac*hit+1.0
1404 if absorb > game.shield:
1405 absorb = game.shield
1406 game.shield -= absorb
1408 # taking a hit blasts us out of a starbase dock
1409 if game.condition == "docked":
1411 # but the shields may take care of it
1412 if propor > 0.1 and hit < 0.005*game.energy:
1414 # hit from this opponent got through shields, so take damage
1416 proutn(_("%d unit hit") % int(hit))
1417 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1418 proutn(_(" on the ") + crmshp())
1419 if not damaged(DSRSENS) and usephasers:
1420 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1422 # Decide if hit is critical
1428 if game.energy <= 0:
1429 # Returning home upon your shield, not with it...
1432 if not attempt and game.condition == "docked":
1433 prout(_("***Enemies decide against attacking your ship."))
1434 percent = 100.0*pfac*game.shield+0.5
1436 # Shields fully protect ship
1437 proutn(_("Enemy attack reduces shield strength to "))
1439 # Emit message if starship suffered hit(s)
1441 proutn(_("Energy left %2d shields ") % int(game.energy))
1444 elif not damaged(DSHIELD):
1447 proutn(_("damaged, "))
1448 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1449 # Check if anyone was hurt
1450 if hitmax >= 200 or hittot >= 500:
1451 icas = randrange(int(hittot * 0.015))
1454 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1455 prout(_(" in that last attack.\""))
1457 game.state.crew -= icas
1458 # After attack, reset average distance to enemies
1459 for enemy in game.enemies:
1460 enemy.kavgd = enemy.kdist
1464 def deadkl(w, etype, mv):
1465 "Kill a Klingon, Tholian, Romulan, or Thingy."
1466 # Added mv to allow enemy to "move" before dying
1467 proutn(crmena(True, etype, "sector", mv))
1468 # Decide what kind of enemy it is and update appropriately
1470 # Chalk up a Romulan
1471 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1473 game.state.nromrem -= 1
1482 # Killed some type of Klingon
1483 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1486 game.state.kcmdr.remove(game.quadrant)
1488 if game.state.kcmdr:
1489 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1490 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1493 game.state.remkl -= 1
1495 game.state.nscrem -= 1
1496 game.state.kscmdr.invalidate()
1501 # For each kind of enemy, finish message to player
1502 prout(_(" destroyed."))
1503 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1506 # Remove enemy ship from arrays describing local conditions
1507 for e in game.enemies:
1514 "Return None if target is invalid, otherwise return a course angle."
1515 if not w.valid_sector():
1519 # C code this was translated from is wacky -- why the sign reversal?
1520 delta.j = (w.j - game.sector.j)
1521 delta.i = (game.sector.i - w.i)
1522 if delta == Coord(0, 0):
1524 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1525 prout(_(" I recommend an immediate review of"))
1526 prout(_(" the Captain's psychological profile.\""))
1529 return delta.bearing()
1532 "Launch photon torpedo salvo."
1535 if damaged(DPHOTON):
1536 prout(_("Photon tubes damaged."))
1540 prout(_("No torpedoes left."))
1543 # First, get torpedo count
1546 if scanner.token == "IHALPHA":
1549 elif scanner.token == "IHEOL" or not scanner.waiting():
1550 prout(_("%d torpedoes left.") % game.torps)
1552 proutn(_("Number of torpedoes to fire- "))
1553 continue # Go back around to get a number
1554 else: # key == "IHREAL"
1556 if n <= 0: # abort command
1561 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1564 scanner.chew() # User requested more torps than available
1565 continue # Go back around
1566 break # All is good, go to next stage
1570 key = scanner.next()
1571 if i == 0 and key == "IHEOL":
1572 break # no coordinate waiting, we will try prompting
1573 if i == 1 and key == "IHEOL":
1574 # direct all torpedoes at one target
1576 target.append(target[0])
1577 tcourse.append(tcourse[0])
1580 scanner.push(scanner.token)
1581 target.append(scanner.getcoord())
1582 if target[-1] == None:
1584 tcourse.append(targetcheck(target[-1]))
1585 if tcourse[-1] == None:
1588 if len(target) == 0:
1589 # prompt for each one
1591 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1593 target.append(scanner.getcoord())
1594 if target[-1] == None:
1596 tcourse.append(targetcheck(target[-1]))
1597 if tcourse[-1] == None:
1600 # Loop for moving <n> torpedoes
1602 if game.condition != "docked":
1604 dispersion = (randreal()+randreal())*0.5 -0.5
1605 if math.fabs(dispersion) >= 0.47:
1607 dispersion *= randreal(1.2, 2.2)
1609 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1611 prouts(_("***TORPEDO MISFIRES."))
1614 prout(_(" Remainder of burst aborted."))
1616 prout(_("***Photon tubes damaged by misfire."))
1617 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1619 if game.shldup or game.condition == "docked":
1620 dispersion *= 1.0 + 0.0001*game.shield
1621 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1622 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1624 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1628 "Check for phasers overheating."
1630 checkburn = (rpow-1500.0)*0.00038
1631 if withprob(checkburn):
1632 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1633 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1635 def checkshctrl(rpow):
1636 "Check shield control."
1639 prout(_("Shields lowered."))
1641 # Something bad has happened
1642 prouts(_("***RED ALERT! RED ALERT!"))
1644 hit = rpow*game.shield/game.inshld
1645 game.energy -= rpow+hit*0.8
1646 game.shield -= hit*0.2
1647 if game.energy <= 0.0:
1648 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1653 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1655 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1656 icas = randrange(int(hit*0.012))
1661 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1662 prout(_(" %d casualties so far.\"") % icas)
1664 game.state.crew -= icas
1666 prout(_("Phaser energy dispersed by shields."))
1667 prout(_("Enemy unaffected."))
1672 "Register a phaser hit on Klingons and Romulans."
1679 dustfac = randreal(0.9, 1.0)
1680 hit = wham*math.pow(dustfac, game.enemies[kk].kdist)
1681 kpini = game.enemies[kk].power
1682 kp = math.fabs(kpini)
1683 if PHASEFAC*hit < kp:
1685 if game.enemies[kk].power < 0:
1686 game.enemies[kk].power -= -kp
1688 game.enemies[kk].power -= kp
1689 kpow = game.enemies[kk].power
1690 w = game.enemies[kk].location
1692 if not damaged(DSRSENS):
1694 proutn(_("%d unit hit on ") % int(hit))
1696 proutn(_("Very small hit on "))
1697 ienm = game.quad[w.i][w.j]
1700 proutn(crmena(False, ienm, "sector", w))
1704 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1708 kk -= 1 # don't do the increment
1710 else: # decide whether or not to emasculate klingon
1711 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1712 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1713 prout(_(" has just lost its firepower.\""))
1714 game.enemies[kk].power = -kpow
1719 "Fire phasers at bad guys."
1723 irec = 0 # Cheating inhibitor
1732 # SR sensors and Computer are needed for automode
1733 if damaged(DSRSENS) or damaged(DCOMPTR):
1735 if game.condition == "docked":
1736 prout(_("Phasers can't be fired through base shields."))
1739 if damaged(DPHASER):
1740 prout(_("Phaser control damaged."))
1744 if damaged(DSHCTRL):
1745 prout(_("High speed shield control damaged."))
1748 if game.energy <= 200.0:
1749 prout(_("Insufficient energy to activate high-speed shield control."))
1752 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1754 # Original code so convoluted, I re-did it all
1755 # (That was Tom Almy talking about the C code, I think -- ESR)
1756 while automode == "NOTSET":
1757 key = scanner.next()
1758 if key == "IHALPHA":
1759 if scanner.sees("manual"):
1760 if len(game.enemies)==0:
1761 prout(_("There is no enemy present to select."))
1764 automode = "AUTOMATIC"
1767 key = scanner.next()
1768 elif scanner.sees("automatic"):
1769 if (not itarg) and len(game.enemies) != 0:
1770 automode = "FORCEMAN"
1772 if len(game.enemies)==0:
1773 prout(_("Energy will be expended into space."))
1774 automode = "AUTOMATIC"
1775 key = scanner.next()
1776 elif scanner.sees("no"):
1781 elif key == "IHREAL":
1782 if len(game.enemies)==0:
1783 prout(_("Energy will be expended into space."))
1784 automode = "AUTOMATIC"
1786 automode = "FORCEMAN"
1788 automode = "AUTOMATIC"
1791 if len(game.enemies)==0:
1792 prout(_("Energy will be expended into space."))
1793 automode = "AUTOMATIC"
1795 automode = "FORCEMAN"
1797 proutn(_("Manual or automatic? "))
1802 if automode == "AUTOMATIC":
1803 if key == "IHALPHA" and scanner.sees("no"):
1805 key = scanner.next()
1806 if key != "IHREAL" and len(game.enemies) != 0:
1807 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1812 for i in range(len(game.enemies)):
1813 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1815 proutn(_("%d units required. ") % irec)
1817 proutn(_("Units to fire= "))
1818 key = scanner.next()
1823 proutn(_("Energy available= %.2f") % avail)
1826 if not rpow > avail:
1832 key = scanner.next()
1833 if key == "IHALPHA" and scanner.sees("no"):
1836 game.energy -= 200 # Go and do it!
1837 if checkshctrl(rpow):
1842 if len(game.enemies):
1845 for i in range(len(game.enemies)):
1849 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1850 over = randreal(1.01, 1.06) * hits[i]
1852 powrem -= hits[i] + over
1853 if powrem <= 0 and temp < hits[i]:
1862 if extra > 0 and not game.alldone:
1864 proutn(_("*** Tholian web absorbs "))
1865 if len(game.enemies)>0:
1866 proutn(_("excess "))
1867 prout(_("phaser energy."))
1869 prout(_("%d expended on empty space.") % int(extra))
1870 elif automode == "FORCEMAN":
1873 if damaged(DCOMPTR):
1874 prout(_("Battle computer damaged, manual fire only."))
1877 prouts(_("---WORKING---"))
1879 prout(_("Short-range-sensors-damaged"))
1880 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1881 prout(_("Manual-fire-must-be-used"))
1883 elif automode == "MANUAL":
1885 for k in range(len(game.enemies)):
1886 aim = game.enemies[k].location
1887 ienm = game.quad[aim.i][aim.j]
1889 proutn(_("Energy available= %.2f") % (avail-0.006))
1893 if damaged(DSRSENS) and \
1894 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1895 prout(cramen(ienm) + _(" can't be located without short range scan."))
1898 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
1903 if itarg and k > kz:
1904 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1907 if not damaged(DCOMPTR):
1912 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1913 key = scanner.next()
1914 if key == "IHALPHA" and scanner.sees("no"):
1916 key = scanner.next()
1918 if key == "IHALPHA":
1922 if k == 1: # Let me say I'm baffled by this
1925 if scanner.real < 0:
1929 hits[k] = scanner.real
1930 rpow += scanner.real
1931 # If total requested is too much, inform and start over
1933 prout(_("Available energy exceeded -- try again."))
1936 key = scanner.next() # scan for next value
1939 # zero energy -- abort
1942 if key == "IHALPHA" and scanner.sees("no"):
1947 game.energy -= 200.0
1948 if checkshctrl(rpow):
1952 # Say shield raised or malfunction, if necessary
1959 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1960 prouts(_(" CLICK CLICK POP . . ."))
1961 prout(_(" No response, sir!"))
1964 prout(_("Shields raised."))
1969 # Code from events,c begins here.
1971 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1972 # event of each type active at any given time. Mostly these means we can
1973 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1974 # BSD Trek, from which we swiped the idea, can have up to 5.
1976 def unschedule(evtype):
1977 "Remove an event from the schedule."
1978 game.future[evtype].date = FOREVER
1979 return game.future[evtype]
1981 def is_scheduled(evtype):
1982 "Is an event of specified type scheduled."
1983 return game.future[evtype].date != FOREVER
1985 def scheduled(evtype):
1986 "When will this event happen?"
1987 return game.future[evtype].date
1989 def schedule(evtype, offset):
1990 "Schedule an event of specified type."
1991 game.future[evtype].date = game.state.date + offset
1992 return game.future[evtype]
1994 def postpone(evtype, offset):
1995 "Postpone a scheduled event."
1996 game.future[evtype].date += offset
1999 "Rest period is interrupted by event."
2002 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2004 game.resting = False
2010 "Run through the event queue looking for things to do."
2012 fintim = game.state.date + game.optime
2021 def tractorbeam(yank):
2022 "Tractor-beaming cases merge here."
2024 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2026 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2027 # If Kirk & Co. screwing around on planet, handle
2028 atover(True) # atover(true) is Grab
2031 if game.icraft: # Caught in Galileo?
2034 # Check to see if shuttle is aboard
2035 if game.iscraft == "offship":
2038 prout(_("Galileo, left on the planet surface, is captured"))
2039 prout(_("by aliens and made into a flying McDonald's."))
2040 game.damage[DSHUTTL] = -10
2041 game.iscraft = "removed"
2043 prout(_("Galileo, left on the planet surface, is well hidden."))
2045 game.quadrant = game.state.kscmdr
2047 game.quadrant = game.state.kcmdr[i]
2048 game.sector = randplace(QUADSIZE)
2049 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2050 % (game.quadrant, game.sector))
2052 prout(_("(Remainder of rest/repair period cancelled.)"))
2053 game.resting = False
2055 if not damaged(DSHIELD) and game.shield > 0:
2056 doshield(shraise=True) # raise shields
2057 game.shldchg = False
2059 prout(_("(Shields not currently useable.)"))
2061 # Adjust finish time to time of tractor beaming?
2062 # fintim = game.state.date+game.optime
2063 attack(torps_ok=False)
2064 if not game.state.kcmdr:
2067 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2070 "Code merges here for any commander destroying a starbase."
2071 # Not perfect, but will have to do
2072 # Handle case where base is in same quadrant as starship
2073 if game.battle == game.quadrant:
2074 game.state.chart[game.battle.i][game.battle.j].starbase = False
2075 game.quad[game.base.i][game.base.j] = '.'
2076 game.base.invalidate()
2079 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2080 elif game.state.baseq and communicating():
2081 # Get word via subspace radio
2084 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2085 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2087 prout(_("the Klingon Super-Commander"))
2089 prout(_("a Klingon Commander"))
2090 game.state.chart[game.battle.i][game.battle.j].starbase = False
2091 # Remove Starbase from galaxy
2092 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2093 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2095 # reinstate a commander's base attack
2099 game.battle.invalidate()
2101 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2102 for i in range(1, NEVENTS):
2103 if i == FSNOVA: proutn("=== Supernova ")
2104 elif i == FTBEAM: proutn("=== T Beam ")
2105 elif i == FSNAP: proutn("=== Snapshot ")
2106 elif i == FBATTAK: proutn("=== Base Attack ")
2107 elif i == FCDBAS: proutn("=== Base Destroy ")
2108 elif i == FSCMOVE: proutn("=== SC Move ")
2109 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2110 elif i == FDSPROB: proutn("=== Probe Move ")
2111 elif i == FDISTR: proutn("=== Distress Call ")
2112 elif i == FENSLV: proutn("=== Enslavement ")
2113 elif i == FREPRO: proutn("=== Klingon Build ")
2115 prout("%.2f" % (scheduled(i)))
2118 radio_was_broken = damaged(DRADIO)
2121 # Select earliest extraneous event, evcode==0 if no events
2126 for l in range(1, NEVENTS):
2127 if game.future[l].date < datemin:
2130 prout("== Event %d fires" % evcode)
2131 datemin = game.future[l].date
2132 xtime = datemin-game.state.date
2133 game.state.date = datemin
2134 # Decrement Federation resources and recompute remaining time
2135 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2137 if game.state.remtime <= 0:
2140 # Any crew left alive?
2141 if game.state.crew <= 0:
2144 # Is life support adequate?
2145 if damaged(DLIFSUP) and game.condition != "docked":
2146 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2149 game.lsupres -= xtime
2150 if game.damage[DLIFSUP] <= xtime:
2151 game.lsupres = game.inlsr
2154 if game.condition == "docked":
2156 # Don't fix Deathray here
2157 for l in range(NDEVICES):
2158 if game.damage[l] > 0.0 and l != DDRAY:
2159 if game.damage[l]-repair > 0.0:
2160 game.damage[l] -= repair
2162 game.damage[l] = 0.0
2163 # If radio repaired, update star chart and attack reports
2164 if radio_was_broken and not damaged(DRADIO):
2165 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2166 prout(_(" surveillance reports are coming in."))
2168 if not game.iseenit:
2172 prout(_(" The star chart is now up to date.\""))
2174 # Cause extraneous event EVCODE to occur
2175 game.optime -= xtime
2176 if evcode == FSNOVA: # Supernova
2179 schedule(FSNOVA, expran(0.5*game.intime))
2180 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2182 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2183 if game.state.nscrem == 0 or \
2184 ictbeam or istract or \
2185 game.condition == "docked" or game.isatb == 1 or game.iscate:
2187 if game.ientesc or \
2188 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2189 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2190 (damaged(DSHIELD) and \
2191 (game.energy < 2500 or damaged(DPHASER)) and \
2192 (game.torps < 5 or damaged(DPHOTON))):
2194 istract = ictbeam = True
2195 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2198 elif evcode == FTBEAM: # Tractor beam
2199 if not game.state.kcmdr:
2202 i = randrange(len(game.state.kcmdr))
2203 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2204 if istract or game.condition == "docked" or yank == 0:
2205 # Drats! Have to reschedule
2207 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2211 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2212 game.snapsht = copy.deepcopy(game.state)
2213 game.state.snap = True
2214 schedule(FSNAP, expran(0.5 * game.intime))
2215 elif evcode == FBATTAK: # Commander attacks starbase
2216 if not game.state.kcmdr or not game.state.baseq:
2222 for ibq in game.state.baseq:
2223 for cmdr in game.state.kcmdr:
2224 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2227 # no match found -- try later
2228 schedule(FBATTAK, expran(0.3*game.intime))
2233 # commander + starbase combination found -- launch attack
2235 schedule(FCDBAS, randreal(1.0, 4.0))
2236 if game.isatb: # extra time if SC already attacking
2237 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2238 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2239 game.iseenit = False
2240 if not communicating():
2241 continue # No warning :-(
2245 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2246 prout(_(" reports that it is under attack and that it can"))
2247 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2250 elif evcode == FSCDBAS: # Supercommander destroys base
2253 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2254 continue # WAS RETURN!
2256 game.battle = game.state.kscmdr
2258 elif evcode == FCDBAS: # Commander succeeds in destroying base
2259 if evcode == FCDBAS:
2261 if not game.state.baseq() \
2262 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2263 game.battle.invalidate()
2265 # find the lucky pair
2266 for cmdr in game.state.kcmdr:
2267 if cmdr == game.battle:
2270 # No action to take after all
2273 elif evcode == FSCMOVE: # Supercommander moves
2274 schedule(FSCMOVE, 0.2777)
2275 if not game.ientesc and not istract and game.isatb != 1 and \
2276 (not game.iscate or not game.justin):
2278 elif evcode == FDSPROB: # Move deep space probe
2279 schedule(FDSPROB, 0.01)
2280 if not game.probe.next():
2281 if not game.probe.quadrant().valid_quadrant() or \
2282 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2283 # Left galaxy or ran into supernova
2287 proutn(_("Lt. Uhura- \"The deep space probe "))
2288 if not game.probe.quadrant().valid_quadrant():
2289 prout(_("has left the galaxy.\""))
2291 prout(_("is no longer transmitting.\""))
2297 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2298 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2300 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2301 chp.klingons = pdest.klingons
2302 chp.starbase = pdest.starbase
2303 chp.stars = pdest.stars
2304 pdest.charted = True
2305 game.probe.moves -= 1 # One less to travel
2306 if game.probe.arrived() and game.isarmed and pdest.stars:
2307 supernova(game.probe) # fire in the hole!
2309 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2311 elif evcode == FDISTR: # inhabited system issues distress call
2313 # try a whole bunch of times to find something suitable
2314 for i in range(100):
2315 # need a quadrant which is not the current one,
2316 # which has some stars which are inhabited and
2317 # not already under attack, which is not
2318 # supernova'ed, and which has some Klingons in it
2319 w = randplace(GALSIZE)
2320 q = game.state.galaxy[w.i][w.j]
2321 if not (game.quadrant == w or q.planet == None or \
2322 not q.planet.inhabited or \
2323 q.supernova or q.status!="secure" or q.klingons<=0):
2326 # can't seem to find one; ignore this call
2328 prout("=== Couldn't find location for distress event.")
2330 # got one!! Schedule its enslavement
2331 ev = schedule(FENSLV, expran(game.intime))
2333 q.status = "distressed"
2334 # tell the captain about it if we can
2336 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2337 % (q.planet, repr(w)))
2338 prout(_("by a Klingon invasion fleet."))
2341 elif evcode == FENSLV: # starsystem is enslaved
2342 ev = unschedule(FENSLV)
2343 # see if current distress call still active
2344 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2348 q.status = "enslaved"
2350 # play stork and schedule the first baby
2351 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2352 ev2.quadrant = ev.quadrant
2354 # report the disaster if we can
2356 prout(_("Uhura- We've lost contact with starsystem %s") % \
2358 prout(_("in Quadrant %s.\n") % ev.quadrant)
2359 elif evcode == FREPRO: # Klingon reproduces
2360 # If we ever switch to a real event queue, we'll need to
2361 # explicitly retrieve and restore the x and y.
2362 ev = schedule(FREPRO, expran(1.0 * game.intime))
2363 # see if current distress call still active
2364 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2368 if game.state.remkl >= MAXKLGAME:
2369 continue # full right now
2370 # reproduce one Klingon
2373 if game.klhere >= MAXKLQUAD:
2375 # this quadrant not ok, pick an adjacent one
2376 for m.i in range(w.i - 1, w.i + 2):
2377 for m.j in range(w.j - 1, w.j + 2):
2378 if not m.valid_quadrant():
2380 q = game.state.galaxy[m.i][m.j]
2381 # check for this quad ok (not full & no snova)
2382 if q.klingons >= MAXKLQUAD or q.supernova:
2386 continue # search for eligible quadrant failed
2390 game.state.remkl += 1
2392 if game.quadrant == w:
2394 game.enemies.append(newkling())
2395 # recompute time left
2398 if game.quadrant == w:
2399 prout(_("Spock- sensors indicate the Klingons have"))
2400 prout(_("launched a warship from %s.") % q.planet)
2402 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2403 if q.planet != None:
2404 proutn(_("near %s ") % q.planet)
2405 prout(_("in Quadrant %s.") % w)
2411 key = scanner.next()
2414 proutn(_("How long? "))
2419 origTime = delay = scanner.real
2422 if delay >= game.state.remtime or len(game.enemies) != 0:
2423 proutn(_("Are you sure? "))
2426 # Alternate resting periods (events) with attacks
2430 game.resting = False
2431 if not game.resting:
2432 prout(_("%d stardates left.") % int(game.state.remtime))
2434 temp = game.optime = delay
2435 if len(game.enemies):
2436 rtime = randreal(1.0, 2.0)
2440 if game.optime < delay:
2441 attack(torps_ok=False)
2449 # Repair Deathray if long rest at starbase
2450 if origTime-delay >= 9.99 and game.condition == "docked":
2451 game.damage[DDRAY] = 0.0
2452 # leave if quadrant supernovas
2453 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2455 game.resting = False
2460 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2461 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2463 # Wow! We've supernova'ed
2464 supernova(game.quadrant)
2466 # handle initial nova
2467 game.quad[nov.i][nov.j] = '.'
2468 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2469 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2470 game.state.starkl += 1
2471 # Set up queue to recursively trigger adjacent stars
2477 for offset.i in range(-1, 1+1):
2478 for offset.j in range(-1, 1+1):
2479 if offset.j == 0 and offset.i == 0:
2481 neighbor = start + offset
2482 if not neighbor.valid_sector():
2484 iquad = game.quad[neighbor.i][neighbor.j]
2485 # Empty space ends reaction
2486 if iquad in ('.', '?', ' ', 'T', '#'):
2488 elif iquad == '*': # Affect another star
2490 # This star supernovas
2491 supernova(game.quadrant)
2494 hits.append(neighbor)
2495 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2496 game.state.starkl += 1
2497 proutn(crmena(True, '*', "sector", neighbor))
2499 game.quad[neighbor.i][neighbor.j] = '.'
2501 elif iquad in ('P', '@'): # Destroy planet
2502 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2504 game.state.nplankl += 1
2506 game.state.nworldkl += 1
2507 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2508 game.iplnet.pclass = "destroyed"
2510 game.plnet.invalidate()
2514 game.quad[neighbor.i][neighbor.j] = '.'
2515 elif iquad == 'B': # Destroy base
2516 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2517 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2518 game.base.invalidate()
2519 game.state.basekl += 1
2521 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2522 game.quad[neighbor.i][neighbor.j] = '.'
2523 elif iquad in ('E', 'F'): # Buffet ship
2524 prout(_("***Starship buffeted by nova."))
2526 if game.shield >= 2000.0:
2527 game.shield -= 2000.0
2529 diff = 2000.0 - game.shield
2533 prout(_("***Shields knocked out."))
2534 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2536 game.energy -= 2000.0
2537 if game.energy <= 0:
2540 # add in course nova contributes to kicking starship
2541 bump += (game.sector-hits[-1]).sgn()
2542 elif iquad == 'K': # kill klingon
2543 deadkl(neighbor, iquad, neighbor)
2544 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2545 for ll in range(len(game.enemies)):
2546 if game.enemies[ll].location == neighbor:
2548 game.enemies[ll].power -= 800.0 # If firepower is lost, die
2549 if game.enemies[ll].power <= 0.0:
2550 deadkl(neighbor, iquad, neighbor)
2552 newc = neighbor + neighbor - hits[-1]
2553 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2554 if not newc.valid_sector():
2555 # can't leave quadrant
2558 iquad1 = game.quad[newc.i][newc.j]
2560 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2562 deadkl(neighbor, iquad, newc)
2565 # can't move into something else
2568 proutn(_(", buffeted to Sector %s") % newc)
2569 game.quad[neighbor.i][neighbor.j] = '.'
2570 game.quad[newc.i][newc.j] = iquad
2571 game.enemies[ll].move(newc)
2572 # Starship affected by nova -- kick it away.
2574 direc = ncourse[3*(bump.i+1)+bump.j+2]
2579 scourse = course(bearing=direc, distance=dist)
2580 game.optime = scourse.time(warp=4)
2582 prout(_("Force of nova displaces starship."))
2583 imove(scourse, noattack=True)
2584 game.optime = scourse.time(warp=4)
2588 "Star goes supernova."
2593 # Scheduled supernova -- select star at random.
2596 for nq.i in range(GALSIZE):
2597 for nq.j in range(GALSIZE):
2598 stars += game.state.galaxy[nq.i][nq.j].stars
2600 return # nothing to supernova exists
2601 num = randrange(stars) + 1
2602 for nq.i in range(GALSIZE):
2603 for nq.j in range(GALSIZE):
2604 num -= game.state.galaxy[nq.i][nq.j].stars
2610 proutn("=== Super nova here?")
2613 if not nq == game.quadrant or game.justin:
2614 # it isn't here, or we just entered (treat as enroute)
2617 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2618 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2621 # we are in the quadrant!
2622 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2623 for ns.i in range(QUADSIZE):
2624 for ns.j in range(QUADSIZE):
2625 if game.quad[ns.i][ns.j]=='*':
2632 prouts(_("***RED ALERT! RED ALERT!"))
2634 prout(_("***Incipient supernova detected at Sector %s") % ns)
2635 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2636 proutn(_("Emergency override attempts t"))
2637 prouts("***************")
2641 # destroy any Klingons in supernovaed quadrant
2642 kldead = game.state.galaxy[nq.i][nq.j].klingons
2643 game.state.galaxy[nq.i][nq.j].klingons = 0
2644 if nq == game.state.kscmdr:
2645 # did in the Supercommander!
2646 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2650 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2651 comkills = len(game.state.kcmdr) - len(survivors)
2652 game.state.kcmdr = survivors
2654 if not game.state.kcmdr:
2656 game.state.remkl -= kldead
2657 # destroy Romulans and planets in supernovaed quadrant
2658 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2659 game.state.galaxy[nq.i][nq.j].romulans = 0
2660 game.state.nromrem -= nrmdead
2662 for loop in range(game.inplan):
2663 if game.state.planets[loop].quadrant == nq:
2664 game.state.planets[loop].pclass = "destroyed"
2666 # Destroy any base in supernovaed quadrant
2667 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2668 # If starship caused supernova, tally up destruction
2670 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2671 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2672 game.state.nplankl += npdead
2673 # mark supernova in galaxy and in star chart
2674 if game.quadrant == nq or communicating():
2675 game.state.galaxy[nq.i][nq.j].supernova = True
2676 # If supernova destroys last Klingons give special message
2677 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2680 prout(_("Lucky you!"))
2681 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2684 # if some Klingons remain, continue or die in supernova
2689 # Code from finish.c ends here.
2692 "Self-destruct maneuver. Finish with a BANG!"
2694 if damaged(DCOMPTR):
2695 prout(_("Computer damaged; cannot execute destruct sequence."))
2697 prouts(_("---WORKING---")); skip(1)
2698 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2699 prouts(" 10"); skip(1)
2700 prouts(" 9"); skip(1)
2701 prouts(" 8"); skip(1)
2702 prouts(" 7"); skip(1)
2703 prouts(" 6"); skip(1)
2705 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2707 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2709 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2712 if game.passwd != scanner.token:
2713 prouts(_("PASSWORD-REJECTED;"))
2715 prouts(_("CONTINUITY-EFFECTED"))
2718 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2719 prouts(" 5"); skip(1)
2720 prouts(" 4"); skip(1)
2721 prouts(" 3"); skip(1)
2722 prouts(" 2"); skip(1)
2723 prouts(" 1"); skip(1)
2725 prouts(_("GOODBYE-CRUEL-WORLD"))
2733 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2737 if len(game.enemies) != 0:
2738 whammo = 25.0 * game.energy
2739 for l in range(len(game.enemies)):
2740 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2741 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2745 "Compute our rate of kils over time."
2746 elapsed = game.state.date - game.indate
2747 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2750 starting = (game.inkling + game.incom + game.inscom)
2751 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2752 return (starting - remaining)/elapsed
2756 badpt = 5.0*game.state.starkl + \
2758 10.0*game.state.nplankl + \
2759 300*game.state.nworldkl + \
2761 100.0*game.state.basekl +\
2763 if game.ship == 'F':
2765 elif game.ship == None:
2770 # end the game, with appropriate notfications
2774 prout(_("It is stardate %.1f.") % game.state.date)
2776 if ifin == FWON: # Game has been won
2777 if game.state.nromrem != 0:
2778 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2781 prout(_("You have smashed the Klingon invasion fleet and saved"))
2782 prout(_("the Federation."))
2787 badpt = 0.0 # Close enough!
2788 # killsPerDate >= RateMax
2789 if game.state.date-game.indate < 5.0 or \
2790 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2792 prout(_("In fact, you have done so well that Starfleet Command"))
2793 if game.skill == SKILL_NOVICE:
2794 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2795 elif game.skill == SKILL_FAIR:
2796 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2797 elif game.skill == SKILL_GOOD:
2798 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2799 elif game.skill == SKILL_EXPERT:
2800 prout(_("promotes you to Commodore Emeritus."))
2802 prout(_("Now that you think you're really good, try playing"))
2803 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2804 elif game.skill == SKILL_EMERITUS:
2806 proutn(_("Computer- "))
2807 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2809 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2811 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2813 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2815 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2817 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2819 prout(_("Now you can retire and write your own Star Trek game!"))
2821 elif game.skill >= SKILL_EXPERT:
2822 if game.thawed and not game.idebug:
2823 prout(_("You cannot get a citation, so..."))
2825 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2829 # Only grant long life if alive (original didn't!)
2831 prout(_("LIVE LONG AND PROSPER."))
2836 elif ifin == FDEPLETE: # Federation Resources Depleted
2837 prout(_("Your time has run out and the Federation has been"))
2838 prout(_("conquered. Your starship is now Klingon property,"))
2839 prout(_("and you are put on trial as a war criminal. On the"))
2840 proutn(_("basis of your record, you are "))
2841 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2842 prout(_("acquitted."))
2844 prout(_("LIVE LONG AND PROSPER."))
2846 prout(_("found guilty and"))
2847 prout(_("sentenced to death by slow torture."))
2851 elif ifin == FLIFESUP:
2852 prout(_("Your life support reserves have run out, and"))
2853 prout(_("you die of thirst, starvation, and asphyxiation."))
2854 prout(_("Your starship is a derelict in space."))
2856 prout(_("Your energy supply is exhausted."))
2858 prout(_("Your starship is a derelict in space."))
2859 elif ifin == FBATTLE:
2860 prout(_("The %s has been destroyed in battle.") % crmshp())
2862 prout(_("Dulce et decorum est pro patria mori."))
2864 prout(_("You have made three attempts to cross the negative energy"))
2865 prout(_("barrier which surrounds the galaxy."))
2867 prout(_("Your navigation is abominable."))
2870 prout(_("Your starship has been destroyed by a nova."))
2871 prout(_("That was a great shot."))
2873 elif ifin == FSNOVAED:
2874 prout(_("The %s has been fried by a supernova.") % crmshp())
2875 prout(_("...Not even cinders remain..."))
2876 elif ifin == FABANDN:
2877 prout(_("You have been captured by the Klingons. If you still"))
2878 prout(_("had a starbase to be returned to, you would have been"))
2879 prout(_("repatriated and given another chance. Since you have"))
2880 prout(_("no starbases, you will be mercilessly tortured to death."))
2881 elif ifin == FDILITHIUM:
2882 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2883 elif ifin == FMATERIALIZE:
2884 prout(_("Starbase was unable to re-materialize your starship."))
2885 prout(_("Sic transit gloria mundi"))
2886 elif ifin == FPHASER:
2887 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2889 prout(_("You and your landing party have been"))
2890 prout(_("converted to energy, disipating through space."))
2891 elif ifin == FMINING:
2892 prout(_("You are left with your landing party on"))
2893 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2895 prout(_("They are very fond of \"Captain Kirk\" soup."))
2897 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2898 elif ifin == FDPLANET:
2899 prout(_("You and your mining party perish."))
2901 prout(_("That was a great shot."))
2904 prout(_("The Galileo is instantly annihilated by the supernova."))
2905 prout(_("You and your mining party are atomized."))
2907 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2908 prout(_("joins the Romulans, wreaking terror on the Federation."))
2909 elif ifin == FPNOVA:
2910 prout(_("You and your mining party are atomized."))
2912 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2913 prout(_("joins the Romulans, wreaking terror on the Federation."))
2914 elif ifin == FSTRACTOR:
2915 prout(_("The shuttle craft Galileo is also caught,"))
2916 prout(_("and breaks up under the strain."))
2918 prout(_("Your debris is scattered for millions of miles."))
2919 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2921 prout(_("The mutants attack and kill Spock."))
2922 prout(_("Your ship is captured by Klingons, and"))
2923 prout(_("your crew is put on display in a Klingon zoo."))
2924 elif ifin == FTRIBBLE:
2925 prout(_("Tribbles consume all remaining water,"))
2926 prout(_("food, and oxygen on your ship."))
2928 prout(_("You die of thirst, starvation, and asphyxiation."))
2929 prout(_("Your starship is a derelict in space."))
2931 prout(_("Your ship is drawn to the center of the black hole."))
2932 prout(_("You are crushed into extremely dense matter."))
2934 prout(_("Your last crew member has died."))
2935 if game.ship == 'F':
2937 elif game.ship == 'E':
2940 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2941 goodies = game.state.remres/game.inresor
2942 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2943 if goodies/baddies >= randreal(1.0, 1.5):
2944 prout(_("As a result of your actions, a treaty with the Klingon"))
2945 prout(_("Empire has been signed. The terms of the treaty are"))
2946 if goodies/baddies >= randreal(3.0):
2947 prout(_("favorable to the Federation."))
2949 prout(_("Congratulations!"))
2951 prout(_("highly unfavorable to the Federation."))
2953 prout(_("The Federation will be destroyed."))
2955 prout(_("Since you took the last Klingon with you, you are a"))
2956 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2957 prout(_("statue in your memory. Rest in peace, and try not"))
2958 prout(_("to think about pigeons."))
2963 "Compute player's score."
2964 timused = game.state.date - game.indate
2965 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2967 game.perdate = killrate()
2968 ithperd = 500*game.perdate + 0.5
2971 iwon = 100*game.skill
2972 if game.ship == 'E':
2974 elif game.ship == 'F':
2978 game.score = 10*(game.inkling - game.state.remkl) \
2979 + 50*(game.incom - len(game.state.kcmdr)) \
2981 + 20*(game.inrom - game.state.nromrem) \
2982 + 200*(game.inscom - game.state.nscrem) \
2983 - game.state.nromrem \
2988 prout(_("Your score --"))
2989 if game.inrom - game.state.nromrem:
2990 prout(_("%6d Romulans destroyed %5d") %
2991 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
2992 if game.state.nromrem and game.gamewon:
2993 prout(_("%6d Romulans captured %5d") %
2994 (game.state.nromrem, game.state.nromrem))
2995 if game.inkling - game.state.remkl:
2996 prout(_("%6d ordinary Klingons destroyed %5d") %
2997 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
2998 if game.incom - len(game.state.kcmdr):
2999 prout(_("%6d Klingon commanders destroyed %5d") %
3000 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3001 if game.inscom - game.state.nscrem:
3002 prout(_("%6d Super-Commander destroyed %5d") %
3003 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3005 prout(_("%6.2f Klingons per stardate %5d") %
3006 (game.perdate, ithperd))
3007 if game.state.starkl:
3008 prout(_("%6d stars destroyed by your action %5d") %
3009 (game.state.starkl, -5*game.state.starkl))
3010 if game.state.nplankl:
3011 prout(_("%6d planets destroyed by your action %5d") %
3012 (game.state.nplankl, -10*game.state.nplankl))
3013 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3014 prout(_("%6d inhabited planets destroyed by your action %5d") %
3015 (game.state.nworldkl, -300*game.state.nworldkl))
3016 if game.state.basekl:
3017 prout(_("%6d bases destroyed by your action %5d") %
3018 (game.state.basekl, -100*game.state.basekl))
3020 prout(_("%6d calls for help from starbase %5d") %
3021 (game.nhelp, -45*game.nhelp))
3023 prout(_("%6d casualties incurred %5d") %
3024 (game.casual, -game.casual))
3026 prout(_("%6d crew abandoned in space %5d") %
3027 (game.abandoned, -3*game.abandoned))
3029 prout(_("%6d ship(s) lost or destroyed %5d") %
3030 (klship, -100*klship))
3032 prout(_("Penalty for getting yourself killed -200"))
3034 proutn(_("Bonus for winning "))
3035 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3036 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3037 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3038 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3039 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3040 prout(" %5d" % iwon)
3042 prout(_("TOTAL SCORE %5d") % game.score)
3045 "Emit winner's commemmorative plaque."
3048 proutn(_("File or device name for your plaque: "))
3051 fp = open(winner, "w")
3054 prout(_("Invalid name."))
3056 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3058 # The 38 below must be 64 for 132-column paper
3059 nskip = 38 - len(winner)/2
3060 fp.write("\n\n\n\n")
3061 # --------DRAW ENTERPRISE PICTURE.
3062 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3063 fp.write(" EEE E : : : E\n" )
3064 fp.write(" EE EEE E : : NCC-1701 : E\n")
3065 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3066 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3067 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3068 fp.write(" EEEEEEE EEEEE E E E E\n")
3069 fp.write(" EEE E E E E\n")
3070 fp.write(" E E E E\n")
3071 fp.write(" EEEEEEEEEEEEE E E\n")
3072 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3073 fp.write(" :E : EEEE E\n")
3074 fp.write(" .-E -:----- E\n")
3075 fp.write(" :E : E\n")
3076 fp.write(" EE : EEEEEEEE\n")
3077 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3079 fp.write(_(" U. S. S. ENTERPRISE\n"))
3080 fp.write("\n\n\n\n")
3081 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3083 fp.write(_(" Starfleet Command bestows to you\n"))
3085 fp.write("%*s%s\n\n" % (nskip, "", winner))
3086 fp.write(_(" the rank of\n\n"))
3087 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3089 if game.skill == SKILL_EXPERT:
3090 fp.write(_(" Expert level\n\n"))
3091 elif game.skill == SKILL_EMERITUS:
3092 fp.write(_("Emeritus level\n\n"))
3094 fp.write(_(" Cheat level\n\n"))
3095 timestring = time.ctime()
3096 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3097 (timestring+4, timestring+20, timestring+11))
3098 fp.write(_(" Your score: %d\n\n") % game.score)
3099 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3102 # Code from io.c begins here
3104 rows = linecount = 0 # for paging
3107 fullscreen_window = None
3108 srscan_window = None
3109 report_window = None
3110 status_window = None
3111 lrscan_window = None
3112 message_window = None
3113 prompt_window = None
3118 "for some recent versions of python2, the following enables UTF8"
3119 "for the older ones we probably need to set C locale, and the python3"
3120 "has no problems at all"
3121 if sys.version_info[0] < 3:
3123 locale.setlocale(locale.LC_ALL, "")
3124 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3125 gettext.textdomain("sst")
3126 if not (game.options & OPTION_CURSES):
3127 ln_env = os.getenv("LINES")
3133 stdscr = curses.initscr()
3137 if game.options & OPTION_COLOR:
3138 curses.start_color()
3139 curses.use_default_colors()
3140 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3141 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3142 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3143 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3144 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3145 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3146 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3147 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3148 global fullscreen_window, srscan_window, report_window, status_window
3149 global lrscan_window, message_window, prompt_window
3150 (rows, columns) = stdscr.getmaxyx()
3151 fullscreen_window = stdscr
3152 srscan_window = curses.newwin(12, 25, 0, 0)
3153 report_window = curses.newwin(11, 0, 1, 25)
3154 status_window = curses.newwin(10, 0, 1, 39)
3155 lrscan_window = curses.newwin(5, 0, 0, 64)
3156 message_window = curses.newwin(0, 0, 12, 0)
3157 prompt_window = curses.newwin(1, 0, rows-2, 0)
3158 message_window.scrollok(True)
3159 setwnd(fullscreen_window)
3163 if game.options & OPTION_CURSES:
3164 stdscr.keypad(False)
3170 "Wait for user action -- OK to do nothing if on a TTY"
3171 if game.options & OPTION_CURSES:
3176 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3180 if game.skill > SKILL_FAIR:
3181 prompt = _("[CONTINUE?]")
3183 prompt = _("[PRESS ENTER TO CONTINUE]")
3185 if game.options & OPTION_CURSES:
3187 setwnd(prompt_window)
3188 prompt_window.clear()
3189 prompt_window.addstr(prompt)
3190 prompt_window.getstr()
3191 prompt_window.clear()
3192 prompt_window.refresh()
3193 setwnd(message_window)
3196 sys.stdout.write('\n')
3200 sys.stdout.write('\n' * rows)
3204 "Skip i lines. Pause game if this would cause a scrolling event."
3205 for dummy in range(i):
3206 if game.options & OPTION_CURSES:
3207 (y, x) = curwnd.getyx()
3210 except curses.error:
3215 if rows and linecount >= rows:
3218 sys.stdout.write('\n')
3221 "Utter a line with no following line feed."
3222 if game.options & OPTION_CURSES:
3223 (y, x) = curwnd.getyx()
3224 (my, mx) = curwnd.getmaxyx()
3225 if curwnd == message_window and y >= my - 2:
3228 # Uncomment this to debug curses problems
3230 logfp.write("#curses: at %s proutn(%s)\n" % ((y, x), repr(line)))
3234 sys.stdout.write(line)
3244 if not replayfp or replayfp.closed: # Don't slow down replays
3247 if game.options & OPTION_CURSES:
3251 if not replayfp or replayfp.closed:
3255 "Get a line of input."
3256 if game.options & OPTION_CURSES:
3257 line = curwnd.getstr() + "\n"
3260 if replayfp and not replayfp.closed:
3262 line = replayfp.readline()
3265 prout("*** Replay finished")
3268 elif line[0] != "#":
3271 line = raw_input() + "\n"
3277 "Change windows -- OK for this to be a no-op in tty mode."
3279 if game.options & OPTION_CURSES:
3280 # Uncomment this to debug curses problems
3282 if wnd == fullscreen_window:
3283 legend = "fullscreen"
3284 elif wnd == srscan_window:
3286 elif wnd == report_window:
3288 elif wnd == status_window:
3290 elif wnd == lrscan_window:
3292 elif wnd == message_window:
3294 elif wnd == prompt_window:
3298 logfp.write("#curses: setwnd(%s)\n" % legend)
3300 # Some curses implementations get confused when you try this.
3302 curses.curs_set(wnd in (fullscreen_window, message_window, prompt_window))
3303 except curses.error:
3307 "Clear to end of line -- can be a no-op in tty mode"
3308 if game.options & OPTION_CURSES:
3313 "Clear screen -- can be a no-op in tty mode."
3315 if game.options & OPTION_CURSES:
3321 def textcolor(color=DEFAULT):
3322 if game.options & OPTION_COLOR:
3323 if color == DEFAULT:
3325 elif color == BLACK: