3 sst.py -- Super Star Trek 2K
5 SST2K is a Python translation of a C translation of a FORTRAN
6 original dating back to 1973. Beautiful Python it is not, but it
7 works. Translation by Eric S. Raymond; original game by David Matuszek
8 and Paul Reynolds, with modifications by Don Smith, Tom Almy,
9 Stas Sergeev, and Eric S. Raymond.
11 See the doc/HACKING file in the distribution for designers notes and advice
12 ion how to modify (and how not to modify!) this code.
14 import os, sys, math, curses, time, readline, cPickle, random, copy, gettext
16 SSTDOC = "/usr/share/doc/sst/sst.doc"
19 def _(str): return gettext.gettext(str)
23 NINHAB = (GALSIZE * GALSIZE / 2)
25 PLNETMAX = (NINHAB + MAXUNINHAB)
28 BASEMAX = (GALSIZE * GALSIZE / 12)
31 FULLCREW = 428 # BSD Trek was 387, that's wrong
36 # How to represent features
60 def __init__(self, x=None, y=None):
63 def valid_quadrant(self):
64 return self.i>=0 and self.i<GALSIZE and self.j>=0 and self.j<GALSIZE
65 def valid_sector(self):
66 return self.i>=0 and self.i<QUADSIZE and self.j>=0 and self.j<QUADSIZE
68 self.i = self.j = None
70 return self.i != None and self.j != None
71 def __eq__(self, other):
72 return other != None and self.i == other.i and self.j == other.j
73 def __ne__(self, other):
74 return other == None or self.i != other.i or self.j != other.j
75 def __add__(self, other):
76 return coord(self.i+other.i, self.j+other.j)
77 def __sub__(self, other):
78 return coord(self.i-other.i, self.j-other.j)
79 def __mul__(self, other):
80 return coord(self.i*other, self.j*other)
81 def __rmul__(self, other):
82 return coord(self.i*other, self.j*other)
83 def __div__(self, other):
84 return coord(self.i/other, self.j/other)
85 def __mod__(self, other):
86 return coord(self.i % other, self.j % other)
87 def __rdiv__(self, other):
88 return coord(self.i/other, self.j/other)
89 def roundtogrid(self):
90 return coord(int(round(self.i)), int(round(self.j)))
91 def distance(self, other=None):
92 if not other: other = coord(0, 0)
93 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
95 return 1.90985*math.atan2(self.j, self.i)
101 s.i = self.i / abs(self.i)
105 s.j = self.j / abs(self.j)
108 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
109 return self.roundtogrid() / QUADSIZE
111 return self.roundtogrid() % QUADSIZE
114 s.i = self.i + randrange(-1, 2)
115 s.j = self.j + randrange(-1, 2)
118 if self.i == None or self.j == None:
120 return "%s - %s" % (self.i+1, self.j+1)
125 self.name = None # string-valued if inhabited
126 self.quadrant = coord() # quadrant located
127 self.pclass = None # could be ""M", "N", "O", or "destroyed"
128 self.crystals = "absent"# could be "mined", "present", "absent"
129 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
130 self.inhabited = False # is it inhabites?
138 self.starbase = False
141 self.supernova = False
143 self.status = "secure" # Could be "secure", "distressed", "enslaved"
151 def fill2d(size, fillfun):
152 "Fill an empty list in 2D."
154 for i in range(size):
156 for j in range(size):
157 lst[i].append(fillfun(i, j))
162 self.snap = False # snapshot taken
163 self.crew = 0 # crew complement
164 self.remkl = 0 # remaining klingons
165 self.nscrem = 0 # remaining super commanders
166 self.starkl = 0 # destroyed stars
167 self.basekl = 0 # destroyed bases
168 self.nromrem = 0 # Romulans remaining
169 self.nplankl = 0 # destroyed uninhabited planets
170 self.nworldkl = 0 # destroyed inhabited planets
171 self.planets = [] # Planet information
172 self.date = 0.0 # stardate
173 self.remres = 0 # remaining resources
174 self.remtime = 0 # remaining time
175 self.baseq = [] # Base quadrant coordinates
176 self.kcmdr = [] # Commander quadrant coordinates
177 self.kscmdr = coord() # Supercommander quadrant coordinates
179 self.galaxy = fill2d(GALSIZE, lambda i, j: quadrant())
181 self.chart = fill2d(GALSIZE, lambda i, j: page())
185 self.date = None # A real number
186 self.quadrant = None # A coord structure
189 OPTION_ALL = 0xffffffff
190 OPTION_TTY = 0x00000001 # old interface
191 OPTION_CURSES = 0x00000002 # new interface
192 OPTION_IOMODES = 0x00000003 # cover both interfaces
193 OPTION_PLANETS = 0x00000004 # planets and mining
194 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
195 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
196 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
197 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
198 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
199 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
200 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
201 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
202 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
203 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
204 OPTION_PLAIN = 0x01000000 # user chose plain game
205 OPTION_ALMY = 0x02000000 # user chose Almy variant
224 NDEVICES= 16 # Number of devices
233 def damaged(dev): return (game.damage[dev] != 0.0)
234 def communicating(): return not damaged(DRADIO) or game.condition=="docked"
236 # Define future events
237 FSPY = 0 # Spy event happens always (no future[] entry)
238 # can cause SC to tractor beam Enterprise
239 FSNOVA = 1 # Supernova
240 FTBEAM = 2 # Commander tractor beams Enterprise
241 FSNAP = 3 # Snapshot for time warp
242 FBATTAK = 4 # Commander attacks base
243 FCDBAS = 5 # Commander destroys base
244 FSCMOVE = 6 # Supercommander moves (might attack base)
245 FSCDBAS = 7 # Supercommander destroys base
246 FDSPROB = 8 # Move deep space probe
247 FDISTR = 9 # Emit distress call from an inhabited world
248 FENSLV = 10 # Inhabited word is enslaved */
249 FREPRO = 11 # Klingons build a ship in an enslaved system
253 # abstract out the event handling -- underlying data structures will change
254 # when we implement stateful events
256 def findevent(evtype): return game.future[evtype]
259 def __init__(self, type=None, loc=None, power=None):
264 self.kpower = power # enemy energy level
265 game.enemies.append(self)
267 motion = (loc != self.kloc)
268 if self.kloc.i is not None and self.kloc.j is not None:
271 game.quad[self.kloc.i][self.kloc.j] = IHWEB
273 game.quad[self.kloc.i][self.kloc.j] = IHDOT
275 self.kloc = copy.copy(loc)
276 game.quad[self.kloc.i][self.kloc.j] = self.type
277 self.kdist = self.kavgd = (game.sector - loc).distance()
280 self.kdist = self.kavgd = None
281 game.enemies.remove(self)
284 return "<%s,%s.%f>" % (self.type, self.kloc, self.kpower) # For debugging
288 self.options = None # Game options
289 self.state = snapshot() # A snapshot structure
290 self.snapsht = snapshot() # Last snapshot taken for time-travel purposes
291 self.quad = None # contents of our quadrant
292 self.damage = [0.0] * NDEVICES # damage encountered
293 self.future = [] # future events
294 for i in range(NEVENTS):
295 self.future.append(event())
296 self.passwd = None; # Self Destruct password
298 self.quadrant = None # where we are in the large
299 self.sector = None # where we are in the small
300 self.tholian = None # Tholian enemy object
301 self.base = None # position of base in current quadrant
302 self.battle = None # base coordinates being attacked
303 self.plnet = None # location of planet in quadrant
304 self.gamewon = False # Finished!
305 self.ididit = False # action taken -- allows enemy to attack
306 self.alive = False # we are alive (not killed)
307 self.justin = False # just entered quadrant
308 self.shldup = False # shields are up
309 self.shldchg = False # shield is changing (affects efficiency)
310 self.iscate = False # super commander is here
311 self.ientesc = False # attempted escape from supercommander
312 self.resting = False # rest time
313 self.icraft = False # Kirk in Galileo
314 self.landed = False # party on planet (true), on ship (false)
315 self.alldone = False # game is now finished
316 self.neutz = False # Romulan Neutral Zone
317 self.isarmed = False # probe is armed
318 self.inorbit = False # orbiting a planet
319 self.imine = False # mining
320 self.icrystl = False # dilithium crystals aboard
321 self.iseenit = False # seen base attack report
322 self.thawed = False # thawed game
323 self.condition = None # "green", "yellow", "red", "docked", "dead"
324 self.iscraft = None # "onship", "offship", "removed"
325 self.skill = None # Player skill level
326 self.inkling = 0 # initial number of klingons
327 self.inbase = 0 # initial number of bases
328 self.incom = 0 # initial number of commanders
329 self.inscom = 0 # initial number of commanders
330 self.inrom = 0 # initial number of commanders
331 self.instar = 0 # initial stars
332 self.intorps = 0 # initial/max torpedoes
333 self.torps = 0 # number of torpedoes
334 self.ship = 0 # ship type -- 'E' is Enterprise
335 self.abandoned = 0 # count of crew abandoned in space
336 self.length = 0 # length of game
337 self.klhere = 0 # klingons here
338 self.casual = 0 # causalties
339 self.nhelp = 0 # calls for help
340 self.nkinks = 0 # count of energy-barrier crossings
341 self.iplnet = None # planet # in quadrant
342 self.inplan = 0 # initial planets
343 self.irhere = 0 # Romulans in quadrant
344 self.isatb = 0 # =1 if super commander is attacking base
345 self.tourn = None # tournament number
346 self.nprobes = 0 # number of probes available
347 self.inresor = 0.0 # initial resources
348 self.intime = 0.0 # initial time
349 self.inenrg = 0.0 # initial/max energy
350 self.inshld = 0.0 # initial/max shield
351 self.inlsr = 0.0 # initial life support resources
352 self.indate = 0.0 # initial date
353 self.energy = 0.0 # energy level
354 self.shield = 0.0 # shield level
355 self.warpfac = 0.0 # warp speed
356 self.wfacsq = 0.0 # squared warp factor
357 self.lsupres = 0.0 # life support reserves
358 self.optime = 0.0 # time taken by current operation
359 self.docfac = 0.0 # repair factor when docking (constant?)
360 self.damfac = 0.0 # damage factor
361 self.lastchart = 0.0 # time star chart was last updated
362 self.cryprob = 0.0 # probability that crystal will work
363 self.probe = None # object holding probe course info
364 self.height = 0.0 # height of orbit around planet
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))
418 #logfp.write("# withprob(%s) -> %f (%s) at %s\n" % (p, v, v<p, traceback.extract_stack()[-2][1:]))
421 def randrange(*args):
422 v = random.randrange(*args)
423 #logfp.write("# randrange%s -> %s at %s\n" % (args, v, traceback.extract_stack()[-2][1:]))
429 v *= args[0] # returns from [0, args[0])
431 v = args[0] + v*(args[1]-args[0]) # returns from [args[0], args[1])
432 #logfp.write("# randreal%s -> %s at %s\n" % (args, v, traceback.extract_stack()[-2][1:]))
435 # Code from ai.c begins here
438 "Would this quadrant welcome another Klingon?"
439 return iq.valid_quadrant() and \
440 not game.state.galaxy[iq.i][iq.j].supernova and \
441 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
443 def tryexit(enemy, look, irun):
444 "A bad guy attempts to bug out."
446 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
447 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
448 if not welcoming(iq):
450 if enemy.type == IHR:
451 return False; # Romulans cannot escape!
453 # avoid intruding on another commander's territory
454 if enemy.type == IHC:
455 if iq in game.state.kcmdr:
457 # refuse to leave if currently attacking starbase
458 if game.battle == game.quadrant:
460 # don't leave if over 1000 units of energy
461 if enemy.kpower > 1000.0:
463 # emit escape message and move out of quadrant.
464 # we know this if either short or long range sensors are working
465 if not damaged(DSRSENS) or not damaged(DLRSENS) or \
466 game.condition == "docked":
467 prout(crmena(True, enemy.type, "sector", enemy.kloc) + \
468 (_(" escapes to Quadrant %s (and regains strength).") % q))
469 # handle local matters related to escape
472 if game.condition != "docked":
474 # Handle global matters related to escape
475 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
476 game.state.galaxy[iq.i][iq.j].klingons += 1
481 schedule(FSCMOVE, 0.2777)
485 for cmdr in game.state.kcmdr:
486 if cmdr == game.quadrant:
487 game.state.kcmdr[n] = iq
489 return True; # success
491 # The bad-guy movement algorithm:
493 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
494 # If both are operating full strength, force is 1000. If both are damaged,
495 # force is -1000. Having shields down subtracts an additional 1000.
497 # 2. Enemy has forces equal to the energy of the attacker plus
498 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
499 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
501 # Attacker Initial energy levels (nominal):
502 # Klingon Romulan Commander Super-Commander
503 # Novice 400 700 1200
505 # Good 450 800 1300 1750
506 # Expert 475 850 1350 1875
507 # Emeritus 500 900 1400 2000
508 # VARIANCE 75 200 200 200
510 # Enemy vessels only move prior to their attack. In Novice - Good games
511 # only commanders move. In Expert games, all enemy vessels move if there
512 # is a commander present. In Emeritus games all enemy vessels move.
514 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
515 # forces are 1000 greater than Enterprise.
517 # Agressive action on average cuts the distance between the ship and
518 # the enemy to 1/4 the original.
520 # 4. At lower energy advantage, movement units are proportional to the
521 # advantage with a 650 advantage being to hold ground, 800 to move forward
522 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
524 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
525 # retreat, especially at high skill levels.
527 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
529 def movebaddy(enemy):
530 "Tactical movement for the bad guys."
531 next = coord(); look = coord()
533 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
534 if game.skill >= SKILL_EXPERT:
535 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
537 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
539 mdist = int(dist1 + 0.5); # Nearest integer distance
540 # If SC, check with spy to see if should hi-tail it
541 if enemy.type==IHS and \
542 (enemy.kpower <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
546 # decide whether to advance, retreat, or hold position
547 forces = enemy.kpower+100.0*len(game.enemies)+400*(nbaddys-1)
549 forces += 1000; # Good for enemy if shield is down!
550 if not damaged(DPHASER) or not damaged(DPHOTON):
551 if damaged(DPHASER): # phasers damaged
554 forces -= 0.2*(game.energy - 2500.0)
555 if damaged(DPHOTON): # photon torpedoes damaged
558 forces -= 50.0*game.torps
560 # phasers and photon tubes both out!
563 if forces <= 1000.0 and game.condition != "docked": # Typical situation
564 motion = ((forces + randreal(200))/150.0) - 5.0
566 if forces > 1000.0: # Very strong -- move in for kill
567 motion = (1.0 - randreal())**2 * dist1 + 1.0
568 if game.condition=="docked" and (game.options & OPTION_BASE): # protected by base -- back off !
569 motion -= game.skill*(2.0-randreal()**2)
571 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
572 # don't move if no motion
575 # Limit motion according to skill
576 if abs(motion) > game.skill:
581 # calculate preferred number of steps
582 nsteps = abs(int(motion))
583 if motion > 0 and nsteps > mdist:
584 nsteps = mdist; # don't overshoot
585 if nsteps > QUADSIZE:
586 nsteps = QUADSIZE; # This shouldn't be necessary
588 nsteps = 1; # This shouldn't be necessary
590 proutn("NSTEPS = %d:" % nsteps)
591 # Compute preferred values of delta X and Y
592 m = game.sector - enemy.kloc
593 if 2.0 * abs(m.i) < abs(m.j):
595 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.kloc.i):
597 m = (motion * m).sgn()
600 for ll in range(nsteps):
602 proutn(" %d" % (ll+1))
603 # Check if preferred position available
614 attempts = 0; # Settle mysterious hang problem
615 while attempts < 20 and not success:
617 if look.i < 0 or look.i >= QUADSIZE:
618 if motion < 0 and tryexit(enemy, look, irun):
620 if krawli == m.i or m.j == 0:
622 look.i = next.i + krawli
624 elif look.j < 0 or look.j >= QUADSIZE:
625 if motion < 0 and tryexit(enemy, look, irun):
627 if krawlj == m.j or m.i == 0:
629 look.j = next.j + krawlj
631 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != IHDOT:
632 # See if enemy should ram ship
633 if game.quad[look.i][look.j] == game.ship and \
634 (enemy.type == IHC or enemy.type == IHS):
635 collision(rammed=True, enemy=enemy)
637 if krawli != m.i and m.j != 0:
638 look.i = next.i + krawli
640 elif krawlj != m.j and m.i != 0:
641 look.j = next.j + krawlj
644 break; # we have failed
656 if not damaged(DSRSENS) or game.condition == "docked":
657 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.kloc))
658 if enemy.kdist < dist1:
659 proutn(_(" advances to "))
661 proutn(_(" retreats to "))
662 prout("Sector %s." % next)
665 "Sequence Klingon tactical movement."
668 # Figure out which Klingon is the commander (or Supercommander)
670 if game.quadrant in game.state.kcmdr:
671 for enemy in game.enemies:
672 if enemy.type == IHC:
674 if game.state.kscmdr==game.quadrant:
675 for enemy in game.enemies:
676 if enemy.type == IHS:
679 # If skill level is high, move other Klingons and Romulans too!
680 # Move these last so they can base their actions on what the
682 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
683 for enemy in game.enemies:
684 if enemy.type in (IHK, IHR):
686 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
688 def movescom(iq, avoid):
689 "Commander movement helper."
690 # Avoid quadrants with bases if we want to avoid Enterprise
691 if not welcoming(iq) or (avoid and iq in game.state.baseq):
693 if game.justin and not game.iscate:
696 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
697 game.state.kscmdr = iq
698 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
699 if game.state.kscmdr==game.quadrant:
700 # SC has scooted, Remove him from current quadrant
705 for enemy in game.enemies:
706 if enemy.type == IHS:
710 if game.condition != "docked":
712 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
713 # check for a helpful planet
714 for i in range(game.inplan):
715 if game.state.planets[i].quadrant == game.state.kscmdr and \
716 game.state.planets[i].crystals == "present":
718 game.state.planets[i].pclass = "destroyed"
719 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
722 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
723 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
724 prout(_(" by the Super-commander.\""))
726 return True; # looks good!
728 def supercommander():
729 "Move the Super Commander."
730 iq = coord(); sc = coord(); ibq = coord(); idelta = coord()
733 prout("== SUPERCOMMANDER")
734 # Decide on being active or passive
735 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 \
736 (game.state.date-game.indate) < 3.0)
737 if not game.iscate and avoid:
738 # compute move away from Enterprise
739 idelta = game.state.kscmdr-game.quadrant
740 if idelta.distance() > 2.0:
742 idelta.i = game.state.kscmdr.j-game.quadrant.j
743 idelta.j = game.quadrant.i-game.state.kscmdr.i
745 # compute distances to starbases
746 if not game.state.baseq:
750 sc = game.state.kscmdr
751 for base in game.state.baseq:
752 basetbl.append((i, (base - sc).distance()))
753 if game.state.baseq > 1:
754 basetbl.sort(lambda x, y: cmp(x[1]. y[1]))
755 # look for nearest base without a commander, no Enterprise, and
756 # without too many Klingons, and not already under attack.
757 ifindit = iwhichb = 0
758 for (i2, base) in enumerate(game.state.baseq):
759 i = basetbl[i2][0]; # bug in original had it not finding nearest
760 if base==game.quadrant or base==game.battle or not welcoming(base):
762 # if there is a commander, and no other base is appropriate,
763 # we will take the one with the commander
764 for cmdr in game.state.kcmdr:
765 if base == cmdr and ifindit != 2:
769 else: # no commander -- use this one
774 return # Nothing suitable -- wait until next time
775 ibq = game.state.baseq[iwhichb]
776 # decide how to move toward base
777 idelta = ibq - game.state.kscmdr
778 # Maximum movement is 1 quadrant in either or both axes
779 idelta = idelta.sgn()
780 # try moving in both x and y directions
781 # there was what looked like a bug in the Almy C code here,
782 # but it might be this translation is just wrong.
783 iq = game.state.kscmdr + idelta
784 if not movescom(iq, avoid):
785 # failed -- try some other maneuvers
786 if idelta.i==0 or idelta.j==0:
789 iq.j = game.state.kscmdr.j + 1
790 if not movescom(iq, avoid):
791 iq.j = game.state.kscmdr.j - 1
794 iq.i = game.state.kscmdr.i + 1
795 if not movescom(iq, avoid):
796 iq.i = game.state.kscmdr.i - 1
799 # try moving just in x or y
800 iq.j = game.state.kscmdr.j
801 if not movescom(iq, avoid):
802 iq.j = game.state.kscmdr.j + idelta.j
803 iq.i = game.state.kscmdr.i
806 if len(game.state.baseq) == 0:
809 for ibq in game.state.baseq:
810 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
813 return # no, don't attack base!
816 schedule(FSCDBAS, randreal(1.0, 3.0))
817 if is_scheduled(FCDBAS):
818 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
819 if not communicating():
823 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
825 prout(_(" reports that it is under attack from the Klingon Super-commander."))
826 proutn(_(" It can survive until stardate %d.\"") \
827 % int(scheduled(FSCDBAS)))
830 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
834 game.optime = 0.0; # actually finished
836 # Check for intelligence report
839 (not communicating()) or \
840 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
843 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
844 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
849 if not game.tholian or game.justin:
852 if game.tholian.kloc.i == 0 and game.tholian.kloc.j == 0:
853 id.i = 0; id.j = QUADSIZE-1
854 elif game.tholian.kloc.i == 0 and game.tholian.kloc.j == QUADSIZE-1:
855 id.i = QUADSIZE-1; id.j = QUADSIZE-1
856 elif game.tholian.kloc.i == QUADSIZE-1 and game.tholian.kloc.j == QUADSIZE-1:
857 id.i = QUADSIZE-1; id.j = 0
858 elif game.tholian.kloc.i == QUADSIZE-1 and game.tholian.kloc.j == 0:
861 # something is wrong!
862 game.tholian.move(None)
863 prout("***Internal error: Tholian in a bad spot.")
865 # do nothing if we are blocked
866 if game.quad[id.i][id.j] not in (IHDOT, IHWEB):
868 here = copy.copy(game.tholian.kloc)
869 delta = (id - game.tholian.kloc).sgn()
871 while here.i != id.i:
873 if game.quad[here.i][here.j]==IHDOT:
874 game.tholian.move(here)
876 while here.j != id.j:
878 if game.quad[here.i][here.j]==IHDOT:
879 game.tholian.move(here)
880 # check to see if all holes plugged
881 for i in range(QUADSIZE):
882 if game.quad[0][i]!=IHWEB and game.quad[0][i]!=IHT:
884 if game.quad[QUADSIZE-1][i]!=IHWEB and game.quad[QUADSIZE-1][i]!=IHT:
886 if game.quad[i][0]!=IHWEB and game.quad[i][0]!=IHT:
888 if game.quad[i][QUADSIZE-1]!=IHWEB and game.quad[i][QUADSIZE-1]!=IHT:
890 # All plugged up -- Tholian splits
891 game.quad[game.tholian.kloc.i][game.tholian.kloc.j]=IHWEB
893 prout(crmena(True, IHT, "sector", game.tholian) + _(" completes web."))
894 game.tholian.move(None)
897 # Code from battle.c begins here
899 def doshield(shraise):
900 "Change shield status."
908 if scanner.sees("transfer"):
912 prout(_("Shields damaged and down."))
914 if scanner.sees("up"):
916 elif scanner.sees("down"):
919 proutn(_("Do you wish to change shield energy? "))
921 proutn(_("Energy to transfer to shields- "))
923 elif damaged(DSHIELD):
924 prout(_("Shields damaged and down."))
927 proutn(_("Shields are up. Do you want them down? "))
934 proutn(_("Shields are down. Do you want them up? "))
940 if action == "SHUP": # raise shields
942 prout(_("Shields already up."))
946 if game.condition != "docked":
948 prout(_("Shields raised."))
951 prout(_("Shields raising uses up last of energy."))
956 elif action == "SHDN":
958 prout(_("Shields already down."))
962 prout(_("Shields lowered."))
965 elif action == "NRG":
966 while scanner.next() != "IHREAL":
968 proutn(_("Energy to transfer to shields- "))
970 if scanner.real == 0:
972 if scanner.real > game.energy:
973 prout(_("Insufficient ship energy."))
976 if game.shield+scanner.real >= game.inshld:
977 prout(_("Shield energy maximized."))
978 if game.shield+scanner.real > game.inshld:
979 prout(_("Excess energy requested returned to ship energy"))
980 game.energy -= game.inshld-game.shield
981 game.shield = game.inshld
983 if scanner.real < 0.0 and game.energy-scanner.real > game.inenrg:
984 # Prevent shield drain loophole
986 prout(_("Engineering to bridge--"))
987 prout(_(" Scott here. Power circuit problem, Captain."))
988 prout(_(" I can't drain the shields."))
991 if game.shield+scanner.real < 0:
992 prout(_("All shield energy transferred to ship."))
993 game.energy += game.shield
996 proutn(_("Scotty- \""))
998 prout(_("Transferring energy to shields.\""))
1000 prout(_("Draining energy from shields.\""))
1001 game.shield += scanner.real
1002 game.energy -= scanner.real
1006 "Choose a device to damage, at random."
1007 # Quoth Eric Allman in the code of BSD-Trek:
1008 # "Under certain conditions you can get a critical hit. This
1009 # sort of hit damages devices. The probability that a given
1010 # device is damaged depends on the device. Well protected
1011 # devices (such as the computer, which is in the core of the
1012 # ship and has considerable redundancy) almost never get
1013 # damaged, whereas devices which are exposed (such as the
1014 # warp engines) or which are particularly delicate (such as
1015 # the transporter) have a much higher probability of being
1018 # This is one place where OPTION_PLAIN does not restore the
1019 # original behavior, which was equiprobable damage across
1020 # all devices. If we wanted that, we'd return randrange(NDEVICES)
1021 # and have done with it. Also, in the original game, DNAVYS
1022 # and DCOMPTR were the same device.
1024 # Instead, we use a table of weights similar to the one from BSD Trek.
1025 # BSD doesn't have the shuttle, shield controller, death ray, or probes.
1026 # We don't have a cloaking device. The shuttle got the allocation
1027 # for the cloaking device, then we shaved a half-percent off
1028 # everything to have some weight to give DSHCTRL/DDRAY/DDSP.
1030 105, # DSRSENS: short range scanners 10.5%
1031 105, # DLRSENS: long range scanners 10.5%
1032 120, # DPHASER: phasers 12.0%
1033 120, # DPHOTON: photon torpedoes 12.0%
1034 25, # DLIFSUP: life support 2.5%
1035 65, # DWARPEN: warp drive 6.5%
1036 70, # DIMPULS: impulse engines 6.5%
1037 145, # DSHIELD: deflector shields 14.5%
1038 30, # DRADIO: subspace radio 3.0%
1039 45, # DSHUTTL: shuttle 4.5%
1040 15, # DCOMPTR: computer 1.5%
1041 20, # NAVCOMP: navigation system 2.0%
1042 75, # DTRANSP: transporter 7.5%
1043 20, # DSHCTRL: high-speed shield controller 2.0%
1044 10, # DDRAY: death ray 1.0%
1045 30, # DDSP: deep-space probes 3.0%
1047 idx = randrange(1000) # weights must sum to 1000
1049 for (i, w) in enumerate(weights):
1053 return None; # we should never get here
1055 def collision(rammed, enemy):
1056 "Collision handling fot rammong events."
1057 prouts(_("***RED ALERT! RED ALERT!"))
1059 prout(_("***COLLISION IMMINENT."))
1063 hardness = {IHR:1.5, IHC:2.0, IHS:2.5, IHT:0.5, IHQUEST:4.0}.get(enemy.type, 1.0)
1065 proutn(_(" rammed by "))
1068 proutn(crmena(False, enemy.type, "sector", enemy.kloc))
1070 proutn(_(" (original position)"))
1072 deadkl(enemy.kloc, enemy.type, game.sector)
1073 proutn("***" + crmship() + " heavily damaged.")
1074 icas = randrange(10, 30)
1075 prout(_("***Sickbay reports %d casualties"), icas)
1077 game.state.crew -= icas
1078 # In the pre-SST2K version, all devices got equiprobably damaged,
1079 # which was silly. Instead, pick up to half the devices at
1080 # random according to our weighting table,
1081 ncrits = randrange(NDEVICES/2)
1082 for m in range(ncrits):
1084 if game.damage[dev] < 0:
1086 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1087 # Damage for at least time of travel!
1088 game.damage[dev] += game.optime + extradm
1090 prout(_("***Shields are down."))
1091 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1098 def torpedo(origin, bearing, dispersion, number, nburst):
1099 "Let a photon torpedo fly"
1100 if not damaged(DSRSENS) or game.condition=="docked":
1101 setwnd(srscan_window)
1103 setwnd(message_window)
1104 ac = bearing + 0.25*dispersion # dispersion is a random variable
1105 bullseye = (15.0 - bearing)*0.5235988
1106 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1107 bumpto = coord(0, 0)
1108 # Loop to move a single torpedo
1109 setwnd(message_window)
1110 for step in range(1, QUADSIZE*2):
1111 if not track.next(): break
1113 if not w.valid_sector():
1115 iquad=game.quad[w.i][w.j]
1116 tracktorpedo(origin, w, step, number, nburst, iquad)
1120 if not damaged(DSRSENS) or game.condition == "docked":
1121 skip(1); # start new line after text track
1122 if iquad in (IHE, IHF): # Hit our ship
1124 prout(_("Torpedo hits %s.") % crmshp())
1125 hit = 700.0 + randreal(100) - \
1126 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1127 newcnd(); # we're blown out of dock
1128 if game.landed or game.condition=="docked":
1129 return hit # Cheat if on a planet
1130 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1131 # is 143 degrees, which is almost exactly 4.8 clockface units
1132 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1134 bumpto = displacement.sector()
1135 if not bumpto.valid_sector():
1137 if game.quad[bumpto.i][bumpto.j]==IHBLANK:
1140 if game.quad[bumpto.i][bumpto.j]!=IHDOT:
1141 # can't move into object
1143 game.sector = bumpto
1145 game.quad[w.i][w.j]=IHDOT
1146 game.quad[bumpto.i][bumpto.j]=iquad
1147 prout(_(" displaced by blast to Sector %s ") % bumpto)
1148 for enemy in game.enemies:
1149 enemy.kdist = enemy.kavgd = (game.sector-enemy.kloc).distance()
1150 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1152 elif iquad in (IHC, IHS, IHR, IHK): # Hit a regular enemy
1154 if iquad in (IHC, IHS) and withprob(0.05):
1155 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1156 prout(_(" torpedo neutralized."))
1158 for enemy in game.enemies:
1161 kp = math.fabs(enemy.kpower)
1162 h1 = 700.0 + randrange(100) - \
1163 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1167 if enemy.kpower < 0:
1171 if enemy.kpower == 0:
1174 proutn(crmena(True, iquad, "sector", w))
1175 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1177 bumpto = displacement.sector()
1178 if not bumpto.valid_sector():
1179 prout(_(" damaged but not destroyed."))
1181 if game.quad[bumpto.i][bumpto.j] == IHBLANK:
1182 prout(_(" buffeted into black hole."))
1183 deadkl(w, iquad, bumpto)
1184 if game.quad[bumpto.i][bumpto.j] != IHDOT:
1185 prout(_(" damaged but not destroyed."))
1187 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1189 game.quad[w.i][w.j]=IHDOT
1190 game.quad[bumpto.i][bumpto.j]=iquad
1191 for enemy in game.enemies:
1192 enemy.kdist = enemy.kavgd = (game.sector-enemy.kloc).distance()
1193 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1195 elif iquad == IHB: # Hit a base
1197 prout(_("***STARBASE DESTROYED.."))
1198 game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
1199 game.quad[w.i][w.j]=IHDOT
1200 game.base.invalidate()
1201 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1
1202 game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1
1203 game.state.basekl += 1
1206 elif iquad == IHP: # Hit a planet
1207 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1208 game.state.nplankl += 1
1209 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1210 game.iplnet.pclass = "destroyed"
1212 game.plnet.invalidate()
1213 game.quad[w.i][w.j] = IHDOT
1215 # captain perishes on planet
1218 elif iquad == IHW: # Hit an inhabited world -- very bad!
1219 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1220 game.state.nworldkl += 1
1221 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1222 game.iplnet.pclass = "destroyed"
1224 game.plnet.invalidate()
1225 game.quad[w.i][w.j] = IHDOT
1227 # captain perishes on planet
1229 prout(_("The torpedo destroyed an inhabited planet."))
1231 elif iquad == IHSTAR: # Hit a star
1235 prout(crmena(True, IHSTAR, "sector", w) + _(" unaffected by photon blast."))
1237 elif iquad == IHQUEST: # Hit a thingy
1238 if not (game.options & OPTION_THINGY) or withprob(0.3):
1240 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1242 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1244 proutn(_("Mr. Spock-"))
1245 prouts(_(" \"Fascinating!\""))
1249 # Stas Sergeev added the possibility that
1250 # you can shove the Thingy and piss it off.
1251 # It then becomes an enemy and may fire at you.
1255 elif iquad == IHBLANK: # Black hole
1257 prout(crmena(True, IHBLANK, "sector", w) + _(" swallows torpedo."))
1259 elif iquad == IHWEB: # hit the web
1261 prout(_("***Torpedo absorbed by Tholian web."))
1263 elif iquad == IHT: # Hit a Tholian
1264 h1 = 700.0 + randrange(100) - \
1265 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle))
1268 game.quad[w.i][w.j] = IHDOT
1273 proutn(crmena(True, IHT, "sector", w))
1275 prout(_(" survives photon blast."))
1277 prout(_(" disappears."))
1278 game.tholian.move(None)
1279 game.quad[w.i][w.j] = IHWEB
1284 proutn("Don't know how to handle torpedo collision with ")
1285 proutn(crmena(True, iquad, "sector", w))
1290 prout(_("Torpedo missed."))
1294 "Critical-hit resolution."
1295 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1297 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1298 proutn(_("***CRITICAL HIT--"))
1299 # Select devices and cause damage
1301 for loop1 in range(ncrit):
1304 # Cheat to prevent shuttle damage unless on ship
1305 if not (game.damage[j]<0.0 or (j==DSHUTTL and game.iscraft != "onship")):
1308 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1309 game.damage[j] += extradm
1311 for (i, j) in enumerate(cdam):
1313 if skipcount % 3 == 2 and i < len(cdam)-1:
1318 prout(_(" damaged."))
1319 if damaged(DSHIELD) and game.shldup:
1320 prout(_("***Shields knocked down."))
1323 def attack(torps_ok):
1324 # bad guy attacks us
1325 # torps_ok == False forces use of phasers in an attack
1326 # game could be over at this point, check
1329 attempt = False; ihurt = False;
1330 hitmax=0.0; hittot=0.0; chgfac=1.0
1333 prout("=== ATTACK!")
1334 # Tholian gets to move before attacking
1337 # if you have just entered the RNZ, you'll get a warning
1338 if game.neutz: # The one chance not to be attacked
1341 # commanders get a chance to tac-move towards you
1342 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:
1344 # if no enemies remain after movement, we're done
1345 if len(game.enemies)==0 or (len(game.enemies)==1 and thing == game.quadrant and not thing.angry):
1347 # set up partial hits if attack happens during shield status change
1348 pfac = 1.0/game.inshld
1350 chgfac = 0.25 + randreal(0.5)
1352 # message verbosity control
1353 if game.skill <= SKILL_FAIR:
1355 for enemy in game.enemies:
1356 if enemy.kpower < 0:
1357 continue; # too weak to attack
1358 # compute hit strength and diminish shield power
1360 # Increase chance of photon torpedos if docked or enemy energy is low
1361 if game.condition == "docked":
1363 if enemy.kpower < 500:
1365 if enemy.type==IHT or (enemy.type==IHQUEST and not thing.angry):
1367 # different enemies have different probabilities of throwing a torp
1368 usephasers = not torps_ok or \
1369 (enemy.type == IHK and r > 0.0005) or \
1370 (enemy.type==IHC and r > 0.015) or \
1371 (enemy.type==IHR and r > 0.3) or \
1372 (enemy.type==IHS and r > 0.07) or \
1373 (enemy.type==IHQUEST and r > 0.05)
1374 if usephasers: # Enemy uses phasers
1375 if game.condition == "docked":
1376 continue; # Don't waste the effort!
1377 attempt = True; # Attempt to attack
1378 dustfac = randreal(0.8, 0.85)
1379 hit = enemy.kpower*math.pow(dustfac,enemy.kavgd)
1380 enemy.kpower *= 0.75
1381 else: # Enemy uses photon torpedo
1382 # We should be able to make the bearing() method work here
1383 course = 1.90985*math.atan2(game.sector.j-enemy.kloc.j, enemy.kloc.i-game.sector.i)
1385 proutn(_("***TORPEDO INCOMING"))
1386 if not damaged(DSRSENS):
1387 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.kloc))
1390 dispersion = (randreal()+randreal())*0.5 - 0.5
1391 dispersion += 0.002*enemy.kpower*dispersion
1392 hit = torpedo(enemy.kloc, course, dispersion, number=1, nburst=1)
1393 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1394 finish(FWON); # Klingons did themselves in!
1395 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1396 return # Supernova or finished
1399 # incoming phaser or torpedo, shields may dissipate it
1400 if game.shldup or game.shldchg or game.condition=="docked":
1401 # shields will take hits
1402 propor = pfac * game.shield
1403 if game.condition =="docked":
1407 hitsh = propor*chgfac*hit+1.0
1409 if absorb > game.shield:
1410 absorb = game.shield
1411 game.shield -= absorb
1413 # taking a hit blasts us out of a starbase dock
1414 if game.condition == "docked":
1416 # but the shields may take care of it
1417 if propor > 0.1 and hit < 0.005*game.energy:
1419 # hit from this opponent got through shields, so take damage
1421 proutn(_("%d unit hit") % int(hit))
1422 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1423 proutn(_(" on the ") + crmshp())
1424 if not damaged(DSRSENS) and usephasers:
1425 prout(_(" from ") + crmena(False, enemy.type, where, enemy.kloc))
1427 # Decide if hit is critical
1433 if game.energy <= 0:
1434 # Returning home upon your shield, not with it...
1437 if not attempt and game.condition == "docked":
1438 prout(_("***Enemies decide against attacking your ship."))
1439 percent = 100.0*pfac*game.shield+0.5
1441 # Shields fully protect ship
1442 proutn(_("Enemy attack reduces shield strength to "))
1444 # Emit message if starship suffered hit(s)
1446 proutn(_("Energy left %2d shields ") % int(game.energy))
1449 elif not damaged(DSHIELD):
1452 proutn(_("damaged, "))
1453 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1454 # Check if anyone was hurt
1455 if hitmax >= 200 or hittot >= 500:
1456 icas = randrange(int(hittot * 0.015))
1459 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1460 prout(_(" in that last attack.\""))
1462 game.state.crew -= icas
1463 # After attack, reset average distance to enemies
1464 for enemy in game.enemies:
1465 enemy.kavgd = enemy.kdist
1466 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1469 def deadkl(w, type, mv):
1470 "Kill a Klingon, Tholian, Romulan, or Thingy."
1471 # Added mv to allow enemy to "move" before dying
1472 proutn(crmena(True, type, "sector", mv))
1473 # Decide what kind of enemy it is and update appropriately
1475 # Chalk up a Romulan
1476 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1478 game.state.nromrem -= 1
1482 elif type == IHQUEST:
1487 # Killed some type of Klingon
1488 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1491 game.state.kcmdr.remove(game.quadrant)
1493 if game.state.kcmdr:
1494 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1495 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1498 game.state.remkl -= 1
1500 game.state.nscrem -= 1
1501 game.state.kscmdr.invalidate()
1506 # For each kind of enemy, finish message to player
1507 prout(_(" destroyed."))
1508 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1511 # Remove enemy ship from arrays describing local conditions
1512 for e in game.enemies:
1519 "Return None if target is invalid, otherwise return a course angle."
1520 if not w.valid_sector():
1524 # FIXME: C code this was translated from is wacky -- why the sign reversal?
1525 delta.j = (w.j - game.sector.j);
1526 delta.i = (game.sector.i - w.i);
1527 if delta == coord(0, 0):
1529 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1530 prout(_(" I recommend an immediate review of"))
1531 prout(_(" the Captain's psychological profile.\""))
1534 return delta.bearing()
1537 "Launch photon torpedo."
1540 if damaged(DPHOTON):
1541 prout(_("Photon tubes damaged."))
1545 prout(_("No torpedoes left."))
1548 # First, get torpedo count
1551 if scanner.token == "IHALPHA":
1554 elif scanner.token == "IHEOL" or not scanner.waiting():
1555 prout(_("%d torpedoes left.") % game.torps)
1557 proutn(_("Number of torpedoes to fire- "))
1558 continue # Go back around to get a number
1559 else: # key == "IHREAL"
1561 if n <= 0: # abort command
1566 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1569 scanner.chew() # User requested more torps than available
1570 continue # Go back around
1571 break # All is good, go to next stage
1575 key = scanner.next()
1576 if i==0 and key == "IHEOL":
1577 break; # no coordinate waiting, we will try prompting
1578 if i==1 and key == "IHEOL":
1579 # direct all torpedoes at one target
1581 target.append(target[0])
1582 course.append(course[0])
1585 scanner.push(scanner.token)
1586 target.append(scanner.getcoord())
1587 if target[-1] == None:
1589 course.append(targetcheck(target[-1]))
1590 if course[-1] == None:
1593 if len(target) == 0:
1594 # prompt for each one
1596 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1598 target.append(scanner.getcoord())
1599 if target[-1] == None:
1601 course.append(targetcheck(target[-1]))
1602 if course[-1] == None:
1605 # Loop for moving <n> torpedoes
1607 if game.condition != "docked":
1609 dispersion = (randreal()+randreal())*0.5 -0.5
1610 if math.fabs(dispersion) >= 0.47:
1612 dispersion *= randreal(1.2, 2.2)
1614 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1616 prouts(_("***TORPEDO MISFIRES."))
1619 prout(_(" Remainder of burst aborted."))
1621 prout(_("***Photon tubes damaged by misfire."))
1622 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1624 if game.shldup or game.condition == "docked":
1625 dispersion *= 1.0 + 0.0001*game.shield
1626 torpedo(game.sector, course[i], dispersion, number=i, nburst=n)
1627 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1629 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1633 "Check for phasers overheating."
1635 checkburn = (rpow-1500.0)*0.00038
1636 if withprob(checkburn):
1637 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1638 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1640 def checkshctrl(rpow):
1641 "Check shield control."
1644 prout(_("Shields lowered."))
1646 # Something bad has happened
1647 prouts(_("***RED ALERT! RED ALERT!"))
1649 hit = rpow*game.shield/game.inshld
1650 game.energy -= rpow+hit*0.8
1651 game.shield -= hit*0.2
1652 if game.energy <= 0.0:
1653 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1658 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1660 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1661 icas = randrange(int(hit*0.012))
1666 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1667 prout(_(" %d casualties so far.\"") % icas)
1669 game.state.crew -= icas
1671 prout(_("Phaser energy dispersed by shields."))
1672 prout(_("Enemy unaffected."))
1677 "Register a phaser hit on Klingons and Romulans."
1678 nenhr2 = len(game.enemies); kk=0
1681 for (k, wham) in enumerate(hits):
1684 dustfac = randreal(0.9, 1.0)
1685 hit = wham*math.pow(dustfac,game.enemies[kk].kdist)
1686 kpini = game.enemies[kk].kpower
1687 kp = math.fabs(kpini)
1688 if PHASEFAC*hit < kp:
1690 if game.enemies[kk].kpower < 0:
1691 game.enemies[kk].kpower -= -kp
1693 game.enemies[kk].kpower -= kp
1694 kpow = game.enemies[kk].kpower
1695 w = game.enemies[kk].kloc
1697 if not damaged(DSRSENS):
1699 proutn(_("%d unit hit on ") % int(hit))
1701 proutn(_("Very small hit on "))
1702 ienm = game.quad[w.i][w.j]
1705 proutn(crmena(False, ienm, "sector", w))
1709 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1713 kk -= 1 # don't do the increment
1715 else: # decide whether or not to emasculate klingon
1716 if kpow>0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1717 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1718 prout(_(" has just lost its firepower.\""))
1719 game.enemies[kk].kpower = -kpow
1724 "Fire phasers at bad guys."
1726 kz = 0; k = 1; irec=0 # Cheating inhibitor
1727 ifast = False; no = False; itarg = True; msgflag = True; rpow=0
1731 # SR sensors and Computer are needed for automode
1732 if damaged(DSRSENS) or damaged(DCOMPTR):
1734 if game.condition == "docked":
1735 prout(_("Phasers can't be fired through base shields."))
1738 if damaged(DPHASER):
1739 prout(_("Phaser control damaged."))
1743 if damaged(DSHCTRL):
1744 prout(_("High speed shield control damaged."))
1747 if game.energy <= 200.0:
1748 prout(_("Insufficient energy to activate high-speed shield control."))
1751 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1753 # Original code so convoluted, I re-did it all
1754 # (That was Tom Almy talking about the C code, I think -- ESR)
1755 while automode=="NOTSET":
1757 if key == "IHALPHA":
1758 if scanner.sees("manual"):
1759 if len(game.enemies)==0:
1760 prout(_("There is no enemy present to select."))
1763 automode="AUTOMATIC"
1766 key = scanner.next()
1767 elif scanner.sees("automatic"):
1768 if (not itarg) and len(game.enemies) != 0:
1769 automode = "FORCEMAN"
1771 if len(game.enemies)==0:
1772 prout(_("Energy will be expended into space."))
1773 automode = "AUTOMATIC"
1774 key = scanner.next()
1775 elif scanner.sees("no"):
1780 elif key == "IHREAL":
1781 if len(game.enemies)==0:
1782 prout(_("Energy will be expended into space."))
1783 automode = "AUTOMATIC"
1785 automode = "FORCEMAN"
1787 automode = "AUTOMATIC"
1790 if len(game.enemies)==0:
1791 prout(_("Energy will be expended into space."))
1792 automode = "AUTOMATIC"
1794 automode = "FORCEMAN"
1796 proutn(_("Manual or automatic? "))
1801 if automode == "AUTOMATIC":
1802 if key == "IHALPHA" and scanner.sees("no"):
1804 key = scanner.next()
1805 if key != "IHREAL" and len(game.enemies) != 0:
1806 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1811 for i in range(len(game.enemies)):
1812 irec += math.fabs(game.enemies[i].kpower)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1814 proutn(_("%d units required. ") % irec)
1816 proutn(_("Units to fire= "))
1817 key = scanner.next()
1822 proutn(_("Energy available= %.2f") % avail)
1825 if not rpow > avail:
1832 if key == "IHALPHA" and scanner.sees("no"):
1835 game.energy -= 200; # Go and do it!
1836 if checkshctrl(rpow):
1841 if len(game.enemies):
1844 for i in range(len(game.enemies)):
1848 hits[i] = math.fabs(game.enemies[i].kpower)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))
1849 over = randreal(1.01, 1.06) * hits[i]
1851 powrem -= hits[i] + over
1852 if powrem <= 0 and temp < hits[i]:
1861 if extra > 0 and not game.alldone:
1863 proutn(_("*** Tholian web absorbs "))
1864 if len(game.enemies)>0:
1865 proutn(_("excess "))
1866 prout(_("phaser energy."))
1868 prout(_("%d expended on empty space.") % int(extra))
1869 elif automode == "FORCEMAN":
1872 if damaged(DCOMPTR):
1873 prout(_("Battle computer damaged, manual fire only."))
1876 prouts(_("---WORKING---"))
1878 prout(_("Short-range-sensors-damaged"))
1879 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1880 prout(_("Manual-fire-must-be-used"))
1882 elif automode == "MANUAL":
1884 for k in range(len(game.enemies)):
1885 aim = game.enemies[k].kloc
1886 ienm = game.quad[aim.i][aim.j]
1888 proutn(_("Energy available= %.2f") % (avail-0.006))
1892 if damaged(DSRSENS) and \
1893 not game.sector.distance(aim)<2**0.5 and ienm in (IHC, IHS):
1894 prout(cramen(ienm) + _(" can't be located without short range scan."))
1897 hits[k] = 0; # prevent overflow -- thanks to Alexei Voitenko
1902 if itarg and k > kz:
1903 irec=(abs(game.enemies[k].kpower)/(PHASEFAC*math.pow(0.9,game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1906 if not damaged(DCOMPTR):
1911 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1912 key = scanner.next()
1913 if key == "IHALPHA" and scanner.sees("no"):
1915 key = scanner.next()
1917 if key == "IHALPHA":
1921 if k==1: # Let me say I'm baffled by this
1924 if scanner.real < 0:
1928 hits[k] = scanner.real
1929 rpow += scanner.real
1930 # If total requested is too much, inform and start over
1932 prout(_("Available energy exceeded -- try again."))
1935 key = scanner.next(); # scan for next value
1938 # zero energy -- abort
1941 if key == "IHALPHA" and scanner.sees("no"):
1946 game.energy -= 200.0
1947 if checkshctrl(rpow):
1951 # Say shield raised or malfunction, if necessary
1958 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1959 prouts(_(" CLICK CLICK POP . . ."))
1960 prout(_(" No response, sir!"))
1963 prout(_("Shields raised."))
1968 # Code from events,c begins here.
1970 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1971 # event of each type active at any given time. Mostly these means we can
1972 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1973 # BSD Trek, from which we swiped the idea, can have up to 5.
1975 def unschedule(evtype):
1976 "Remove an event from the schedule."
1977 game.future[evtype].date = FOREVER
1978 return game.future[evtype]
1980 def is_scheduled(evtype):
1981 "Is an event of specified type scheduled."
1982 return game.future[evtype].date != FOREVER
1984 def scheduled(evtype):
1985 "When will this event happen?"
1986 return game.future[evtype].date
1988 def schedule(evtype, offset):
1989 "Schedule an event of specified type."
1990 game.future[evtype].date = game.state.date + offset
1991 return game.future[evtype]
1993 def postpone(evtype, offset):
1994 "Postpone a scheduled event."
1995 game.future[evtype].date += offset
1998 "Rest period is interrupted by event."
2001 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2003 game.resting = False
2009 "Run through the event queue looking for things to do."
2011 fintim = game.state.date + game.optime; yank=0
2012 ictbeam = False; istract = False
2013 w = coord(); hold = coord()
2014 ev = event(); ev2 = event()
2016 def tractorbeam(yank):
2017 "Tractor-beaming cases merge here."
2019 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2021 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2022 # If Kirk & Co. screwing around on planet, handle
2023 atover(True) # atover(true) is Grab
2026 if game.icraft: # Caught in Galileo?
2029 # Check to see if shuttle is aboard
2030 if game.iscraft == "offship":
2033 prout(_("Galileo, left on the planet surface, is captured"))
2034 prout(_("by aliens and made into a flying McDonald's."))
2035 game.damage[DSHUTTL] = -10
2036 game.iscraft = "removed"
2038 prout(_("Galileo, left on the planet surface, is well hidden."))
2040 game.quadrant = game.state.kscmdr
2042 game.quadrant = game.state.kcmdr[i]
2043 game.sector = randplace(QUADSIZE)
2044 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2045 % (game.quadrant, game.sector))
2047 prout(_("(Remainder of rest/repair period cancelled.)"))
2048 game.resting = False
2050 if not damaged(DSHIELD) and game.shield > 0:
2051 doshield(shraise=True) # raise shields
2052 game.shldchg = False
2054 prout(_("(Shields not currently useable.)"))
2056 # Adjust finish time to time of tractor beaming
2057 fintim = game.state.date+game.optime
2058 attack(torps_ok=False)
2059 if not game.state.kcmdr:
2062 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2065 "Code merges here for any commander destroying a starbase."
2066 # Not perfect, but will have to do
2067 # Handle case where base is in same quadrant as starship
2068 if game.battle == game.quadrant:
2069 game.state.chart[game.battle.i][game.battle.j].starbase = False
2070 game.quad[game.base.i][game.base.j] = IHDOT
2071 game.base.invalidate()
2074 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2075 elif game.state.baseq and communicating():
2076 # Get word via subspace radio
2079 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2080 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2082 prout(_("the Klingon Super-Commander"))
2084 prout(_("a Klingon Commander"))
2085 game.state.chart[game.battle.i][game.battle.j].starbase = False
2086 # Remove Starbase from galaxy
2087 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2088 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2090 # reinstate a commander's base attack
2094 game.battle.invalidate()
2096 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2097 for i in range(1, NEVENTS):
2098 if i == FSNOVA: proutn("=== Supernova ")
2099 elif i == FTBEAM: proutn("=== T Beam ")
2100 elif i == FSNAP: proutn("=== Snapshot ")
2101 elif i == FBATTAK: proutn("=== Base Attack ")
2102 elif i == FCDBAS: proutn("=== Base Destroy ")
2103 elif i == FSCMOVE: proutn("=== SC Move ")
2104 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2105 elif i == FDSPROB: proutn("=== Probe Move ")
2106 elif i == FDISTR: proutn("=== Distress Call ")
2107 elif i == FENSLV: proutn("=== Enslavement ")
2108 elif i == FREPRO: proutn("=== Klingon Build ")
2110 prout("%.2f" % (scheduled(i)))
2113 radio_was_broken = damaged(DRADIO)
2116 # Select earliest extraneous event, evcode==0 if no events
2121 for l in range(1, NEVENTS):
2122 if game.future[l].date < datemin:
2125 prout("== Event %d fires" % evcode)
2126 datemin = game.future[l].date
2127 xtime = datemin-game.state.date
2128 game.state.date = datemin
2129 # Decrement Federation resources and recompute remaining time
2130 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2132 if game.state.remtime <=0:
2135 # Any crew left alive?
2136 if game.state.crew <=0:
2139 # Is life support adequate?
2140 if damaged(DLIFSUP) and game.condition != "docked":
2141 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2144 game.lsupres -= xtime
2145 if game.damage[DLIFSUP] <= xtime:
2146 game.lsupres = game.inlsr
2149 if game.condition == "docked":
2150 repair /= game.docfac
2151 # Don't fix Deathray here
2152 for l in range(NDEVICES):
2153 if game.damage[l] > 0.0 and l != DDRAY:
2154 if game.damage[l]-repair > 0.0:
2155 game.damage[l] -= repair
2157 game.damage[l] = 0.0
2158 # If radio repaired, update star chart and attack reports
2159 if radio_was_broken and not damaged(DRADIO):
2160 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2161 prout(_(" surveillance reports are coming in."))
2163 if not game.iseenit:
2167 prout(_(" The star chart is now up to date.\""))
2169 # Cause extraneous event EVCODE to occur
2170 game.optime -= xtime
2171 if evcode == FSNOVA: # Supernova
2174 schedule(FSNOVA, expran(0.5*game.intime))
2175 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2177 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2178 if game.state.nscrem == 0 or \
2179 ictbeam or istract or \
2180 game.condition=="docked" or game.isatb==1 or game.iscate:
2182 if game.ientesc or \
2183 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2184 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2185 (damaged(DSHIELD) and \
2186 (game.energy < 2500 or damaged(DPHASER)) and \
2187 (game.torps < 5 or damaged(DPHOTON))):
2189 istract = ictbeam = True
2190 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2193 elif evcode == FTBEAM: # Tractor beam
2194 if not game.state.kcmdr:
2197 i = randrange(len(game.state.kcmdr))
2198 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2199 if istract or game.condition == "docked" or yank == 0:
2200 # Drats! Have to reschedule
2202 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2206 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2207 game.snapsht = copy.deepcopy(game.state)
2208 game.state.snap = True
2209 schedule(FSNAP, expran(0.5 * game.intime))
2210 elif evcode == FBATTAK: # Commander attacks starbase
2211 if not game.state.kcmdr or not game.state.baseq:
2217 for ibq in game.state.baseq:
2218 for cmdr in game.state.kcmdr:
2219 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2222 # no match found -- try later
2223 schedule(FBATTAK, expran(0.3*game.intime))
2228 # commander + starbase combination found -- launch attack
2230 schedule(FCDBAS, randreal(1.0, 4.0))
2231 if game.isatb: # extra time if SC already attacking
2232 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2233 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2234 game.iseenit = False
2235 if not communicating():
2236 continue # No warning :-(
2240 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2241 prout(_(" reports that it is under attack and that it can"))
2242 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2245 elif evcode == FSCDBAS: # Supercommander destroys base
2248 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2249 continue # WAS RETURN!
2251 game.battle = game.state.kscmdr
2253 elif evcode == FCDBAS: # Commander succeeds in destroying base
2256 if not game.state.baseq() \
2257 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2258 game.battle.invalidate()
2260 # find the lucky pair
2261 for cmdr in game.state.kcmdr:
2262 if cmdr == game.battle:
2265 # No action to take after all
2268 elif evcode == FSCMOVE: # Supercommander moves
2269 schedule(FSCMOVE, 0.2777)
2270 if not game.ientesc and not istract and game.isatb != 1 and \
2271 (not game.iscate or not game.justin):
2273 elif evcode == FDSPROB: # Move deep space probe
2274 schedule(FDSPROB, 0.01)
2275 if not game.probe.next():
2276 if not game.probe.quadrant().valid_quadrant() or \
2277 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2278 # Left galaxy or ran into supernova
2282 proutn(_("Lt. Uhura- \"The deep space probe "))
2283 if not game.probe.quadrant().valid_quadrant():
2284 prout(_("has left the galaxy.\""))
2286 prout(_("is no longer transmitting.\""))
2292 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2293 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2295 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2296 chp.klingons = pdest.klingons
2297 chp.starbase = pdest.starbase
2298 chp.stars = pdest.stars
2299 pdest.charted = True
2300 game.probe.moves -= 1 # One less to travel
2301 if game.probe.arrived() and game.isarmed and pdest.stars:
2302 supernova(game.probe) # fire in the hole!
2304 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2306 elif evcode == FDISTR: # inhabited system issues distress call
2308 # try a whole bunch of times to find something suitable
2309 for i in range(100):
2310 # need a quadrant which is not the current one,
2311 # which has some stars which are inhabited and
2312 # not already under attack, which is not
2313 # supernova'ed, and which has some Klingons in it
2314 w = randplace(GALSIZE)
2315 q = game.state.galaxy[w.i][w.j]
2316 if not (game.quadrant == w or q.planet == None or \
2317 not q.planet.inhabited or \
2318 q.supernova or q.status!="secure" or q.klingons<=0):
2321 # can't seem to find one; ignore this call
2323 prout("=== Couldn't find location for distress event.")
2325 # got one!! Schedule its enslavement
2326 ev = schedule(FENSLV, expran(game.intime))
2328 q.status = "distressed"
2329 # tell the captain about it if we can
2331 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2333 prout(_("by a Klingon invasion fleet."))
2336 elif evcode == FENSLV: # starsystem is enslaved
2337 ev = unschedule(FENSLV)
2338 # see if current distress call still active
2339 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2343 q.status = "enslaved"
2345 # play stork and schedule the first baby
2346 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2347 ev2.quadrant = ev.quadrant
2349 # report the disaster if we can
2351 prout(_("Uhura- We've lost contact with starsystem %s") % \
2353 prout(_("in Quadrant %s.\n") % ev.quadrant)
2354 elif evcode == FREPRO: # Klingon reproduces
2355 # If we ever switch to a real event queue, we'll need to
2356 # explicitly retrieve and restore the x and y.
2357 ev = schedule(FREPRO, expran(1.0 * game.intime))
2358 # see if current distress call still active
2359 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2363 if game.state.remkl >=MAXKLGAME:
2364 continue # full right now
2365 # reproduce one Klingon
2368 if game.klhere >= MAXKLQUAD:
2370 # this quadrant not ok, pick an adjacent one
2371 for m.i in range(w.i - 1, w.i + 2):
2372 for m.j in range(w.j - 1, w.j + 2):
2373 if not m.valid_quadrant():
2375 q = game.state.galaxy[m.i][m.j]
2376 # check for this quad ok (not full & no snova)
2377 if q.klingons >= MAXKLQUAD or q.supernova:
2381 continue # search for eligible quadrant failed
2385 game.state.remkl += 1
2387 if game.quadrant == w:
2389 game.enemies.append(newkling())
2390 # recompute time left
2393 if game.quadrant == w:
2394 prout(_("Spock- sensors indicate the Klingons have"))
2395 prout(_("launched a warship from %s.") % q.planet)
2397 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2398 if q.planet != None:
2399 proutn(_("near %s") % q.planet)
2400 prout(_("in Quadrant %s.") % w)
2406 key = scanner.next()
2409 proutn(_("How long? "))
2414 origTime = delay = scanner.real
2417 if delay >= game.state.remtime or len(game.enemies) != 0:
2418 proutn(_("Are you sure? "))
2421 # Alternate resting periods (events) with attacks
2425 game.resting = False
2426 if not game.resting:
2427 prout(_("%d stardates left.") % int(game.state.remtime))
2429 temp = game.optime = delay
2430 if len(game.enemies):
2431 rtime = randreal(1.0, 2.0)
2435 if game.optime < delay:
2436 attack(torps_ok=False)
2444 # Repair Deathray if long rest at starbase
2445 if origTime-delay >= 9.99 and game.condition == "docked":
2446 game.damage[DDRAY] = 0.0
2447 # leave if quadrant supernovas
2448 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2450 game.resting = False
2455 course = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2456 newc = coord(); neighbor = coord(); bump = coord(0, 0)
2458 # Wow! We've supernova'ed
2459 supernova(game.quadrant)
2461 # handle initial nova
2462 game.quad[nov.i][nov.j] = IHDOT
2463 prout(crmena(False, IHSTAR, "sector", nov) + _(" novas."))
2464 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2465 game.state.starkl += 1
2466 # Set up queue to recursively trigger adjacent stars
2472 for offset.i in range(-1, 1+1):
2473 for offset.j in range(-1, 1+1):
2474 if offset.j==0 and offset.i==0:
2476 neighbor = start + offset
2477 if not neighbor.valid_sector():
2479 iquad = game.quad[neighbor.i][neighbor.j]
2480 # Empty space ends reaction
2481 if iquad in (IHDOT, IHQUEST, IHBLANK, IHT, IHWEB):
2483 elif iquad == IHSTAR: # Affect another star
2485 # This star supernovas
2486 supernova(game.quadrant)
2489 hits.append(neighbor)
2490 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2491 game.state.starkl += 1
2492 proutn(crmena(True, IHSTAR, "sector", neighbor))
2494 game.quad[neighbor.i][neighbor.j] = IHDOT
2496 elif iquad in (IHP, IHW): # Destroy planet
2497 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2499 game.state.nplankl += 1
2501 game.state.worldkl += 1
2502 prout(crmena(True, IHB, "sector", neighbor) + _(" destroyed."))
2503 game.iplnet.pclass = "destroyed"
2505 game.plnet.invalidate()
2509 game.quad[neighbor.i][neighbor.j] = IHDOT
2510 elif iquad == IHB: # Destroy base
2511 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2512 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2513 game.base.invalidate()
2514 game.state.basekl += 1
2516 prout(crmena(True, IHB, "sector", neighbor) + _(" destroyed."))
2517 game.quad[neighbor.i][neighbor.j] = IHDOT
2518 elif iquad in (IHE, IHF): # Buffet ship
2519 prout(_("***Starship buffeted by nova."))
2521 if game.shield >= 2000.0:
2522 game.shield -= 2000.0
2524 diff = 2000.0 - game.shield
2528 prout(_("***Shields knocked out."))
2529 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2531 game.energy -= 2000.0
2532 if game.energy <= 0:
2535 # add in course nova contributes to kicking starship
2536 bump += (game.sector-hits[mm]).sgn()
2537 elif iquad == IHK: # kill klingon
2538 deadkl(neighbor, iquad, neighbor)
2539 elif iquad in (IHC,IHS,IHR): # Damage/destroy big enemies
2540 for ll in range(len(game.enemies)):
2541 if game.enemies[ll].kloc == neighbor:
2543 game.enemies[ll].kpower -= 800.0 # If firepower is lost, die
2544 if game.enemies[ll].kpower <= 0.0:
2545 deadkl(neighbor, iquad, neighbor)
2547 newc = neighbor + neighbor - hits[mm]
2548 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2549 if not newc.valid_sector():
2550 # can't leave quadrant
2553 iquad1 = game.quad[newc.i][newc.j]
2554 if iquad1 == IHBLANK:
2555 proutn(_(", blasted into ") + crmena(False, IHBLANK, "sector", newc))
2557 deadkl(neighbor, iquad, newc)
2560 # can't move into something else
2563 proutn(_(", buffeted to Sector %s") % newc)
2564 game.quad[neighbor.i][neighbor.j] = IHDOT
2565 game.quad[newc.i][newc.j] = iquad
2566 game.enemies[ll].move(newc)
2567 # Starship affected by nova -- kick it away.
2569 direc = course[3*(bump.i+1)+bump.j+2]
2574 course = course(bearing=direc, distance=dist)
2575 game.optime = course.time(warp=4)
2577 prout(_("Force of nova displaces starship."))
2578 imove(course, noattack=True)
2579 game.optime = course.time(warp=4)
2583 "Star goes supernova."
2588 # Scheduled supernova -- select star at random.
2591 for nq.i in range(GALSIZE):
2592 for nq.j in range(GALSIZE):
2593 stars += game.state.galaxy[nq.i][nq.j].stars
2595 return # nothing to supernova exists
2596 num = randrange(stars) + 1
2597 for nq.i in range(GALSIZE):
2598 for nq.j in range(GALSIZE):
2599 num -= game.state.galaxy[nq.i][nq.j].stars
2605 proutn("=== Super nova here?")
2608 if not nq == game.quadrant or game.justin:
2609 # it isn't here, or we just entered (treat as enroute)
2612 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2613 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2616 # we are in the quadrant!
2617 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2618 for ns.i in range(QUADSIZE):
2619 for ns.j in range(QUADSIZE):
2620 if game.quad[ns.i][ns.j]==IHSTAR:
2627 prouts(_("***RED ALERT! RED ALERT!"))
2629 prout(_("***Incipient supernova detected at Sector %s") % ns)
2630 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2631 proutn(_("Emergency override attempts t"))
2632 prouts("***************")
2636 # destroy any Klingons in supernovaed quadrant
2637 kldead = game.state.galaxy[nq.i][nq.j].klingons
2638 game.state.galaxy[nq.i][nq.j].klingons = 0
2639 if nq == game.state.kscmdr:
2640 # did in the Supercommander!
2641 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2645 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2646 comkills = len(game.state.kcmdr) - len(survivors)
2647 game.state.kcmdr = survivors
2649 if not game.state.kcmdr:
2651 game.state.remkl -= kldead
2652 # destroy Romulans and planets in supernovaed quadrant
2653 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2654 game.state.galaxy[nq.i][nq.j].romulans = 0
2655 game.state.nromrem -= nrmdead
2657 for loop in range(game.inplan):
2658 if game.state.planets[loop].quadrant == nq:
2659 game.state.planets[loop].pclass = "destroyed"
2661 # Destroy any base in supernovaed quadrant
2662 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2663 # If starship caused supernova, tally up destruction
2665 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2666 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2667 game.state.nplankl += npdead
2668 # mark supernova in galaxy and in star chart
2669 if game.quadrant == nq or communicating():
2670 game.state.galaxy[nq.i][nq.j].supernova = True
2671 # If supernova destroys last Klingons give special message
2672 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2675 prout(_("Lucky you!"))
2676 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2679 # if some Klingons remain, continue or die in supernova
2684 # Code from finish.c ends here.
2687 "Self-destruct maneuver. Finish with a BANG!"
2689 if damaged(DCOMPTR):
2690 prout(_("Computer damaged; cannot execute destruct sequence."))
2692 prouts(_("---WORKING---")); skip(1)
2693 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2694 prouts(" 10"); skip(1)
2695 prouts(" 9"); skip(1)
2696 prouts(" 8"); skip(1)
2697 prouts(" 7"); skip(1)
2698 prouts(" 6"); skip(1)
2700 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2702 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2704 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2708 if game.passwd != scanner.token:
2709 prouts(_("PASSWORD-REJECTED;"))
2711 prouts(_("CONTINUITY-EFFECTED"))
2714 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2715 prouts(" 5"); skip(1)
2716 prouts(" 4"); skip(1)
2717 prouts(" 3"); skip(1)
2718 prouts(" 2"); skip(1)
2719 prouts(" 1"); skip(1)
2721 prouts(_("GOODBYE-CRUEL-WORLD"))
2729 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2733 if len(game.enemies) != 0:
2734 whammo = 25.0 * game.energy
2736 while l <= len(game.enemies):
2737 if game.enemies[l].kpower*game.enemies[l].kdist <= whammo:
2738 deadkl(game.enemies[l].kloc, game.quad[game.enemies[l].kloc.i][game.enemies[l].kloc.j], game.enemies[l].kloc)
2743 "Compute our rate of kils over time."
2744 elapsed = game.state.date - game.indate
2745 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2748 starting = (game.inkling + game.incom + game.inscom)
2749 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2750 return (starting - remaining)/elapsed
2754 badpt = 5.0*game.state.starkl + \
2756 10.0*game.state.nplankl + \
2757 300*game.state.nworldkl + \
2759 100.0*game.state.basekl +\
2761 if game.ship == IHF:
2763 elif game.ship == None:
2768 # end the game, with appropriate notfications
2772 prout(_("It is stardate %.1f.") % game.state.date)
2774 if ifin == FWON: # Game has been won
2775 if game.state.nromrem != 0:
2776 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2779 prout(_("You have smashed the Klingon invasion fleet and saved"))
2780 prout(_("the Federation."))
2785 badpt = 0.0 # Close enough!
2786 # killsPerDate >= RateMax
2787 if game.state.date-game.indate < 5.0 or \
2788 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2790 prout(_("In fact, you have done so well that Starfleet Command"))
2791 if game.skill == SKILL_NOVICE:
2792 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2793 elif game.skill == SKILL_FAIR:
2794 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2795 elif game.skill == SKILL_GOOD:
2796 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2797 elif game.skill == SKILL_EXPERT:
2798 prout(_("promotes you to Commodore Emeritus."))
2800 prout(_("Now that you think you're really good, try playing"))
2801 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2802 elif game.skill == SKILL_EMERITUS:
2804 proutn(_("Computer- "))
2805 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2807 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2809 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2811 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2813 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2815 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2817 prout(_("Now you can retire and write your own Star Trek game!"))
2819 elif game.skill >= SKILL_EXPERT:
2820 if game.thawed and not idebug:
2821 prout(_("You cannot get a citation, so..."))
2823 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2827 # Only grant long life if alive (original didn't!)
2829 prout(_("LIVE LONG AND PROSPER."))
2834 elif ifin == FDEPLETE: # Federation Resources Depleted
2835 prout(_("Your time has run out and the Federation has been"))
2836 prout(_("conquered. Your starship is now Klingon property,"))
2837 prout(_("and you are put on trial as a war criminal. On the"))
2838 proutn(_("basis of your record, you are "))
2839 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2840 prout(_("acquitted."))
2842 prout(_("LIVE LONG AND PROSPER."))
2844 prout(_("found guilty and"))
2845 prout(_("sentenced to death by slow torture."))
2849 elif ifin == FLIFESUP:
2850 prout(_("Your life support reserves have run out, and"))
2851 prout(_("you die of thirst, starvation, and asphyxiation."))
2852 prout(_("Your starship is a derelict in space."))
2854 prout(_("Your energy supply is exhausted."))
2856 prout(_("Your starship is a derelict in space."))
2857 elif ifin == FBATTLE:
2858 prout(_("The %s has been destroyed in battle.") % crmshp())
2860 prout(_("Dulce et decorum est pro patria mori."))
2862 prout(_("You have made three attempts to cross the negative energy"))
2863 prout(_("barrier which surrounds the galaxy."))
2865 prout(_("Your navigation is abominable."))
2868 prout(_("Your starship has been destroyed by a nova."))
2869 prout(_("That was a great shot."))
2871 elif ifin == FSNOVAED:
2872 prout(_("The %s has been fried by a supernova.") % crmshp())
2873 prout(_("...Not even cinders remain..."))
2874 elif ifin == FABANDN:
2875 prout(_("You have been captured by the Klingons. If you still"))
2876 prout(_("had a starbase to be returned to, you would have been"))
2877 prout(_("repatriated and given another chance. Since you have"))
2878 prout(_("no starbases, you will be mercilessly tortured to death."))
2879 elif ifin == FDILITHIUM:
2880 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2881 elif ifin == FMATERIALIZE:
2882 prout(_("Starbase was unable to re-materialize your starship."))
2883 prout(_("Sic transit gloria mundi"))
2884 elif ifin == FPHASER:
2885 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2887 prout(_("You and your landing party have been"))
2888 prout(_("converted to energy, disipating through space."))
2889 elif ifin == FMINING:
2890 prout(_("You are left with your landing party on"))
2891 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2893 prout(_("They are very fond of \"Captain Kirk\" soup."))
2895 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2896 elif ifin == FDPLANET:
2897 prout(_("You and your mining party perish."))
2899 prout(_("That was a great shot."))
2902 prout(_("The Galileo is instantly annihilated by the supernova."))
2903 prout(_("You and your mining party are atomized."))
2905 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2906 prout(_("joins the Romulans, wreaking terror on the Federation."))
2907 elif ifin == FPNOVA:
2908 prout(_("You and your mining party are atomized."))
2910 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2911 prout(_("joins the Romulans, wreaking terror on the Federation."))
2912 elif ifin == FSTRACTOR:
2913 prout(_("The shuttle craft Galileo is also caught,"))
2914 prout(_("and breaks up under the strain."))
2916 prout(_("Your debris is scattered for millions of miles."))
2917 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2919 prout(_("The mutants attack and kill Spock."))
2920 prout(_("Your ship is captured by Klingons, and"))
2921 prout(_("your crew is put on display in a Klingon zoo."))
2922 elif ifin == FTRIBBLE:
2923 prout(_("Tribbles consume all remaining water,"))
2924 prout(_("food, and oxygen on your ship."))
2926 prout(_("You die of thirst, starvation, and asphyxiation."))
2927 prout(_("Your starship is a derelict in space."))
2929 prout(_("Your ship is drawn to the center of the black hole."))
2930 prout(_("You are crushed into extremely dense matter."))
2932 prout(_("Your last crew member has died."))
2933 if game.ship == IHF:
2935 elif game.ship == IHE:
2938 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2939 goodies = game.state.remres/game.inresor
2940 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2941 if goodies/baddies >= randreal(1.0, 1.5):
2942 prout(_("As a result of your actions, a treaty with the Klingon"))
2943 prout(_("Empire has been signed. The terms of the treaty are"))
2944 if goodies/baddies >= randreal(3.0):
2945 prout(_("favorable to the Federation."))
2947 prout(_("Congratulations!"))
2949 prout(_("highly unfavorable to the Federation."))
2951 prout(_("The Federation will be destroyed."))
2953 prout(_("Since you took the last Klingon with you, you are a"))
2954 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2955 prout(_("statue in your memory. Rest in peace, and try not"))
2956 prout(_("to think about pigeons."))
2961 "Compute player's score."
2962 timused = game.state.date - game.indate
2964 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2966 perdate = killrate()
2967 ithperd = 500*perdate + 0.5
2970 iwon = 100*game.skill
2971 if game.ship == IHE:
2973 elif game.ship == IHF:
2977 if not game.gamewon:
2978 game.state.nromrem = 0 # None captured if no win
2979 iscore = 10*(game.inkling - game.state.remkl) \
2980 + 50*(game.incom - len(game.state.kcmdr)) \
2982 + 20*(game.inrom - game.state.nromrem) \
2983 + 200*(game.inscom - game.state.nscrem) \
2984 - game.state.nromrem \
2989 prout(_("Your score --"))
2990 if game.inrom - game.state.nromrem:
2991 prout(_("%6d Romulans destroyed %5d") %
2992 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
2993 if game.state.nromrem:
2994 prout(_("%6d Romulans captured %5d") %
2995 (game.state.nromrem, game.state.nromrem))
2996 if game.inkling - game.state.remkl:
2997 prout(_("%6d ordinary Klingons destroyed %5d") %
2998 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
2999 if game.incom - len(game.state.kcmdr):
3000 prout(_("%6d Klingon commanders destroyed %5d") %
3001 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
3002 if game.inscom - game.state.nscrem:
3003 prout(_("%6d Super-Commander destroyed %5d") %
3004 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3006 prout(_("%6.2f Klingons per stardate %5d") %
3008 if game.state.starkl:
3009 prout(_("%6d stars destroyed by your action %5d") %
3010 (game.state.starkl, -5*game.state.starkl))
3011 if game.state.nplankl:
3012 prout(_("%6d planets destroyed by your action %5d") %
3013 (game.state.nplankl, -10*game.state.nplankl))
3014 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3015 prout(_("%6d inhabited planets destroyed by your action %5d") %
3016 (game.state.nplankl, -300*game.state.nworldkl))
3017 if game.state.basekl:
3018 prout(_("%6d bases destroyed by your action %5d") %
3019 (game.state.basekl, -100*game.state.basekl))
3021 prout(_("%6d calls for help from starbase %5d") %
3022 (game.nhelp, -45*game.nhelp))
3024 prout(_("%6d casualties incurred %5d") %
3025 (game.casual, -game.casual))
3027 prout(_("%6d crew abandoned in space %5d") %
3028 (game.abandoned, -3*game.abandoned))
3030 prout(_("%6d ship(s) lost or destroyed %5d") %
3031 (klship, -100*klship))
3033 prout(_("Penalty for getting yourself killed -200"))
3035 proutn(_("Bonus for winning "))
3036 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3037 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3038 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3039 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3040 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3041 prout(" %5d" % iwon)
3043 prout(_("TOTAL SCORE %5d") % iscore)
3046 "Emit winner's commemmorative plaque."
3049 proutn(_("File or device name for your plaque: "))
3052 fp = open(winner, "w")
3055 prout(_("Invalid name."))
3057 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3059 # The 38 below must be 64 for 132-column paper
3060 nskip = 38 - len(winner)/2
3061 fp.write("\n\n\n\n")
3062 # --------DRAW ENTERPRISE PICTURE.
3063 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3064 fp.write(" EEE E : : : E\n" )
3065 fp.write(" EE EEE E : : NCC-1701 : E\n")
3066 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3067 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3068 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3069 fp.write(" EEEEEEE EEEEE E E E E\n")
3070 fp.write(" EEE E E E E\n")
3071 fp.write(" E E E E\n")
3072 fp.write(" EEEEEEEEEEEEE E E\n")
3073 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3074 fp.write(" :E : EEEE E\n")
3075 fp.write(" .-E -:----- E\n")
3076 fp.write(" :E : E\n")
3077 fp.write(" EE : EEEEEEEE\n")
3078 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3080 fp.write(_(" U. S. S. ENTERPRISE\n"))
3081 fp.write("\n\n\n\n")
3082 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3084 fp.write(_(" Starfleet Command bestows to you\n"))
3086 fp.write("%*s%s\n\n" % (nskip, "", winner))
3087 fp.write(_(" the rank of\n\n"))
3088 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3090 if game.skill == SKILL_EXPERT:
3091 fp.write(_(" Expert level\n\n"))
3092 elif game.skill == SKILL_EMERITUS:
3093 fp.write(_("Emeritus level\n\n"))
3095 fp.write(_(" Cheat level\n\n"))
3096 timestring = time.ctime()
3097 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3098 (timestring+4, timestring+20, timestring+11))
3099 fp.write(_(" Your score: %d\n\n") % iscore)
3100 fp.write(_(" Klingons per stardate: %.2f\n") % perdate)
3103 # Code from io.c begins here
3105 rows = linecount = 0 # for paging
3108 fullscreen_window = None
3109 srscan_window = None
3110 report_window = None
3111 status_window = None
3112 lrscan_window = None
3113 message_window = None
3114 prompt_window = None
3119 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3120 gettext.textdomain("sst")
3121 if not (game.options & OPTION_CURSES):
3122 ln_env = os.getenv("LINES")
3128 stdscr = curses.initscr()
3132 global fullscreen_window, srscan_window, report_window, status_window
3133 global lrscan_window, message_window, prompt_window
3134 (rows, columns) = stdscr.getmaxyx()
3135 fullscreen_window = stdscr
3136 srscan_window = curses.newwin(12, 25, 0, 0)
3137 report_window = curses.newwin(11, 0, 1, 25)
3138 status_window = curses.newwin(10, 0, 1, 39)
3139 lrscan_window = curses.newwin(5, 0, 0, 64)
3140 message_window = curses.newwin(0, 0, 12, 0)
3141 prompt_window = curses.newwin(1, 0, rows-2, 0)
3142 message_window.scrollok(True)
3143 setwnd(fullscreen_window)
3147 if game.options & OPTION_CURSES:
3148 stdscr.keypad(False)
3154 "Wait for user action -- OK to do nothing if on a TTY"
3155 if game.options & OPTION_CURSES:
3160 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3164 if game.skill > SKILL_FAIR:
3165 prompt = _("[CONTINUE?]")
3167 prompt = _("[PRESS ENTER TO CONTINUE]")
3169 if game.options & OPTION_CURSES:
3171 setwnd(prompt_window)
3172 prompt_window.clear()
3173 prompt_window.addstr(prompt)
3174 prompt_window.getstr()
3175 prompt_window.clear()
3176 prompt_window.refresh()
3177 setwnd(message_window)
3180 sys.stdout.write('\n')
3183 for j in range(rows):
3184 sys.stdout.write('\n')
3188 "Skip i lines. Pause game if this would cause a scrolling event."
3189 for dummy in range(i):
3190 if game.options & OPTION_CURSES:
3191 (y, x) = curwnd.getyx()
3192 (my, mx) = curwnd.getmaxyx()
3193 if curwnd == message_window and y >= my - 3:
3199 except curses.error:
3204 if rows and linecount >= rows:
3207 sys.stdout.write('\n')
3210 "Utter a line with no following line feed."
3211 if game.options & OPTION_CURSES:
3215 sys.stdout.write(line)
3225 if not replayfp or replayfp.closed: # Don't slow down replays
3228 if game.options & OPTION_CURSES:
3232 if not replayfp or replayfp.closed:
3236 "Get a line of input."
3237 if game.options & OPTION_CURSES:
3238 line = curwnd.getstr() + "\n"
3241 if replayfp and not replayfp.closed:
3243 line = replayfp.readline()
3246 prout("*** Replay finished")
3249 elif line[0] != "#":
3252 line = raw_input() + "\n"
3258 "Change windows -- OK for this to be a no-op in tty mode."
3260 if game.options & OPTION_CURSES:
3262 curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window)
3265 "Clear to end of line -- can be a no-op in tty mode"
3266 if game.options & OPTION_CURSES:
3271 "Clear screen -- can be a no-op in tty mode."
3273 if game.options & OPTION_CURSES:
3280 "Set highlight video, if this is reasonable."
3281 if game.options & OPTION_CURSES:
3282 curwnd.attron(curses.A_REVERSE)
3285 # Things past this point have policy implications.
3289 "Hook to be called after moving to redraw maps."
3290 if game.options & OPTION_CURSES:
3293 setwnd(srscan_window)
3297 setwnd(status_window)
3298 status_window.clear()
3299 status_window.move(0, 0)