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)
3300 setwnd(report_window)
3301 report_window.clear()
3302 report_window.move(0, 0)
3304 setwnd(lrscan_window)
3305 lrscan_window.clear()
3306 lrscan_window.move(0, 0)
3307 lrscan(silent=False)
3309 def put_srscan_sym(w, sym):
3310 "Emit symbol for short-range scan."
3311 srscan_window.move(w.i+1, w.j*2+2)
3312 srscan_window.addch(sym)
3313 srscan_window.refresh()
3316 "Enemy fall down, go boom."
3317 if game.options & OPTION_CURSES:
3319 setwnd(srscan_window)
3320 srscan_window.attron(curses.A_REVERSE)
3321 put_srscan_sym(w, game.quad[w.i][w.j])
3325 srscan_window.attroff(curses.A_REVERSE)
3326 put_srscan_sym(w, game.quad[w.i][w.j])
3327 curses.delay_output(500)
3328 setwnd(message_window)
3331 "Sound and visual effects for teleportation."
3332 if game.options & OPTION_CURSES:
3334 setwnd(message_window)
3336 prouts(" . . . . . ")
3337 if game.options & OPTION_CURSES:
3338 #curses.delay_output(1000)
3342 def tracktorpedo(origin, w, step, i, n, iquad):
3343 "Torpedo-track animation."
3344 if not game.options & OPTION_CURSES:
3348 proutn(_("Track for torpedo number %d- ") % (i+1))
3351 proutn(_("Torpedo track- "))
3352 elif step==4 or step==9:
3356 if not damaged(DSRSENS) or game.condition=="docked":
3357 if i != 0 and step == 1:
3360 if (iquad==IHDOT) or (iquad==IHBLANK):
3361 put_srscan_sym(w, '+')
3365 put_srscan_sym(w, iquad)
3367 curwnd.attron(curses.A_REVERSE)
3368 put_srscan_sym(w, iquad)
3372 curwnd.attroff(curses.A_REVERSE)
3373 put_srscan_sym(w, iquad)
3378 "Display the current galaxy chart."
3379 if game.options & OPTION_CURSES:
3380 setwnd(message_window)
3381 message_window.clear()
3383 if game.options & OPTION_TTY:
3388 def prstat(txt, data):
3390 if game.options & OPTION_CURSES:
3392 setwnd(status_window)
3394 proutn(" " * (NSYM - len(txt)))
3397 if game.options & OPTION_CURSES:
3398 setwnd(report_window)
3400 # Code from moving.c begins here
3402 def imove(course=None, noattack=False):
3403 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3406 def newquadrant(noattack):
3407 # Leaving quadrant -- allow final enemy attack
3408 # Don't do it if being pushed by Nova
3409 if len(game.enemies) != 0 and not noattack:
3411 for enemy in game.enemies:
3412 finald = (w - enemy.kloc).distance()
3413 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3414 # Stas Sergeev added the condition
3415 # that attacks only happen if Klingons
3416 # are present and your skill is good.
3417 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3418 attack(torps_ok=False)
3421 # check for edge of galaxy
3425 if course.final.i < 0:
3426 course.final.i = -course.final.i
3428 if course.final.j < 0:
3429 course.final.j = -course.final.j
3431 if course.final.i >= GALSIZE*QUADSIZE:
3432 course.final.i = (GALSIZE*QUADSIZE*2) - course.final.i
3434 if course.final.j >= GALSIZE*QUADSIZE:
3435 course.final.j = (GALSIZE*QUADSIZE*2) - course.final.j
3443 if game.nkinks == 3:
3444 # Three strikes -- you're out!
3448 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3449 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3450 prout(_("YOU WILL BE DESTROYED."))
3451 # Compute final position in new quadrant
3452 if trbeam: # Don't bother if we are to be beamed
3454 game.quadrant = course.final.quadrant()
3455 game.sector = course.final.sector()
3457 prout(_("Entering Quadrant %s.") % game.quadrant)
3458 game.quad[game.sector.i][game.sector.j] = game.ship
3460 if game.skill>SKILL_NOVICE:
3461 attack(torps_ok=False)
3463 def check_collision(h):
3464 iquad = game.quad[h.i][h.j]
3466 # object encountered in flight path
3467 stopegy = 50.0*course.distance/game.optime
3468 if iquad in (IHT, IHK, IHC, IHS, IHR, IHQUEST):
3469 for enemy in game.enemies:
3470 if enemy.kloc == game.sector:
3472 collision(rammed=False, enemy=enemy)
3474 elif iquad == IHBLANK:
3476 prouts(_("***RED ALERT! RED ALERT!"))
3478 proutn("***" + crmshp())
3479 proutn(_(" pulled into black hole at Sector %s") % h)
3480 # Getting pulled into a black hole was certain
3481 # death in Almy's original. Stas Sergeev added a
3482 # possibility that you'll get timewarped instead.
3484 for m in range(NDEVICES):
3485 if game.damage[m]>0:
3487 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3488 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3498 prout(_(" encounters Tholian web at %s;") % h)
3500 prout(_(" blocked by object at %s;") % h)
3501 proutn(_("Emergency stop required "))
3502 prout(_("%2d units of energy.") % int(stopegy))
3503 game.energy -= stopegy
3504 if game.energy <= 0:
3511 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3512 game.inorbit = False
3513 # If tractor beam is to occur, don't move full distance
3514 if game.state.date+game.optime >= scheduled(FTBEAM):
3516 game.condition = "red"
3517 course.distance = course.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3518 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3520 game.quad[game.sector.i][game.sector.j] = IHDOT
3521 for m in range(course.moves):
3524 if course.origin.quadrant() != course.location.quadrant():
3525 newquadrant(noattack)
3527 elif check_collision(w):
3528 print "Collision detected"
3532 # We're in destination quadrant -- compute new average enemy distances
3533 game.quad[game.sector.i][game.sector.j] = game.ship
3535 for enemy in game.enemies:
3536 finald = (w-enemy.kloc).distance()
3537 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3538 enemy.kdist = finald
3539 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
3540 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3541 attack(torps_ok=False)
3542 for enemy in game.enemies:
3543 enemy.kavgd = enemy.kdist
3546 setwnd(message_window)
3550 "Dock our ship at a starbase."
3552 if game.condition == "docked" and verbose:
3553 prout(_("Already docked."))
3556 prout(_("You must first leave standard orbit."))
3558 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3559 prout(crmshp() + _(" not adjacent to base."))
3561 game.condition = "docked"
3565 if game.energy < game.inenrg:
3566 game.energy = game.inenrg
3567 game.shield = game.inshld
3568 game.torps = game.intorps
3569 game.lsupres = game.inlsr
3570 game.state.crew = FULLCREW
3571 if not damaged(DRADIO) and \
3572 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3573 # get attack report from base
3574 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3578 # This program originally required input in terms of a (clock)
3579 # direction and distance. Somewhere in history, it was changed to
3580 # cartesian coordinates. So we need to convert. Probably
3581 # "manual" input should still be done this way -- it's a real
3582 # pain if the computer isn't working! Manual mode is still confusing
3583 # because it involves giving x and y motions, yet the coordinates
3584 # are always displayed y - x, where +y is downward!
3586 def cartesian(loc1=None, loc2=None):
3588 return game.quadrant * QUADSIZE + game.sector
3590 return game.quadrant * QUADSIZE + loc1
3592 return loc1 * QUADSIZE + loc2
3594 def getcourse(isprobe):
3595 "Get a course and distance from the user."
3597 dquad = copy.copy(game.quadrant)
3598 navmode = "unspecified"
3602 if game.landed and not isprobe:
3603 prout(_("Dummy! You can't leave standard orbit until you"))
3604 proutn(_("are back aboard the ship."))
3607 while navmode == "unspecified":
3608 if damaged(DNAVSYS):
3610 prout(_("Computer damaged; manual navigation only"))
3612 prout(_("Computer damaged; manual movement only"))
3617 key = scanner.next()
3619 proutn(_("Manual or automatic- "))
3622 elif key == "IHALPHA":
3623 if scanner.sees("manual"):
3625 key = scanner.next()
3627 elif scanner.sees("automatic"):
3628 navmode = "automatic"
3629 key = scanner.next()
3637 prout(_("(Manual navigation assumed.)"))
3639 prout(_("(Manual movement assumed.)"))
3643 if navmode == "automatic":
3644 while key == "IHEOL":
3646 proutn(_("Target quadrant or quadrant§or- "))
3648 proutn(_("Destination sector or quadrant§or- "))
3651 key = scanner.next()
3655 xi = int(round(scanner.real))-1
3656 key = scanner.next()
3660 xj = int(round(scanner.real))-1
3661 key = scanner.next()
3663 # both quadrant and sector specified
3664 xk = int(round(scanner.real))-1
3665 key = scanner.next()
3669 xl = int(round(scanner.real))-1
3675 # only one pair of numbers was specified
3677 # only quadrant specified -- go to center of dest quad
3680 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3682 # only sector specified
3686 if not dquad.valid_quadrant() or not dsect.valid_sector():
3693 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3695 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3696 # the actual deltas get computed here
3697 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3698 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3700 while key == "IHEOL":
3701 proutn(_("X and Y displacements- "))
3704 key = scanner.next()
3709 delta.j = scanner.real
3710 key = scanner.next()
3714 delta.i = scanner.real
3715 # Check for zero movement
3716 if delta.i == 0 and delta.j == 0:
3719 if itemp == "verbose" and not isprobe:
3721 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3723 return course(bearing=delta.bearing(), distance=delta.distance())
3726 def __init__(self, bearing, distance, origin=None):
3727 self.distance = distance
3728 self.bearing = bearing
3730 self.origin = cartesian(game.quadrant, game.sector)
3732 self.origin = origin
3733 # The bearing() code we inherited from FORTRAN is actually computing
3734 # clockface directions!
3735 if self.bearing < 0.0:
3736 self.bearing += 12.0
3737 self.angle = ((15.0 - self.bearing) * 0.5235988)
3739 self.origin = cartesian(game.quadrant, game.sector)
3741 self.origin = cartesian(game.quadrant, origin)
3742 self.increment = coord(-math.sin(self.angle), math.cos(self.angle))
3743 bigger = max(abs(self.increment.i), abs(self.increment.j))
3744 self.increment /= bigger
3745 self.moves = int(round(10*self.distance*bigger))
3747 self.final = (self.location + self.moves*self.increment).roundtogrid()
3749 self.location = self.origin
3752 return self.location.roundtogrid() == self.final
3754 "Next step on course."
3756 self.nextlocation = self.location + self.increment
3757 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3758 self.location = self.nextlocation
3761 return self.location.quadrant()
3763 return self.location.sector()
3764 def power(self, warp):
3765 return self.distance*(warp**3)*(game.shldup+1)
3766 def time(self, warp):
3767 return 10.0*self.distance/warp**2
3770 "Move under impulse power."
3772 if damaged(DIMPULS):
3775 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3777 if game.energy > 30.0:
3779 course = getcourse(isprobe=False)
3782 power = 20.0 + 100.0*course.distance
3785 if power >= game.energy:
3786 # Insufficient power for trip
3788 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3789 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3790 if game.energy > 30:
3791 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3792 int(0.01 * (game.energy-20.0)-0.05))
3793 prout(_(" quadrants.\""))
3795 prout(_("quadrant. They are, therefore, useless.\""))
3798 # Make sure enough time is left for the trip
3799 game.optime = course.dist/0.095
3800 if game.optime >= game.state.remtime:
3801 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3802 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3803 proutn(_("we dare spend the time?\" "))
3806 # Activate impulse engines and pay the cost
3807 imove(course, noattack=False)
3811 power = 20.0 + 100.0*course.dist
3812 game.energy -= power
3813 game.optime = course.dist/0.095
3814 if game.energy <= 0:
3818 def warp(course, involuntary):
3819 "ove under warp drive."
3820 blooey = False; twarp = False
3821 if not involuntary: # Not WARPX entry
3823 if game.damage[DWARPEN] > 10.0:
3826 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3828 if damaged(DWARPEN) and game.warpfac > 4.0:
3831 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3832 prout(_(" is repaired, I can only give you warp 4.\""))
3834 # Read in course and distance
3837 course = getcourse(isprobe=False)
3840 # Make sure starship has enough energy for the trip
3841 # Note: this formula is slightly different from the C version,
3842 # and lets you skate a bit closer to the edge.
3843 if course.power(game.warpfac) >= game.energy:
3844 # Insufficient power for trip
3847 prout(_("Engineering to bridge--"))
3848 if not game.shldup or 0.5*power > game.energy:
3849 iwarp = (game.energy/(course.dist+0.05)) ** 0.333333333
3851 prout(_("We can't do it, Captain. We don't have enough energy."))
3853 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3856 prout(_("if you'll lower the shields."))
3860 prout(_("We haven't the energy to go that far with the shields up."))
3862 # Make sure enough time is left for the trip
3863 game.optime = course.time(game.warpfac)
3864 if game.optime >= 0.8*game.state.remtime:
3866 prout(_("First Officer Spock- \"Captain, I compute that such"))
3867 proutn(_(" a trip would require approximately %2.0f") %
3868 (100.0*game.optime/game.state.remtime))
3869 prout(_(" percent of our"))
3870 proutn(_(" remaining time. Are you sure this is wise?\" "))
3876 if game.warpfac > 6.0:
3877 # Decide if engine damage will occur
3878 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3879 prob = course.distance*(6.0-game.warpfac)**2/66.666666666
3880 if prob > randreal():
3882 course.distance = randreal(course.distance)
3883 # Decide if time warp will occur
3884 if 0.5*course.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3886 if idebug and game.warpfac==10 and not twarp:
3888 proutn("=== Force time warp? ")
3892 # If time warp or engine damage, check path
3893 # If it is obstructed, don't do warp or damage
3894 for m in range(course.moves):
3897 if not w.valid_sector():
3899 if game.quad[w.i][w.j] != IHDOT:
3903 # Activate Warp Engines and pay the cost
3904 imove(course, noattack=False)
3907 game.energy -= course.power(game.warpfac)
3908 if game.energy <= 0:
3910 game.optime = course.time(game.warpfac)
3914 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
3916 prout(_("Engineering to bridge--"))
3917 prout(_(" Scott here. The warp engines are damaged."))
3918 prout(_(" We'll have to reduce speed to warp 4."))
3923 "Change the warp factor."
3929 proutn(_("Warp factor- "))
3934 if game.damage[DWARPEN] > 10.0:
3935 prout(_("Warp engines inoperative."))
3937 if damaged(DWARPEN) and scanner.real > 4.0:
3938 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
3939 prout(_(" but right now we can only go warp 4.\""))
3941 if scanner.real > 10.0:
3942 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
3944 if scanner.real < 1.0:
3945 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
3947 oldfac = game.warpfac
3948 game.warpfac = scanner.real
3949 if game.warpfac <= oldfac or game.warpfac <= 6.0:
3950 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
3953 if game.warpfac < 8.00:
3954 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
3956 if game.warpfac == 10.0:
3957 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
3959 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
3963 "Cope with being tossed out of quadrant by supernova or yanked by beam."
3965 # is captain on planet?
3967 if damaged(DTRANSP):
3970 prout(_("Scotty rushes to the transporter controls."))
3972 prout(_("But with the shields up it's hopeless."))
3974 prouts(_("His desperate attempt to rescue you . . ."))
3979 prout(_("SUCCEEDS!"))
3982 proutn(_("The crystals mined were "))
3990 # Check to see if captain in shuttle craft
3995 # Inform captain of attempt to reach safety
3999 prouts(_("***RED ALERT! RED ALERT!"))
4001 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4002 prouts(_(" a supernova."))
4004 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4005 prout(_("safely out of quadrant."))
4006 if not damaged(DRADIO):
4007 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4008 # Try to use warp engines
4009 if damaged(DWARPEN):
4011 prout(_("Warp engines damaged."))
4014 game.warpfac = randreal(6.0, 8.0)
4015 prout(_("Warp factor set to %d") % int(game.warpfac))
4016 power = 0.75*game.energy
4017 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4018 dist = max(dist, randreal(math.sqrt(2)))
4019 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4020 game.optime = bugout.time(game.warpfac)
4022 game.inorbit = False
4023 warp(bugout, involuntary=True)
4025 # This is bad news, we didn't leave quadrant.
4029 prout(_("Insufficient energy to leave quadrant."))
4032 # Repeat if another snova
4033 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4035 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4036 finish(FWON) # Snova killed remaining enemy.
4039 "Let's do the time warp again."
4040 prout(_("***TIME WARP ENTERED."))
4041 if game.state.snap and withprob(0.5):
4043 prout(_("You are traveling backwards in time %d stardates.") %
4044 int(game.state.date-game.snapsht.date))
4045 game.state = game.snapsht
4046 game.state.snap = False
4047 if len(game.state.kcmdr):
4048 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4049 schedule(FBATTAK, expran(0.3*game.intime))
4050 schedule(FSNOVA, expran(0.5*game.intime))
4051 # next snapshot will be sooner
4052 schedule(FSNAP, expran(0.25*game.state.remtime))
4054 if game.state.nscrem:
4055 schedule(FSCMOVE, 0.2777)
4059 game.battle.invalidate()
4060 # Make sure Galileo is consistant -- Snapshot may have been taken
4061 # when on planet, which would give us two Galileos!
4063 for l in range(game.inplan):
4064 if game.state.planets[l].known == "shuttle_down":
4066 if game.iscraft == "onship" and game.ship==IHE:
4067 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4068 game.iscraft = "offship"
4069 # Likewise, if in the original time the Galileo was abandoned, but
4070 # was on ship earlier, it would have vanished -- let's restore it.
4071 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4072 prout(_("Checkov- \"Security reports the Galileo has reappeared in the dock!\""))
4073 game.iscraft = "onship"
4074 # There used to be code to do the actual reconstrction here,
4075 # but the starchart is now part of the snapshotted galaxy state.
4076 prout(_("Spock has reconstructed a correct star chart from memory"))
4078 # Go forward in time
4079 game.optime = -0.5*game.intime*math.log(randreal())
4080 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4081 # cheat to make sure no tractor beams occur during time warp
4082 postpone(FTBEAM, game.optime)
4083 game.damage[DRADIO] += game.optime
4085 events() # Stas Sergeev added this -- do pending events
4088 "Launch deep-space probe."
4089 # New code to launch a deep space probe
4090 if game.nprobes == 0:
4093 if game.ship == IHE:
4094 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4096 prout(_("Ye Faerie Queene has no deep space probes."))
4101 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4103 if is_scheduled(FDSPROB):
4106 if damaged(DRADIO) and game.condition != "docked":
4107 prout(_("Spock- \"Records show the previous probe has not yet"))
4108 prout(_(" reached its destination.\""))
4110 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4112 key = scanner.next()
4114 if game.nprobes == 1:
4115 prout(_("1 probe left."))
4117 prout(_("%d probes left") % game.nprobes)
4118 proutn(_("Are you sure you want to fire a probe? "))
4121 game.isarmed = False
4122 if key == "IHALPHA" and scanner.token == "armed":
4124 key = scanner.next()
4125 elif key == "IHEOL":
4126 proutn(_("Arm NOVAMAX warhead? "))
4128 elif key == "IHREAL": # first element of course
4129 scanner.push(scanner.token)
4131 game.probe = getcourse(isprobe=True)
4135 schedule(FDSPROB, 0.01) # Time to move one sector
4136 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4141 "Yell for help from nearest starbase."
4142 # There's more than one way to move in this game!
4144 # Test for conditions which prevent calling for help
4145 if game.condition == "docked":
4146 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4149 prout(_("Subspace radio damaged."))
4151 if not game.state.baseq:
4152 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4155 prout(_("You must be aboard the %s.") % crmshp())
4157 # OK -- call for help from nearest starbase
4160 # There's one in this quadrant
4161 ddist = (game.base - game.sector).distance()
4164 for ibq in game.state.baseq:
4165 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4168 # Since starbase not in quadrant, set up new quadrant
4171 # dematerialize starship
4172 game.quad[game.sector.i][game.sector.j]=IHDOT
4173 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4174 % (game.quadrant, crmshp()))
4175 game.sector.invalidate()
4176 for m in range(1, 5+1):
4177 w = game.base.scatter()
4178 if w.valid_sector() and game.quad[w.i][w.j]==IHDOT:
4179 # found one -- finish up
4182 if not game.sector.is_valid():
4183 prout(_("You have been lost in space..."))
4184 finish(FMATERIALIZE)
4186 # Give starbase three chances to rematerialize starship
4187 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4188 for m in range(1, 3+1):
4189 if m == 1: proutn(_("1st"))
4190 elif m == 2: proutn(_("2nd"))
4191 elif m == 3: proutn(_("3rd"))
4192 proutn(_(" attempt to re-materialize ") + crmshp())
4193 game.quad[ix][iy]=(IHMATER0,IHMATER1,IHMATER2)[m-1]
4196 if randreal() > probf:
4199 curses.delay_output(500)
4202 game.quad[ix][iy]=IHQUEST
4205 setwnd(message_window)
4206 finish(FMATERIALIZE)
4208 game.quad[ix][iy]=game.ship
4210 prout(_("succeeds."))
4214 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4219 if game.condition=="docked":
4221 prout(_("You cannot abandon Ye Faerie Queene."))
4224 # Must take shuttle craft to exit
4225 if game.damage[DSHUTTL]==-1:
4226 prout(_("Ye Faerie Queene has no shuttle craft."))
4228 if game.damage[DSHUTTL]<0:
4229 prout(_("Shuttle craft now serving Big Macs."))
4231 if game.damage[DSHUTTL]>0:
4232 prout(_("Shuttle craft damaged."))
4235 prout(_("You must be aboard the ship."))
4237 if game.iscraft != "onship":
4238 prout(_("Shuttle craft not currently available."))
4240 # Emit abandon ship messages
4242 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4244 prouts(_("***ALL HANDS ABANDON SHIP!"))
4246 prout(_("Captain and crew escape in shuttle craft."))
4247 if not game.state.baseq:
4248 # Oops! no place to go...
4251 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4253 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4254 prout(_("Remainder of ship's complement beam down"))
4255 prout(_("to nearest habitable planet."))
4256 elif q.planet != None and not damaged(DTRANSP):
4257 prout(_("Remainder of ship's complement beam down to %s.") %
4260 prout(_("Entire crew of %d left to die in outer space.") %
4262 game.casual += game.state.crew
4263 game.abandoned += game.state.crew
4264 # If at least one base left, give 'em the Faerie Queene
4266 game.icrystl = False # crystals are lost
4267 game.nprobes = 0 # No probes
4268 prout(_("You are captured by Klingons and released to"))
4269 prout(_("the Federation in a prisoner-of-war exchange."))
4270 nb = randrange(len(game.state.baseq))
4271 # Set up quadrant and position FQ adjacient to base
4272 if not game.quadrant == game.state.baseq[nb]:
4273 game.quadrant = game.state.baseq[nb]
4274 game.sector.i = game.sector.j = 5
4277 # position next to base by trial and error
4278 game.quad[game.sector.i][game.sector.j] = IHDOT
4279 for l in range(QUADSIZE):
4280 game.sector = game.base.scatter()
4281 if game.sector.valid_sector() and \
4282 game.quad[game.sector.i][game.sector.j] == IHDOT:
4285 break # found a spot
4286 game.sector.i=QUADSIZE/2
4287 game.sector.j=QUADSIZE/2
4289 # Get new commission
4290 game.quad[game.sector.i][game.sector.j] = game.ship = IHF
4291 game.state.crew = FULLCREW
4292 prout(_("Starfleet puts you in command of another ship,"))
4293 prout(_("the Faerie Queene, which is antiquated but,"))
4294 prout(_("still useable."))
4296 prout(_("The dilithium crystals have been moved."))
4298 game.iscraft = "offship" # Galileo disappears
4300 game.condition="docked"
4301 for l in range(NDEVICES):
4302 game.damage[l] = 0.0
4303 game.damage[DSHUTTL] = -1
4304 game.energy = game.inenrg = 3000.0
4305 game.shield = game.inshld = 1250.0
4306 game.torps = game.intorps = 6
4307 game.lsupres=game.inlsr=3.0
4312 # Code from planets.c begins here.
4315 "Abort a lengthy operation if an event interrupts it."
4318 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4323 "Report on (uninhabited) planets in the galaxy."
4327 prout(_("Spock- \"Planet report follows, Captain.\""))
4329 for i in range(game.inplan):
4330 if game.state.planets[i].pclass == "destroyed":
4332 if (game.state.planets[i].known != "unknown" \
4333 and not game.state.planets[i].inhabited) \
4336 if idebug and game.state.planets[i].known=="unknown":
4337 proutn("(Unknown) ")
4338 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4339 proutn(_(" class "))
4340 proutn(game.state.planets[i].pclass)
4342 if game.state.planets[i].crystals != present:
4344 prout(_("dilithium crystals present."))
4345 if game.state.planets[i].known=="shuttle_down":
4346 prout(_(" Shuttle Craft Galileo on surface."))
4348 prout(_("No information available."))
4351 "Enter standard orbit."
4355 prout(_("Already in standard orbit."))
4357 if damaged(DWARPEN) and damaged(DIMPULS):
4358 prout(_("Both warp and impulse engines damaged."))
4360 if not game.plnet.is_valid():
4361 prout("There is no planet in this sector.")
4363 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4364 prout(crmshp() + _(" not adjacent to planet."))
4367 game.optime = randreal(0.02, 0.05)
4368 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4372 game.height = randreal(1400, 8600)
4373 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4378 "Examine planets in this quadrant."
4379 if damaged(DSRSENS):
4380 if game.options & OPTION_TTY:
4381 prout(_("Short range sensors damaged."))
4383 if game.iplnet == None:
4384 if game.options & OPTION_TTY:
4385 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4387 if game.iplnet.known == "unknown":
4388 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4390 prout(_(" Planet at Sector %s is of class %s.") %
4391 (game.plnet, game.iplnet.pclass))
4392 if game.iplnet.known=="shuttle_down":
4393 prout(_(" Sensors show Galileo still on surface."))
4394 proutn(_(" Readings indicate"))
4395 if game.iplnet.crystals != "present":
4397 prout(_(" dilithium crystals present.\""))
4398 if game.iplnet.known == "unknown":
4399 game.iplnet.known = "known"
4400 elif game.iplnet.inhabited:
4401 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4402 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4405 "Use the transporter."
4409 if damaged(DTRANSP):
4410 prout(_("Transporter damaged."))
4411 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4413 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4417 if not game.inorbit:
4418 prout(crmshp() + _(" not in standard orbit."))
4421 prout(_("Impossible to transport through shields."))
4423 if game.iplnet.known=="unknown":
4424 prout(_("Spock- \"Captain, we have no information on this planet"))
4425 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4426 prout(_(" you may not go down.\""))
4428 if not game.landed and game.iplnet.crystals=="absent":
4429 prout(_("Spock- \"Captain, I fail to see the logic in"))
4430 prout(_(" exploring a planet with no dilithium crystals."))
4431 proutn(_(" Are you sure this is wise?\" "))
4435 if not (game.options & OPTION_PLAIN):
4436 nrgneed = 50 * game.skill + game.height / 100.0
4437 if nrgneed > game.energy:
4438 prout(_("Engineering to bridge--"))
4439 prout(_(" Captain, we don't have enough energy for transportation."))
4441 if not game.landed and nrgneed * 2 > game.energy:
4442 prout(_("Engineering to bridge--"))
4443 prout(_(" Captain, we have enough energy only to transport you down to"))
4444 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4445 if game.iplnet.known == "shuttle_down":
4446 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4447 proutn(_(" Are you sure this is wise?\" "))
4452 # Coming from planet
4453 if game.iplnet.known=="shuttle_down":
4454 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4458 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4459 prout(_("Landing party assembled, ready to beam up."))
4461 prout(_("Kirk whips out communicator..."))
4462 prouts(_("BEEP BEEP BEEP"))
4464 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4467 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4469 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4471 prout(_("Kirk- \"Energize.\""))
4474 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4477 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4479 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4482 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4483 game.landed = not game.landed
4484 game.energy -= nrgneed
4486 prout(_("Transport complete."))
4487 if game.landed and game.iplnet.known=="shuttle_down":
4488 prout(_("The shuttle craft Galileo is here!"))
4489 if not game.landed and game.imine:
4496 "Strip-mine a world for dilithium."
4500 prout(_("Mining party not on planet."))
4502 if game.iplnet.crystals == "mined":
4503 prout(_("This planet has already been strip-mined for dilithium."))
4505 elif game.iplnet.crystals == "absent":
4506 prout(_("No dilithium crystals on this planet."))
4509 prout(_("You've already mined enough crystals for this trip."))
4511 if game.icrystl and game.cryprob == 0.05:
4512 prout(_("With all those fresh crystals aboard the ") + crmshp())
4513 prout(_("there's no reason to mine more at this time."))
4515 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4518 prout(_("Mining operation complete."))
4519 game.iplnet.crystals = "mined"
4520 game.imine = game.ididit = True
4523 "Use dilithium crystals."
4527 if not game.icrystl:
4528 prout(_("No dilithium crystals available."))
4530 if game.energy >= 1000:
4531 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4532 prout(_(" except when Condition Yellow exists."))
4534 prout(_("Spock- \"Captain, I must warn you that loading"))
4535 prout(_(" raw dilithium crystals into the ship's power"))
4536 prout(_(" system may risk a severe explosion."))
4537 proutn(_(" Are you sure this is wise?\" "))
4542 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4543 prout(_(" Mr. Spock and I will try it.\""))
4545 prout(_("Spock- \"Crystals in place, Sir."))
4546 prout(_(" Ready to activate circuit.\""))
4548 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4550 if with(game.cryprob):
4551 prouts(_(" \"Activating now! - - No good! It's***"))
4553 prouts(_("***RED ALERT! RED A*L********************************"))
4556 prouts(_("****************** KA-BOOM!!!! *******************"))
4560 game.energy += randreal(5000.0, 5500.0)
4561 prouts(_(" \"Activating now! - - "))
4562 prout(_("The instruments"))
4563 prout(_(" are going crazy, but I think it's"))
4564 prout(_(" going to work!! Congratulations, Sir!\""))
4569 "Use shuttlecraft for planetary jaunt."
4572 if damaged(DSHUTTL):
4573 if game.damage[DSHUTTL] == -1.0:
4574 if game.inorbit and game.iplnet.known == "shuttle_down":
4575 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4577 prout(_("Ye Faerie Queene had no shuttle craft."))
4578 elif game.damage[DSHUTTL] > 0:
4579 prout(_("The Galileo is damaged."))
4580 else: # game.damage[DSHUTTL] < 0
4581 prout(_("Shuttle craft is now serving Big Macs."))
4583 if not game.inorbit:
4584 prout(crmshp() + _(" not in standard orbit."))
4586 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4587 prout(_("Shuttle craft not currently available."))
4589 if not game.landed and game.iplnet.known=="shuttle_down":
4590 prout(_("You will have to beam down to retrieve the shuttle craft."))
4592 if game.shldup or game.condition == "docked":
4593 prout(_("Shuttle craft cannot pass through shields."))
4595 if game.iplnet.known=="unknown":
4596 prout(_("Spock- \"Captain, we have no information on this planet"))
4597 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4598 prout(_(" you may not fly down.\""))
4600 game.optime = 3.0e-5*game.height
4601 if game.optime >= 0.8*game.state.remtime:
4602 prout(_("First Officer Spock- \"Captain, I compute that such"))
4603 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4604 int(100*game.optime/game.state.remtime))
4605 prout(_("remaining time."))
4606 proutn(_("Are you sure this is wise?\" "))
4612 if game.iscraft == "onship":
4614 if not damaged(DTRANSP):
4615 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4619 proutn(_("Shuttle crew"))
4621 proutn(_("Rescue party"))
4622 prout(_(" boards Galileo and swoops toward planet surface."))
4623 game.iscraft = "offship"
4627 game.iplnet.known="shuttle_down"
4628 prout(_("Trip complete."))
4631 # Ready to go back to ship
4632 prout(_("You and your mining party board the"))
4633 prout(_("shuttle craft for the trip back to the Enterprise."))
4635 prouts(_("The short hop begins . . ."))
4637 game.iplnet.known="known"
4643 game.iscraft = "onship"
4649 prout(_("Trip complete."))
4652 # Kirk on ship and so is Galileo
4653 prout(_("Mining party assembles in the hangar deck,"))
4654 prout(_("ready to board the shuttle craft \"Galileo\"."))
4656 prouts(_("The hangar doors open; the trip begins."))
4659 game.iscraft = "offship"
4662 game.iplnet.known = "shuttle_down"
4665 prout(_("Trip complete."))
4669 "Use the big zapper."
4673 if game.ship != IHE:
4674 prout(_("Ye Faerie Queene has no death ray."))
4676 if len(game.enemies)==0:
4677 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4680 prout(_("Death Ray is damaged."))
4682 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4683 prout(_(" is highly unpredictible. Considering the alternatives,"))
4684 proutn(_(" are you sure this is wise?\" "))
4687 prout(_("Spock- \"Acknowledged.\""))
4690 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4692 prout(_("Crew scrambles in emergency preparation."))
4693 prout(_("Spock and Scotty ready the death ray and"))
4694 prout(_("prepare to channel all ship's power to the device."))
4696 prout(_("Spock- \"Preparations complete, sir.\""))
4697 prout(_("Kirk- \"Engage!\""))
4699 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4702 if game.options & OPTION_PLAIN:
4706 prouts(_("Sulu- \"Captain! It's working!\""))
4708 while len(game.enemies) > 0:
4709 deadkl(game.enemies[1].kloc, game.quad[game.enemies[1].kloc.i][game.enemies[1].kloc.j],game.enemies[1].kloc)
4710 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4711 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4713 if (game.options & OPTION_PLAIN) == 0:
4714 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4716 prout(_(" is still operational.\""))
4718 prout(_(" has been rendered nonfunctional.\""))
4719 game.damage[DDRAY] = 39.95
4721 r = randreal() # Pick failure method
4723 prouts(_("Sulu- \"Captain! It's working!\""))
4725 prouts(_("***RED ALERT! RED ALERT!"))
4727 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4729 prouts(_("***RED ALERT! RED A*L********************************"))
4732 prouts(_("****************** KA-BOOM!!!! *******************"))
4737 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4739 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4741 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4742 prout(_(" have apparently been transformed into strange mutations."))
4743 prout(_(" Vulcans do not seem to be affected."))
4745 prout(_("Kirk- \"Raauch! Raauch!\""))
4750 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4752 proutn(_("Spock- \"I believe the word is"))
4753 prouts(_(" *ASTONISHING*"))
4754 prout(_(" Mr. Sulu."))
4755 for i in range(QUADSIZE):
4756 for j in range(QUADSIZE):
4757 if game.quad[i][j] == IHDOT:
4758 game.quad[i][j] = IHQUEST
4759 prout(_(" Captain, our quadrant is now infested with"))
4760 prouts(_(" - - - - - - *THINGS*."))
4762 prout(_(" I have no logical explanation.\""))
4764 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4766 prout(_("Scotty- \"There are so many tribbles down here"))
4767 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4771 # Code from reports.c begins here
4773 def attackreport(curt):
4774 "eport status of bases under attack."
4776 if is_scheduled(FCDBAS):
4777 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4778 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4779 elif game.isatb == 1:
4780 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4781 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4783 prout(_("No Starbase is currently under attack."))
4785 if is_scheduled(FCDBAS):
4786 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4788 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4792 # report on general game status
4794 s1 = "" and game.thawed and _("thawed ")
4795 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4796 s3 = (None, _("novice"). _("fair"),
4797 _("good"), _("expert"), _("emeritus"))[game.skill]
4798 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4799 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4800 prout(_("No plaque is allowed."))
4802 prout(_("This is tournament game %d.") % game.tourn)
4803 prout(_("Your secret password is \"%s\"") % game.passwd)
4804 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4805 (game.inkling + game.incom + game.inscom)))
4806 if game.incom - len(game.state.kcmdr):
4807 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4808 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4809 prout(_(", but no Commanders."))
4812 if game.skill > SKILL_FAIR:
4813 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4814 if len(game.state.baseq) != game.inbase:
4816 if game.inbase-len(game.state.baseq)==1:
4817 proutn(_("has been 1 base"))
4819 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4820 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4822 prout(_("There are %d bases.") % game.inbase)
4823 if communicating() or game.iseenit:
4824 # Don't report this if not seen and
4825 # either the radio is dead or not at base!
4829 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4831 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4832 if game.ship == IHE:
4833 proutn(_("You have "))
4835 proutn("%d" % (game.nprobes))
4838 proutn(_(" deep space probe"))
4842 if communicating() and is_scheduled(FDSPROB):
4844 proutn(_("An armed deep space probe is in "))
4846 proutn(_("A deep space probe is in "))
4847 prout("Quadrant %s." % game.probec)
4849 if game.cryprob <= .05:
4850 prout(_("Dilithium crystals aboard ship... not yet used."))
4854 while game.cryprob > ai:
4857 prout(_("Dilithium crystals have been used %d time%s.") % \
4858 (i, (_("s"), "")[i==1]))
4862 "Long-range sensor scan."
4863 if damaged(DLRSENS):
4864 # Now allow base's sensors if docked
4865 if game.condition != "docked":
4867 prout(_("LONG-RANGE SENSORS DAMAGED."))
4870 prout(_("Starbase's long-range scan"))
4872 prout(_("Long-range scan"))
4873 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4876 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4877 if not coord(x, y).valid_quadrant():
4881 if not damaged(DRADIO):
4882 game.state.galaxy[x][y].charted = True
4883 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4884 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4885 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4886 if not silent and game.state.galaxy[x][y].supernova:
4889 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4896 for i in range(NDEVICES):
4899 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4900 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4902 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4903 game.damage[i]+0.05,
4904 game.docfac*game.damage[i]+0.005))
4906 prout(_("All devices functional."))
4909 "Update the chart in the Enterprise's computer from galaxy data."
4910 game.lastchart = game.state.date
4911 for i in range(GALSIZE):
4912 for j in range(GALSIZE):
4913 if game.state.galaxy[i][j].charted:
4914 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
4915 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
4916 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
4919 "Display the star chart."
4921 if (game.options & OPTION_AUTOSCAN):
4923 if not damaged(DRADIO):
4925 if game.lastchart < game.state.date and game.condition == "docked":
4926 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
4928 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
4929 if game.state.date > game.lastchart:
4930 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
4931 prout(" 1 2 3 4 5 6 7 8")
4932 for i in range(GALSIZE):
4933 proutn("%d |" % (i+1))
4934 for j in range(GALSIZE):
4935 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4939 if game.state.galaxy[i][j].supernova:
4941 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
4943 elif game.state.galaxy[i][j].charted:
4944 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
4948 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4956 def sectscan(goodScan, i, j):
4957 "Light up an individual dot in a sector."
4958 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
4959 if (game.quad[i][j]==IHMATER0) or (game.quad[i][j]==IHMATER1) or (game.quad[i][j]==IHMATER2) or (game.quad[i][j]==IHE) or (game.quad[i][j]==IHF):
4960 #if game.condition == "red": textcolor("red")
4961 #elif game.condition == "green": textcolor("green")
4962 #elif game.condition == "yellow": textcolor("yellow")
4963 #elif game.condition == "docked": textcolor("cyan")
4964 #elif game.condition == "dead": textcolor("brown")
4965 if game.quad[i][j] != game.ship:
4967 proutn("%c " % game.quad[i][j])
4973 "Emit status report lines"
4974 if not req or req == 1:
4975 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
4976 % (game.state.date, game.state.remtime))
4977 if not req or req == 2:
4978 if game.condition != "docked":
4980 prstat(_("Condition"), _("%s, %i DAMAGES") % \
4981 (game.condition.upper(), sum(map(lambda x: x > 0, game.damage))))
4982 if not req or req == 3:
4983 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
4984 if not req or req == 4:
4985 if damaged(DLIFSUP):
4986 if game.condition == "docked":
4987 s = _("DAMAGED, Base provides")
4989 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
4992 prstat(_("Life Support"), s)
4993 if not req or req == 5:
4994 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
4995 if not req or req == 6:
4997 if game.icrystl and (game.options & OPTION_SHOWME):
4998 extra = _(" (have crystals)")
4999 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5000 if not req or req == 7:
5001 prstat(_("Torpedoes"), "%d" % (game.torps))
5002 if not req or req == 8:
5003 if damaged(DSHIELD):
5009 data = _(" %d%% %.1f units") \
5010 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5011 prstat(_("Shields"), s+data)
5012 if not req or req == 9:
5013 prstat(_("Klingons Left"), "%d" \
5014 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5015 if not req or req == 10:
5016 if game.options & OPTION_WORLDS:
5017 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5018 if plnet and plnet.inhabited:
5019 prstat(_("Major system"), plnet.name)
5021 prout(_("Sector is uninhabited"))
5022 elif not req or req == 11:
5023 attackreport(not req)
5026 "Request specified status data, a historical relic from slow TTYs."
5027 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5028 while scanner.next() == "IHEOL":
5029 proutn(_("Information desired? "))
5031 if scanner.token in requests:
5032 status(requests.index(scanner.token))
5034 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5035 prout((" date, condition, position, lsupport, warpfactor,"))
5036 prout((" energy, torpedoes, shields, klingons, system, time."))
5041 if damaged(DSRSENS):
5042 # Allow base's sensors if docked
5043 if game.condition != "docked":
5044 prout(_(" S.R. SENSORS DAMAGED!"))
5047 prout(_(" [Using Base's sensors]"))
5049 prout(_(" Short-range scan"))
5050 if goodScan and not damaged(DRADIO):
5051 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5052 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5053 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5054 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5055 prout(" 1 2 3 4 5 6 7 8 9 10")
5056 if game.condition != "docked":
5058 for i in range(QUADSIZE):
5059 proutn("%2d " % (i+1))
5060 for j in range(QUADSIZE):
5061 sectscan(goodScan, i, j)
5065 "Use computer to get estimated time of arrival for a warp jump."
5066 w1 = coord(); w2 = coord()
5068 if damaged(DCOMPTR):
5069 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5072 if scanner.next() != "IHREAL":
5075 proutn(_("Destination quadrant and/or sector? "))
5076 if scanner.next()!="IHREAL":
5079 w1.j = int(scanner.real-0.5)
5080 if scanner.next() != "IHREAL":
5083 w1.i = int(scanner.real-0.5)
5084 if scanner.next() == "IHREAL":
5085 w2.j = int(scanner.real-0.5)
5086 if scanner.next() != "IHREAL":
5089 w2.i = int(scanner.real-0.5)
5091 if game.quadrant.j>w1.i:
5095 if game.quadrant.i>w1.j:
5099 if not w1.valid_quadrant() or not w2.valid_sector():
5102 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5103 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5106 prout(_("Answer \"no\" if you don't know the value:"))
5109 proutn(_("Time or arrival date? "))
5110 if scanner.next()=="IHREAL":
5111 ttime = scanner.real
5112 if ttime > game.state.date:
5113 ttime -= game.state.date # Actually a star date
5114 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5115 if ttime <= 1e-10 or twarp > 10:
5116 prout(_("We'll never make it, sir."))
5123 proutn(_("Warp factor? "))
5124 if scanner.next()== "IHREAL":
5126 twarp = scanner.real
5127 if twarp<1.0 or twarp > 10.0:
5131 prout(_("Captain, certainly you can give me one of these."))
5134 ttime = (10.0*dist)/twarp**2
5135 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5136 if tpower >= game.energy:
5137 prout(_("Insufficient energy, sir."))
5138 if not game.shldup or tpower > game.energy*2.0:
5141 proutn(_("New warp factor to try? "))
5142 if scanner.next() == "IHREAL":
5144 twarp = scanner.real
5145 if twarp<1.0 or twarp > 10.0:
5153 prout(_("But if you lower your shields,"))
5154 proutn(_("remaining"))
5157 proutn(_("Remaining"))
5158 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5160 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5162 prout(_("Any warp speed is adequate."))
5164 prout(_("Minimum warp needed is %.2f,") % (twarp))
5165 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5166 if game.state.remtime < ttime:
5167 prout(_("Unfortunately, the Federation will be destroyed by then."))
5169 prout(_("You'll be taking risks at that speed, Captain"))
5170 if (game.isatb==1 and game.state.kscmdr == w1 and \
5171 scheduled(FSCDBAS)< ttime+game.state.date) or \
5172 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5173 prout(_("The starbase there will be destroyed by then."))
5174 proutn(_("New warp factor to try? "))
5175 if scanner.next() == "IHREAL":
5177 twarp = scanner.real
5178 if twarp<1.0 or twarp > 10.0:
5186 # Code from setup.c begins here
5189 "Issue a historically correct banner."
5191 prout(_("-SUPER- STAR TREK"))
5193 # From the FORTRAN original
5194 # prout(_("Latest update-21 Sept 78"))
5200 scanner.push("emsave.trk")
5201 key = scanner.next()
5203 proutn(_("File name: "))
5204 key = scanner.next()
5205 if key != "IHALPHA":
5209 if '.' not in scanner.token:
5210 scanner.token += ".trk"
5212 fp = open(scanner.token, "wb")
5214 prout(_("Can't freeze game as file %s") % scanner.token)
5216 cPickle.dump(game, fp)
5220 "Retrieve saved game."
5221 game.passwd[0] = '\0'
5222 key = scanner.next()
5224 proutn(_("File name: "))
5225 key = scanner.next()
5226 if key != "IHALPHA":
5230 if '.' not in scanner.token:
5231 scanner.token += ".trk"
5233 fp = open(scanner.token, "rb")
5235 prout(_("Can't thaw game in %s") % scanner.token)
5237 game = cPickle.load(fp)
5241 # I used <http://www.memory-alpha.org> to find planets
5242 # with references in ST:TOS. Eath and the Alpha Centauri
5243 # Colony have been omitted.
5245 # Some planets marked Class G and P here will be displayed as class M
5246 # because of the way planets are generated. This is a known bug.
5249 _("Andoria (Fesoan)"), # several episodes
5250 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5251 _("Vulcan (T'Khasi)"), # many episodes
5252 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5253 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5254 _("Ardana"), # TOS: "The Cloud Minders"
5255 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5256 _("Gideon"), # TOS: "The Mark of Gideon"
5257 _("Aldebaran III"), # TOS: "The Deadly Years"
5258 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5259 _("Altair IV"), # TOS: "Amok Time
5260 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5261 _("Benecia"), # TOS: "The Conscience of the King"
5262 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5263 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5264 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5265 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5266 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5267 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5268 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5269 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5270 _("Ingraham B"), # TOS: "Operation: Annihilate"
5271 _("Janus IV"), # TOS: "The Devil in the Dark"
5272 _("Makus III"), # TOS: "The Galileo Seven"
5273 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5274 _("Omega IV"), # TOS: "The Omega Glory"
5275 _("Regulus V"), # TOS: "Amok Time
5276 _("Deneva"), # TOS: "Operation -- Annihilate!"
5277 # Worlds from BSD Trek
5278 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5279 _("Beta III"), # TOS: "The Return of the Archons"
5280 _("Triacus"), # TOS: "And the Children Shall Lead",
5281 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5283 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5284 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5285 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5286 # _("Izar"), # TOS: "Whom Gods Destroy"
5287 # _("Tiburon"), # TOS: "The Way to Eden"
5288 # _("Merak II"), # TOS: "The Cloud Minders"
5289 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5290 # _("Iotia"), # TOS: "A Piece of the Action"
5294 _("S. R. Sensors"), \
5295 _("L. R. Sensors"), \
5297 _("Photon Tubes"), \
5298 _("Life Support"), \
5299 _("Warp Engines"), \
5300 _("Impulse Engines"), \
5302 _("Subspace Radio"), \
5303 _("Shuttle Craft"), \
5305 _("Navigation System"), \
5307 _("Shield Control"), \
5313 "Prepare to play, set up cosmos."
5315 # Decide how many of everything
5317 return # frozen game
5318 # Prepare the Enterprise
5319 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5321 game.state.crew = FULLCREW
5322 game.energy = game.inenrg = 5000.0
5323 game.shield = game.inshld = 2500.0
5326 game.quadrant = randplace(GALSIZE)
5327 game.sector = randplace(QUADSIZE)
5328 game.torps = game.intorps = 10
5329 game.nprobes = randrange(2, 5)
5331 for i in range(NDEVICES):
5332 game.damage[i] = 0.0
5333 # Set up assorted game parameters
5334 game.battle = coord()
5335 game.state.date = game.indate = 100.0 * randreal(20, 51)
5336 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5337 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5338 game.isatb = game.state.nplankl = 0
5339 game.state.starkl = game.state.basekl = 0
5340 game.iscraft = "onship"
5344 # Starchart is functional but we've never seen it
5345 game.lastchart = FOREVER
5346 # Put stars in the galaxy
5348 for i in range(GALSIZE):
5349 for j in range(GALSIZE):
5350 k = randrange(1, QUADSIZE**2/10+1)
5352 game.state.galaxy[i][j].stars = k
5353 # Locate star bases in galaxy
5354 for i in range(game.inbase):
5357 w = randplace(GALSIZE)
5358 if not game.state.galaxy[w.i][w.j].starbase:
5361 # C version: for (j = i-1; j > 0; j--)
5362 # so it did them in the opposite order.
5363 for j in range(1, i):
5364 # Improved placement algorithm to spread out bases
5365 distq = (w - game.state.baseq[j]).distance()
5366 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5369 prout("=== Abandoning base #%d at %s" % (i, w))
5371 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5373 prout("=== Saving base #%d, close to #%d" % (i, j))
5376 game.state.baseq.append(w)
5377 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5378 # Position ordinary Klingon Battle Cruisers
5380 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5381 if klumper > MAXKLQUAD:
5385 klump = (1.0 - r*r)*klumper
5390 w = randplace(GALSIZE)
5391 if not game.state.galaxy[w.i][w.j].supernova and \
5392 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5394 game.state.galaxy[w.i][w.j].klingons += int(klump)
5397 # Position Klingon Commander Ships
5398 for i in range(game.incom):
5400 w = randplace(GALSIZE)
5401 if not welcoming(w) or w in game.state.kcmdr:
5403 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5405 game.state.galaxy[w.i][w.j].klingons += 1
5406 game.state.kcmdr.append(w)
5407 # Locate planets in galaxy
5408 for i in range(game.inplan):
5410 w = randplace(GALSIZE)
5411 if game.state.galaxy[w.i][w.j].planet == None:
5415 new.crystals = "absent"
5416 if (game.options & OPTION_WORLDS) and i < NINHAB:
5417 new.pclass = "M" # All inhabited planets are class M
5418 new.crystals = "absent"
5420 new.name = systnames[i]
5421 new.inhabited = True
5423 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5425 new.crystals = "present"
5426 new.known = "unknown"
5427 new.inhabited = False
5428 game.state.galaxy[w.i][w.j].planet = new
5429 game.state.planets.append(new)
5431 for i in range(game.state.nromrem):
5432 w = randplace(GALSIZE)
5433 game.state.galaxy[w.i][w.j].romulans += 1
5434 # Place the Super-Commander if needed
5435 if game.state.nscrem > 0:
5437 w = randplace(GALSIZE)
5440 game.state.kscmdr = w
5441 game.state.galaxy[w.i][w.j].klingons += 1
5442 # Initialize times for extraneous events
5443 schedule(FSNOVA, expran(0.5 * game.intime))
5444 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5445 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5446 schedule(FBATTAK, expran(0.3*game.intime))
5448 if game.state.nscrem:
5449 schedule(FSCMOVE, 0.2777)
5454 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5455 schedule(FDISTR, expran(1.0 + game.intime))
5460 # Place thing (in tournament game, we don't want one!)
5461 # New in SST2K: never place the Thing near a starbase.
5462 # This makes sense and avoids a special case in the old code.
5464 if game.tourn is None:
5466 thing = randplace(GALSIZE)
5467 if thing not in game.state.baseq:
5470 game.state.snap = False
5471 if game.skill == SKILL_NOVICE:
5472 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5473 prout(_("a deadly Klingon invasion force. As captain of the United"))
5474 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5475 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5476 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5477 prout(_("your mission. As you proceed you may be given more time."))
5479 prout(_("You will have %d supporting starbases.") % (game.inbase))
5480 proutn(_("Starbase locations- "))
5482 prout(_("Stardate %d.") % int(game.state.date))
5484 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5485 prout(_("An unknown number of Romulans."))
5486 if game.state.nscrem:
5487 prout(_("And one (GULP) Super-Commander."))
5488 prout(_("%d stardates.") % int(game.intime))
5489 proutn(_("%d starbases in ") % game.inbase)
5490 for i in range(game.inbase):
5491 proutn(`game.state.baseq[i]`)
5494 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5495 proutn(_(" Sector %s") % game.sector)
5497 prout(_("Good Luck!"))
5498 if game.state.nscrem:
5499 prout(_(" YOU'LL NEED IT."))
5502 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5504 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5505 attack(torps_ok=False)
5508 "Choose your game type."
5513 game.skill = SKILL_NONE
5515 if not scanner.inqueue: # Can start with command line options
5516 proutn(_("Would you like a regular, tournament, or saved game? "))
5518 if scanner.sees("tournament"):
5519 while scanner.next() == "IHEOL":
5520 proutn(_("Type in tournament number-"))
5521 if scanner.real == 0:
5523 continue # We don't want a blank entry
5524 game.tourn = int(round(scanner.real))
5525 random.seed(scanner.real)
5527 logfp.write("# random.seed(%d)\n" % scanner.real)
5529 if scanner.sees("saved") or scanner.sees("frozen"):
5533 if game.passwd == None:
5535 if not game.alldone:
5536 game.thawed = True # No plaque if not finished
5540 if scanner.sees("regular"):
5542 proutn(_("What is \"%s\"?") % scanner.token)
5544 while game.length==0 or game.skill==SKILL_NONE:
5545 if scanner.next() == "IHALPHA":
5546 if scanner.sees("short"):
5548 elif scanner.sees("medium"):
5550 elif scanner.sees("long"):
5552 elif scanner.sees("novice"):
5553 game.skill = SKILL_NOVICE
5554 elif scanner.sees("fair"):
5555 game.skill = SKILL_FAIR
5556 elif scanner.sees("good"):
5557 game.skill = SKILL_GOOD
5558 elif scanner.sees("expert"):
5559 game.skill = SKILL_EXPERT
5560 elif scanner.sees("emeritus"):
5561 game.skill = SKILL_EMERITUS
5563 proutn(_("What is \""))
5564 proutn(scanner.token)
5569 proutn(_("Would you like a Short, Medium, or Long game? "))
5570 elif game.skill == SKILL_NONE:
5571 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5572 # Choose game options -- added by ESR for SST2K
5573 if scanner.next() != "IHALPHA":
5575 proutn(_("Choose your game style (or just press enter): "))
5577 if scanner.sees("plain"):
5578 # Approximates the UT FORTRAN version.
5579 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5580 game.options |= OPTION_PLAIN
5581 elif scanner.sees("almy"):
5582 # Approximates Tom Almy's version.
5583 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5584 game.options |= OPTION_ALMY
5585 elif scanner.sees("fancy") or scanner.sees("\n"):
5587 elif len(scanner.token):
5588 proutn(_("What is \"%s\"?") % scanner.token)
5590 if game.passwd == "debug":
5592 prout("=== Debug mode enabled.")
5593 # Use parameters to generate initial values of things
5594 game.damfac = 0.5 * game.skill
5595 game.inbase = randrange(BASEMIN, BASEMAX+1)
5597 if game.options & OPTION_PLANETS:
5598 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5599 if game.options & OPTION_WORLDS:
5600 game.inplan += int(NINHAB)
5601 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5602 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5603 game.state.remtime = 7.0 * game.length
5604 game.intime = game.state.remtime
5605 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5606 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5607 game.state.remres = (game.inkling+4*game.incom)*game.intime
5608 game.inresor = game.state.remres
5609 if game.inkling > 50:
5610 game.state.inbase += 1
5613 def dropin(iquad=None):
5614 "Drop a feature on a random dot in the current quadrant."
5616 w = randplace(QUADSIZE)
5617 if game.quad[w.i][w.j] == IHDOT:
5619 if iquad is not None:
5620 game.quad[w.i][w.j] = iquad
5624 "Update our alert status."
5625 game.condition = "green"
5626 if game.energy < 1000.0:
5627 game.condition = "yellow"
5628 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5629 game.condition = "red"
5631 game.condition="dead"
5634 "Drop new Klingon into current quadrant."
5635 return enemy(IHK, loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5638 "Set up a new state of quadrant, for when we enter or re-enter it."
5641 game.neutz = game.inorbit = game.landed = False
5642 game.ientesc = game.iseenit = False
5643 # Create a blank quadrant
5644 game.quad = fill2d(QUADSIZE, lambda i, j: IHDOT)
5646 # Attempt to escape Super-commander, so tbeam back!
5649 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5650 # cope with supernova
5653 game.klhere = q.klingons
5654 game.irhere = q.romulans
5656 game.quad[game.sector.i][game.sector.j] = game.ship
5659 # Position ordinary Klingons
5660 for i in range(game.klhere):
5662 # If we need a commander, promote a Klingon
5663 for cmdr in game.state.kcmdr:
5664 if cmdr == game.quadrant:
5665 e = game.enemies[game.klhere-1]
5666 game.quad[e.kloc.i][e.kloc.j] = IHC
5667 e.kpower = randreal(950,1350) + 50.0*game.skill
5669 # If we need a super-commander, promote a Klingon
5670 if game.quadrant == game.state.kscmdr:
5672 game.quad[e.kloc.i][e.kloc.j] = IHS
5673 e.kpower = randreal(1175.0, 1575.0) + 125.0*game.skill
5674 game.iscate = (game.state.remkl > 1)
5675 # Put in Romulans if needed
5676 for i in range(q.romulans):
5677 enemy(IHR, loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5678 # If quadrant needs a starbase, put it in
5680 game.base = dropin(IHB)
5681 # If quadrant needs a planet, put it in
5683 game.iplnet = q.planet
5684 if not q.planet.inhabited:
5685 game.plnet = dropin(IHP)
5687 game.plnet = dropin(IHW)
5688 # Check for condition
5691 if game.irhere > 0 and game.klhere == 0:
5693 if not damaged(DRADIO):
5695 prout(_("LT. Uhura- \"Captain, an urgent message."))
5696 prout(_(" I'll put it on audio.\" CLICK"))
5698 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5699 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5700 # Put in THING if needed
5701 if thing == game.quadrant:
5702 enemy(type=IHQUEST, loc=dropin(),
5703 power=randreal(6000,6500.0)+250.0*game.skill)
5704 if not damaged(DSRSENS):
5706 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5707 prout(_(" Please examine your short-range scan.\""))
5708 # Decide if quadrant needs a Tholian; lighten up if skill is low
5709 if game.options & OPTION_THOLIAN:
5710 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5711 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5712 (game.skill > SKILL_GOOD and withprob(0.08)):
5715 w.i = withprob(0.5) * (QUADSIZE-1)
5716 w.j = withprob(0.5) * (QUADSIZE-1)
5717 if game.quad[w.i][w.j] == IHDOT:
5719 game.tholian = enemy(type=IHT, loc=w,
5720 power=randrange(100, 500) + 25.0*game.skill)
5721 # Reserve unoccupied corners
5722 if game.quad[0][0]==IHDOT:
5723 game.quad[0][0] = 'X'
5724 if game.quad[0][QUADSIZE-1]==IHDOT:
5725 game.quad[0][QUADSIZE-1] = 'X'
5726 if game.quad[QUADSIZE-1][0]==IHDOT:
5727 game.quad[QUADSIZE-1][0] = 'X'
5728 if game.quad[QUADSIZE-1][QUADSIZE-1]==IHDOT:
5729 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5730 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
5731 # And finally the stars
5732 for i in range(q.stars):
5734 # Put in a few black holes
5735 for i in range(1, 3+1):
5738 # Take out X's in corners if Tholian present
5740 if game.quad[0][0]=='X':
5741 game.quad[0][0] = IHDOT
5742 if game.quad[0][QUADSIZE-1]=='X':
5743 game.quad[0][QUADSIZE-1] = IHDOT
5744 if game.quad[QUADSIZE-1][0]=='X':
5745 game.quad[QUADSIZE-1][0] = IHDOT
5746 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5747 game.quad[QUADSIZE-1][QUADSIZE-1] = IHDOT
5750 "Set the self-destruct password."
5751 if game.options & OPTION_PLAIN:
5754 proutn(_("Please type in a secret password- "))
5756 game.passwd = scanner.token
5757 if game.passwd != None:
5762 game.passwd += chr(ord('a')+randrange(26))
5764 # Code from sst.c begins here
5767 "SRSCAN": OPTION_TTY,
5768 "STATUS": OPTION_TTY,
5769 "REQUEST": OPTION_TTY,
5770 "LRSCAN": OPTION_TTY,
5783 "SENSORS": OPTION_PLANETS,
5784 "ORBIT": OPTION_PLANETS,
5785 "TRANSPORT": OPTION_PLANETS,
5786 "MINE": OPTION_PLANETS,
5787 "CRYSTALS": OPTION_PLANETS,
5788 "SHUTTLE": OPTION_PLANETS,
5789 "PLANETS": OPTION_PLANETS,
5794 "PROBE": OPTION_PROBE,
5796 "FREEZE": 0, # Synonym for SAVE
5802 "SOS": 0, # Synonym for MAYDAY
5803 "CALL": 0, # Synonym for MAYDAY
5809 "Generate a list of legal commands."
5810 prout(_("LEGAL COMMANDS ARE:"))
5812 for key in commands:
5813 if not commands[key] or (commands[key] & game.options):
5814 proutn("%-12s " % key)
5816 if emitted % 5 == 4:
5821 "Browse on-line help."
5822 key = scanner.next()
5825 setwnd(prompt_window)
5826 proutn(_("Help on what command? "))
5827 key = scanner.next()
5828 setwnd(message_window)
5831 if scanner.token in commands or scanner.token == "ABBREV":
5838 cmd = scanner.token.upper()
5840 fp = open(SSTDOC, "r")
5843 fp = open(DOC_NAME, "r")
5845 prout(_("Spock- \"Captain, that information is missing from the"))
5846 proutn(_(" computer. You need to find "))
5848 prout(_(" and put it in the"))
5849 proutn(_(" current directory or to "))
5852 # This used to continue: "You need to find SST.DOC and put
5853 # it in the current directory."
5856 linebuf = fp.readline()
5858 prout(_("Spock- \"Captain, there is no information on that command.\""))
5861 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5862 linebuf = linebuf[3:].strip()
5866 prout(_("Spock- \"Captain, I've found the following information:\""))
5868 while linebuf in fp:
5869 if "******" in linebuf:
5875 "Command-interpretation loop."
5877 setwnd(message_window)
5878 while True: # command loop
5880 while True: # get a command
5885 setwnd(prompt_window)
5888 if scanner.next() == "IHEOL":
5889 if game.options & OPTION_CURSES:
5892 elif scanner.token == "":
5896 setwnd(message_window)
5898 candidates = filter(lambda x: x.startswith(scanner.token.upper()),
5900 if len(candidates) == 1:
5903 elif candidates and not (game.options & OPTION_PLAIN):
5904 prout("Commands with prefix '%s': %s" % (scanner.token, " ".join(candidates)))
5908 if cmd == "SRSCAN": # srscan
5910 elif cmd == "STATUS": # status
5912 elif cmd == "REQUEST": # status request
5914 elif cmd == "LRSCAN": # long range scan
5915 lrscan(silent=False)
5916 elif cmd == "PHASERS": # phasers
5920 elif cmd == "TORPEDO": # photon torpedos
5924 elif cmd == "MOVE": # move under warp
5925 warp(course=None, involuntary=False)
5926 elif cmd == "SHIELDS": # shields
5927 doshield(shraise=False)
5930 game.shldchg = False
5931 elif cmd == "DOCK": # dock at starbase
5934 attack(torps_ok=False)
5935 elif cmd == "DAMAGES": # damage reports
5937 elif cmd == "CHART": # chart
5939 elif cmd == "IMPULSE": # impulse
5941 elif cmd == "REST": # rest
5945 elif cmd == "WARP": # warp
5947 elif cmd == "SCORE": # score
5949 elif cmd == "SENSORS": # sensors
5951 elif cmd == "ORBIT": # orbit
5955 elif cmd == "TRANSPORT": # transport "beam"
5957 elif cmd == "MINE": # mine
5961 elif cmd == "CRYSTALS": # crystals
5965 elif cmd == "SHUTTLE": # shuttle
5969 elif cmd == "PLANETS": # Planet list
5971 elif cmd == "REPORT": # Game Report
5973 elif cmd == "COMPUTER": # use COMPUTER!
5975 elif cmd == "COMMANDS":
5977 elif cmd == "EMEXIT": # Emergency exit
5978 clrscr() # Hide screen
5979 freeze(True) # forced save
5980 raise SysExit,1 # And quick exit
5981 elif cmd == "PROBE":
5982 probe() # Launch probe
5985 elif cmd == "ABANDON": # Abandon Ship
5987 elif cmd == "DESTRUCT": # Self Destruct
5989 elif cmd == "SAVE": # Save Game
5992 if game.skill > SKILL_GOOD:
5993 prout(_("WARNING--Saved games produce no plaques!"))
5994 elif cmd == "DEATHRAY": # Try a desparation measure
5998 elif cmd == "DEBUGCMD": # What do we want for debug???
6000 elif cmd == "MAYDAY": # Call for help
6005 game.alldone = True # quit the game
6010 break # Game has ended
6011 if game.optime != 0.0:
6014 break # Events did us in
6015 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6018 if hitme and not game.justin:
6019 attack(torps_ok=True)
6022 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6033 "Emit the name of an enemy or feature."
6034 if type == IHR: s = _("Romulan")
6035 elif type == IHK: s = _("Klingon")
6036 elif type == IHC: s = _("Commander")
6037 elif type == IHS: s = _("Super-commander")
6038 elif type == IHSTAR: s = _("Star")
6039 elif type == IHP: s = _("Planet")
6040 elif type == IHB: s = _("Starbase")
6041 elif type == IHBLANK: s = _("Black hole")
6042 elif type == IHT: s = _("Tholian")
6043 elif type == IHWEB: s = _("Tholian web")
6044 elif type == IHQUEST: s = _("Stranger")
6045 elif type == IHW: s = _("Inhabited World")
6046 else: s = "Unknown??"
6049 def crmena(stars, enemy, loctype, w):
6050 "Emit the name of an enemy and his location."
6054 buf += cramen(enemy) + _(" at ")
6055 if loctype == "quadrant":
6056 buf += _("Quadrant ")
6057 elif loctype == "sector":
6062 "Emit our ship name."
6063 return{IHE:_("Enterprise"),IHF:_("Faerie Queene")}.get(game.ship,"Ship???")
6066 "Emit a line of stars"
6067 prouts("******************************************************")
6071 return -avrage*math.log(1e-7 + randreal())
6073 def randplace(size):
6074 "Choose a random location."
6076 w.i = randrange(size)
6077 w.j = randrange(size)
6087 # Get a token from the user
6090 # Fill the token quue if nothing here
6091 while not self.inqueue:
6093 if curwnd==prompt_window:
6095 setwnd(message_window)
6102 self.inqueue = line.lstrip().split() + ["\n"]
6103 # From here on in it's all looking at the queue
6104 self.token = self.inqueue.pop(0)
6105 if self.token == "\n":
6109 self.real = float(self.token)
6110 self.type = "IHREAL"
6115 self.token = self.token.lower()
6116 self.type = "IHALPHA"
6119 def append(self, tok):
6120 self.inqueue.append(tok)
6121 def push(self, tok):
6122 self.inqueue.insert(0, tok)
6126 # Demand input for next scan
6128 self.real = self.token = None
6130 # compares s to item and returns true if it matches to the length of s
6131 return s.startswith(self.token)
6133 # Round token value to nearest integer
6134 return int(round(scanner.real))
6138 if scanner.type != "IHREAL":
6141 s.i = scanner.int()-1
6143 if scanner.type != "IHREAL":
6146 s.j = scanner.int()-1
6149 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6152 "Yes-or-no confirmation."
6156 if scanner.token == 'y':
6158 if scanner.token == 'n':
6161 proutn(_("Please answer with \"y\" or \"n\": "))
6164 "Complain about unparseable input."
6167 prout(_("Beg your pardon, Captain?"))
6170 "Access to the internals for debugging."
6171 proutn("Reset levels? ")
6173 if game.energy < game.inenrg:
6174 game.energy = game.inenrg
6175 game.shield = game.inshld
6176 game.torps = game.intorps
6177 game.lsupres = game.inlsr
6178 proutn("Reset damage? ")
6180 for i in range(NDEVICES):
6181 if game.damage[i] > 0.0:
6182 game.damage[i] = 0.0
6183 proutn("Toggle debug flag? ")
6187 prout("Debug output ON")
6189 prout("Debug output OFF")
6190 proutn("Cause selective damage? ")
6192 for i in range(NDEVICES):
6193 proutn("Kill %s?" % device[i])
6195 key = scanner.next()
6196 if key == "IHALPHA" and scanner.sees("y"):
6197 game.damage[i] = 10.0
6198 proutn("Examine/change events? ")
6203 FSNOVA: "Supernova ",
6206 FBATTAK: "Base Attack ",
6207 FCDBAS: "Base Destroy ",
6208 FSCMOVE: "SC Move ",
6209 FSCDBAS: "SC Base Destroy ",
6210 FDSPROB: "Probe Move ",
6211 FDISTR: "Distress Call ",
6212 FENSLV: "Enslavement ",
6213 FREPRO: "Klingon Build ",
6215 for i in range(1, NEVENTS):
6218 proutn("%.2f" % (scheduled(i)-game.state.date))
6219 if i == FENSLV or i == FREPRO:
6221 proutn(" in %s" % ev.quadrant)
6226 key = scanner.next()
6230 elif key == "IHREAL":
6231 ev = schedule(i, scanner.real)
6232 if i == FENSLV or i == FREPRO:
6234 proutn("In quadrant- ")
6235 key = scanner.next()
6236 # "IHEOL" says to leave coordinates as they are
6239 prout("Event %d canceled, no x coordinate." % (i))
6242 w.i = int(round(scanner.real))
6243 key = scanner.next()
6245 prout("Event %d canceled, no y coordinate." % (i))
6248 w.j = int(round(scanner.real))
6251 proutn("Induce supernova here? ")
6253 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6256 if __name__ == '__main__':
6257 import getopt, socket
6259 global line, thing, game, idebug
6265 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6266 if os.getenv("TERM"):
6267 game.options |= OPTION_CURSES
6269 game.options |= OPTION_TTY
6270 seed = int(time.time())
6271 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:tx")
6272 for (switch, val) in options:
6275 replayfp = open(val, "r")
6277 sys.stderr.write("sst: can't open replay file %s\n" % val)
6280 line = replayfp.readline().strip()
6281 (leader, key, seed) = line.split()
6283 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6284 line = replayfp.readline().strip()
6285 arguments += line.split()[2:]
6287 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6289 game.options |= OPTION_TTY
6290 game.options &=~ OPTION_CURSES
6291 elif switch == '-s':
6293 elif switch == '-t':
6294 game.options |= OPTION_TTY
6295 game.options &=~ OPTION_CURSES
6296 elif switch == '-x':
6299 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6301 # where to save the input in case of bugs
6303 logfp = open("/usr/tmp/sst-input.log", "w")
6305 sys.stderr.write("sst: warning, can't open logfile\n")
6307 logfp.write("# seed %s\n" % seed)
6308 logfp.write("# options %s\n" % " ".join(arguments))
6309 logfp.write("# recorded by %s@%s on %s\n" % \
6310 (os.getenv("LOGNAME"),socket.gethostname(),time.ctime()))
6312 scanner = sstscanner()
6313 map(scanner.append, arguments)
6316 while True: # Play a game
6317 setwnd(fullscreen_window)
6323 game.alldone = False
6329 if game.tourn and game.alldone:
6330 proutn(_("Do you want your score recorded?"))
6336 proutn(_("Do you want to play again? "))
6340 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6344 except KeyboardInterrupt: