3 sst.py -- Super Star Trek 2K
5 SST2K is a Python translation of a C translation of a FORTRAN
6 original dating back to 1973. Beautiful Python it is not, but it
7 works. Translation by Eric S. Raymond; original game by David Matuszek
8 and Paul Reynolds, with modifications by Don Smith, Tom Almy,
9 Stas Sergeev, and Eric S. Raymond.
11 See the doc/HACKING file in the distribution for designers notes and advice
12 on how to modify (and how not to modify!) this code.
14 import os, sys, math, curses, time, readline, cPickle, random, copy, gettext, getpass
18 docpath = (".", "../doc", "/usr/share/doc/sst")
21 return gettext.gettext(st)
23 GALSIZE = 8 # Galaxy size in quadrants
24 NINHAB = (GALSIZE * GALSIZE / 2) # Number of inhabited worlds
25 MAXUNINHAB = 10 # Maximum uninhabited worlds
26 QUADSIZE = 10 # Quadrant size in sectors
27 BASEMIN = 2 # Minimum starbases
28 BASEMAX = (GALSIZE * GALSIZE / 12) # Maximum starbases
29 MAXKLGAME = 127 # Maximum Klingons per game
30 MAXKLQUAD = 9 # Maximum Klingons per quadrant
31 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
32 FOREVER = 1e30 # Time for the indefinite future
33 MAXBURST = 3 # Max # of torps you can launch in one turn
34 MINCMDR = 10 # Minimum number of Klingon commanders
35 DOCKFAC = 0.25 # Repair faster when docked
36 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
56 class TrekError(Exception):
59 class JumpOut(Exception):
63 def __init__(self, x=None, y=None):
66 def valid_quadrant(self):
67 return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
68 def valid_sector(self):
69 return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
71 self.i = self.j = None
73 return self.i != None and self.j != None
74 def __eq__(self, other):
75 return other != None and self.i == other.i and self.j == other.j
76 def __ne__(self, other):
77 return other == None or self.i != other.i or self.j != other.j
78 def __add__(self, other):
79 return Coord(self.i+other.i, self.j+other.j)
80 def __sub__(self, other):
81 return Coord(self.i-other.i, self.j-other.j)
82 def __mul__(self, other):
83 return Coord(self.i*other, self.j*other)
84 def __rmul__(self, other):
85 return Coord(self.i*other, self.j*other)
86 def __div__(self, other):
87 return Coord(self.i/other, self.j/other)
88 def __mod__(self, other):
89 return Coord(self.i % other, self.j % other)
90 def __rdiv__(self, other):
91 return Coord(self.i/other, self.j/other)
92 def roundtogrid(self):
93 return Coord(int(round(self.i)), int(round(self.j)))
94 def distance(self, other=None):
97 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
99 return 1.90985*math.atan2(self.j, self.i)
105 s.i = self.i / abs(self.i)
109 s.j = self.j / abs(self.j)
112 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
113 return self.roundtogrid() / QUADSIZE
115 return self.roundtogrid() % QUADSIZE
118 s.i = self.i + randrange(-1, 2)
119 s.j = self.j + randrange(-1, 2)
122 if self.i == None or self.j == None:
124 return "%s - %s" % (self.i+1, self.j+1)
128 "Do not anger the Space Thingy!"
137 self.name = None # string-valued if inhabited
138 self.quadrant = Coord() # quadrant located
139 self.pclass = None # could be ""M", "N", "O", or "destroyed"
140 self.crystals = "absent"# could be "mined", "present", "absent"
141 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
142 self.inhabited = False # is it inhabites?
150 self.starbase = False
153 self.supernova = False
155 self.status = "secure" # Could be "secure", "distressed", "enslaved"
163 def fill2d(size, fillfun):
164 "Fill an empty list in 2D."
166 for i in range(size):
168 for j in range(size):
169 lst[i].append(fillfun(i, j))
174 self.snap = False # snapshot taken
175 self.crew = 0 # crew complement
176 self.remkl = 0 # remaining klingons
177 self.nscrem = 0 # remaining super commanders
178 self.starkl = 0 # destroyed stars
179 self.basekl = 0 # destroyed bases
180 self.nromrem = 0 # Romulans remaining
181 self.nplankl = 0 # destroyed uninhabited planets
182 self.nworldkl = 0 # destroyed inhabited planets
183 self.planets = [] # Planet information
184 self.date = 0.0 # stardate
185 self.remres = 0 # remaining resources
186 self.remtime = 0 # remaining time
187 self.baseq = [] # Base quadrant coordinates
188 self.kcmdr = [] # Commander quadrant coordinates
189 self.kscmdr = Coord() # Supercommander quadrant coordinates
191 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
193 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
197 self.date = None # A real number
198 self.quadrant = None # A coord structure
201 OPTION_ALL = 0xffffffff
202 OPTION_TTY = 0x00000001 # old interface
203 OPTION_CURSES = 0x00000002 # new interface
204 OPTION_IOMODES = 0x00000003 # cover both interfaces
205 OPTION_PLANETS = 0x00000004 # planets and mining
206 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
207 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
208 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
209 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
210 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
211 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
212 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
213 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
214 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
215 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
216 OPTION_PLAIN = 0x01000000 # user chose plain game
217 OPTION_ALMY = 0x02000000 # user chose Almy variant
218 OPTION_COLOR = 0x04000000 # enable color display (experimental, ESR, 2010)
237 NDEVICES = 16 # Number of devices
247 return (game.damage[dev] != 0.0)
249 return not damaged(DRADIO) or game.condition=="docked"
251 # Define future events
252 FSPY = 0 # Spy event happens always (no future[] entry)
253 # can cause SC to tractor beam Enterprise
254 FSNOVA = 1 # Supernova
255 FTBEAM = 2 # Commander tractor beams Enterprise
256 FSNAP = 3 # Snapshot for time warp
257 FBATTAK = 4 # Commander attacks base
258 FCDBAS = 5 # Commander destroys base
259 FSCMOVE = 6 # Supercommander moves (might attack base)
260 FSCDBAS = 7 # Supercommander destroys base
261 FDSPROB = 8 # Move deep space probe
262 FDISTR = 9 # Emit distress call from an inhabited world
263 FENSLV = 10 # Inhabited word is enslaved */
264 FREPRO = 11 # Klingons build a ship in an enslaved system
267 # Abstract out the event handling -- underlying data structures will change
268 # when we implement stateful events
269 def findevent(evtype):
270 return game.future[evtype]
273 def __init__(self, etype=None, loc=None, power=None):
275 self.location = Coord()
278 self.power = power # enemy energy level
279 game.enemies.append(self)
281 motion = (loc != self.location)
282 if self.location.i is not None and self.location.j is not None:
285 game.quad[self.location.i][self.location.j] = '#'
287 game.quad[self.location.i][self.location.j] = '.'
289 self.location = copy.copy(loc)
290 game.quad[self.location.i][self.location.j] = self.type
291 self.kdist = self.kavgd = (game.sector - loc).distance()
293 self.location = Coord()
294 self.kdist = self.kavgd = None
295 game.enemies.remove(self)
298 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
302 self.options = None # Game options
303 self.state = Snapshot() # A snapshot structure
304 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
305 self.quad = None # contents of our quadrant
306 self.damage = [0.0] * NDEVICES # damage encountered
307 self.future = [] # future events
311 self.future.append(Event())
312 self.passwd = None # Self Destruct password
314 self.quadrant = None # where we are in the large
315 self.sector = None # where we are in the small
316 self.tholian = None # Tholian enemy object
317 self.base = None # position of base in current quadrant
318 self.battle = None # base coordinates being attacked
319 self.plnet = None # location of planet in quadrant
320 self.gamewon = False # Finished!
321 self.ididit = False # action taken -- allows enemy to attack
322 self.alive = False # we are alive (not killed)
323 self.justin = False # just entered quadrant
324 self.shldup = False # shields are up
325 self.shldchg = False # shield is changing (affects efficiency)
326 self.iscate = False # super commander is here
327 self.ientesc = False # attempted escape from supercommander
328 self.resting = False # rest time
329 self.icraft = False # Kirk in Galileo
330 self.landed = False # party on planet (true), on ship (false)
331 self.alldone = False # game is now finished
332 self.neutz = False # Romulan Neutral Zone
333 self.isarmed = False # probe is armed
334 self.inorbit = False # orbiting a planet
335 self.imine = False # mining
336 self.icrystl = False # dilithium crystals aboard
337 self.iseenit = False # seen base attack report
338 self.thawed = False # thawed game
339 self.condition = None # "green", "yellow", "red", "docked", "dead"
340 self.iscraft = None # "onship", "offship", "removed"
341 self.skill = None # Player skill level
342 self.inkling = 0 # initial number of klingons
343 self.inbase = 0 # initial number of bases
344 self.incom = 0 # initial number of commanders
345 self.inscom = 0 # initial number of commanders
346 self.inrom = 0 # initial number of commanders
347 self.instar = 0 # initial stars
348 self.intorps = 0 # initial/max torpedoes
349 self.torps = 0 # number of torpedoes
350 self.ship = 0 # ship type -- 'E' is Enterprise
351 self.abandoned = 0 # count of crew abandoned in space
352 self.length = 0 # length of game
353 self.klhere = 0 # klingons here
354 self.casual = 0 # causalties
355 self.nhelp = 0 # calls for help
356 self.nkinks = 0 # count of energy-barrier crossings
357 self.iplnet = None # planet # in quadrant
358 self.inplan = 0 # initial planets
359 self.irhere = 0 # Romulans in quadrant
360 self.isatb = 0 # =2 if super commander is attacking base
361 self.tourn = None # tournament number
362 self.nprobes = 0 # number of probes available
363 self.inresor = 0.0 # initial resources
364 self.intime = 0.0 # initial time
365 self.inenrg = 0.0 # initial/max energy
366 self.inshld = 0.0 # initial/max shield
367 self.inlsr = 0.0 # initial life support resources
368 self.indate = 0.0 # initial date
369 self.energy = 0.0 # energy level
370 self.shield = 0.0 # shield level
371 self.warpfac = 0.0 # warp speed
372 self.lsupres = 0.0 # life support reserves
373 self.optime = 0.0 # time taken by current operation
374 self.damfac = 0.0 # damage factor
375 self.lastchart = 0.0 # time star chart was last updated
376 self.cryprob = 0.0 # probability that crystal will work
377 self.probe = None # object holding probe course info
378 self.height = 0.0 # height of orbit around planet
379 self.score = 0.0 # overall score
380 self.perdate = 0.0 # rate of kills
381 self.idebug = False # Debugging instrumentation enabled?
383 # Stas thinks this should be (C expression):
384 # game.state.remkl + len(game.state.kcmdr) > 0 ?
385 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
386 # He says the existing expression is prone to divide-by-zero errors
387 # after killing the last klingon when score is shown -- perhaps also
388 # if the only remaining klingon is SCOM.
389 game.state.remtime = game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr))
415 return random.random() < p
417 def randrange(*args):
418 return random.randrange(*args)
423 v *= args[0] # from [0, args[0])
425 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
428 # Code from ai.c begins here
431 "Would this quadrant welcome another Klingon?"
432 return iq.valid_quadrant() and \
433 not game.state.galaxy[iq.i][iq.j].supernova and \
434 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
436 def tryexit(enemy, look, irun):
437 "A bad guy attempts to bug out."
439 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
440 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
441 if not welcoming(iq):
443 if enemy.type == 'R':
444 return False # Romulans cannot escape!
446 # avoid intruding on another commander's territory
447 if enemy.type == 'C':
448 if iq in game.state.kcmdr:
450 # refuse to leave if currently attacking starbase
451 if game.battle == game.quadrant:
453 # don't leave if over 1000 units of energy
454 if enemy.power > 1000.0:
456 # emit escape message and move out of quadrant.
457 # we know this if either short or long range sensors are working
458 if not damaged(DSRSENS) or not damaged(DLRSENS) or \
459 game.condition == "docked":
460 prout(crmena(True, enemy.type, "sector", enemy.location) + \
461 (_(" escapes to Quadrant %s (and regains strength).") % iq))
462 # handle local matters related to escape
465 if game.condition != "docked":
467 # Handle global matters related to escape
468 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
469 game.state.galaxy[iq.i][iq.j].klingons += 1
470 if enemy.type == 'S':
474 schedule(FSCMOVE, 0.2777)
476 game.state.kscmdr = iq
478 for cmdr in game.state.kcmdr:
479 if cmdr == game.quadrant:
480 game.state.kcmdr.append(iq)
482 return True # success
484 # The bad-guy movement algorithm:
486 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
487 # If both are operating full strength, force is 1000. If both are damaged,
488 # force is -1000. Having shields down subtracts an additional 1000.
490 # 2. Enemy has forces equal to the energy of the attacker plus
491 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
492 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
494 # Attacker Initial energy levels (nominal):
495 # Klingon Romulan Commander Super-Commander
496 # Novice 400 700 1200
498 # Good 450 800 1300 1750
499 # Expert 475 850 1350 1875
500 # Emeritus 500 900 1400 2000
501 # VARIANCE 75 200 200 200
503 # Enemy vessels only move prior to their attack. In Novice - Good games
504 # only commanders move. In Expert games, all enemy vessels move if there
505 # is a commander present. In Emeritus games all enemy vessels move.
507 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
508 # forces are 1000 greater than Enterprise.
510 # Agressive action on average cuts the distance between the ship and
511 # the enemy to 1/4 the original.
513 # 4. At lower energy advantage, movement units are proportional to the
514 # advantage with a 650 advantage being to hold ground, 800 to move forward
515 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
517 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
518 # retreat, especially at high skill levels.
520 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
522 def movebaddy(enemy):
523 "Tactical movement for the bad guys."
527 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
528 if game.skill >= SKILL_EXPERT:
529 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
531 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
533 mdist = int(dist1 + 0.5) # Nearest integer distance
534 # If SC, check with spy to see if should hi-tail it
535 if enemy.type == 'S' and \
536 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
540 # decide whether to advance, retreat, or hold position
541 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
543 forces += 1000 # Good for enemy if shield is down!
544 if not damaged(DPHASER) or not damaged(DPHOTON):
545 if damaged(DPHASER): # phasers damaged
548 forces -= 0.2*(game.energy - 2500.0)
549 if damaged(DPHOTON): # photon torpedoes damaged
552 forces -= 50.0*game.torps
554 # phasers and photon tubes both out!
557 if forces <= 1000.0 and game.condition != "docked": # Typical situation
558 motion = ((forces + randreal(200))/150.0) - 5.0
560 if forces > 1000.0: # Very strong -- move in for kill
561 motion = (1.0 - randreal())**2 * dist1 + 1.0
562 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
563 motion -= game.skill*(2.0-randreal()**2)
565 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
566 # don't move if no motion
569 # Limit motion according to skill
570 if abs(motion) > game.skill:
575 # calculate preferred number of steps
576 nsteps = abs(int(motion))
577 if motion > 0 and nsteps > mdist:
578 nsteps = mdist # don't overshoot
579 if nsteps > QUADSIZE:
580 nsteps = QUADSIZE # This shouldn't be necessary
582 nsteps = 1 # This shouldn't be necessary
584 proutn("NSTEPS = %d:" % nsteps)
585 # Compute preferred values of delta X and Y
586 m = game.sector - enemy.location
587 if 2.0 * abs(m.i) < abs(m.j):
589 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
591 m = (motion * m).sgn()
592 goto = enemy.location
594 for ll in range(nsteps):
596 proutn(" %d" % (ll+1))
597 # Check if preferred position available
608 attempts = 0 # Settle mysterious hang problem
609 while attempts < 20 and not success:
611 if look.i < 0 or look.i >= QUADSIZE:
612 if motion < 0 and tryexit(enemy, look, irun):
614 if krawli == m.i or m.j == 0:
616 look.i = goto.i + krawli
618 elif look.j < 0 or look.j >= QUADSIZE:
619 if motion < 0 and tryexit(enemy, look, irun):
621 if krawlj == m.j or m.i == 0:
623 look.j = goto.j + krawlj
625 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
626 # See if enemy should ram ship
627 if game.quad[look.i][look.j] == game.ship and \
628 (enemy.type == 'C' or enemy.type == 'S'):
629 collision(rammed=True, enemy=enemy)
631 if krawli != m.i and m.j != 0:
632 look.i = goto.i + krawli
634 elif krawlj != m.j and m.i != 0:
635 look.j = goto.j + krawlj
638 break # we have failed
650 if not damaged(DSRSENS) or game.condition == "docked":
651 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
652 if enemy.kdist < dist1:
653 proutn(_(" advances to "))
655 proutn(_(" retreats to "))
656 prout("Sector %s." % goto)
659 "Sequence Klingon tactical movement."
662 # Figure out which Klingon is the commander (or Supercommander)
664 if game.quadrant in game.state.kcmdr:
665 for enemy in game.enemies:
666 if enemy.type == 'C':
668 if game.state.kscmdr == game.quadrant:
669 for enemy in game.enemies:
670 if enemy.type == 'S':
673 # If skill level is high, move other Klingons and Romulans too!
674 # Move these last so they can base their actions on what the
676 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
677 for enemy in game.enemies:
678 if enemy.type in ('K', 'R'):
682 def movescom(iq, avoid):
683 "Commander movement helper."
684 # Avoid quadrants with bases if we want to avoid Enterprise
685 if not welcoming(iq) or (avoid and iq in game.state.baseq):
687 if game.justin and not game.iscate:
690 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
691 game.state.kscmdr = iq
692 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
693 if game.state.kscmdr == game.quadrant:
694 # SC has scooted, remove him from current quadrant
699 for enemy in game.enemies:
700 if enemy.type == 'S':
704 if game.condition != "docked":
707 # check for a helpful planet
708 for i in range(game.inplan):
709 if game.state.planets[i].quadrant == game.state.kscmdr and \
710 game.state.planets[i].crystals == "present":
712 game.state.planets[i].pclass = "destroyed"
713 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
716 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
717 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
718 prout(_(" by the Super-commander.\""))
720 return True # looks good!
722 def supercommander():
723 "Move the Super Commander."
730 prout("== SUPERCOMMANDER")
731 # Decide on being active or passive
732 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 \
733 (game.state.date-game.indate) < 3.0)
734 if not game.iscate and avoid:
735 # compute move away from Enterprise
736 idelta = game.state.kscmdr-game.quadrant
737 if idelta.distance() > 2.0:
739 idelta.i = game.state.kscmdr.j-game.quadrant.j
740 idelta.j = game.quadrant.i-game.state.kscmdr.i
742 # compute distances to starbases
743 if not game.state.baseq:
747 sc = game.state.kscmdr
748 for (i, base) in enumerate(game.state.baseq):
749 basetbl.append((i, (base - sc).distance()))
750 if game.state.baseq > 1:
751 basetbl.sort(lambda x, y: cmp(x[1], y[1]))
752 # look for nearest base without a commander, no Enterprise, and
753 # without too many Klingons, and not already under attack.
754 ifindit = iwhichb = 0
755 for (i2, base) in enumerate(game.state.baseq):
756 i = basetbl[i2][0] # bug in original had it not finding nearest
757 if base == game.quadrant or base == game.battle or not welcoming(base):
759 # if there is a commander, and no other base is appropriate,
760 # we will take the one with the commander
761 for cmdr in game.state.kcmdr:
762 if base == cmdr and ifindit != 2:
766 else: # no commander -- use this one
771 return # Nothing suitable -- wait until next time
772 ibq = game.state.baseq[iwhichb]
773 # decide how to move toward base
774 idelta = ibq - game.state.kscmdr
775 # Maximum movement is 1 quadrant in either or both axes
776 idelta = idelta.sgn()
777 # try moving in both x and y directions
778 # there was what looked like a bug in the Almy C code here,
779 # but it might be this translation is just wrong.
780 iq = game.state.kscmdr + idelta
781 if not movescom(iq, avoid):
782 # failed -- try some other maneuvers
783 if idelta.i == 0 or idelta.j == 0:
786 iq.j = game.state.kscmdr.j + 1
787 if not movescom(iq, avoid):
788 iq.j = game.state.kscmdr.j - 1
791 iq.i = game.state.kscmdr.i + 1
792 if not movescom(iq, avoid):
793 iq.i = game.state.kscmdr.i - 1
796 # try moving just in x or y
797 iq.j = game.state.kscmdr.j
798 if not movescom(iq, avoid):
799 iq.j = game.state.kscmdr.j + idelta.j
800 iq.i = game.state.kscmdr.i
803 if len(game.state.baseq) == 0:
806 for ibq in game.state.baseq:
807 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
810 return # no, don't attack base!
813 schedule(FSCDBAS, randreal(1.0, 3.0))
814 if is_scheduled(FCDBAS):
815 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
816 if not communicating():
820 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
822 prout(_(" reports that it is under attack from the Klingon Super-commander."))
823 proutn(_(" It can survive until stardate %d.\"") \
824 % int(scheduled(FSCDBAS)))
827 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
831 game.optime = 0.0 # actually finished
833 # Check for intelligence report
834 if not game.idebug and \
836 (not communicating()) or \
837 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
840 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
841 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
846 if not game.tholian or game.justin:
849 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
852 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
855 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
858 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
862 # something is wrong!
863 game.tholian.move(None)
864 prout("***Internal error: Tholian in a bad spot.")
866 # do nothing if we are blocked
867 if game.quad[tid.i][tid.j] not in ('.', '#'):
869 here = copy.copy(game.tholian.location)
870 delta = (tid - game.tholian.location).sgn()
872 while here.i != tid.i:
874 if game.quad[here.i][here.j] == '.':
875 game.tholian.move(here)
877 while here.j != tid.j:
879 if game.quad[here.i][here.j] == '.':
880 game.tholian.move(here)
881 # check to see if all holes plugged
882 for i in range(QUADSIZE):
883 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
885 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
887 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
889 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
891 # All plugged up -- Tholian splits
892 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
894 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
895 game.tholian.move(None)
898 # Code from battle.c begins here
900 def doshield(shraise):
901 "Change shield status."
909 if scanner.sees("transfer"):
913 prout(_("Shields damaged and down."))
915 if scanner.sees("up"):
917 elif scanner.sees("down"):
920 proutn(_("Do you wish to change shield energy? "))
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- "))
973 if nrg > game.energy:
974 prout(_("Insufficient ship energy."))
977 if game.shield+nrg >= game.inshld:
978 prout(_("Shield energy maximized."))
979 if game.shield+nrg > game.inshld:
980 prout(_("Excess energy requested returned to ship energy"))
981 game.energy -= game.inshld-game.shield
982 game.shield = game.inshld
984 if nrg < 0.0 and game.energy-nrg > game.inenrg:
985 # Prevent shield drain loophole
987 prout(_("Engineering to bridge--"))
988 prout(_(" Scott here. Power circuit problem, Captain."))
989 prout(_(" I can't drain the shields."))
992 if game.shield+nrg < 0:
993 prout(_("All shield energy transferred to ship."))
994 game.energy += game.shield
997 proutn(_("Scotty- \""))
999 prout(_("Transferring energy to shields.\""))
1001 prout(_("Draining energy from shields.\""))
1007 "Choose a device to damage, at random."
1009 105, # DSRSENS: short range scanners 10.5%
1010 105, # DLRSENS: long range scanners 10.5%
1011 120, # DPHASER: phasers 12.0%
1012 120, # DPHOTON: photon torpedoes 12.0%
1013 25, # DLIFSUP: life support 2.5%
1014 65, # DWARPEN: warp drive 6.5%
1015 70, # DIMPULS: impulse engines 6.5%
1016 145, # DSHIELD: deflector shields 14.5%
1017 30, # DRADIO: subspace radio 3.0%
1018 45, # DSHUTTL: shuttle 4.5%
1019 15, # DCOMPTR: computer 1.5%
1020 20, # NAVCOMP: navigation system 2.0%
1021 75, # DTRANSP: transporter 7.5%
1022 20, # DSHCTRL: high-speed shield controller 2.0%
1023 10, # DDRAY: death ray 1.0%
1024 30, # DDSP: deep-space probes 3.0%
1026 assert(sum(weights) == 1000)
1027 idx = randrange(1000)
1029 for (i, w) in enumerate(weights):
1033 return None # we should never get here
1035 def collision(rammed, enemy):
1036 "Collision handling fot rammong events."
1037 prouts(_("***RED ALERT! RED ALERT!"))
1039 prout(_("***COLLISION IMMINENT."))
1043 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1045 proutn(_(" rammed by "))
1048 proutn(crmena(False, enemy.type, "sector", enemy.location))
1050 proutn(_(" (original position)"))
1052 deadkl(enemy.location, enemy.type, game.sector)
1053 proutn("***" + crmshp() + " heavily damaged.")
1054 icas = randrange(10, 30)
1055 prout(_("***Sickbay reports %d casualties") % icas)
1057 game.state.crew -= icas
1058 # In the pre-SST2K version, all devices got equiprobably damaged,
1059 # which was silly. Instead, pick up to half the devices at
1060 # random according to our weighting table,
1061 ncrits = randrange(NDEVICES/2)
1065 if game.damage[dev] < 0:
1067 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1068 # Damage for at least time of travel!
1069 game.damage[dev] += game.optime + extradm
1071 prout(_("***Shields are down."))
1072 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1079 def torpedo(origin, bearing, dispersion, number, nburst):
1080 "Let a photon torpedo fly"
1081 if not damaged(DSRSENS) or game.condition == "docked":
1082 setwnd(srscan_window)
1084 setwnd(message_window)
1085 ac = bearing + 0.25*dispersion # dispersion is a random variable
1086 bullseye = (15.0 - bearing)*0.5235988
1087 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1088 bumpto = Coord(0, 0)
1089 # Loop to move a single torpedo
1090 setwnd(message_window)
1091 for step in range(1, QUADSIZE*2):
1092 if not track.next():
1095 if not w.valid_sector():
1097 iquad = game.quad[w.i][w.j]
1098 tracktorpedo(w, step, number, nburst, iquad)
1102 if not damaged(DSRSENS) or game.condition == "docked":
1103 skip(1) # start new line after text track
1104 if iquad in ('E', 'F'): # Hit our ship
1106 prout(_("Torpedo hits %s.") % crmshp())
1107 hit = 700.0 + randreal(100) - \
1108 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1109 newcnd() # we're blown out of dock
1110 if game.landed or game.condition == "docked":
1111 return hit # Cheat if on a planet
1112 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1113 # is 143 degrees, which is almost exactly 4.8 clockface units
1114 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1116 bumpto = displacement.sector()
1117 if not bumpto.valid_sector():
1119 if game.quad[bumpto.i][bumpto.j] == ' ':
1122 if game.quad[bumpto.i][bumpto.j] != '.':
1123 # can't move into object
1125 game.sector = bumpto
1127 game.quad[w.i][w.j] = '.'
1128 game.quad[bumpto.i][bumpto.j] = iquad
1129 prout(_(" displaced by blast to Sector %s ") % bumpto)
1130 for enemy in game.enemies:
1131 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1134 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1136 if iquad in ('C', 'S') and withprob(0.05):
1137 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1138 prout(_(" torpedo neutralized."))
1140 for enemy in game.enemies:
1141 if w == enemy.location:
1143 kp = math.fabs(enemy.power)
1144 h1 = 700.0 + randrange(100) - \
1145 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1153 if enemy.power == 0:
1156 proutn(crmena(True, iquad, "sector", w))
1157 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1159 bumpto = displacement.sector()
1160 if not bumpto.valid_sector():
1161 prout(_(" damaged but not destroyed."))
1163 if game.quad[bumpto.i][bumpto.j] == ' ':
1164 prout(_(" buffeted into black hole."))
1165 deadkl(w, iquad, bumpto)
1166 if game.quad[bumpto.i][bumpto.j] != '.':
1167 prout(_(" damaged but not destroyed."))
1169 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1170 enemy.location = bumpto
1171 game.quad[w.i][w.j] = '.'
1172 game.quad[bumpto.i][bumpto.j] = iquad
1173 for enemy in game.enemies:
1174 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1177 elif iquad == 'B': # Hit a base
1179 prout(_("***STARBASE DESTROYED.."))
1180 game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
1181 game.quad[w.i][w.j] = '.'
1182 game.base.invalidate()
1183 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1
1184 game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1
1185 game.state.basekl += 1
1188 elif iquad == 'P': # Hit a planet
1189 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1190 game.state.nplankl += 1
1191 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1192 game.iplnet.pclass = "destroyed"
1194 game.plnet.invalidate()
1195 game.quad[w.i][w.j] = '.'
1197 # captain perishes on planet
1200 elif iquad == '@': # Hit an inhabited world -- very bad!
1201 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1202 game.state.nworldkl += 1
1203 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1204 game.iplnet.pclass = "destroyed"
1206 game.plnet.invalidate()
1207 game.quad[w.i][w.j] = '.'
1209 # captain perishes on planet
1211 prout(_("The torpedo destroyed an inhabited planet."))
1213 elif iquad == '*': # Hit a star
1217 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1219 elif iquad == '?': # Hit a thingy
1220 if not (game.options & OPTION_THINGY) or withprob(0.3):
1222 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1224 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1226 proutn(_("Mr. Spock-"))
1227 prouts(_(" \"Fascinating!\""))
1231 # Stas Sergeev added the possibility that
1232 # you can shove the Thingy and piss it off.
1233 # It then becomes an enemy and may fire at you.
1236 elif iquad == ' ': # Black hole
1238 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1240 elif iquad == '#': # hit the web
1242 prout(_("***Torpedo absorbed by Tholian web."))
1244 elif iquad == 'T': # Hit a Tholian
1245 h1 = 700.0 + randrange(100) - \
1246 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1249 game.quad[w.i][w.j] = '.'
1254 proutn(crmena(True, 'T', "sector", w))
1256 prout(_(" survives photon blast."))
1258 prout(_(" disappears."))
1259 game.tholian.move(None)
1260 game.quad[w.i][w.j] = '#'
1265 proutn("Don't know how to handle torpedo collision with ")
1266 proutn(crmena(True, iquad, "sector", w))
1271 prout(_("Torpedo missed."))
1275 "Critical-hit resolution."
1276 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1278 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1279 proutn(_("***CRITICAL HIT--"))
1280 # Select devices and cause damage
1286 # Cheat to prevent shuttle damage unless on ship
1287 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship")):
1290 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1291 game.damage[j] += extradm
1293 for (i, j) in enumerate(cdam):
1295 if skipcount % 3 == 2 and i < len(cdam)-1:
1300 prout(_(" damaged."))
1301 if damaged(DSHIELD) and game.shldup:
1302 prout(_("***Shields knocked down."))
1305 def attack(torps_ok):
1306 # bad guy attacks us
1307 # torps_ok == False forces use of phasers in an attack
1308 # game could be over at this point, check
1318 prout("=== ATTACK!")
1319 # Tholian gets to move before attacking
1322 # if you have just entered the RNZ, you'll get a warning
1323 if game.neutz: # The one chance not to be attacked
1326 # commanders get a chance to tac-move towards you
1327 if (((game.quadrant in game.state.kcmdr or game.state.kscmdr == game.quadrant) and not game.justin) or game.skill == SKILL_EMERITUS) and torps_ok:
1329 # if no enemies remain after movement, we're done
1330 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing == game.quadrant and not thing.angered):
1332 # set up partial hits if attack happens during shield status change
1333 pfac = 1.0/game.inshld
1335 chgfac = 0.25 + randreal(0.5)
1337 # message verbosity control
1338 if game.skill <= SKILL_FAIR:
1340 for enemy in game.enemies:
1342 continue # too weak to attack
1343 # compute hit strength and diminish shield power
1345 # Increase chance of photon torpedos if docked or enemy energy is low
1346 if game.condition == "docked":
1348 if enemy.power < 500:
1350 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1352 # different enemies have different probabilities of throwing a torp
1353 usephasers = not torps_ok or \
1354 (enemy.type == 'K' and r > 0.0005) or \
1355 (enemy.type == 'C' and r > 0.015) or \
1356 (enemy.type == 'R' and r > 0.3) or \
1357 (enemy.type == 'S' and r > 0.07) or \
1358 (enemy.type == '?' and r > 0.05)
1359 if usephasers: # Enemy uses phasers
1360 if game.condition == "docked":
1361 continue # Don't waste the effort!
1362 attempt = True # Attempt to attack
1363 dustfac = randreal(0.8, 0.85)
1364 hit = enemy.power*math.pow(dustfac,enemy.kavgd)
1366 else: # Enemy uses photon torpedo
1367 # We should be able to make the bearing() method work here
1368 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1370 proutn(_("***TORPEDO INCOMING"))
1371 if not damaged(DSRSENS):
1372 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1375 dispersion = (randreal()+randreal())*0.5 - 0.5
1376 dispersion += 0.002*enemy.power*dispersion
1377 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1378 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1379 finish(FWON) # Klingons did themselves in!
1380 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1381 return # Supernova or finished
1384 # incoming phaser or torpedo, shields may dissipate it
1385 if game.shldup or game.shldchg or game.condition == "docked":
1386 # shields will take hits
1387 propor = pfac * game.shield
1388 if game.condition == "docked":
1392 hitsh = propor*chgfac*hit+1.0
1394 if absorb > game.shield:
1395 absorb = game.shield
1396 game.shield -= absorb
1398 # taking a hit blasts us out of a starbase dock
1399 if game.condition == "docked":
1401 # but the shields may take care of it
1402 if propor > 0.1 and hit < 0.005*game.energy:
1404 # hit from this opponent got through shields, so take damage
1406 proutn(_("%d unit hit") % int(hit))
1407 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1408 proutn(_(" on the ") + crmshp())
1409 if not damaged(DSRSENS) and usephasers:
1410 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1412 # Decide if hit is critical
1418 if game.energy <= 0:
1419 # Returning home upon your shield, not with it...
1422 if not attempt and game.condition == "docked":
1423 prout(_("***Enemies decide against attacking your ship."))
1424 percent = 100.0*pfac*game.shield+0.5
1426 # Shields fully protect ship
1427 proutn(_("Enemy attack reduces shield strength to "))
1429 # Emit message if starship suffered hit(s)
1431 proutn(_("Energy left %2d shields ") % int(game.energy))
1434 elif not damaged(DSHIELD):
1437 proutn(_("damaged, "))
1438 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1439 # Check if anyone was hurt
1440 if hitmax >= 200 or hittot >= 500:
1441 icas = randrange(int(hittot * 0.015))
1444 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1445 prout(_(" in that last attack.\""))
1447 game.state.crew -= icas
1448 # After attack, reset average distance to enemies
1449 for enemy in game.enemies:
1450 enemy.kavgd = enemy.kdist
1454 def deadkl(w, etype, mv):
1455 "Kill a Klingon, Tholian, Romulan, or Thingy."
1456 # Added mv to allow enemy to "move" before dying
1457 proutn(crmena(True, etype, "sector", mv))
1458 # Decide what kind of enemy it is and update appropriately
1460 # Chalk up a Romulan
1461 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1463 game.state.nromrem -= 1
1472 # Killed some type of Klingon
1473 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1476 game.state.kcmdr.remove(game.quadrant)
1478 if game.state.kcmdr:
1479 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1480 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1483 game.state.remkl -= 1
1485 game.state.nscrem -= 1
1486 game.state.kscmdr.invalidate()
1491 # For each kind of enemy, finish message to player
1492 prout(_(" destroyed."))
1493 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1496 # Remove enemy ship from arrays describing local conditions
1497 for e in game.enemies:
1504 "Return None if target is invalid, otherwise return a course angle."
1505 if not w.valid_sector():
1509 # C code this was translated from is wacky -- why the sign reversal?
1510 delta.j = (w.j - game.sector.j)
1511 delta.i = (game.sector.i - w.i)
1512 if delta == Coord(0, 0):
1514 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1515 prout(_(" I recommend an immediate review of"))
1516 prout(_(" the Captain's psychological profile.\""))
1519 return delta.bearing()
1522 "Launch photon torpedo salvo."
1525 if damaged(DPHOTON):
1526 prout(_("Photon tubes damaged."))
1530 prout(_("No torpedoes left."))
1533 # First, get torpedo count
1536 if scanner.token == "IHALPHA":
1539 elif scanner.token == "IHEOL" or not scanner.waiting():
1540 prout(_("%d torpedoes left.") % game.torps)
1542 proutn(_("Number of torpedoes to fire- "))
1543 continue # Go back around to get a number
1544 else: # key == "IHREAL"
1546 if n <= 0: # abort command
1551 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1554 scanner.chew() # User requested more torps than available
1555 continue # Go back around
1556 break # All is good, go to next stage
1560 key = scanner.next()
1561 if i == 0 and key == "IHEOL":
1562 break # no coordinate waiting, we will try prompting
1563 if i == 1 and key == "IHEOL":
1564 # direct all torpedoes at one target
1566 target.append(target[0])
1567 tcourse.append(tcourse[0])
1570 scanner.push(scanner.token)
1571 target.append(scanner.getcoord())
1572 if target[-1] == None:
1574 tcourse.append(targetcheck(target[-1]))
1575 if tcourse[-1] == None:
1578 if len(target) == 0:
1579 # prompt for each one
1581 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1583 target.append(scanner.getcoord())
1584 if target[-1] == None:
1586 tcourse.append(targetcheck(target[-1]))
1587 if tcourse[-1] == None:
1590 # Loop for moving <n> torpedoes
1592 if game.condition != "docked":
1594 dispersion = (randreal()+randreal())*0.5 -0.5
1595 if math.fabs(dispersion) >= 0.47:
1597 dispersion *= randreal(1.2, 2.2)
1599 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1601 prouts(_("***TORPEDO MISFIRES."))
1604 prout(_(" Remainder of burst aborted."))
1606 prout(_("***Photon tubes damaged by misfire."))
1607 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1609 if game.shldup or game.condition == "docked":
1610 dispersion *= 1.0 + 0.0001*game.shield
1611 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1612 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1614 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1618 "Check for phasers overheating."
1620 checkburn = (rpow-1500.0)*0.00038
1621 if withprob(checkburn):
1622 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1623 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1625 def checkshctrl(rpow):
1626 "Check shield control."
1629 prout(_("Shields lowered."))
1631 # Something bad has happened
1632 prouts(_("***RED ALERT! RED ALERT!"))
1634 hit = rpow*game.shield/game.inshld
1635 game.energy -= rpow+hit*0.8
1636 game.shield -= hit*0.2
1637 if game.energy <= 0.0:
1638 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1643 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1645 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1646 icas = randrange(int(hit*0.012))
1651 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1652 prout(_(" %d casualties so far.\"") % icas)
1654 game.state.crew -= icas
1656 prout(_("Phaser energy dispersed by shields."))
1657 prout(_("Enemy unaffected."))
1662 "Register a phaser hit on Klingons and Romulans."
1665 for (kk, wham) in enumerate(hits):
1668 dustfac = randreal(0.9, 1.0)
1669 hit = wham*math.pow(dustfac,game.enemies[kk].kdist)
1670 kpini = game.enemies[kk].power
1671 kp = math.fabs(kpini)
1672 if PHASEFAC*hit < kp:
1674 if game.enemies[kk].power < 0:
1675 game.enemies[kk].power -= -kp
1677 game.enemies[kk].power -= kp
1678 kpow = game.enemies[kk].power
1679 w = game.enemies[kk].location
1681 if not damaged(DSRSENS):
1683 proutn(_("%d unit hit on ") % int(hit))
1685 proutn(_("Very small hit on "))
1686 ienm = game.quad[w.i][w.j]
1689 proutn(crmena(False, ienm, "sector", w))
1693 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1697 kk -= 1 # don't do the increment
1699 else: # decide whether or not to emasculate klingon
1700 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1701 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1702 prout(_(" has just lost its firepower.\""))
1703 game.enemies[kk].power = -kpow
1708 "Fire phasers at bad guys."
1710 kz = 0; k = 1; irec=0 # Cheating inhibitor
1711 ifast = False; no = False; itarg = True; msgflag = True; rpow=0
1715 # SR sensors and Computer are needed for automode
1716 if damaged(DSRSENS) or damaged(DCOMPTR):
1718 if game.condition == "docked":
1719 prout(_("Phasers can't be fired through base shields."))
1722 if damaged(DPHASER):
1723 prout(_("Phaser control damaged."))
1727 if damaged(DSHCTRL):
1728 prout(_("High speed shield control damaged."))
1731 if game.energy <= 200.0:
1732 prout(_("Insufficient energy to activate high-speed shield control."))
1735 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1737 # Original code so convoluted, I re-did it all
1738 # (That was Tom Almy talking about the C code, I think -- ESR)
1739 while automode=="NOTSET":
1741 if key == "IHALPHA":
1742 if scanner.sees("manual"):
1743 if len(game.enemies)==0:
1744 prout(_("There is no enemy present to select."))
1747 automode="AUTOMATIC"
1750 key = scanner.next()
1751 elif scanner.sees("automatic"):
1752 if (not itarg) and len(game.enemies) != 0:
1753 automode = "FORCEMAN"
1755 if len(game.enemies)==0:
1756 prout(_("Energy will be expended into space."))
1757 automode = "AUTOMATIC"
1758 key = scanner.next()
1759 elif scanner.sees("no"):
1764 elif key == "IHREAL":
1765 if len(game.enemies)==0:
1766 prout(_("Energy will be expended into space."))
1767 automode = "AUTOMATIC"
1769 automode = "FORCEMAN"
1771 automode = "AUTOMATIC"
1774 if len(game.enemies)==0:
1775 prout(_("Energy will be expended into space."))
1776 automode = "AUTOMATIC"
1778 automode = "FORCEMAN"
1780 proutn(_("Manual or automatic? "))
1785 if automode == "AUTOMATIC":
1786 if key == "IHALPHA" and scanner.sees("no"):
1788 key = scanner.next()
1789 if key != "IHREAL" and len(game.enemies) != 0:
1790 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1795 for i in range(len(game.enemies)):
1796 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1798 proutn(_("%d units required. ") % irec)
1800 proutn(_("Units to fire= "))
1801 key = scanner.next()
1806 proutn(_("Energy available= %.2f") % avail)
1809 if not rpow > avail:
1816 if key == "IHALPHA" and scanner.sees("no"):
1819 game.energy -= 200 # Go and do it!
1820 if checkshctrl(rpow):
1825 if len(game.enemies):
1828 for i in range(len(game.enemies)):
1832 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))
1833 over = randreal(1.01, 1.06) * hits[i]
1835 powrem -= hits[i] + over
1836 if powrem <= 0 and temp < hits[i]:
1845 if extra > 0 and not game.alldone:
1847 proutn(_("*** Tholian web absorbs "))
1848 if len(game.enemies)>0:
1849 proutn(_("excess "))
1850 prout(_("phaser energy."))
1852 prout(_("%d expended on empty space.") % int(extra))
1853 elif automode == "FORCEMAN":
1856 if damaged(DCOMPTR):
1857 prout(_("Battle computer damaged, manual fire only."))
1860 prouts(_("---WORKING---"))
1862 prout(_("Short-range-sensors-damaged"))
1863 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1864 prout(_("Manual-fire-must-be-used"))
1866 elif automode == "MANUAL":
1868 for k in range(len(game.enemies)):
1869 aim = game.enemies[k].location
1870 ienm = game.quad[aim.i][aim.j]
1872 proutn(_("Energy available= %.2f") % (avail-0.006))
1876 if damaged(DSRSENS) and \
1877 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1878 prout(cramen(ienm) + _(" can't be located without short range scan."))
1881 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
1886 if itarg and k > kz:
1887 irec=(abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9,game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1890 if not damaged(DCOMPTR):
1895 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1896 key = scanner.next()
1897 if key == "IHALPHA" and scanner.sees("no"):
1899 key = scanner.next()
1901 if key == "IHALPHA":
1905 if k == 1: # Let me say I'm baffled by this
1908 if scanner.real < 0:
1912 hits[k] = scanner.real
1913 rpow += scanner.real
1914 # If total requested is too much, inform and start over
1916 prout(_("Available energy exceeded -- try again."))
1919 key = scanner.next() # scan for next value
1922 # zero energy -- abort
1925 if key == "IHALPHA" and scanner.sees("no"):
1930 game.energy -= 200.0
1931 if checkshctrl(rpow):
1935 # Say shield raised or malfunction, if necessary
1942 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1943 prouts(_(" CLICK CLICK POP . . ."))
1944 prout(_(" No response, sir!"))
1947 prout(_("Shields raised."))
1952 # Code from events,c begins here.
1954 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1955 # event of each type active at any given time. Mostly these means we can
1956 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1957 # BSD Trek, from which we swiped the idea, can have up to 5.
1959 def unschedule(evtype):
1960 "Remove an event from the schedule."
1961 game.future[evtype].date = FOREVER
1962 return game.future[evtype]
1964 def is_scheduled(evtype):
1965 "Is an event of specified type scheduled."
1966 return game.future[evtype].date != FOREVER
1968 def scheduled(evtype):
1969 "When will this event happen?"
1970 return game.future[evtype].date
1972 def schedule(evtype, offset):
1973 "Schedule an event of specified type."
1974 game.future[evtype].date = game.state.date + offset
1975 return game.future[evtype]
1977 def postpone(evtype, offset):
1978 "Postpone a scheduled event."
1979 game.future[evtype].date += offset
1982 "Rest period is interrupted by event."
1985 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
1987 game.resting = False
1993 "Run through the event queue looking for things to do."
1995 fintim = game.state.date + game.optime
1999 w = Coord(); hold = Coord()
2000 ev = Event(); ev2 = Event()
2002 def tractorbeam(yank):
2003 "Tractor-beaming cases merge here."
2005 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2007 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2008 # If Kirk & Co. screwing around on planet, handle
2009 atover(True) # atover(true) is Grab
2012 if game.icraft: # Caught in Galileo?
2015 # Check to see if shuttle is aboard
2016 if game.iscraft == "offship":
2019 prout(_("Galileo, left on the planet surface, is captured"))
2020 prout(_("by aliens and made into a flying McDonald's."))
2021 game.damage[DSHUTTL] = -10
2022 game.iscraft = "removed"
2024 prout(_("Galileo, left on the planet surface, is well hidden."))
2026 game.quadrant = game.state.kscmdr
2028 game.quadrant = game.state.kcmdr[i]
2029 game.sector = randplace(QUADSIZE)
2030 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2031 % (game.quadrant, game.sector))
2033 prout(_("(Remainder of rest/repair period cancelled.)"))
2034 game.resting = False
2036 if not damaged(DSHIELD) and game.shield > 0:
2037 doshield(shraise=True) # raise shields
2038 game.shldchg = False
2040 prout(_("(Shields not currently useable.)"))
2042 # Adjust finish time to time of tractor beaming
2043 fintim = game.state.date+game.optime
2044 attack(torps_ok=False)
2045 if not game.state.kcmdr:
2048 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2051 "Code merges here for any commander destroying a starbase."
2052 # Not perfect, but will have to do
2053 # Handle case where base is in same quadrant as starship
2054 if game.battle == game.quadrant:
2055 game.state.chart[game.battle.i][game.battle.j].starbase = False
2056 game.quad[game.base.i][game.base.j] = '.'
2057 game.base.invalidate()
2060 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2061 elif game.state.baseq and communicating():
2062 # Get word via subspace radio
2065 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2066 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2068 prout(_("the Klingon Super-Commander"))
2070 prout(_("a Klingon Commander"))
2071 game.state.chart[game.battle.i][game.battle.j].starbase = False
2072 # Remove Starbase from galaxy
2073 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2074 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2076 # reinstate a commander's base attack
2080 game.battle.invalidate()
2082 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2083 for i in range(1, NEVENTS):
2084 if i == FSNOVA: proutn("=== Supernova ")
2085 elif i == FTBEAM: proutn("=== T Beam ")
2086 elif i == FSNAP: proutn("=== Snapshot ")
2087 elif i == FBATTAK: proutn("=== Base Attack ")
2088 elif i == FCDBAS: proutn("=== Base Destroy ")
2089 elif i == FSCMOVE: proutn("=== SC Move ")
2090 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2091 elif i == FDSPROB: proutn("=== Probe Move ")
2092 elif i == FDISTR: proutn("=== Distress Call ")
2093 elif i == FENSLV: proutn("=== Enslavement ")
2094 elif i == FREPRO: proutn("=== Klingon Build ")
2096 prout("%.2f" % (scheduled(i)))
2099 radio_was_broken = damaged(DRADIO)
2102 # Select earliest extraneous event, evcode==0 if no events
2107 for l in range(1, NEVENTS):
2108 if game.future[l].date < datemin:
2111 prout("== Event %d fires" % evcode)
2112 datemin = game.future[l].date
2113 xtime = datemin-game.state.date
2114 game.state.date = datemin
2115 # Decrement Federation resources and recompute remaining time
2116 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2118 if game.state.remtime <= 0:
2121 # Any crew left alive?
2122 if game.state.crew <=0:
2125 # Is life support adequate?
2126 if damaged(DLIFSUP) and game.condition != "docked":
2127 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2130 game.lsupres -= xtime
2131 if game.damage[DLIFSUP] <= xtime:
2132 game.lsupres = game.inlsr
2135 if game.condition == "docked":
2137 # Don't fix Deathray here
2138 for l in range(NDEVICES):
2139 if game.damage[l] > 0.0 and l != DDRAY:
2140 if game.damage[l]-repair > 0.0:
2141 game.damage[l] -= repair
2143 game.damage[l] = 0.0
2144 # If radio repaired, update star chart and attack reports
2145 if radio_was_broken and not damaged(DRADIO):
2146 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2147 prout(_(" surveillance reports are coming in."))
2149 if not game.iseenit:
2153 prout(_(" The star chart is now up to date.\""))
2155 # Cause extraneous event EVCODE to occur
2156 game.optime -= xtime
2157 if evcode == FSNOVA: # Supernova
2160 schedule(FSNOVA, expran(0.5*game.intime))
2161 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2163 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2164 if game.state.nscrem == 0 or \
2165 ictbeam or istract or \
2166 game.condition=="docked" or game.isatb==1 or game.iscate:
2168 if game.ientesc or \
2169 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2170 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2171 (damaged(DSHIELD) and \
2172 (game.energy < 2500 or damaged(DPHASER)) and \
2173 (game.torps < 5 or damaged(DPHOTON))):
2175 istract = ictbeam = True
2176 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2179 elif evcode == FTBEAM: # Tractor beam
2180 if not game.state.kcmdr:
2183 i = randrange(len(game.state.kcmdr))
2184 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2185 if istract or game.condition == "docked" or yank == 0:
2186 # Drats! Have to reschedule
2188 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2192 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2193 game.snapsht = copy.deepcopy(game.state)
2194 game.state.snap = True
2195 schedule(FSNAP, expran(0.5 * game.intime))
2196 elif evcode == FBATTAK: # Commander attacks starbase
2197 if not game.state.kcmdr or not game.state.baseq:
2203 for ibq in game.state.baseq:
2204 for cmdr in game.state.kcmdr:
2205 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2208 # no match found -- try later
2209 schedule(FBATTAK, expran(0.3*game.intime))
2214 # commander + starbase combination found -- launch attack
2216 schedule(FCDBAS, randreal(1.0, 4.0))
2217 if game.isatb: # extra time if SC already attacking
2218 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2219 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2220 game.iseenit = False
2221 if not communicating():
2222 continue # No warning :-(
2226 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2227 prout(_(" reports that it is under attack and that it can"))
2228 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2231 elif evcode == FSCDBAS: # Supercommander destroys base
2234 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2235 continue # WAS RETURN!
2237 game.battle = game.state.kscmdr
2239 elif evcode == FCDBAS: # Commander succeeds in destroying base
2240 if evcode == FCDBAS:
2242 if not game.state.baseq() \
2243 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2244 game.battle.invalidate()
2246 # find the lucky pair
2247 for cmdr in game.state.kcmdr:
2248 if cmdr == game.battle:
2251 # No action to take after all
2254 elif evcode == FSCMOVE: # Supercommander moves
2255 schedule(FSCMOVE, 0.2777)
2256 if not game.ientesc and not istract and game.isatb != 1 and \
2257 (not game.iscate or not game.justin):
2259 elif evcode == FDSPROB: # Move deep space probe
2260 schedule(FDSPROB, 0.01)
2261 if not game.probe.next():
2262 if not game.probe.quadrant().valid_quadrant() or \
2263 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2264 # Left galaxy or ran into supernova
2268 proutn(_("Lt. Uhura- \"The deep space probe "))
2269 if not game.probe.quadrant().valid_quadrant():
2270 prout(_("has left the galaxy.\""))
2272 prout(_("is no longer transmitting.\""))
2278 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2279 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2281 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2282 chp.klingons = pdest.klingons
2283 chp.starbase = pdest.starbase
2284 chp.stars = pdest.stars
2285 pdest.charted = True
2286 game.probe.moves -= 1 # One less to travel
2287 if game.probe.arrived() and game.isarmed and pdest.stars:
2288 supernova(game.probe) # fire in the hole!
2290 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2292 elif evcode == FDISTR: # inhabited system issues distress call
2294 # try a whole bunch of times to find something suitable
2295 for i in range(100):
2296 # need a quadrant which is not the current one,
2297 # which has some stars which are inhabited and
2298 # not already under attack, which is not
2299 # supernova'ed, and which has some Klingons in it
2300 w = randplace(GALSIZE)
2301 q = game.state.galaxy[w.i][w.j]
2302 if not (game.quadrant == w or q.planet == None or \
2303 not q.planet.inhabited or \
2304 q.supernova or q.status!="secure" or q.klingons<=0):
2307 # can't seem to find one; ignore this call
2309 prout("=== Couldn't find location for distress event.")
2311 # got one!! Schedule its enslavement
2312 ev = schedule(FENSLV, expran(game.intime))
2314 q.status = "distressed"
2315 # tell the captain about it if we can
2317 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2319 prout(_("by a Klingon invasion fleet."))
2322 elif evcode == FENSLV: # starsystem is enslaved
2323 ev = unschedule(FENSLV)
2324 # see if current distress call still active
2325 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2329 q.status = "enslaved"
2331 # play stork and schedule the first baby
2332 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2333 ev2.quadrant = ev.quadrant
2335 # report the disaster if we can
2337 prout(_("Uhura- We've lost contact with starsystem %s") % \
2339 prout(_("in Quadrant %s.\n") % ev.quadrant)
2340 elif evcode == FREPRO: # Klingon reproduces
2341 # If we ever switch to a real event queue, we'll need to
2342 # explicitly retrieve and restore the x and y.
2343 ev = schedule(FREPRO, expran(1.0 * game.intime))
2344 # see if current distress call still active
2345 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2349 if game.state.remkl >=MAXKLGAME:
2350 continue # full right now
2351 # reproduce one Klingon
2354 if game.klhere >= MAXKLQUAD:
2356 # this quadrant not ok, pick an adjacent one
2357 for m.i in range(w.i - 1, w.i + 2):
2358 for m.j in range(w.j - 1, w.j + 2):
2359 if not m.valid_quadrant():
2361 q = game.state.galaxy[m.i][m.j]
2362 # check for this quad ok (not full & no snova)
2363 if q.klingons >= MAXKLQUAD or q.supernova:
2367 continue # search for eligible quadrant failed
2371 game.state.remkl += 1
2373 if game.quadrant == w:
2375 game.enemies.append(newkling())
2376 # recompute time left
2379 if game.quadrant == w:
2380 prout(_("Spock- sensors indicate the Klingons have"))
2381 prout(_("launched a warship from %s.") % q.planet)
2383 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2384 if q.planet != None:
2385 proutn(_("near %s ") % q.planet)
2386 prout(_("in Quadrant %s.") % w)
2392 key = scanner.next()
2395 proutn(_("How long? "))
2400 origTime = delay = scanner.real
2403 if delay >= game.state.remtime or len(game.enemies) != 0:
2404 proutn(_("Are you sure? "))
2407 # Alternate resting periods (events) with attacks
2411 game.resting = False
2412 if not game.resting:
2413 prout(_("%d stardates left.") % int(game.state.remtime))
2415 temp = game.optime = delay
2416 if len(game.enemies):
2417 rtime = randreal(1.0, 2.0)
2421 if game.optime < delay:
2422 attack(torps_ok=False)
2430 # Repair Deathray if long rest at starbase
2431 if origTime-delay >= 9.99 and game.condition == "docked":
2432 game.damage[DDRAY] = 0.0
2433 # leave if quadrant supernovas
2434 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2436 game.resting = False
2441 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2442 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2444 # Wow! We've supernova'ed
2445 supernova(game.quadrant)
2447 # handle initial nova
2448 game.quad[nov.i][nov.j] = '.'
2449 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2450 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2451 game.state.starkl += 1
2452 # Set up queue to recursively trigger adjacent stars
2458 for offset.i in range(-1, 1+1):
2459 for offset.j in range(-1, 1+1):
2460 if offset.j==0 and offset.i==0:
2462 neighbor = start + offset
2463 if not neighbor.valid_sector():
2465 iquad = game.quad[neighbor.i][neighbor.j]
2466 # Empty space ends reaction
2467 if iquad in ('.', '?', ' ', 'T', '#'):
2469 elif iquad == '*': # Affect another star
2471 # This star supernovas
2472 supernova(game.quadrant)
2475 hits.append(neighbor)
2476 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2477 game.state.starkl += 1
2478 proutn(crmena(True, '*', "sector", neighbor))
2480 game.quad[neighbor.i][neighbor.j] = '.'
2482 elif iquad in ('P', '@'): # Destroy planet
2483 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2485 game.state.nplankl += 1
2487 game.state.worldkl += 1
2488 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2489 game.iplnet.pclass = "destroyed"
2491 game.plnet.invalidate()
2495 game.quad[neighbor.i][neighbor.j] = '.'
2496 elif iquad == 'B': # Destroy base
2497 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2498 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2499 game.base.invalidate()
2500 game.state.basekl += 1
2502 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2503 game.quad[neighbor.i][neighbor.j] = '.'
2504 elif iquad in ('E', 'F'): # Buffet ship
2505 prout(_("***Starship buffeted by nova."))
2507 if game.shield >= 2000.0:
2508 game.shield -= 2000.0
2510 diff = 2000.0 - game.shield
2514 prout(_("***Shields knocked out."))
2515 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2517 game.energy -= 2000.0
2518 if game.energy <= 0:
2521 # add in course nova contributes to kicking starship
2522 bump += (game.sector-hits[-1]).sgn()
2523 elif iquad == 'K': # kill klingon
2524 deadkl(neighbor, iquad, neighbor)
2525 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2526 for ll in range(len(game.enemies)):
2527 if game.enemies[ll].location == neighbor:
2529 game.enemies[ll].power -= 800.0 # If firepower is lost, die
2530 if game.enemies[ll].power <= 0.0:
2531 deadkl(neighbor, iquad, neighbor)
2533 newc = neighbor + neighbor - hits[-1]
2534 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2535 if not newc.valid_sector():
2536 # can't leave quadrant
2539 iquad1 = game.quad[newc.i][newc.j]
2541 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2543 deadkl(neighbor, iquad, newc)
2546 # can't move into something else
2549 proutn(_(", buffeted to Sector %s") % newc)
2550 game.quad[neighbor.i][neighbor.j] = '.'
2551 game.quad[newc.i][newc.j] = iquad
2552 game.enemies[ll].move(newc)
2553 # Starship affected by nova -- kick it away.
2555 direc = ncourse[3*(bump.i+1)+bump.j+2]
2560 scourse = course(bearing=direc, distance=dist)
2561 game.optime = scourse.time(warp=4)
2563 prout(_("Force of nova displaces starship."))
2564 imove(scourse, noattack=True)
2565 game.optime = scourse.time(warp=4)
2569 "Star goes supernova."
2574 # Scheduled supernova -- select star at random.
2577 for nq.i in range(GALSIZE):
2578 for nq.j in range(GALSIZE):
2579 stars += game.state.galaxy[nq.i][nq.j].stars
2581 return # nothing to supernova exists
2582 num = randrange(stars) + 1
2583 for nq.i in range(GALSIZE):
2584 for nq.j in range(GALSIZE):
2585 num -= game.state.galaxy[nq.i][nq.j].stars
2591 proutn("=== Super nova here?")
2594 if not nq == game.quadrant or game.justin:
2595 # it isn't here, or we just entered (treat as enroute)
2598 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2599 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2602 # we are in the quadrant!
2603 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2604 for ns.i in range(QUADSIZE):
2605 for ns.j in range(QUADSIZE):
2606 if game.quad[ns.i][ns.j]=='*':
2613 prouts(_("***RED ALERT! RED ALERT!"))
2615 prout(_("***Incipient supernova detected at Sector %s") % ns)
2616 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2617 proutn(_("Emergency override attempts t"))
2618 prouts("***************")
2622 # destroy any Klingons in supernovaed quadrant
2623 kldead = game.state.galaxy[nq.i][nq.j].klingons
2624 game.state.galaxy[nq.i][nq.j].klingons = 0
2625 if nq == game.state.kscmdr:
2626 # did in the Supercommander!
2627 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2631 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2632 comkills = len(game.state.kcmdr) - len(survivors)
2633 game.state.kcmdr = survivors
2635 if not game.state.kcmdr:
2637 game.state.remkl -= kldead
2638 # destroy Romulans and planets in supernovaed quadrant
2639 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2640 game.state.galaxy[nq.i][nq.j].romulans = 0
2641 game.state.nromrem -= nrmdead
2643 for loop in range(game.inplan):
2644 if game.state.planets[loop].quadrant == nq:
2645 game.state.planets[loop].pclass = "destroyed"
2647 # Destroy any base in supernovaed quadrant
2648 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2649 # If starship caused supernova, tally up destruction
2651 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2652 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2653 game.state.nplankl += npdead
2654 # mark supernova in galaxy and in star chart
2655 if game.quadrant == nq or communicating():
2656 game.state.galaxy[nq.i][nq.j].supernova = True
2657 # If supernova destroys last Klingons give special message
2658 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2661 prout(_("Lucky you!"))
2662 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2665 # if some Klingons remain, continue or die in supernova
2670 # Code from finish.c ends here.
2673 "Self-destruct maneuver. Finish with a BANG!"
2675 if damaged(DCOMPTR):
2676 prout(_("Computer damaged; cannot execute destruct sequence."))
2678 prouts(_("---WORKING---")); skip(1)
2679 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2680 prouts(" 10"); skip(1)
2681 prouts(" 9"); skip(1)
2682 prouts(" 8"); skip(1)
2683 prouts(" 7"); skip(1)
2684 prouts(" 6"); skip(1)
2686 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2688 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2690 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2693 if game.passwd != scanner.token:
2694 prouts(_("PASSWORD-REJECTED;"))
2696 prouts(_("CONTINUITY-EFFECTED"))
2699 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2700 prouts(" 5"); skip(1)
2701 prouts(" 4"); skip(1)
2702 prouts(" 3"); skip(1)
2703 prouts(" 2"); skip(1)
2704 prouts(" 1"); skip(1)
2706 prouts(_("GOODBYE-CRUEL-WORLD"))
2714 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2718 if len(game.enemies) != 0:
2719 whammo = 25.0 * game.energy
2720 for l in range(len(game.enemies)):
2721 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2722 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2726 "Compute our rate of kils over time."
2727 elapsed = game.state.date - game.indate
2728 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2731 starting = (game.inkling + game.incom + game.inscom)
2732 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2733 return (starting - remaining)/elapsed
2737 badpt = 5.0*game.state.starkl + \
2739 10.0*game.state.nplankl + \
2740 300*game.state.nworldkl + \
2742 100.0*game.state.basekl +\
2744 if game.ship == 'F':
2746 elif game.ship == None:
2751 # end the game, with appropriate notfications
2755 prout(_("It is stardate %.1f.") % game.state.date)
2757 if ifin == FWON: # Game has been won
2758 if game.state.nromrem != 0:
2759 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2762 prout(_("You have smashed the Klingon invasion fleet and saved"))
2763 prout(_("the Federation."))
2768 badpt = 0.0 # Close enough!
2769 # killsPerDate >= RateMax
2770 if game.state.date-game.indate < 5.0 or \
2771 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2773 prout(_("In fact, you have done so well that Starfleet Command"))
2774 if game.skill == SKILL_NOVICE:
2775 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2776 elif game.skill == SKILL_FAIR:
2777 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2778 elif game.skill == SKILL_GOOD:
2779 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2780 elif game.skill == SKILL_EXPERT:
2781 prout(_("promotes you to Commodore Emeritus."))
2783 prout(_("Now that you think you're really good, try playing"))
2784 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2785 elif game.skill == SKILL_EMERITUS:
2787 proutn(_("Computer- "))
2788 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2790 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2792 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2794 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2796 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2798 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2800 prout(_("Now you can retire and write your own Star Trek game!"))
2802 elif game.skill >= SKILL_EXPERT:
2803 if game.thawed and not game.idebug:
2804 prout(_("You cannot get a citation, so..."))
2806 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2810 # Only grant long life if alive (original didn't!)
2812 prout(_("LIVE LONG AND PROSPER."))
2817 elif ifin == FDEPLETE: # Federation Resources Depleted
2818 prout(_("Your time has run out and the Federation has been"))
2819 prout(_("conquered. Your starship is now Klingon property,"))
2820 prout(_("and you are put on trial as a war criminal. On the"))
2821 proutn(_("basis of your record, you are "))
2822 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2823 prout(_("acquitted."))
2825 prout(_("LIVE LONG AND PROSPER."))
2827 prout(_("found guilty and"))
2828 prout(_("sentenced to death by slow torture."))
2832 elif ifin == FLIFESUP:
2833 prout(_("Your life support reserves have run out, and"))
2834 prout(_("you die of thirst, starvation, and asphyxiation."))
2835 prout(_("Your starship is a derelict in space."))
2837 prout(_("Your energy supply is exhausted."))
2839 prout(_("Your starship is a derelict in space."))
2840 elif ifin == FBATTLE:
2841 prout(_("The %s has been destroyed in battle.") % crmshp())
2843 prout(_("Dulce et decorum est pro patria mori."))
2845 prout(_("You have made three attempts to cross the negative energy"))
2846 prout(_("barrier which surrounds the galaxy."))
2848 prout(_("Your navigation is abominable."))
2851 prout(_("Your starship has been destroyed by a nova."))
2852 prout(_("That was a great shot."))
2854 elif ifin == FSNOVAED:
2855 prout(_("The %s has been fried by a supernova.") % crmshp())
2856 prout(_("...Not even cinders remain..."))
2857 elif ifin == FABANDN:
2858 prout(_("You have been captured by the Klingons. If you still"))
2859 prout(_("had a starbase to be returned to, you would have been"))
2860 prout(_("repatriated and given another chance. Since you have"))
2861 prout(_("no starbases, you will be mercilessly tortured to death."))
2862 elif ifin == FDILITHIUM:
2863 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2864 elif ifin == FMATERIALIZE:
2865 prout(_("Starbase was unable to re-materialize your starship."))
2866 prout(_("Sic transit gloria mundi"))
2867 elif ifin == FPHASER:
2868 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2870 prout(_("You and your landing party have been"))
2871 prout(_("converted to energy, disipating through space."))
2872 elif ifin == FMINING:
2873 prout(_("You are left with your landing party on"))
2874 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2876 prout(_("They are very fond of \"Captain Kirk\" soup."))
2878 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2879 elif ifin == FDPLANET:
2880 prout(_("You and your mining party perish."))
2882 prout(_("That was a great shot."))
2885 prout(_("The Galileo is instantly annihilated by the supernova."))
2886 prout(_("You and your mining party are atomized."))
2888 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2889 prout(_("joins the Romulans, wreaking terror on the Federation."))
2890 elif ifin == FPNOVA:
2891 prout(_("You and your mining party are atomized."))
2893 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2894 prout(_("joins the Romulans, wreaking terror on the Federation."))
2895 elif ifin == FSTRACTOR:
2896 prout(_("The shuttle craft Galileo is also caught,"))
2897 prout(_("and breaks up under the strain."))
2899 prout(_("Your debris is scattered for millions of miles."))
2900 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2902 prout(_("The mutants attack and kill Spock."))
2903 prout(_("Your ship is captured by Klingons, and"))
2904 prout(_("your crew is put on display in a Klingon zoo."))
2905 elif ifin == FTRIBBLE:
2906 prout(_("Tribbles consume all remaining water,"))
2907 prout(_("food, and oxygen on your ship."))
2909 prout(_("You die of thirst, starvation, and asphyxiation."))
2910 prout(_("Your starship is a derelict in space."))
2912 prout(_("Your ship is drawn to the center of the black hole."))
2913 prout(_("You are crushed into extremely dense matter."))
2915 prout(_("Your last crew member has died."))
2916 if game.ship == 'F':
2918 elif game.ship == 'E':
2921 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2922 goodies = game.state.remres/game.inresor
2923 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2924 if goodies/baddies >= randreal(1.0, 1.5):
2925 prout(_("As a result of your actions, a treaty with the Klingon"))
2926 prout(_("Empire has been signed. The terms of the treaty are"))
2927 if goodies/baddies >= randreal(3.0):
2928 prout(_("favorable to the Federation."))
2930 prout(_("Congratulations!"))
2932 prout(_("highly unfavorable to the Federation."))
2934 prout(_("The Federation will be destroyed."))
2936 prout(_("Since you took the last Klingon with you, you are a"))
2937 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2938 prout(_("statue in your memory. Rest in peace, and try not"))
2939 prout(_("to think about pigeons."))
2944 "Compute player's score."
2945 timused = game.state.date - game.indate
2946 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2948 game.perdate = killrate()
2949 ithperd = 500*game.perdate + 0.5
2952 iwon = 100*game.skill
2953 if game.ship == 'E':
2955 elif game.ship == 'F':
2959 game.score = 10*(game.inkling - game.state.remkl) \
2960 + 50*(game.incom - len(game.state.kcmdr)) \
2962 + 20*(game.inrom - game.state.nromrem) \
2963 + 200*(game.inscom - game.state.nscrem) \
2964 - game.state.nromrem \
2969 prout(_("Your score --"))
2970 if game.inrom - game.state.nromrem:
2971 prout(_("%6d Romulans destroyed %5d") %
2972 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
2973 if game.state.nromrem and game.gamewon:
2974 prout(_("%6d Romulans captured %5d") %
2975 (game.state.nromrem, game.state.nromrem))
2976 if game.inkling - game.state.remkl:
2977 prout(_("%6d ordinary Klingons destroyed %5d") %
2978 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
2979 if game.incom - len(game.state.kcmdr):
2980 prout(_("%6d Klingon commanders destroyed %5d") %
2981 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
2982 if game.inscom - game.state.nscrem:
2983 prout(_("%6d Super-Commander destroyed %5d") %
2984 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
2986 prout(_("%6.2f Klingons per stardate %5d") %
2987 (game.perdate, ithperd))
2988 if game.state.starkl:
2989 prout(_("%6d stars destroyed by your action %5d") %
2990 (game.state.starkl, -5*game.state.starkl))
2991 if game.state.nplankl:
2992 prout(_("%6d planets destroyed by your action %5d") %
2993 (game.state.nplankl, -10*game.state.nplankl))
2994 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
2995 prout(_("%6d inhabited planets destroyed by your action %5d") %
2996 (game.state.nworldkl, -300*game.state.nworldkl))
2997 if game.state.basekl:
2998 prout(_("%6d bases destroyed by your action %5d") %
2999 (game.state.basekl, -100*game.state.basekl))
3001 prout(_("%6d calls for help from starbase %5d") %
3002 (game.nhelp, -45*game.nhelp))
3004 prout(_("%6d casualties incurred %5d") %
3005 (game.casual, -game.casual))
3007 prout(_("%6d crew abandoned in space %5d") %
3008 (game.abandoned, -3*game.abandoned))
3010 prout(_("%6d ship(s) lost or destroyed %5d") %
3011 (klship, -100*klship))
3013 prout(_("Penalty for getting yourself killed -200"))
3015 proutn(_("Bonus for winning "))
3016 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3017 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3018 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3019 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3020 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3021 prout(" %5d" % iwon)
3023 prout(_("TOTAL SCORE %5d") % game.score)
3026 "Emit winner's commemmorative plaque."
3029 proutn(_("File or device name for your plaque: "))
3032 fp = open(winner, "w")
3035 prout(_("Invalid name."))
3037 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3039 # The 38 below must be 64 for 132-column paper
3040 nskip = 38 - len(winner)/2
3041 fp.write("\n\n\n\n")
3042 # --------DRAW ENTERPRISE PICTURE.
3043 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3044 fp.write(" EEE E : : : E\n" )
3045 fp.write(" EE EEE E : : NCC-1701 : E\n")
3046 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3047 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3048 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3049 fp.write(" EEEEEEE EEEEE E E E E\n")
3050 fp.write(" EEE E E E E\n")
3051 fp.write(" E E E E\n")
3052 fp.write(" EEEEEEEEEEEEE E E\n")
3053 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3054 fp.write(" :E : EEEE E\n")
3055 fp.write(" .-E -:----- E\n")
3056 fp.write(" :E : E\n")
3057 fp.write(" EE : EEEEEEEE\n")
3058 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3060 fp.write(_(" U. S. S. ENTERPRISE\n"))
3061 fp.write("\n\n\n\n")
3062 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3064 fp.write(_(" Starfleet Command bestows to you\n"))
3066 fp.write("%*s%s\n\n" % (nskip, "", winner))
3067 fp.write(_(" the rank of\n\n"))
3068 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3070 if game.skill == SKILL_EXPERT:
3071 fp.write(_(" Expert level\n\n"))
3072 elif game.skill == SKILL_EMERITUS:
3073 fp.write(_("Emeritus level\n\n"))
3075 fp.write(_(" Cheat level\n\n"))
3076 timestring = time.ctime()
3077 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3078 (timestring+4, timestring+20, timestring+11))
3079 fp.write(_(" Your score: %d\n\n") % game.score)
3080 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3083 # Code from io.c begins here
3085 rows = linecount = 0 # for paging
3088 fullscreen_window = None
3089 srscan_window = None
3090 report_window = None
3091 status_window = None
3092 lrscan_window = None
3093 message_window = None
3094 prompt_window = None
3099 "for some recent versions of python2, the following enables UTF8"
3100 "for the older ones we probably need to set C locale, and the python3"
3101 "has no problems at all"
3102 if sys.version_info[0] < 3:
3104 locale.setlocale(locale.LC_ALL, "")
3105 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3106 gettext.textdomain("sst")
3107 if not (game.options & OPTION_CURSES):
3108 ln_env = os.getenv("LINES")
3114 stdscr = curses.initscr()
3118 if game.options & OPTION_COLOR:
3119 curses.start_color()
3120 curses.use_default_colors()
3121 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3122 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3123 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3124 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3125 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3126 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3127 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3128 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3129 global fullscreen_window, srscan_window, report_window, status_window
3130 global lrscan_window, message_window, prompt_window
3131 (rows, columns) = stdscr.getmaxyx()
3132 fullscreen_window = stdscr
3133 srscan_window = curses.newwin(12, 25, 0, 0)
3134 report_window = curses.newwin(11, 0, 1, 25)
3135 status_window = curses.newwin(10, 0, 1, 39)
3136 lrscan_window = curses.newwin(5, 0, 0, 64)
3137 message_window = curses.newwin(0, 0, 12, 0)
3138 prompt_window = curses.newwin(1, 0, rows-2, 0)
3139 message_window.scrollok(True)
3140 setwnd(fullscreen_window)
3144 if game.options & OPTION_CURSES:
3145 stdscr.keypad(False)
3151 "Wait for user action -- OK to do nothing if on a TTY"
3152 if game.options & OPTION_CURSES:
3157 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3161 if game.skill > SKILL_FAIR:
3162 prompt = _("[CONTINUE?]")
3164 prompt = _("[PRESS ENTER TO CONTINUE]")
3166 if game.options & OPTION_CURSES:
3168 setwnd(prompt_window)
3169 prompt_window.clear()
3170 prompt_window.addstr(prompt)
3171 prompt_window.getstr()
3172 prompt_window.clear()
3173 prompt_window.refresh()
3174 setwnd(message_window)
3177 sys.stdout.write('\n')
3180 sys.stdout.write('\n' * rows)
3184 "Skip i lines. Pause game if this would cause a scrolling event."
3185 for dummy in range(i):
3186 if game.options & OPTION_CURSES:
3187 (y, x) = curwnd.getyx()
3190 except curses.error:
3195 if rows and linecount >= rows:
3198 sys.stdout.write('\n')
3201 "Utter a line with no following line feed."
3202 if game.options & OPTION_CURSES:
3203 (y, x) = curwnd.getyx()
3204 (my, mx) = curwnd.getmaxyx()
3205 if curwnd == message_window and y >= my - 2:
3211 sys.stdout.write(line)
3221 if not replayfp or replayfp.closed: # Don't slow down replays
3224 if game.options & OPTION_CURSES:
3228 if not replayfp or replayfp.closed:
3232 "Get a line of input."
3233 if game.options & OPTION_CURSES:
3234 line = curwnd.getstr() + "\n"
3237 if replayfp and not replayfp.closed:
3239 line = replayfp.readline()
3242 prout("*** Replay finished")
3245 elif line[0] != "#":
3248 line = raw_input() + "\n"
3254 "Change windows -- OK for this to be a no-op in tty mode."
3256 if game.options & OPTION_CURSES:
3258 curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window)
3261 "Clear to end of line -- can be a no-op in tty mode"
3262 if game.options & OPTION_CURSES:
3267 "Clear screen -- can be a no-op in tty mode."
3269 if game.options & OPTION_CURSES:
3275 def textcolor(color=DEFAULT):
3276 if game.options & OPTION_COLOR:
3277 if color == DEFAULT:
3279 elif color == BLACK:
3280 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3282 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3283 elif color == GREEN:
3284 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3286 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3288 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3289 elif color == MAGENTA:
3290 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3291 elif color == BROWN:
3292 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3293 elif color == LIGHTGRAY:
3294 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3295 elif color == DARKGRAY:
3296 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3297 elif color == LIGHTBLUE:
3298 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3299 elif color == LIGHTGREEN:
3300 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3301 elif color == LIGHTCYAN:
3302 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3303 elif color == LIGHTRED:
3304 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3305 elif color == LIGHTMAGENTA:
3306 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3307 elif color == YELLOW:
3308 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3309 elif color == WHITE:
3310 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3313 if game.options & OPTION_COLOR:
3314 curwnd.attron(curses.A_REVERSE)
3317 # Things past this point have policy implications.
3321 "Hook to be called after moving to redraw maps."
3322 if game.options & OPTION_CURSES:
3325 setwnd(srscan_window)
3329 setwnd(status_window)
3330 status_window.clear()
3331 status_window.move(0, 0)
3332 setwnd(report_window)
3333 report_window.clear()
3334 report_window.move(0, 0)
3336 setwnd(lrscan_window)
3337 lrscan_window.clear()
3338 lrscan_window.move(0, 0)
3339 lrscan(silent=False)
3341 def put_srscan_sym(w, sym):
3342 "Emit symbol for short-range scan."
3343 srscan_window.move(w.i+1, w.j*2+2)
3344 srscan_window.addch(sym)
3345 srscan_window.refresh()
3348 "Enemy fall down, go boom."
3349 if game.options & OPTION_CURSES:
3351 setwnd(srscan_window)
3352 srscan_window.attron(curses.A_REVERSE)
3353 put_srscan_sym(w, game.quad[w.i][w.j])
3357 srscan_window.attroff(curses.A_REVERSE)
3358 put_srscan_sym(w, game.quad[w.i][w.j])
3359 curses.delay_output(500)
3360 setwnd(message_window)
3363 "Sound and visual effects for teleportation."
3364 if game.options & OPTION_CURSES:
3366 setwnd(message_window)
3368 prouts(" . . . . . ")
3369 if game.options & OPTION_CURSES:
3370 #curses.delay_output(1000)
3374 def tracktorpedo(w, step, i, n, iquad):
3375 "Torpedo-track animation."
3376 if not game.options & OPTION_CURSES:
3380 proutn(_("Track for torpedo number %d- ") % (i+1))
3383 proutn(_("Torpedo track- "))
3384 elif step==4 or step==9:
3388 if not damaged(DSRSENS) or game.condition=="docked":
3389 if i != 0 and step == 1:
3392 if (iquad=='.') or (iquad==' '):
3393 put_srscan_sym(w, '+')
3397 put_srscan_sym(w, iquad)
3399 curwnd.attron(curses.A_REVERSE)
3400 put_srscan_sym(w, iquad)
3404 curwnd.attroff(curses.A_REVERSE)
3405 put_srscan_sym(w, iquad)
3410 "Display the current galaxy chart."
3411 if game.options & OPTION_CURSES:
3412 setwnd(message_window)
3413 message_window.clear()
3415 if game.options & OPTION_TTY:
3420 def prstat(txt, data):
3422 if game.options & OPTION_CURSES:
3424 setwnd(status_window)
3426 proutn(" " * (NSYM - len(txt)))
3429 if game.options & OPTION_CURSES:
3430 setwnd(report_window)
3432 # Code from moving.c begins here
3434 def imove(icourse=None, noattack=False):
3435 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3438 def newquadrant(noattack):
3439 # Leaving quadrant -- allow final enemy attack
3440 # Don't do it if being pushed by Nova
3441 if len(game.enemies) != 0 and not noattack:
3443 for enemy in game.enemies:
3444 finald = (w - enemy.location).distance()
3445 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3446 # Stas Sergeev added the condition
3447 # that attacks only happen if Klingons
3448 # are present and your skill is good.
3449 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3450 attack(torps_ok=False)
3453 # check for edge of galaxy
3457 if icourse.final.i < 0:
3458 icourse.final.i = -icourse.final.i
3460 if icourse.final.j < 0:
3461 icourse.final.j = -icourse.final.j
3463 if icourse.final.i >= GALSIZE*QUADSIZE:
3464 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3466 if icourse.final.j >= GALSIZE*QUADSIZE:
3467 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3475 if game.nkinks == 3:
3476 # Three strikes -- you're out!
3480 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3481 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3482 prout(_("YOU WILL BE DESTROYED."))
3483 # Compute final position in new quadrant
3484 if trbeam: # Don't bother if we are to be beamed
3486 game.quadrant = icourse.final.quadrant()
3487 game.sector = icourse.final.sector()
3489 prout(_("Entering Quadrant %s.") % game.quadrant)
3490 game.quad[game.sector.i][game.sector.j] = game.ship
3492 if game.skill>SKILL_NOVICE:
3493 attack(torps_ok=False)
3495 def check_collision(h):
3496 iquad = game.quad[h.i][h.j]
3498 # object encountered in flight path
3499 stopegy = 50.0*icourse.distance/game.optime
3500 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3501 for enemy in game.enemies:
3502 if enemy.location == game.sector:
3504 collision(rammed=False, enemy=enemy)
3508 prouts(_("***RED ALERT! RED ALERT!"))
3510 proutn("***" + crmshp())
3511 proutn(_(" pulled into black hole at Sector %s") % h)
3512 # Getting pulled into a black hole was certain
3513 # death in Almy's original. Stas Sergeev added a
3514 # possibility that you'll get timewarped instead.
3516 for m in range(NDEVICES):
3517 if game.damage[m]>0:
3519 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3520 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3530 prout(_(" encounters Tholian web at %s;") % h)
3532 prout(_(" blocked by object at %s;") % h)
3533 proutn(_("Emergency stop required "))
3534 prout(_("%2d units of energy.") % int(stopegy))
3535 game.energy -= stopegy
3536 if game.energy <= 0:
3543 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3544 game.inorbit = False
3545 # If tractor beam is to occur, don't move full distance
3546 if game.state.date+game.optime >= scheduled(FTBEAM):
3548 game.condition = "red"
3549 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3550 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3552 game.quad[game.sector.i][game.sector.j] = '.'
3553 for m in range(icourse.moves):
3555 w = icourse.sector()
3556 if icourse.origin.quadrant() != icourse.location.quadrant():
3557 newquadrant(noattack)
3559 elif check_collision(w):
3560 print "Collision detected"
3564 # We're in destination quadrant -- compute new average enemy distances
3565 game.quad[game.sector.i][game.sector.j] = game.ship
3567 for enemy in game.enemies:
3568 finald = (w-enemy.location).distance()
3569 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3570 enemy.kdist = finald
3572 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3573 attack(torps_ok=False)
3574 for enemy in game.enemies:
3575 enemy.kavgd = enemy.kdist
3578 setwnd(message_window)
3582 "Dock our ship at a starbase."
3584 if game.condition == "docked" and verbose:
3585 prout(_("Already docked."))
3588 prout(_("You must first leave standard orbit."))
3590 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3591 prout(crmshp() + _(" not adjacent to base."))
3593 game.condition = "docked"
3597 if game.energy < game.inenrg:
3598 game.energy = game.inenrg
3599 game.shield = game.inshld
3600 game.torps = game.intorps
3601 game.lsupres = game.inlsr
3602 game.state.crew = FULLCREW
3603 if not damaged(DRADIO) and \
3604 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3605 # get attack report from base
3606 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3610 def cartesian(loc1=None, loc2=None):
3612 return game.quadrant * QUADSIZE + game.sector
3614 return game.quadrant * QUADSIZE + loc1
3616 return loc1 * QUADSIZE + loc2
3618 def getcourse(isprobe):
3619 "Get a course and distance from the user."
3621 dquad = copy.copy(game.quadrant)
3622 navmode = "unspecified"
3626 if game.landed and not isprobe:
3627 prout(_("Dummy! You can't leave standard orbit until you"))
3628 proutn(_("are back aboard the ship."))
3631 while navmode == "unspecified":
3632 if damaged(DNAVSYS):
3634 prout(_("Computer damaged; manual navigation only"))
3636 prout(_("Computer damaged; manual movement only"))
3641 key = scanner.next()
3643 proutn(_("Manual or automatic- "))
3646 elif key == "IHALPHA":
3647 if scanner.sees("manual"):
3649 key = scanner.next()
3651 elif scanner.sees("automatic"):
3652 navmode = "automatic"
3653 key = scanner.next()
3661 prout(_("(Manual navigation assumed.)"))
3663 prout(_("(Manual movement assumed.)"))
3667 if navmode == "automatic":
3668 while key == "IHEOL":
3670 proutn(_("Target quadrant or quadrant§or- "))
3672 proutn(_("Destination sector or quadrant§or- "))
3675 key = scanner.next()
3679 xi = int(round(scanner.real))-1
3680 key = scanner.next()
3684 xj = int(round(scanner.real))-1
3685 key = scanner.next()
3687 # both quadrant and sector specified
3688 xk = int(round(scanner.real))-1
3689 key = scanner.next()
3693 xl = int(round(scanner.real))-1
3699 # only one pair of numbers was specified
3701 # only quadrant specified -- go to center of dest quad
3704 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3706 # only sector specified
3710 if not dquad.valid_quadrant() or not dsect.valid_sector():
3717 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3719 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3720 # the actual deltas get computed here
3721 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3722 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3724 while key == "IHEOL":
3725 proutn(_("X and Y displacements- "))
3728 key = scanner.next()
3733 delta.j = scanner.real
3734 key = scanner.next()
3738 delta.i = scanner.real
3739 # Check for zero movement
3740 if delta.i == 0 and delta.j == 0:
3743 if itemp == "verbose" and not isprobe:
3745 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3747 return course(bearing=delta.bearing(), distance=delta.distance())
3750 def __init__(self, bearing, distance, origin=None):
3751 self.distance = distance
3752 self.bearing = bearing
3754 self.origin = cartesian(game.quadrant, game.sector)
3756 self.origin = origin
3757 # The bearing() code we inherited from FORTRAN is actually computing
3758 # clockface directions!
3759 if self.bearing < 0.0:
3760 self.bearing += 12.0
3761 self.angle = ((15.0 - self.bearing) * 0.5235988)
3763 self.origin = cartesian(game.quadrant, game.sector)
3765 self.origin = cartesian(game.quadrant, origin)
3766 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
3767 bigger = max(abs(self.increment.i), abs(self.increment.j))
3768 self.increment /= bigger
3769 self.moves = int(round(10*self.distance*bigger))
3771 self.final = (self.location + self.moves*self.increment).roundtogrid()
3773 self.location = self.origin
3776 return self.location.roundtogrid() == self.final
3778 "Next step on course."
3780 self.nextlocation = self.location + self.increment
3781 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3782 self.location = self.nextlocation
3785 return self.location.quadrant()
3787 return self.location.sector()
3788 def power(self, warp):
3789 return self.distance*(warp**3)*(game.shldup+1)
3790 def time(self, warp):
3791 return 10.0*self.distance/warp**2
3794 "Move under impulse power."
3796 if damaged(DIMPULS):
3799 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3801 if game.energy > 30.0:
3803 course = getcourse(isprobe=False)
3806 power = 20.0 + 100.0*course.distance
3809 if power >= game.energy:
3810 # Insufficient power for trip
3812 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3813 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3814 if game.energy > 30:
3815 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3816 int(0.01 * (game.energy-20.0)-0.05))
3817 prout(_(" quadrants.\""))
3819 prout(_("quadrant. They are, therefore, useless.\""))
3822 # Make sure enough time is left for the trip
3823 game.optime = course.dist/0.095
3824 if game.optime >= game.state.remtime:
3825 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3826 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3827 proutn(_("we dare spend the time?\" "))
3830 # Activate impulse engines and pay the cost
3831 imove(course, noattack=False)
3835 power = 20.0 + 100.0*course.dist
3836 game.energy -= power
3837 game.optime = course.dist/0.095
3838 if game.energy <= 0:
3842 def warp(wcourse, involuntary):
3843 "ove under warp drive."
3844 blooey = False; twarp = False
3845 if not involuntary: # Not WARPX entry
3847 if game.damage[DWARPEN] > 10.0:
3850 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3852 if damaged(DWARPEN) and game.warpfac > 4.0:
3855 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3856 prout(_(" is repaired, I can only give you warp 4.\""))
3858 # Read in course and distance
3861 wcourse = getcourse(isprobe=False)
3864 # Make sure starship has enough energy for the trip
3865 # Note: this formula is slightly different from the C version,
3866 # and lets you skate a bit closer to the edge.
3867 if wcourse.power(game.warpfac) >= game.energy:
3868 # Insufficient power for trip
3871 prout(_("Engineering to bridge--"))
3872 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
3873 iwarp = (game.energy/(wcourse.dist+0.05)) ** 0.333333333
3875 prout(_("We can't do it, Captain. We don't have enough energy."))
3877 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3880 prout(_("if you'll lower the shields."))
3884 prout(_("We haven't the energy to go that far with the shields up."))
3886 # Make sure enough time is left for the trip
3887 game.optime = wcourse.time(game.warpfac)
3888 if game.optime >= 0.8*game.state.remtime:
3890 prout(_("First Officer Spock- \"Captain, I compute that such"))
3891 proutn(_(" a trip would require approximately %2.0f") %
3892 (100.0*game.optime/game.state.remtime))
3893 prout(_(" percent of our"))
3894 proutn(_(" remaining time. Are you sure this is wise?\" "))
3900 if game.warpfac > 6.0:
3901 # Decide if engine damage will occur
3902 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3903 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
3904 if prob > randreal():
3906 wcourse.distance = randreal(wcourse.distance)
3907 # Decide if time warp will occur
3908 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3910 if game.idebug and game.warpfac==10 and not twarp:
3912 proutn("=== Force time warp? ")
3916 # If time warp or engine damage, check path
3917 # If it is obstructed, don't do warp or damage
3918 look = wcourse.moves
3922 w = wcourse.sector()
3923 if not w.valid_sector():
3925 if game.quad[w.i][w.j] != '.':
3929 # Activate Warp Engines and pay the cost
3930 imove(wcourse, noattack=False)
3933 game.energy -= wcourse.power(game.warpfac)
3934 if game.energy <= 0:
3936 game.optime = wcourse.time(game.warpfac)
3940 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
3942 prout(_("Engineering to bridge--"))
3943 prout(_(" Scott here. The warp engines are damaged."))
3944 prout(_(" We'll have to reduce speed to warp 4."))
3949 "Change the warp factor."
3955 proutn(_("Warp factor- "))
3959 if game.damage[DWARPEN] > 10.0:
3960 prout(_("Warp engines inoperative."))
3962 if damaged(DWARPEN) and scanner.real > 4.0:
3963 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
3964 prout(_(" but right now we can only go warp 4.\""))
3966 if scanner.real > 10.0:
3967 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
3969 if scanner.real < 1.0:
3970 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
3972 oldfac = game.warpfac
3973 game.warpfac = scanner.real
3974 if game.warpfac <= oldfac or game.warpfac <= 6.0:
3975 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
3978 if game.warpfac < 8.00:
3979 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
3981 if game.warpfac == 10.0:
3982 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
3984 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
3988 "Cope with being tossed out of quadrant by supernova or yanked by beam."
3990 # is captain on planet?
3992 if damaged(DTRANSP):
3995 prout(_("Scotty rushes to the transporter controls."))
3997 prout(_("But with the shields up it's hopeless."))
3999 prouts(_("His desperate attempt to rescue you . . ."))
4004 prout(_("SUCCEEDS!"))
4007 proutn(_("The crystals mined were "))
4015 # Check to see if captain in shuttle craft
4020 # Inform captain of attempt to reach safety
4024 prouts(_("***RED ALERT! RED ALERT!"))
4026 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4027 prouts(_(" a supernova."))
4029 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4030 prout(_("safely out of quadrant."))
4031 if not damaged(DRADIO):
4032 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4033 # Try to use warp engines
4034 if damaged(DWARPEN):
4036 prout(_("Warp engines damaged."))
4039 game.warpfac = randreal(6.0, 8.0)
4040 prout(_("Warp factor set to %d") % int(game.warpfac))
4041 power = 0.75*game.energy
4042 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4043 dist = max(dist, randreal(math.sqrt(2)))
4044 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4045 game.optime = bugout.time(game.warpfac)
4047 game.inorbit = False
4048 warp(bugout, involuntary=True)
4050 # This is bad news, we didn't leave quadrant.
4054 prout(_("Insufficient energy to leave quadrant."))
4057 # Repeat if another snova
4058 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4060 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4061 finish(FWON) # Snova killed remaining enemy.
4064 "Let's do the time warp again."
4065 prout(_("***TIME WARP ENTERED."))
4066 if game.state.snap and withprob(0.5):
4068 prout(_("You are traveling backwards in time %d stardates.") %
4069 int(game.state.date-game.snapsht.date))
4070 game.state = game.snapsht
4071 game.state.snap = False
4072 if len(game.state.kcmdr):
4073 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4074 schedule(FBATTAK, expran(0.3*game.intime))
4075 schedule(FSNOVA, expran(0.5*game.intime))
4076 # next snapshot will be sooner
4077 schedule(FSNAP, expran(0.25*game.state.remtime))
4079 if game.state.nscrem:
4080 schedule(FSCMOVE, 0.2777)
4084 game.battle.invalidate()
4085 # Make sure Galileo is consistant -- Snapshot may have been taken
4086 # when on planet, which would give us two Galileos!
4088 for l in range(game.inplan):
4089 if game.state.planets[l].known == "shuttle_down":
4091 if game.iscraft == "onship" and game.ship=='E':
4092 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4093 game.iscraft = "offship"
4094 # Likewise, if in the original time the Galileo was abandoned, but
4095 # was on ship earlier, it would have vanished -- let's restore it.
4096 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4097 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4098 game.iscraft = "onship"
4099 # There used to be code to do the actual reconstrction here,
4100 # but the starchart is now part of the snapshotted galaxy state.
4101 prout(_("Spock has reconstructed a correct star chart from memory"))
4103 # Go forward in time
4104 game.optime = expran(0.5*game.intime)
4105 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4106 # cheat to make sure no tractor beams occur during time warp
4107 postpone(FTBEAM, game.optime)
4108 game.damage[DRADIO] += game.optime
4110 events() # Stas Sergeev added this -- do pending events
4113 "Launch deep-space probe."
4114 # New code to launch a deep space probe
4115 if game.nprobes == 0:
4118 if game.ship == 'E':
4119 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4121 prout(_("Ye Faerie Queene has no deep space probes."))
4126 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4128 if is_scheduled(FDSPROB):
4131 if damaged(DRADIO) and game.condition != "docked":
4132 prout(_("Spock- \"Records show the previous probe has not yet"))
4133 prout(_(" reached its destination.\""))
4135 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4137 key = scanner.next()
4139 if game.nprobes == 1:
4140 prout(_("1 probe left."))
4142 prout(_("%d probes left") % game.nprobes)
4143 proutn(_("Are you sure you want to fire a probe? "))
4146 game.isarmed = False
4147 if key == "IHALPHA" and scanner.token == "armed":
4149 key = scanner.next()
4150 elif key == "IHEOL":
4151 proutn(_("Arm NOVAMAX warhead? "))
4153 elif key == "IHREAL": # first element of course
4154 scanner.push(scanner.token)
4156 game.probe = getcourse(isprobe=True)
4160 schedule(FDSPROB, 0.01) # Time to move one sector
4161 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4166 "Yell for help from nearest starbase."
4167 # There's more than one way to move in this game!
4169 # Test for conditions which prevent calling for help
4170 if game.condition == "docked":
4171 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4174 prout(_("Subspace radio damaged."))
4176 if not game.state.baseq:
4177 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4180 prout(_("You must be aboard the %s.") % crmshp())
4182 # OK -- call for help from nearest starbase
4185 # There's one in this quadrant
4186 ddist = (game.base - game.sector).distance()
4189 for ibq in game.state.baseq:
4190 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4193 # Since starbase not in quadrant, set up new quadrant
4196 # dematerialize starship
4197 game.quad[game.sector.i][game.sector.j]='.'
4198 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4199 % (game.quadrant, crmshp()))
4200 game.sector.invalidate()
4201 for m in range(1, 5+1):
4202 w = game.base.scatter()
4203 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4204 # found one -- finish up
4207 if not game.sector.is_valid():
4208 prout(_("You have been lost in space..."))
4209 finish(FMATERIALIZE)
4211 # Give starbase three chances to rematerialize starship
4212 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4213 for m in range(1, 3+1):
4214 if m == 1: proutn(_("1st"))
4215 elif m == 2: proutn(_("2nd"))
4216 elif m == 3: proutn(_("3rd"))
4217 proutn(_(" attempt to re-materialize ") + crmshp())
4218 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4221 if randreal() > probf:
4225 curses.delay_output(500)
4227 game.quad[game.sector.i][game.sector.j]='?'
4230 setwnd(message_window)
4231 finish(FMATERIALIZE)
4233 game.quad[game.sector.i][game.sector.j]=game.ship
4235 prout(_("succeeds."))
4239 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4244 if game.condition=="docked":
4246 prout(_("You cannot abandon Ye Faerie Queene."))
4249 # Must take shuttle craft to exit
4250 if game.damage[DSHUTTL]==-1:
4251 prout(_("Ye Faerie Queene has no shuttle craft."))
4253 if game.damage[DSHUTTL]<0:
4254 prout(_("Shuttle craft now serving Big Macs."))
4256 if game.damage[DSHUTTL]>0:
4257 prout(_("Shuttle craft damaged."))
4260 prout(_("You must be aboard the ship."))
4262 if game.iscraft != "onship":
4263 prout(_("Shuttle craft not currently available."))
4265 # Emit abandon ship messages
4267 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4269 prouts(_("***ALL HANDS ABANDON SHIP!"))
4271 prout(_("Captain and crew escape in shuttle craft."))
4272 if not game.state.baseq:
4273 # Oops! no place to go...
4276 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4278 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4279 prout(_("Remainder of ship's complement beam down"))
4280 prout(_("to nearest habitable planet."))
4281 elif q.planet != None and not damaged(DTRANSP):
4282 prout(_("Remainder of ship's complement beam down to %s.") %
4285 prout(_("Entire crew of %d left to die in outer space.") %
4287 game.casual += game.state.crew
4288 game.abandoned += game.state.crew
4289 # If at least one base left, give 'em the Faerie Queene
4291 game.icrystl = False # crystals are lost
4292 game.nprobes = 0 # No probes
4293 prout(_("You are captured by Klingons and released to"))
4294 prout(_("the Federation in a prisoner-of-war exchange."))
4295 nb = randrange(len(game.state.baseq))
4296 # Set up quadrant and position FQ adjacient to base
4297 if not game.quadrant == game.state.baseq[nb]:
4298 game.quadrant = game.state.baseq[nb]
4299 game.sector.i = game.sector.j = 5
4302 # position next to base by trial and error
4303 game.quad[game.sector.i][game.sector.j] = '.'
4304 for l in range(QUADSIZE):
4305 game.sector = game.base.scatter()
4306 if game.sector.valid_sector() and \
4307 game.quad[game.sector.i][game.sector.j] == '.':
4310 break # found a spot
4311 game.sector.i=QUADSIZE/2
4312 game.sector.j=QUADSIZE/2
4314 # Get new commission
4315 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4316 game.state.crew = FULLCREW
4317 prout(_("Starfleet puts you in command of another ship,"))
4318 prout(_("the Faerie Queene, which is antiquated but,"))
4319 prout(_("still useable."))
4321 prout(_("The dilithium crystals have been moved."))
4323 game.iscraft = "offship" # Galileo disappears
4325 game.condition="docked"
4326 for l in range(NDEVICES):
4327 game.damage[l] = 0.0
4328 game.damage[DSHUTTL] = -1
4329 game.energy = game.inenrg = 3000.0
4330 game.shield = game.inshld = 1250.0
4331 game.torps = game.intorps = 6
4332 game.lsupres=game.inlsr=3.0
4337 # Code from planets.c begins here.
4340 "Abort a lengthy operation if an event interrupts it."
4343 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4348 "Report on (uninhabited) planets in the galaxy."
4352 prout(_("Spock- \"Planet report follows, Captain.\""))
4354 for i in range(game.inplan):
4355 if game.state.planets[i].pclass == "destroyed":
4357 if (game.state.planets[i].known != "unknown" \
4358 and not game.state.planets[i].inhabited) \
4361 if game.idebug and game.state.planets[i].known=="unknown":
4362 proutn("(Unknown) ")
4363 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4364 proutn(_(" class "))
4365 proutn(game.state.planets[i].pclass)
4367 if game.state.planets[i].crystals != "present":
4369 prout(_("dilithium crystals present."))
4370 if game.state.planets[i].known=="shuttle_down":
4371 prout(_(" Shuttle Craft Galileo on surface."))
4373 prout(_("No information available."))
4376 "Enter standard orbit."
4380 prout(_("Already in standard orbit."))
4382 if damaged(DWARPEN) and damaged(DIMPULS):
4383 prout(_("Both warp and impulse engines damaged."))
4385 if not game.plnet.is_valid():
4386 prout("There is no planet in this sector.")
4388 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4389 prout(crmshp() + _(" not adjacent to planet."))
4392 game.optime = randreal(0.02, 0.05)
4393 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4397 game.height = randreal(1400, 8600)
4398 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4403 "Examine planets in this quadrant."
4404 if damaged(DSRSENS):
4405 if game.options & OPTION_TTY:
4406 prout(_("Short range sensors damaged."))
4408 if game.iplnet == None:
4409 if game.options & OPTION_TTY:
4410 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4412 if game.iplnet.known == "unknown":
4413 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4415 prout(_(" Planet at Sector %s is of class %s.") %
4416 (game.plnet, game.iplnet.pclass))
4417 if game.iplnet.known=="shuttle_down":
4418 prout(_(" Sensors show Galileo still on surface."))
4419 proutn(_(" Readings indicate"))
4420 if game.iplnet.crystals != "present":
4422 prout(_(" dilithium crystals present.\""))
4423 if game.iplnet.known == "unknown":
4424 game.iplnet.known = "known"
4425 elif game.iplnet.inhabited:
4426 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4427 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4430 "Use the transporter."
4434 if damaged(DTRANSP):
4435 prout(_("Transporter damaged."))
4436 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4438 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4442 if not game.inorbit:
4443 prout(crmshp() + _(" not in standard orbit."))
4446 prout(_("Impossible to transport through shields."))
4448 if game.iplnet.known=="unknown":
4449 prout(_("Spock- \"Captain, we have no information on this planet"))
4450 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4451 prout(_(" you may not go down.\""))
4453 if not game.landed and game.iplnet.crystals=="absent":
4454 prout(_("Spock- \"Captain, I fail to see the logic in"))
4455 prout(_(" exploring a planet with no dilithium crystals."))
4456 proutn(_(" Are you sure this is wise?\" "))
4460 if not (game.options & OPTION_PLAIN):
4461 nrgneed = 50 * game.skill + game.height / 100.0
4462 if nrgneed > game.energy:
4463 prout(_("Engineering to bridge--"))
4464 prout(_(" Captain, we don't have enough energy for transportation."))
4466 if not game.landed and nrgneed * 2 > game.energy:
4467 prout(_("Engineering to bridge--"))
4468 prout(_(" Captain, we have enough energy only to transport you down to"))
4469 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4470 if game.iplnet.known == "shuttle_down":
4471 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4472 proutn(_(" Are you sure this is wise?\" "))
4477 # Coming from planet
4478 if game.iplnet.known=="shuttle_down":
4479 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4483 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4484 prout(_("Landing party assembled, ready to beam up."))
4486 prout(_("Kirk whips out communicator..."))
4487 prouts(_("BEEP BEEP BEEP"))
4489 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4492 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4494 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4496 prout(_("Kirk- \"Energize.\""))
4499 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4502 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4504 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4507 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4508 game.landed = not game.landed
4509 game.energy -= nrgneed
4511 prout(_("Transport complete."))
4512 if game.landed and game.iplnet.known=="shuttle_down":
4513 prout(_("The shuttle craft Galileo is here!"))
4514 if not game.landed and game.imine:
4521 "Strip-mine a world for dilithium."
4525 prout(_("Mining party not on planet."))
4527 if game.iplnet.crystals == "mined":
4528 prout(_("This planet has already been strip-mined for dilithium."))
4530 elif game.iplnet.crystals == "absent":
4531 prout(_("No dilithium crystals on this planet."))
4534 prout(_("You've already mined enough crystals for this trip."))
4536 if game.icrystl and game.cryprob == 0.05:
4537 prout(_("With all those fresh crystals aboard the ") + crmshp())
4538 prout(_("there's no reason to mine more at this time."))
4540 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4543 prout(_("Mining operation complete."))
4544 game.iplnet.crystals = "mined"
4545 game.imine = game.ididit = True
4548 "Use dilithium crystals."
4552 if not game.icrystl:
4553 prout(_("No dilithium crystals available."))
4555 if game.energy >= 1000:
4556 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4557 prout(_(" except when Condition Yellow exists."))
4559 prout(_("Spock- \"Captain, I must warn you that loading"))
4560 prout(_(" raw dilithium crystals into the ship's power"))
4561 prout(_(" system may risk a severe explosion."))
4562 proutn(_(" Are you sure this is wise?\" "))
4567 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4568 prout(_(" Mr. Spock and I will try it.\""))
4570 prout(_("Spock- \"Crystals in place, Sir."))
4571 prout(_(" Ready to activate circuit.\""))
4573 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4575 if withprob(game.cryprob):
4576 prouts(_(" \"Activating now! - - No good! It's***"))
4578 prouts(_("***RED ALERT! RED A*L********************************"))
4581 prouts(_("****************** KA-BOOM!!!! *******************"))
4585 game.energy += randreal(5000.0, 5500.0)
4586 prouts(_(" \"Activating now! - - "))
4587 prout(_("The instruments"))
4588 prout(_(" are going crazy, but I think it's"))
4589 prout(_(" going to work!! Congratulations, Sir!\""))
4594 "Use shuttlecraft for planetary jaunt."
4597 if damaged(DSHUTTL):
4598 if game.damage[DSHUTTL] == -1.0:
4599 if game.inorbit and game.iplnet.known == "shuttle_down":
4600 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4602 prout(_("Ye Faerie Queene had no shuttle craft."))
4603 elif game.damage[DSHUTTL] > 0:
4604 prout(_("The Galileo is damaged."))
4605 else: # game.damage[DSHUTTL] < 0
4606 prout(_("Shuttle craft is now serving Big Macs."))
4608 if not game.inorbit:
4609 prout(crmshp() + _(" not in standard orbit."))
4611 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4612 prout(_("Shuttle craft not currently available."))
4614 if not game.landed and game.iplnet.known=="shuttle_down":
4615 prout(_("You will have to beam down to retrieve the shuttle craft."))
4617 if game.shldup or game.condition == "docked":
4618 prout(_("Shuttle craft cannot pass through shields."))
4620 if game.iplnet.known=="unknown":
4621 prout(_("Spock- \"Captain, we have no information on this planet"))
4622 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4623 prout(_(" you may not fly down.\""))
4625 game.optime = 3.0e-5*game.height
4626 if game.optime >= 0.8*game.state.remtime:
4627 prout(_("First Officer Spock- \"Captain, I compute that such"))
4628 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4629 int(100*game.optime/game.state.remtime))
4630 prout(_("remaining time."))
4631 proutn(_("Are you sure this is wise?\" "))
4637 if game.iscraft == "onship":
4639 if not damaged(DTRANSP):
4640 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4644 proutn(_("Shuttle crew"))
4646 proutn(_("Rescue party"))
4647 prout(_(" boards Galileo and swoops toward planet surface."))
4648 game.iscraft = "offship"
4652 game.iplnet.known="shuttle_down"
4653 prout(_("Trip complete."))
4656 # Ready to go back to ship
4657 prout(_("You and your mining party board the"))
4658 prout(_("shuttle craft for the trip back to the Enterprise."))
4660 prouts(_("The short hop begins . . ."))
4662 game.iplnet.known="known"
4668 game.iscraft = "onship"
4674 prout(_("Trip complete."))
4677 # Kirk on ship and so is Galileo
4678 prout(_("Mining party assembles in the hangar deck,"))
4679 prout(_("ready to board the shuttle craft \"Galileo\"."))
4681 prouts(_("The hangar doors open; the trip begins."))
4684 game.iscraft = "offship"
4687 game.iplnet.known = "shuttle_down"
4690 prout(_("Trip complete."))
4694 "Use the big zapper."
4698 if game.ship != 'E':
4699 prout(_("Ye Faerie Queene has no death ray."))
4701 if len(game.enemies)==0:
4702 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4705 prout(_("Death Ray is damaged."))
4707 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4708 prout(_(" is highly unpredictible. Considering the alternatives,"))
4709 proutn(_(" are you sure this is wise?\" "))
4712 prout(_("Spock- \"Acknowledged.\""))
4715 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4717 prout(_("Crew scrambles in emergency preparation."))
4718 prout(_("Spock and Scotty ready the death ray and"))
4719 prout(_("prepare to channel all ship's power to the device."))
4721 prout(_("Spock- \"Preparations complete, sir.\""))
4722 prout(_("Kirk- \"Engage!\""))
4724 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4727 if game.options & OPTION_PLAIN:
4731 prouts(_("Sulu- \"Captain! It's working!\""))
4733 while len(game.enemies) > 0:
4734 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4735 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4736 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4738 if (game.options & OPTION_PLAIN) == 0:
4739 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4741 prout(_(" is still operational.\""))
4743 prout(_(" has been rendered nonfunctional.\""))
4744 game.damage[DDRAY] = 39.95
4746 r = randreal() # Pick failure method
4748 prouts(_("Sulu- \"Captain! It's working!\""))
4750 prouts(_("***RED ALERT! RED ALERT!"))
4752 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4754 prouts(_("***RED ALERT! RED A*L********************************"))
4757 prouts(_("****************** KA-BOOM!!!! *******************"))
4762 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4764 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4766 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4767 prout(_(" have apparently been transformed into strange mutations."))
4768 prout(_(" Vulcans do not seem to be affected."))
4770 prout(_("Kirk- \"Raauch! Raauch!\""))
4774 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4776 proutn(_("Spock- \"I believe the word is"))
4777 prouts(_(" *ASTONISHING*"))
4778 prout(_(" Mr. Sulu."))
4779 for i in range(QUADSIZE):
4780 for j in range(QUADSIZE):
4781 if game.quad[i][j] == '.':
4782 game.quad[i][j] = '?'
4783 prout(_(" Captain, our quadrant is now infested with"))
4784 prouts(_(" - - - - - - *THINGS*."))
4786 prout(_(" I have no logical explanation.\""))
4788 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4790 prout(_("Scotty- \"There are so many tribbles down here"))
4791 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4795 # Code from reports.c begins here
4797 def attackreport(curt):
4798 "eport status of bases under attack."
4800 if is_scheduled(FCDBAS):
4801 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4802 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4803 elif game.isatb == 1:
4804 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4805 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4807 prout(_("No Starbase is currently under attack."))
4809 if is_scheduled(FCDBAS):
4810 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4812 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4816 # report on general game status
4818 s1 = (game.thawed and _("thawed ")) or ""
4819 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4820 s3 = (None, _("novice"), _("fair"),
4821 _("good"), _("expert"), _("emeritus"))[game.skill]
4822 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4823 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4824 prout(_("No plaque is allowed."))
4826 prout(_("This is tournament game %d.") % game.tourn)
4827 prout(_("Your secret password is \"%s\"") % game.passwd)
4828 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4829 (game.inkling + game.incom + game.inscom)))
4830 if game.incom - len(game.state.kcmdr):
4831 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4832 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4833 prout(_(", but no Commanders."))
4836 if game.skill > SKILL_FAIR:
4837 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4838 if len(game.state.baseq) != game.inbase:
4840 if game.inbase-len(game.state.baseq)==1:
4841 proutn(_("has been 1 base"))
4843 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4844 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4846 prout(_("There are %d bases.") % game.inbase)
4847 if communicating() or game.iseenit:
4848 # Don't report this if not seen and
4849 # either the radio is dead or not at base!
4853 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4855 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4856 if game.ship == 'E':
4857 proutn(_("You have "))
4859 proutn("%d" % (game.nprobes))
4862 proutn(_(" deep space probe"))
4866 if communicating() and is_scheduled(FDSPROB):
4868 proutn(_("An armed deep space probe is in "))
4870 proutn(_("A deep space probe is in "))
4871 prout("Quadrant %s." % game.probec)
4873 if game.cryprob <= .05:
4874 prout(_("Dilithium crystals aboard ship... not yet used."))
4878 while game.cryprob > ai:
4881 prout(_("Dilithium crystals have been used %d time%s.") % \
4882 (i, (_("s"), "")[i==1]))
4886 "Long-range sensor scan."
4887 if damaged(DLRSENS):
4888 # Now allow base's sensors if docked
4889 if game.condition != "docked":
4891 prout(_("LONG-RANGE SENSORS DAMAGED."))
4894 prout(_("Starbase's long-range scan"))
4896 prout(_("Long-range scan"))
4897 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4900 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4901 if not Coord(x, y).valid_quadrant():
4905 if not damaged(DRADIO):
4906 game.state.galaxy[x][y].charted = True
4907 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4908 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4909 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4910 if not silent and game.state.galaxy[x][y].supernova:
4913 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4921 for i in range(NDEVICES):
4924 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4925 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4927 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4928 game.damage[i]+0.05,
4929 DOCKFAC*game.damage[i]+0.005))
4931 prout(_("All devices functional."))
4934 "Update the chart in the Enterprise's computer from galaxy data."
4935 game.lastchart = game.state.date
4936 for i in range(GALSIZE):
4937 for j in range(GALSIZE):
4938 if game.state.galaxy[i][j].charted:
4939 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
4940 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
4941 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
4944 "Display the star chart."
4946 if (game.options & OPTION_AUTOSCAN):
4948 if not damaged(DRADIO):
4950 if game.lastchart < game.state.date and game.condition == "docked":
4951 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
4953 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
4954 if game.state.date > game.lastchart:
4955 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
4956 prout(" 1 2 3 4 5 6 7 8")
4957 for i in range(GALSIZE):
4958 proutn("%d |" % (i+1))
4959 for j in range(GALSIZE):
4960 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4964 if game.state.galaxy[i][j].supernova:
4966 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
4968 elif game.state.galaxy[i][j].charted:
4969 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
4973 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4981 def sectscan(goodScan, i, j):
4982 "Light up an individual dot in a sector."
4983 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
4984 textcolor({"green":GREEN,
4988 "dead":BROWN}[game.condition])
4989 if game.quad[i][j] != game.ship:
4991 proutn("%c " % game.quad[i][j])
4997 "Emit status report lines"
4998 if not req or req == 1:
4999 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5000 % (game.state.date, game.state.remtime))
5001 if not req or req == 2:
5002 if game.condition != "docked":
5004 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5005 (game.condition.upper(), sum(map(lambda x: x > 0, game.damage))))
5006 if not req or req == 3:
5007 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5008 if not req or req == 4:
5009 if damaged(DLIFSUP):
5010 if game.condition == "docked":
5011 s = _("DAMAGED, Base provides")
5013 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5016 prstat(_("Life Support"), s)
5017 if not req or req == 5:
5018 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5019 if not req or req == 6:
5021 if game.icrystl and (game.options & OPTION_SHOWME):
5022 extra = _(" (have crystals)")
5023 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5024 if not req or req == 7:
5025 prstat(_("Torpedoes"), "%d" % (game.torps))
5026 if not req or req == 8:
5027 if damaged(DSHIELD):
5033 data = _(" %d%% %.1f units") \
5034 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5035 prstat(_("Shields"), s+data)
5036 if not req or req == 9:
5037 prstat(_("Klingons Left"), "%d" \
5038 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5039 if not req or req == 10:
5040 if game.options & OPTION_WORLDS:
5041 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5042 if plnet and plnet.inhabited:
5043 prstat(_("Major system"), plnet.name)
5045 prout(_("Sector is uninhabited"))
5046 elif not req or req == 11:
5047 attackreport(not req)
5050 "Request specified status data, a historical relic from slow TTYs."
5051 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5052 while scanner.next() == "IHEOL":
5053 proutn(_("Information desired? "))
5055 if scanner.token in requests:
5056 status(requests.index(scanner.token))
5058 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5059 prout((" date, condition, position, lsupport, warpfactor,"))
5060 prout((" energy, torpedoes, shields, klingons, system, time."))
5065 if damaged(DSRSENS):
5066 # Allow base's sensors if docked
5067 if game.condition != "docked":
5068 prout(_(" S.R. SENSORS DAMAGED!"))
5071 prout(_(" [Using Base's sensors]"))
5073 prout(_(" Short-range scan"))
5074 if goodScan and not damaged(DRADIO):
5075 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5076 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5077 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5078 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5079 prout(" 1 2 3 4 5 6 7 8 9 10")
5080 if game.condition != "docked":
5082 for i in range(QUADSIZE):
5083 proutn("%2d " % (i+1))
5084 for j in range(QUADSIZE):
5085 sectscan(goodScan, i, j)
5089 "Use computer to get estimated time of arrival for a warp jump."
5090 w1 = Coord(); w2 = Coord()
5092 if damaged(DCOMPTR):
5093 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5096 if scanner.next() != "IHREAL":
5099 proutn(_("Destination quadrant and/or sector? "))
5100 if scanner.next()!="IHREAL":
5103 w1.j = int(scanner.real-0.5)
5104 if scanner.next() != "IHREAL":
5107 w1.i = int(scanner.real-0.5)
5108 if scanner.next() == "IHREAL":
5109 w2.j = int(scanner.real-0.5)
5110 if scanner.next() != "IHREAL":
5113 w2.i = int(scanner.real-0.5)
5115 if game.quadrant.j>w1.i:
5119 if game.quadrant.i>w1.j:
5123 if not w1.valid_quadrant() or not w2.valid_sector():
5126 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5127 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5130 prout(_("Answer \"no\" if you don't know the value:"))
5133 proutn(_("Time or arrival date? "))
5134 if scanner.next()=="IHREAL":
5135 ttime = scanner.real
5136 if ttime > game.state.date:
5137 ttime -= game.state.date # Actually a star date
5138 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5139 if ttime <= 1e-10 or twarp > 10:
5140 prout(_("We'll never make it, sir."))
5147 proutn(_("Warp factor? "))
5148 if scanner.next()== "IHREAL":
5150 twarp = scanner.real
5151 if twarp<1.0 or twarp > 10.0:
5155 prout(_("Captain, certainly you can give me one of these."))
5158 ttime = (10.0*dist)/twarp**2
5159 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5160 if tpower >= game.energy:
5161 prout(_("Insufficient energy, sir."))
5162 if not game.shldup or tpower > game.energy*2.0:
5165 proutn(_("New warp factor to try? "))
5166 if scanner.next() == "IHREAL":
5168 twarp = scanner.real
5169 if twarp<1.0 or twarp > 10.0:
5177 prout(_("But if you lower your shields,"))
5178 proutn(_("remaining"))
5181 proutn(_("Remaining"))
5182 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5184 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5186 prout(_("Any warp speed is adequate."))
5188 prout(_("Minimum warp needed is %.2f,") % (twarp))
5189 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5190 if game.state.remtime < ttime:
5191 prout(_("Unfortunately, the Federation will be destroyed by then."))
5193 prout(_("You'll be taking risks at that speed, Captain"))
5194 if (game.isatb==1 and game.state.kscmdr == w1 and \
5195 scheduled(FSCDBAS)< ttime+game.state.date) or \
5196 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5197 prout(_("The starbase there will be destroyed by then."))
5198 proutn(_("New warp factor to try? "))
5199 if scanner.next() == "IHREAL":
5201 twarp = scanner.real
5202 if twarp<1.0 or twarp > 10.0:
5210 # Code from setup.c begins here
5213 "Issue a historically correct banner."
5215 prout(_("-SUPER- STAR TREK"))
5217 # From the FORTRAN original
5218 # prout(_("Latest update-21 Sept 78"))
5224 scanner.push("emsave.trk")
5225 key = scanner.next()
5227 proutn(_("File name: "))
5228 key = scanner.next()
5229 if key != "IHALPHA":
5232 if '.' not in scanner.token:
5233 scanner.token += ".trk"
5235 fp = open(scanner.token, "wb")
5237 prout(_("Can't freeze game as file %s") % scanner.token)
5239 cPickle.dump(game, fp)
5244 "Retrieve saved game."
5247 key = scanner.next()
5249 proutn(_("File name: "))
5250 key = scanner.next()
5251 if key != "IHALPHA":
5254 if '.' not in scanner.token:
5255 scanner.token += ".trk"
5257 fp = open(scanner.token, "rb")
5259 prout(_("Can't thaw game in %s") % scanner.token)
5261 game = cPickle.load(fp)
5266 # I used <http://www.memory-alpha.org> to find planets
5267 # with references in ST:TOS. Earth and the Alpha Centauri
5268 # Colony have been omitted.
5270 # Some planets marked Class G and P here will be displayed as class M
5271 # because of the way planets are generated. This is a known bug.
5274 _("Andoria (Fesoan)"), # several episodes
5275 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5276 _("Vulcan (T'Khasi)"), # many episodes
5277 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5278 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5279 _("Ardana"), # TOS: "The Cloud Minders"
5280 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5281 _("Gideon"), # TOS: "The Mark of Gideon"
5282 _("Aldebaran III"), # TOS: "The Deadly Years"
5283 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5284 _("Altair IV"), # TOS: "Amok Time
5285 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5286 _("Benecia"), # TOS: "The Conscience of the King"
5287 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5288 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5289 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5290 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5291 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5292 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5293 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5294 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5295 _("Ingraham B"), # TOS: "Operation: Annihilate"
5296 _("Janus IV"), # TOS: "The Devil in the Dark"
5297 _("Makus III"), # TOS: "The Galileo Seven"
5298 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5299 _("Omega IV"), # TOS: "The Omega Glory"
5300 _("Regulus V"), # TOS: "Amok Time
5301 _("Deneva"), # TOS: "Operation -- Annihilate!"
5302 # Worlds from BSD Trek
5303 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5304 _("Beta III"), # TOS: "The Return of the Archons"
5305 _("Triacus"), # TOS: "And the Children Shall Lead",
5306 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5308 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5309 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5310 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5311 # _("Izar"), # TOS: "Whom Gods Destroy"
5312 # _("Tiburon"), # TOS: "The Way to Eden"
5313 # _("Merak II"), # TOS: "The Cloud Minders"
5314 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5315 # _("Iotia"), # TOS: "A Piece of the Action"
5319 _("S. R. Sensors"), \
5320 _("L. R. Sensors"), \
5322 _("Photon Tubes"), \
5323 _("Life Support"), \
5324 _("Warp Engines"), \
5325 _("Impulse Engines"), \
5327 _("Subspace Radio"), \
5328 _("Shuttle Craft"), \
5330 _("Navigation System"), \
5332 _("Shield Control"), \
5338 "Prepare to play, set up cosmos."
5340 # Decide how many of everything
5342 return # frozen game
5343 # Prepare the Enterprise
5344 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5346 game.state.crew = FULLCREW
5347 game.energy = game.inenrg = 5000.0
5348 game.shield = game.inshld = 2500.0
5351 game.quadrant = randplace(GALSIZE)
5352 game.sector = randplace(QUADSIZE)
5353 game.torps = game.intorps = 10
5354 game.nprobes = randrange(2, 5)
5356 for i in range(NDEVICES):
5357 game.damage[i] = 0.0
5358 # Set up assorted game parameters
5359 game.battle = Coord()
5360 game.state.date = game.indate = 100.0 * randreal(20, 51)
5361 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5362 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5363 game.isatb = game.state.nplankl = 0
5364 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5365 game.iscraft = "onship"
5370 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5372 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5374 game.state.planets = [] # Planet information
5375 game.state.baseq = [] # Base quadrant coordinates
5376 game.state.kcmdr = [] # Commander quadrant coordinates
5377 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5379 # Starchart is functional but we've never seen it
5380 game.lastchart = FOREVER
5381 # Put stars in the galaxy
5383 for i in range(GALSIZE):
5384 for j in range(GALSIZE):
5385 k = randrange(1, QUADSIZE**2/10+1)
5387 game.state.galaxy[i][j].stars = k
5388 # Locate star bases in galaxy
5389 for i in range(game.inbase):
5392 w = randplace(GALSIZE)
5393 if not game.state.galaxy[w.i][w.j].starbase:
5396 # C version: for (j = i-1; j > 0; j--)
5397 # so it did them in the opposite order.
5398 for j in range(1, i):
5399 # Improved placement algorithm to spread out bases
5400 distq = (w - game.state.baseq[j]).distance()
5401 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5404 prout("=== Abandoning base #%d at %s" % (i, w))
5406 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5408 prout("=== Saving base #%d, close to #%d" % (i, j))
5411 game.state.baseq.append(w)
5412 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5413 # Position ordinary Klingon Battle Cruisers
5415 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5416 if klumper > MAXKLQUAD:
5420 klump = (1.0 - r*r)*klumper
5425 w = randplace(GALSIZE)
5426 if not game.state.galaxy[w.i][w.j].supernova and \
5427 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5429 game.state.galaxy[w.i][w.j].klingons += int(klump)
5432 # Position Klingon Commander Ships
5433 for i in range(game.incom):
5435 w = randplace(GALSIZE)
5436 if not welcoming(w) or w in game.state.kcmdr:
5438 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5440 game.state.galaxy[w.i][w.j].klingons += 1
5441 game.state.kcmdr.append(w)
5442 # Locate planets in galaxy
5443 for i in range(game.inplan):
5445 w = randplace(GALSIZE)
5446 if game.state.galaxy[w.i][w.j].planet == None:
5450 new.crystals = "absent"
5451 if (game.options & OPTION_WORLDS) and i < NINHAB:
5452 new.pclass = "M" # All inhabited planets are class M
5453 new.crystals = "absent"
5455 new.name = systnames[i]
5456 new.inhabited = True
5458 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5460 new.crystals = "present"
5461 new.known = "unknown"
5462 new.inhabited = False
5463 game.state.galaxy[w.i][w.j].planet = new
5464 game.state.planets.append(new)
5466 for i in range(game.state.nromrem):
5467 w = randplace(GALSIZE)
5468 game.state.galaxy[w.i][w.j].romulans += 1
5469 # Place the Super-Commander if needed
5470 if game.state.nscrem > 0:
5472 w = randplace(GALSIZE)
5475 game.state.kscmdr = w
5476 game.state.galaxy[w.i][w.j].klingons += 1
5477 # Initialize times for extraneous events
5478 schedule(FSNOVA, expran(0.5 * game.intime))
5479 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5480 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5481 schedule(FBATTAK, expran(0.3*game.intime))
5483 if game.state.nscrem:
5484 schedule(FSCMOVE, 0.2777)
5489 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5490 schedule(FDISTR, expran(1.0 + game.intime))
5495 # Place thing (in tournament game, we don't want one!)
5496 # New in SST2K: never place the Thing near a starbase.
5497 # This makes sense and avoids a special case in the old code.
5499 if game.tourn is None:
5501 thing = randplace(GALSIZE)
5502 if thing not in game.state.baseq:
5505 game.state.snap = False
5506 if game.skill == SKILL_NOVICE:
5507 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5508 prout(_("a deadly Klingon invasion force. As captain of the United"))
5509 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5510 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5511 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5512 prout(_("your mission. As you proceed you may be given more time."))
5514 prout(_("You will have %d supporting starbases.") % (game.inbase))
5515 proutn(_("Starbase locations- "))
5517 prout(_("Stardate %d.") % int(game.state.date))
5519 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5520 prout(_("An unknown number of Romulans."))
5521 if game.state.nscrem:
5522 prout(_("And one (GULP) Super-Commander."))
5523 prout(_("%d stardates.") % int(game.intime))
5524 proutn(_("%d starbases in ") % game.inbase)
5525 for i in range(game.inbase):
5526 proutn(`game.state.baseq[i]`)
5529 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5530 proutn(_(" Sector %s") % game.sector)
5532 prout(_("Good Luck!"))
5533 if game.state.nscrem:
5534 prout(_(" YOU'LL NEED IT."))
5537 setwnd(message_window)
5539 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5541 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5542 attack(torps_ok=False)
5545 "Choose your game type."
5547 game.tourn = game.length = 0
5549 game.skill = SKILL_NONE
5551 # if not scanner.inqueue: # Can start with command line options
5552 proutn(_("Would you like a regular, tournament, or saved game? "))
5554 if scanner.sees("tournament"):
5555 while scanner.next() == "IHEOL":
5556 proutn(_("Type in tournament number-"))
5557 if scanner.real == 0:
5559 continue # We don't want a blank entry
5560 game.tourn = int(round(scanner.real))
5561 random.seed(scanner.real)
5563 logfp.write("# random.seed(%d)\n" % scanner.real)
5565 if scanner.sees("saved") or scanner.sees("frozen"):
5569 if game.passwd == None:
5571 if not game.alldone:
5572 game.thawed = True # No plaque if not finished
5576 if scanner.sees("regular"):
5578 proutn(_("What is \"%s\"? ") % scanner.token)
5580 while game.length==0 or game.skill==SKILL_NONE:
5581 if scanner.next() == "IHALPHA":
5582 if scanner.sees("short"):
5584 elif scanner.sees("medium"):
5586 elif scanner.sees("long"):
5588 elif scanner.sees("novice"):
5589 game.skill = SKILL_NOVICE
5590 elif scanner.sees("fair"):
5591 game.skill = SKILL_FAIR
5592 elif scanner.sees("good"):
5593 game.skill = SKILL_GOOD
5594 elif scanner.sees("expert"):
5595 game.skill = SKILL_EXPERT
5596 elif scanner.sees("emeritus"):
5597 game.skill = SKILL_EMERITUS
5599 proutn(_("What is \""))
5600 proutn(scanner.token)
5605 proutn(_("Would you like a Short, Medium, or Long game? "))
5606 elif game.skill == SKILL_NONE:
5607 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5608 # Choose game options -- added by ESR for SST2K
5609 if scanner.next() != "IHALPHA":
5611 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5613 if scanner.sees("plain"):
5614 # Approximates the UT FORTRAN version.
5615 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5616 game.options |= OPTION_PLAIN
5617 elif scanner.sees("almy"):
5618 # Approximates Tom Almy's version.
5619 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5620 game.options |= OPTION_ALMY
5621 elif scanner.sees("fancy") or scanner.sees("\n"):
5623 elif len(scanner.token):
5624 proutn(_("What is \"%s\"?") % scanner.token)
5625 game.options &=~ OPTION_COLOR
5627 if game.passwd == "debug":
5629 prout("=== Debug mode enabled.")
5630 # Use parameters to generate initial values of things
5631 game.damfac = 0.5 * game.skill
5632 game.inbase = randrange(BASEMIN, BASEMAX+1)
5634 if game.options & OPTION_PLANETS:
5635 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5636 if game.options & OPTION_WORLDS:
5637 game.inplan += int(NINHAB)
5638 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5639 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5640 game.state.remtime = 7.0 * game.length
5641 game.intime = game.state.remtime
5642 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5643 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5644 game.state.remres = (game.inkling+4*game.incom)*game.intime
5645 game.inresor = game.state.remres
5646 if game.inkling > 50:
5647 game.state.inbase += 1
5650 def dropin(iquad=None):
5651 "Drop a feature on a random dot in the current quadrant."
5653 w = randplace(QUADSIZE)
5654 if game.quad[w.i][w.j] == '.':
5656 if iquad is not None:
5657 game.quad[w.i][w.j] = iquad
5661 "Update our alert status."
5662 game.condition = "green"
5663 if game.energy < 1000.0:
5664 game.condition = "yellow"
5665 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5666 game.condition = "red"
5668 game.condition="dead"
5671 "Drop new Klingon into current quadrant."
5672 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5675 "Sort enemies by distance so 'nearest' is meaningful."
5676 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
5679 "Set up a new state of quadrant, for when we enter or re-enter it."
5682 game.neutz = game.inorbit = game.landed = False
5683 game.ientesc = game.iseenit = False
5684 # Create a blank quadrant
5685 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5687 # Attempt to escape Super-commander, so tbeam back!
5690 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5691 # cope with supernova
5694 game.klhere = q.klingons
5695 game.irhere = q.romulans
5697 game.quad[game.sector.i][game.sector.j] = game.ship
5700 # Position ordinary Klingons
5701 for i in range(game.klhere):
5703 # If we need a commander, promote a Klingon
5704 for cmdr in game.state.kcmdr:
5705 if cmdr == game.quadrant:
5706 e = game.enemies[game.klhere-1]
5707 game.quad[e.location.i][e.location.j] = 'C'
5708 e.power = randreal(950,1350) + 50.0*game.skill
5710 # If we need a super-commander, promote a Klingon
5711 if game.quadrant == game.state.kscmdr:
5713 game.quad[e.location.i][e.location.j] = 'S'
5714 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5715 game.iscate = (game.state.remkl > 1)
5716 # Put in Romulans if needed
5717 for i in range(q.romulans):
5718 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5719 # If quadrant needs a starbase, put it in
5721 game.base = dropin('B')
5722 # If quadrant needs a planet, put it in
5724 game.iplnet = q.planet
5725 if not q.planet.inhabited:
5726 game.plnet = dropin('P')
5728 game.plnet = dropin('@')
5729 # Check for condition
5732 if game.irhere > 0 and game.klhere == 0:
5734 if not damaged(DRADIO):
5736 prout(_("LT. Uhura- \"Captain, an urgent message."))
5737 prout(_(" I'll put it on audio.\" CLICK"))
5739 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5740 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5741 # Put in THING if needed
5742 if thing == game.quadrant:
5743 Enemy(type='?', loc=dropin(),
5744 power=randreal(6000,6500.0)+250.0*game.skill)
5745 if not damaged(DSRSENS):
5747 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5748 prout(_(" Please examine your short-range scan.\""))
5749 # Decide if quadrant needs a Tholian; lighten up if skill is low
5750 if game.options & OPTION_THOLIAN:
5751 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5752 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5753 (game.skill > SKILL_GOOD and withprob(0.08)):
5756 w.i = withprob(0.5) * (QUADSIZE-1)
5757 w.j = withprob(0.5) * (QUADSIZE-1)
5758 if game.quad[w.i][w.j] == '.':
5760 game.tholian = Enemy(type='T', loc=w,
5761 power=randrange(100, 500) + 25.0*game.skill)
5762 # Reserve unoccupied corners
5763 if game.quad[0][0]=='.':
5764 game.quad[0][0] = 'X'
5765 if game.quad[0][QUADSIZE-1]=='.':
5766 game.quad[0][QUADSIZE-1] = 'X'
5767 if game.quad[QUADSIZE-1][0]=='.':
5768 game.quad[QUADSIZE-1][0] = 'X'
5769 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5770 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5772 # And finally the stars
5773 for i in range(q.stars):
5775 # Put in a few black holes
5776 for i in range(1, 3+1):
5779 # Take out X's in corners if Tholian present
5781 if game.quad[0][0]=='X':
5782 game.quad[0][0] = '.'
5783 if game.quad[0][QUADSIZE-1]=='X':
5784 game.quad[0][QUADSIZE-1] = '.'
5785 if game.quad[QUADSIZE-1][0]=='X':
5786 game.quad[QUADSIZE-1][0] = '.'
5787 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5788 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5791 "Set the self-destruct password."
5792 if game.options & OPTION_PLAIN:
5795 proutn(_("Please type in a secret password- "))
5797 game.passwd = scanner.token
5798 if game.passwd != None:
5802 game.passwd += chr(ord('a')+randrange(26))
5803 game.passwd += chr(ord('a')+randrange(26))
5804 game.passwd += chr(ord('a')+randrange(26))
5806 # Code from sst.c begins here
5809 ("SRSCAN", OPTION_TTY),
5810 ("STATUS", OPTION_TTY),
5811 ("REQUEST", OPTION_TTY),
5812 ("LRSCAN", OPTION_TTY),
5825 ("SENSORS", OPTION_PLANETS),
5826 ("ORBIT", OPTION_PLANETS),
5827 ("TRANSPORT", OPTION_PLANETS),
5828 ("MINE", OPTION_PLANETS),
5829 ("CRYSTALS", OPTION_PLANETS),
5830 ("SHUTTLE", OPTION_PLANETS),
5831 ("PLANETS", OPTION_PLANETS),
5836 ("PROBE", OPTION_PROBE),
5838 ("FREEZE", 0), # Synonym for SAVE
5844 ("SOS", 0), # Synonym for MAYDAY
5845 ("CALL", 0), # Synonym for MAYDAY
5852 "Generate a list of legal commands."
5853 prout(_("LEGAL COMMANDS ARE:"))
5855 for (key, opt) in commands:
5856 if not opt or (opt & game.options):
5857 proutn("%-12s " % key)
5859 if emitted % 5 == 4:
5864 "Browse on-line help."
5865 key = scanner.next()
5868 setwnd(prompt_window)
5869 proutn(_("Help on what command? "))
5870 key = scanner.next()
5871 setwnd(message_window)
5874 cmds = map(lambda x: x[0], commands)
5875 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
5882 cmd = scanner.token.upper()
5883 for directory in docpath:
5885 fp = open(os.path.join(directory, "sst.doc"), "r")
5890 prout(_("Spock- \"Captain, that information is missing from the"))
5891 prout(_(" computer. You need to find sst.doc and put it somewhere"))
5892 proutn(_(" in these directories: %s") % ":".join(docpath))
5894 # This used to continue: "You need to find SST.DOC and put
5895 # it in the current directory."
5898 linebuf = fp.readline()
5900 prout(_("Spock- \"Captain, there is no information on that command.\""))
5903 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5904 linebuf = linebuf[3:].strip()
5905 if cmd.upper() == linebuf:
5908 prout(_("Spock- \"Captain, I've found the following information:\""))
5911 linebuf = fp.readline()
5912 if "******" in linebuf:
5918 "Command-interpretation loop."
5919 while True: # command loop
5921 while True: # get a command
5923 game.optime = game.justin = False
5925 setwnd(prompt_window)
5928 if scanner.next() == "IHEOL":
5929 if game.options & OPTION_CURSES:
5932 elif scanner.token == "":
5936 setwnd(message_window)
5938 abandon_passed = False
5939 for (cmd, opt) in commands:
5940 # commands after ABANDON cannot be abbreviated
5941 if cmd == "ABANDON":
5942 abandon_passed = True
5943 if cmd == scanner.token.upper() or (not abandon_passed \
5944 and cmd.startswith(scanner.token.upper())):
5951 if cmd == "SRSCAN": # srscan
5953 elif cmd == "STATUS": # status
5955 elif cmd == "REQUEST": # status request
5957 elif cmd == "LRSCAN": # long range scan
5958 lrscan(silent=False)
5959 elif cmd == "PHASERS": # phasers
5963 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
5967 elif cmd == "MOVE": # move under warp
5968 warp(wcourse=None, involuntary=False)
5969 elif cmd == "SHIELDS": # shields
5970 doshield(shraise=False)
5973 game.shldchg = False
5974 elif cmd == "DOCK": # dock at starbase
5977 attack(torps_ok=False)
5978 elif cmd == "DAMAGES": # damage reports
5980 elif cmd == "CHART": # chart
5982 elif cmd == "IMPULSE": # impulse
5984 elif cmd == "REST": # rest
5988 elif cmd == "WARP": # warp
5990 elif cmd == "SCORE": # score
5992 elif cmd == "SENSORS": # sensors
5994 elif cmd == "ORBIT": # orbit
5998 elif cmd == "TRANSPORT": # transport "beam"
6000 elif cmd == "MINE": # mine
6004 elif cmd == "CRYSTALS": # crystals
6008 elif cmd == "SHUTTLE": # shuttle
6012 elif cmd == "PLANETS": # Planet list
6014 elif cmd == "REPORT": # Game Report
6016 elif cmd == "COMPUTER": # use COMPUTER!
6018 elif cmd == "COMMANDS":
6020 elif cmd == "EMEXIT": # Emergency exit
6021 clrscr() # Hide screen
6022 freeze(True) # forced save
6023 raise SystemExit,1 # And quick exit
6024 elif cmd == "PROBE":
6025 probe() # Launch probe
6028 elif cmd == "ABANDON": # Abandon Ship
6030 elif cmd == "DESTRUCT": # Self Destruct
6032 elif cmd == "SAVE": # Save Game
6035 if game.skill > SKILL_GOOD:
6036 prout(_("WARNING--Saved games produce no plaques!"))
6037 elif cmd == "DEATHRAY": # Try a desparation measure
6041 elif cmd == "DEBUGCMD": # What do we want for debug???
6043 elif cmd == "MAYDAY": # Call for help
6048 game.alldone = True # quit the game
6053 break # Game has ended
6054 if game.optime != 0.0:
6057 break # Events did us in
6058 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6061 if hitme and not game.justin:
6062 attack(torps_ok=True)
6065 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6076 "Emit the name of an enemy or feature."
6077 if type == 'R': s = _("Romulan")
6078 elif type == 'K': s = _("Klingon")
6079 elif type == 'C': s = _("Commander")
6080 elif type == 'S': s = _("Super-commander")
6081 elif type == '*': s = _("Star")
6082 elif type == 'P': s = _("Planet")
6083 elif type == 'B': s = _("Starbase")
6084 elif type == ' ': s = _("Black hole")
6085 elif type == 'T': s = _("Tholian")
6086 elif type == '#': s = _("Tholian web")
6087 elif type == '?': s = _("Stranger")
6088 elif type == '@': s = _("Inhabited World")
6089 else: s = "Unknown??"
6092 def crmena(stars, enemy, loctype, w):
6093 "Emit the name of an enemy and his location."
6097 buf += cramen(enemy) + _(" at ")
6098 if loctype == "quadrant":
6099 buf += _("Quadrant ")
6100 elif loctype == "sector":
6105 "Emit our ship name."
6106 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6109 "Emit a line of stars"
6110 prouts("******************************************************")
6114 return -avrage*math.log(1e-7 + randreal())
6116 def randplace(size):
6117 "Choose a random location."
6119 w.i = randrange(size)
6120 w.j = randrange(size)
6130 # Get a token from the user
6133 # Fill the token quue if nothing here
6134 while not self.inqueue:
6136 if curwnd==prompt_window:
6138 setwnd(message_window)
6145 self.inqueue = line.lstrip().split() + ["\n"]
6146 # From here on in it's all looking at the queue
6147 self.token = self.inqueue.pop(0)
6148 if self.token == "\n":
6152 self.real = float(self.token)
6153 self.type = "IHREAL"
6158 self.token = self.token.lower()
6159 self.type = "IHALPHA"
6162 def append(self, tok):
6163 self.inqueue.append(tok)
6164 def push(self, tok):
6165 self.inqueue.insert(0, tok)
6169 # Demand input for next scan
6171 self.real = self.token = None
6173 # compares s to item and returns true if it matches to the length of s
6174 return s.startswith(self.token)
6176 # Round token value to nearest integer
6177 return int(round(scanner.real))
6181 if scanner.type != "IHREAL":
6184 s.i = scanner.int()-1
6186 if scanner.type != "IHREAL":
6189 s.j = scanner.int()-1
6192 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6195 "Yes-or-no confirmation."
6199 if scanner.token == 'y':
6201 if scanner.token == 'n':
6204 proutn(_("Please answer with \"y\" or \"n\": "))
6207 "Complain about unparseable input."
6210 prout(_("Beg your pardon, Captain?"))
6213 "Access to the internals for debugging."
6214 proutn("Reset levels? ")
6216 if game.energy < game.inenrg:
6217 game.energy = game.inenrg
6218 game.shield = game.inshld
6219 game.torps = game.intorps
6220 game.lsupres = game.inlsr
6221 proutn("Reset damage? ")
6223 for i in range(NDEVICES):
6224 if game.damage[i] > 0.0:
6225 game.damage[i] = 0.0
6226 proutn("Toggle debug flag? ")
6228 game.idebug = not game.idebug
6230 prout("Debug output ON")
6232 prout("Debug output OFF")
6233 proutn("Cause selective damage? ")
6235 for i in range(NDEVICES):
6236 proutn("Kill %s?" % device[i])
6238 key = scanner.next()
6239 if key == "IHALPHA" and scanner.sees("y"):
6240 game.damage[i] = 10.0
6241 proutn("Examine/change events? ")
6246 FSNOVA: "Supernova ",
6249 FBATTAK: "Base Attack ",
6250 FCDBAS: "Base Destroy ",
6251 FSCMOVE: "SC Move ",
6252 FSCDBAS: "SC Base Destroy ",
6253 FDSPROB: "Probe Move ",
6254 FDISTR: "Distress Call ",
6255 FENSLV: "Enslavement ",
6256 FREPRO: "Klingon Build ",
6258 for i in range(1, NEVENTS):
6261 proutn("%.2f" % (scheduled(i)-game.state.date))
6262 if i == FENSLV or i == FREPRO:
6264 proutn(" in %s" % ev.quadrant)
6269 key = scanner.next()
6273 elif key == "IHREAL":
6274 ev = schedule(i, scanner.real)
6275 if i == FENSLV or i == FREPRO:
6277 proutn("In quadrant- ")
6278 key = scanner.next()
6279 # "IHEOL" says to leave coordinates as they are
6282 prout("Event %d canceled, no x coordinate." % (i))
6285 w.i = int(round(scanner.real))
6286 key = scanner.next()
6288 prout("Event %d canceled, no y coordinate." % (i))
6291 w.j = int(round(scanner.real))
6294 proutn("Induce supernova here? ")
6296 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6299 if __name__ == '__main__':
6300 import getopt, socket
6302 global line, thing, game
6306 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6307 if os.getenv("TERM"):
6308 game.options |= OPTION_CURSES
6310 game.options |= OPTION_TTY
6311 seed = int(time.time())
6312 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6313 for (switch, val) in options:
6316 replayfp = open(val, "r")
6318 sys.stderr.write("sst: can't open replay file %s\n" % val)
6321 line = replayfp.readline().strip()
6322 (leader, key, seed) = line.split()
6324 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6325 line = replayfp.readline().strip()
6326 arguments += line.split()[2:]
6328 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6330 game.options |= OPTION_TTY
6331 game.options &=~ OPTION_CURSES
6332 elif switch == '-s':
6334 elif switch == '-t':
6335 game.options |= OPTION_TTY
6336 game.options &=~ OPTION_CURSES
6337 elif switch == '-x':
6339 elif switch == '-V':
6340 print "SST2K", version
6343 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6345 # where to save the input in case of bugs
6346 if "TMPDIR" in os.environ:
6347 tmpdir = os.environ['TMPDIR']
6351 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6353 sys.stderr.write("sst: warning, can't open logfile\n")
6356 logfp.write("# seed %s\n" % seed)
6357 logfp.write("# options %s\n" % " ".join(arguments))
6358 logfp.write("# recorded by %s@%s on %s\n" % \
6359 (getpass.getuser(),socket.gethostname(),time.ctime()))
6361 scanner = sstscanner()
6362 map(scanner.append, arguments)
6365 while True: # Play a game
6366 setwnd(fullscreen_window)
6372 game.alldone = False
6378 if game.tourn and game.alldone:
6379 proutn(_("Do you want your score recorded?"))
6385 proutn(_("Do you want to play again? "))
6389 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6393 except KeyboardInterrupt: