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 self.state.remtime = self.state.remres/(self.state.remkl + 4*len(self.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."
1712 irec = 0 # Cheating inhibitor
1721 # SR sensors and Computer are needed for automode
1722 if damaged(DSRSENS) or damaged(DCOMPTR):
1724 if game.condition == "docked":
1725 prout(_("Phasers can't be fired through base shields."))
1728 if damaged(DPHASER):
1729 prout(_("Phaser control damaged."))
1733 if damaged(DSHCTRL):
1734 prout(_("High speed shield control damaged."))
1737 if game.energy <= 200.0:
1738 prout(_("Insufficient energy to activate high-speed shield control."))
1741 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1743 # Original code so convoluted, I re-did it all
1744 # (That was Tom Almy talking about the C code, I think -- ESR)
1745 while automode == "NOTSET":
1746 key = scanner.next()
1747 if key == "IHALPHA":
1748 if scanner.sees("manual"):
1749 if len(game.enemies)==0:
1750 prout(_("There is no enemy present to select."))
1753 automode = "AUTOMATIC"
1756 key = scanner.next()
1757 elif scanner.sees("automatic"):
1758 if (not itarg) and len(game.enemies) != 0:
1759 automode = "FORCEMAN"
1761 if len(game.enemies)==0:
1762 prout(_("Energy will be expended into space."))
1763 automode = "AUTOMATIC"
1764 key = scanner.next()
1765 elif scanner.sees("no"):
1770 elif key == "IHREAL":
1771 if len(game.enemies)==0:
1772 prout(_("Energy will be expended into space."))
1773 automode = "AUTOMATIC"
1775 automode = "FORCEMAN"
1777 automode = "AUTOMATIC"
1780 if len(game.enemies)==0:
1781 prout(_("Energy will be expended into space."))
1782 automode = "AUTOMATIC"
1784 automode = "FORCEMAN"
1786 proutn(_("Manual or automatic? "))
1791 if automode == "AUTOMATIC":
1792 if key == "IHALPHA" and scanner.sees("no"):
1794 key = scanner.next()
1795 if key != "IHREAL" and len(game.enemies) != 0:
1796 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1801 for i in range(len(game.enemies)):
1802 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1804 proutn(_("%d units required. ") % irec)
1806 proutn(_("Units to fire= "))
1807 key = scanner.next()
1812 proutn(_("Energy available= %.2f") % avail)
1815 if not rpow > avail:
1821 key = scanner.next()
1822 if key == "IHALPHA" and scanner.sees("no"):
1825 game.energy -= 200 # Go and do it!
1826 if checkshctrl(rpow):
1831 if len(game.enemies):
1834 for i in range(len(game.enemies)):
1838 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90, game.enemies[i].kdist))
1839 over = randreal(1.01, 1.06) * hits[i]
1841 powrem -= hits[i] + over
1842 if powrem <= 0 and temp < hits[i]:
1851 if extra > 0 and not game.alldone:
1853 proutn(_("*** Tholian web absorbs "))
1854 if len(game.enemies)>0:
1855 proutn(_("excess "))
1856 prout(_("phaser energy."))
1858 prout(_("%d expended on empty space.") % int(extra))
1859 elif automode == "FORCEMAN":
1862 if damaged(DCOMPTR):
1863 prout(_("Battle computer damaged, manual fire only."))
1866 prouts(_("---WORKING---"))
1868 prout(_("Short-range-sensors-damaged"))
1869 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1870 prout(_("Manual-fire-must-be-used"))
1872 elif automode == "MANUAL":
1874 for k in range(len(game.enemies)):
1875 aim = game.enemies[k].location
1876 ienm = game.quad[aim.i][aim.j]
1878 proutn(_("Energy available= %.2f") % (avail-0.006))
1882 if damaged(DSRSENS) and \
1883 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1884 prout(cramen(ienm) + _(" can't be located without short range scan."))
1887 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
1892 if itarg and k > kz:
1893 irec = (abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9, game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1896 if not damaged(DCOMPTR):
1901 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1902 key = scanner.next()
1903 if key == "IHALPHA" and scanner.sees("no"):
1905 key = scanner.next()
1907 if key == "IHALPHA":
1911 if k == 1: # Let me say I'm baffled by this
1914 if scanner.real < 0:
1918 hits[k] = scanner.real
1919 rpow += scanner.real
1920 # If total requested is too much, inform and start over
1922 prout(_("Available energy exceeded -- try again."))
1925 key = scanner.next() # scan for next value
1928 # zero energy -- abort
1931 if key == "IHALPHA" and scanner.sees("no"):
1936 game.energy -= 200.0
1937 if checkshctrl(rpow):
1941 # Say shield raised or malfunction, if necessary
1948 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1949 prouts(_(" CLICK CLICK POP . . ."))
1950 prout(_(" No response, sir!"))
1953 prout(_("Shields raised."))
1958 # Code from events,c begins here.
1960 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1961 # event of each type active at any given time. Mostly these means we can
1962 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1963 # BSD Trek, from which we swiped the idea, can have up to 5.
1965 def unschedule(evtype):
1966 "Remove an event from the schedule."
1967 game.future[evtype].date = FOREVER
1968 return game.future[evtype]
1970 def is_scheduled(evtype):
1971 "Is an event of specified type scheduled."
1972 return game.future[evtype].date != FOREVER
1974 def scheduled(evtype):
1975 "When will this event happen?"
1976 return game.future[evtype].date
1978 def schedule(evtype, offset):
1979 "Schedule an event of specified type."
1980 game.future[evtype].date = game.state.date + offset
1981 return game.future[evtype]
1983 def postpone(evtype, offset):
1984 "Postpone a scheduled event."
1985 game.future[evtype].date += offset
1988 "Rest period is interrupted by event."
1991 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
1993 game.resting = False
1999 "Run through the event queue looking for things to do."
2001 fintim = game.state.date + game.optime
2010 def tractorbeam(yank):
2011 "Tractor-beaming cases merge here."
2013 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2015 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2016 # If Kirk & Co. screwing around on planet, handle
2017 atover(True) # atover(true) is Grab
2020 if game.icraft: # Caught in Galileo?
2023 # Check to see if shuttle is aboard
2024 if game.iscraft == "offship":
2027 prout(_("Galileo, left on the planet surface, is captured"))
2028 prout(_("by aliens and made into a flying McDonald's."))
2029 game.damage[DSHUTTL] = -10
2030 game.iscraft = "removed"
2032 prout(_("Galileo, left on the planet surface, is well hidden."))
2034 game.quadrant = game.state.kscmdr
2036 game.quadrant = game.state.kcmdr[i]
2037 game.sector = randplace(QUADSIZE)
2038 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2039 % (game.quadrant, game.sector))
2041 prout(_("(Remainder of rest/repair period cancelled.)"))
2042 game.resting = False
2044 if not damaged(DSHIELD) and game.shield > 0:
2045 doshield(shraise=True) # raise shields
2046 game.shldchg = False
2048 prout(_("(Shields not currently useable.)"))
2050 # Adjust finish time to time of tractor beaming
2051 fintim = game.state.date+game.optime
2052 attack(torps_ok=False)
2053 if not game.state.kcmdr:
2056 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2059 "Code merges here for any commander destroying a starbase."
2060 # Not perfect, but will have to do
2061 # Handle case where base is in same quadrant as starship
2062 if game.battle == game.quadrant:
2063 game.state.chart[game.battle.i][game.battle.j].starbase = False
2064 game.quad[game.base.i][game.base.j] = '.'
2065 game.base.invalidate()
2068 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2069 elif game.state.baseq and communicating():
2070 # Get word via subspace radio
2073 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2074 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2076 prout(_("the Klingon Super-Commander"))
2078 prout(_("a Klingon Commander"))
2079 game.state.chart[game.battle.i][game.battle.j].starbase = False
2080 # Remove Starbase from galaxy
2081 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2082 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2084 # reinstate a commander's base attack
2088 game.battle.invalidate()
2090 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2091 for i in range(1, NEVENTS):
2092 if i == FSNOVA: proutn("=== Supernova ")
2093 elif i == FTBEAM: proutn("=== T Beam ")
2094 elif i == FSNAP: proutn("=== Snapshot ")
2095 elif i == FBATTAK: proutn("=== Base Attack ")
2096 elif i == FCDBAS: proutn("=== Base Destroy ")
2097 elif i == FSCMOVE: proutn("=== SC Move ")
2098 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2099 elif i == FDSPROB: proutn("=== Probe Move ")
2100 elif i == FDISTR: proutn("=== Distress Call ")
2101 elif i == FENSLV: proutn("=== Enslavement ")
2102 elif i == FREPRO: proutn("=== Klingon Build ")
2104 prout("%.2f" % (scheduled(i)))
2107 radio_was_broken = damaged(DRADIO)
2110 # Select earliest extraneous event, evcode==0 if no events
2115 for l in range(1, NEVENTS):
2116 if game.future[l].date < datemin:
2119 prout("== Event %d fires" % evcode)
2120 datemin = game.future[l].date
2121 xtime = datemin-game.state.date
2122 game.state.date = datemin
2123 # Decrement Federation resources and recompute remaining time
2124 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2126 if game.state.remtime <= 0:
2129 # Any crew left alive?
2130 if game.state.crew <= 0:
2133 # Is life support adequate?
2134 if damaged(DLIFSUP) and game.condition != "docked":
2135 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2138 game.lsupres -= xtime
2139 if game.damage[DLIFSUP] <= xtime:
2140 game.lsupres = game.inlsr
2143 if game.condition == "docked":
2145 # Don't fix Deathray here
2146 for l in range(NDEVICES):
2147 if game.damage[l] > 0.0 and l != DDRAY:
2148 if game.damage[l]-repair > 0.0:
2149 game.damage[l] -= repair
2151 game.damage[l] = 0.0
2152 # If radio repaired, update star chart and attack reports
2153 if radio_was_broken and not damaged(DRADIO):
2154 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2155 prout(_(" surveillance reports are coming in."))
2157 if not game.iseenit:
2161 prout(_(" The star chart is now up to date.\""))
2163 # Cause extraneous event EVCODE to occur
2164 game.optime -= xtime
2165 if evcode == FSNOVA: # Supernova
2168 schedule(FSNOVA, expran(0.5*game.intime))
2169 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2171 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2172 if game.state.nscrem == 0 or \
2173 ictbeam or istract or \
2174 game.condition == "docked" or game.isatb == 1 or game.iscate:
2176 if game.ientesc or \
2177 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2178 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2179 (damaged(DSHIELD) and \
2180 (game.energy < 2500 or damaged(DPHASER)) and \
2181 (game.torps < 5 or damaged(DPHOTON))):
2183 istract = ictbeam = True
2184 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2187 elif evcode == FTBEAM: # Tractor beam
2188 if not game.state.kcmdr:
2191 i = randrange(len(game.state.kcmdr))
2192 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2193 if istract or game.condition == "docked" or yank == 0:
2194 # Drats! Have to reschedule
2196 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2200 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2201 game.snapsht = copy.deepcopy(game.state)
2202 game.state.snap = True
2203 schedule(FSNAP, expran(0.5 * game.intime))
2204 elif evcode == FBATTAK: # Commander attacks starbase
2205 if not game.state.kcmdr or not game.state.baseq:
2211 for ibq in game.state.baseq:
2212 for cmdr in game.state.kcmdr:
2213 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2216 # no match found -- try later
2217 schedule(FBATTAK, expran(0.3*game.intime))
2222 # commander + starbase combination found -- launch attack
2224 schedule(FCDBAS, randreal(1.0, 4.0))
2225 if game.isatb: # extra time if SC already attacking
2226 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2227 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2228 game.iseenit = False
2229 if not communicating():
2230 continue # No warning :-(
2234 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2235 prout(_(" reports that it is under attack and that it can"))
2236 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2239 elif evcode == FSCDBAS: # Supercommander destroys base
2242 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2243 continue # WAS RETURN!
2245 game.battle = game.state.kscmdr
2247 elif evcode == FCDBAS: # Commander succeeds in destroying base
2248 if evcode == FCDBAS:
2250 if not game.state.baseq() \
2251 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2252 game.battle.invalidate()
2254 # find the lucky pair
2255 for cmdr in game.state.kcmdr:
2256 if cmdr == game.battle:
2259 # No action to take after all
2262 elif evcode == FSCMOVE: # Supercommander moves
2263 schedule(FSCMOVE, 0.2777)
2264 if not game.ientesc and not istract and game.isatb != 1 and \
2265 (not game.iscate or not game.justin):
2267 elif evcode == FDSPROB: # Move deep space probe
2268 schedule(FDSPROB, 0.01)
2269 if not game.probe.next():
2270 if not game.probe.quadrant().valid_quadrant() or \
2271 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2272 # Left galaxy or ran into supernova
2276 proutn(_("Lt. Uhura- \"The deep space probe "))
2277 if not game.probe.quadrant().valid_quadrant():
2278 prout(_("has left the galaxy.\""))
2280 prout(_("is no longer transmitting.\""))
2286 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2287 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2289 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2290 chp.klingons = pdest.klingons
2291 chp.starbase = pdest.starbase
2292 chp.stars = pdest.stars
2293 pdest.charted = True
2294 game.probe.moves -= 1 # One less to travel
2295 if game.probe.arrived() and game.isarmed and pdest.stars:
2296 supernova(game.probe) # fire in the hole!
2298 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2300 elif evcode == FDISTR: # inhabited system issues distress call
2302 # try a whole bunch of times to find something suitable
2303 for i in range(100):
2304 # need a quadrant which is not the current one,
2305 # which has some stars which are inhabited and
2306 # not already under attack, which is not
2307 # supernova'ed, and which has some Klingons in it
2308 w = randplace(GALSIZE)
2309 q = game.state.galaxy[w.i][w.j]
2310 if not (game.quadrant == w or q.planet == None or \
2311 not q.planet.inhabited or \
2312 q.supernova or q.status!="secure" or q.klingons<=0):
2315 # can't seem to find one; ignore this call
2317 prout("=== Couldn't find location for distress event.")
2319 # got one!! Schedule its enslavement
2320 ev = schedule(FENSLV, expran(game.intime))
2322 q.status = "distressed"
2323 # tell the captain about it if we can
2325 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2326 % (q.planet, repr(w)))
2327 prout(_("by a Klingon invasion fleet."))
2330 elif evcode == FENSLV: # starsystem is enslaved
2331 ev = unschedule(FENSLV)
2332 # see if current distress call still active
2333 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2337 q.status = "enslaved"
2339 # play stork and schedule the first baby
2340 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2341 ev2.quadrant = ev.quadrant
2343 # report the disaster if we can
2345 prout(_("Uhura- We've lost contact with starsystem %s") % \
2347 prout(_("in Quadrant %s.\n") % ev.quadrant)
2348 elif evcode == FREPRO: # Klingon reproduces
2349 # If we ever switch to a real event queue, we'll need to
2350 # explicitly retrieve and restore the x and y.
2351 ev = schedule(FREPRO, expran(1.0 * game.intime))
2352 # see if current distress call still active
2353 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2357 if game.state.remkl >= MAXKLGAME:
2358 continue # full right now
2359 # reproduce one Klingon
2362 if game.klhere >= MAXKLQUAD:
2364 # this quadrant not ok, pick an adjacent one
2365 for m.i in range(w.i - 1, w.i + 2):
2366 for m.j in range(w.j - 1, w.j + 2):
2367 if not m.valid_quadrant():
2369 q = game.state.galaxy[m.i][m.j]
2370 # check for this quad ok (not full & no snova)
2371 if q.klingons >= MAXKLQUAD or q.supernova:
2375 continue # search for eligible quadrant failed
2379 game.state.remkl += 1
2381 if game.quadrant == w:
2383 game.enemies.append(newkling())
2384 # recompute time left
2387 if game.quadrant == w:
2388 prout(_("Spock- sensors indicate the Klingons have"))
2389 prout(_("launched a warship from %s.") % q.planet)
2391 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2392 if q.planet != None:
2393 proutn(_("near %s ") % q.planet)
2394 prout(_("in Quadrant %s.") % w)
2400 key = scanner.next()
2403 proutn(_("How long? "))
2408 origTime = delay = scanner.real
2411 if delay >= game.state.remtime or len(game.enemies) != 0:
2412 proutn(_("Are you sure? "))
2415 # Alternate resting periods (events) with attacks
2419 game.resting = False
2420 if not game.resting:
2421 prout(_("%d stardates left.") % int(game.state.remtime))
2423 temp = game.optime = delay
2424 if len(game.enemies):
2425 rtime = randreal(1.0, 2.0)
2429 if game.optime < delay:
2430 attack(torps_ok=False)
2438 # Repair Deathray if long rest at starbase
2439 if origTime-delay >= 9.99 and game.condition == "docked":
2440 game.damage[DDRAY] = 0.0
2441 # leave if quadrant supernovas
2442 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2444 game.resting = False
2449 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2450 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2452 # Wow! We've supernova'ed
2453 supernova(game.quadrant)
2455 # handle initial nova
2456 game.quad[nov.i][nov.j] = '.'
2457 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2458 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2459 game.state.starkl += 1
2460 # Set up queue to recursively trigger adjacent stars
2466 for offset.i in range(-1, 1+1):
2467 for offset.j in range(-1, 1+1):
2468 if offset.j == 0 and offset.i == 0:
2470 neighbor = start + offset
2471 if not neighbor.valid_sector():
2473 iquad = game.quad[neighbor.i][neighbor.j]
2474 # Empty space ends reaction
2475 if iquad in ('.', '?', ' ', 'T', '#'):
2477 elif iquad == '*': # Affect another star
2479 # This star supernovas
2480 supernova(game.quadrant)
2483 hits.append(neighbor)
2484 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2485 game.state.starkl += 1
2486 proutn(crmena(True, '*', "sector", neighbor))
2488 game.quad[neighbor.i][neighbor.j] = '.'
2490 elif iquad in ('P', '@'): # Destroy planet
2491 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2493 game.state.nplankl += 1
2495 game.state.nworldkl += 1
2496 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2497 game.iplnet.pclass = "destroyed"
2499 game.plnet.invalidate()
2503 game.quad[neighbor.i][neighbor.j] = '.'
2504 elif iquad == 'B': # Destroy base
2505 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2506 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2507 game.base.invalidate()
2508 game.state.basekl += 1
2510 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2511 game.quad[neighbor.i][neighbor.j] = '.'
2512 elif iquad in ('E', 'F'): # Buffet ship
2513 prout(_("***Starship buffeted by nova."))
2515 if game.shield >= 2000.0:
2516 game.shield -= 2000.0
2518 diff = 2000.0 - game.shield
2522 prout(_("***Shields knocked out."))
2523 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2525 game.energy -= 2000.0
2526 if game.energy <= 0:
2529 # add in course nova contributes to kicking starship
2530 bump += (game.sector-hits[-1]).sgn()
2531 elif iquad == 'K': # kill klingon
2532 deadkl(neighbor, iquad, neighbor)
2533 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2534 for ll in range(len(game.enemies)):
2535 if game.enemies[ll].location == neighbor:
2537 game.enemies[ll].power -= 800.0 # If firepower is lost, die
2538 if game.enemies[ll].power <= 0.0:
2539 deadkl(neighbor, iquad, neighbor)
2541 newc = neighbor + neighbor - hits[-1]
2542 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2543 if not newc.valid_sector():
2544 # can't leave quadrant
2547 iquad1 = game.quad[newc.i][newc.j]
2549 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2551 deadkl(neighbor, iquad, newc)
2554 # can't move into something else
2557 proutn(_(", buffeted to Sector %s") % newc)
2558 game.quad[neighbor.i][neighbor.j] = '.'
2559 game.quad[newc.i][newc.j] = iquad
2560 game.enemies[ll].move(newc)
2561 # Starship affected by nova -- kick it away.
2563 direc = ncourse[3*(bump.i+1)+bump.j+2]
2568 scourse = course(bearing=direc, distance=dist)
2569 game.optime = scourse.time(warp=4)
2571 prout(_("Force of nova displaces starship."))
2572 imove(scourse, noattack=True)
2573 game.optime = scourse.time(warp=4)
2577 "Star goes supernova."
2582 # Scheduled supernova -- select star at random.
2585 for nq.i in range(GALSIZE):
2586 for nq.j in range(GALSIZE):
2587 stars += game.state.galaxy[nq.i][nq.j].stars
2589 return # nothing to supernova exists
2590 num = randrange(stars) + 1
2591 for nq.i in range(GALSIZE):
2592 for nq.j in range(GALSIZE):
2593 num -= game.state.galaxy[nq.i][nq.j].stars
2599 proutn("=== Super nova here?")
2602 if not nq == game.quadrant or game.justin:
2603 # it isn't here, or we just entered (treat as enroute)
2606 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2607 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2610 # we are in the quadrant!
2611 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2612 for ns.i in range(QUADSIZE):
2613 for ns.j in range(QUADSIZE):
2614 if game.quad[ns.i][ns.j]=='*':
2621 prouts(_("***RED ALERT! RED ALERT!"))
2623 prout(_("***Incipient supernova detected at Sector %s") % ns)
2624 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2625 proutn(_("Emergency override attempts t"))
2626 prouts("***************")
2630 # destroy any Klingons in supernovaed quadrant
2631 kldead = game.state.galaxy[nq.i][nq.j].klingons
2632 game.state.galaxy[nq.i][nq.j].klingons = 0
2633 if nq == game.state.kscmdr:
2634 # did in the Supercommander!
2635 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2639 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2640 comkills = len(game.state.kcmdr) - len(survivors)
2641 game.state.kcmdr = survivors
2643 if not game.state.kcmdr:
2645 game.state.remkl -= kldead
2646 # destroy Romulans and planets in supernovaed quadrant
2647 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2648 game.state.galaxy[nq.i][nq.j].romulans = 0
2649 game.state.nromrem -= nrmdead
2651 for loop in range(game.inplan):
2652 if game.state.planets[loop].quadrant == nq:
2653 game.state.planets[loop].pclass = "destroyed"
2655 # Destroy any base in supernovaed quadrant
2656 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2657 # If starship caused supernova, tally up destruction
2659 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2660 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2661 game.state.nplankl += npdead
2662 # mark supernova in galaxy and in star chart
2663 if game.quadrant == nq or communicating():
2664 game.state.galaxy[nq.i][nq.j].supernova = True
2665 # If supernova destroys last Klingons give special message
2666 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2669 prout(_("Lucky you!"))
2670 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2673 # if some Klingons remain, continue or die in supernova
2678 # Code from finish.c ends here.
2681 "Self-destruct maneuver. Finish with a BANG!"
2683 if damaged(DCOMPTR):
2684 prout(_("Computer damaged; cannot execute destruct sequence."))
2686 prouts(_("---WORKING---")); skip(1)
2687 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2688 prouts(" 10"); skip(1)
2689 prouts(" 9"); skip(1)
2690 prouts(" 8"); skip(1)
2691 prouts(" 7"); skip(1)
2692 prouts(" 6"); skip(1)
2694 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2696 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2698 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2701 if game.passwd != scanner.token:
2702 prouts(_("PASSWORD-REJECTED;"))
2704 prouts(_("CONTINUITY-EFFECTED"))
2707 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2708 prouts(" 5"); skip(1)
2709 prouts(" 4"); skip(1)
2710 prouts(" 3"); skip(1)
2711 prouts(" 2"); skip(1)
2712 prouts(" 1"); skip(1)
2714 prouts(_("GOODBYE-CRUEL-WORLD"))
2722 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2726 if len(game.enemies) != 0:
2727 whammo = 25.0 * game.energy
2728 for l in range(len(game.enemies)):
2729 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2730 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2734 "Compute our rate of kils over time."
2735 elapsed = game.state.date - game.indate
2736 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2739 starting = (game.inkling + game.incom + game.inscom)
2740 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2741 return (starting - remaining)/elapsed
2745 badpt = 5.0*game.state.starkl + \
2747 10.0*game.state.nplankl + \
2748 300*game.state.nworldkl + \
2750 100.0*game.state.basekl +\
2752 if game.ship == 'F':
2754 elif game.ship == None:
2759 # end the game, with appropriate notfications
2763 prout(_("It is stardate %.1f.") % game.state.date)
2765 if ifin == FWON: # Game has been won
2766 if game.state.nromrem != 0:
2767 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2770 prout(_("You have smashed the Klingon invasion fleet and saved"))
2771 prout(_("the Federation."))
2776 badpt = 0.0 # Close enough!
2777 # killsPerDate >= RateMax
2778 if game.state.date-game.indate < 5.0 or \
2779 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2781 prout(_("In fact, you have done so well that Starfleet Command"))
2782 if game.skill == SKILL_NOVICE:
2783 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2784 elif game.skill == SKILL_FAIR:
2785 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2786 elif game.skill == SKILL_GOOD:
2787 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2788 elif game.skill == SKILL_EXPERT:
2789 prout(_("promotes you to Commodore Emeritus."))
2791 prout(_("Now that you think you're really good, try playing"))
2792 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2793 elif game.skill == SKILL_EMERITUS:
2795 proutn(_("Computer- "))
2796 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2798 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2800 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2802 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2804 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2806 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2808 prout(_("Now you can retire and write your own Star Trek game!"))
2810 elif game.skill >= SKILL_EXPERT:
2811 if game.thawed and not game.idebug:
2812 prout(_("You cannot get a citation, so..."))
2814 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2818 # Only grant long life if alive (original didn't!)
2820 prout(_("LIVE LONG AND PROSPER."))
2825 elif ifin == FDEPLETE: # Federation Resources Depleted
2826 prout(_("Your time has run out and the Federation has been"))
2827 prout(_("conquered. Your starship is now Klingon property,"))
2828 prout(_("and you are put on trial as a war criminal. On the"))
2829 proutn(_("basis of your record, you are "))
2830 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2831 prout(_("acquitted."))
2833 prout(_("LIVE LONG AND PROSPER."))
2835 prout(_("found guilty and"))
2836 prout(_("sentenced to death by slow torture."))
2840 elif ifin == FLIFESUP:
2841 prout(_("Your life support reserves have run out, and"))
2842 prout(_("you die of thirst, starvation, and asphyxiation."))
2843 prout(_("Your starship is a derelict in space."))
2845 prout(_("Your energy supply is exhausted."))
2847 prout(_("Your starship is a derelict in space."))
2848 elif ifin == FBATTLE:
2849 prout(_("The %s has been destroyed in battle.") % crmshp())
2851 prout(_("Dulce et decorum est pro patria mori."))
2853 prout(_("You have made three attempts to cross the negative energy"))
2854 prout(_("barrier which surrounds the galaxy."))
2856 prout(_("Your navigation is abominable."))
2859 prout(_("Your starship has been destroyed by a nova."))
2860 prout(_("That was a great shot."))
2862 elif ifin == FSNOVAED:
2863 prout(_("The %s has been fried by a supernova.") % crmshp())
2864 prout(_("...Not even cinders remain..."))
2865 elif ifin == FABANDN:
2866 prout(_("You have been captured by the Klingons. If you still"))
2867 prout(_("had a starbase to be returned to, you would have been"))
2868 prout(_("repatriated and given another chance. Since you have"))
2869 prout(_("no starbases, you will be mercilessly tortured to death."))
2870 elif ifin == FDILITHIUM:
2871 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2872 elif ifin == FMATERIALIZE:
2873 prout(_("Starbase was unable to re-materialize your starship."))
2874 prout(_("Sic transit gloria mundi"))
2875 elif ifin == FPHASER:
2876 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2878 prout(_("You and your landing party have been"))
2879 prout(_("converted to energy, disipating through space."))
2880 elif ifin == FMINING:
2881 prout(_("You are left with your landing party on"))
2882 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2884 prout(_("They are very fond of \"Captain Kirk\" soup."))
2886 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2887 elif ifin == FDPLANET:
2888 prout(_("You and your mining party perish."))
2890 prout(_("That was a great shot."))
2893 prout(_("The Galileo is instantly annihilated by the supernova."))
2894 prout(_("You and your mining party are atomized."))
2896 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2897 prout(_("joins the Romulans, wreaking terror on the Federation."))
2898 elif ifin == FPNOVA:
2899 prout(_("You and your mining party are atomized."))
2901 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2902 prout(_("joins the Romulans, wreaking terror on the Federation."))
2903 elif ifin == FSTRACTOR:
2904 prout(_("The shuttle craft Galileo is also caught,"))
2905 prout(_("and breaks up under the strain."))
2907 prout(_("Your debris is scattered for millions of miles."))
2908 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2910 prout(_("The mutants attack and kill Spock."))
2911 prout(_("Your ship is captured by Klingons, and"))
2912 prout(_("your crew is put on display in a Klingon zoo."))
2913 elif ifin == FTRIBBLE:
2914 prout(_("Tribbles consume all remaining water,"))
2915 prout(_("food, and oxygen on your ship."))
2917 prout(_("You die of thirst, starvation, and asphyxiation."))
2918 prout(_("Your starship is a derelict in space."))
2920 prout(_("Your ship is drawn to the center of the black hole."))
2921 prout(_("You are crushed into extremely dense matter."))
2923 prout(_("Your last crew member has died."))
2924 if game.ship == 'F':
2926 elif game.ship == 'E':
2929 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2930 goodies = game.state.remres/game.inresor
2931 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2932 if goodies/baddies >= randreal(1.0, 1.5):
2933 prout(_("As a result of your actions, a treaty with the Klingon"))
2934 prout(_("Empire has been signed. The terms of the treaty are"))
2935 if goodies/baddies >= randreal(3.0):
2936 prout(_("favorable to the Federation."))
2938 prout(_("Congratulations!"))
2940 prout(_("highly unfavorable to the Federation."))
2942 prout(_("The Federation will be destroyed."))
2944 prout(_("Since you took the last Klingon with you, you are a"))
2945 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2946 prout(_("statue in your memory. Rest in peace, and try not"))
2947 prout(_("to think about pigeons."))
2952 "Compute player's score."
2953 timused = game.state.date - game.indate
2954 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2956 game.perdate = killrate()
2957 ithperd = 500*game.perdate + 0.5
2960 iwon = 100*game.skill
2961 if game.ship == 'E':
2963 elif game.ship == 'F':
2967 game.score = 10*(game.inkling - game.state.remkl) \
2968 + 50*(game.incom - len(game.state.kcmdr)) \
2970 + 20*(game.inrom - game.state.nromrem) \
2971 + 200*(game.inscom - game.state.nscrem) \
2972 - game.state.nromrem \
2977 prout(_("Your score --"))
2978 if game.inrom - game.state.nromrem:
2979 prout(_("%6d Romulans destroyed %5d") %
2980 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
2981 if game.state.nromrem and game.gamewon:
2982 prout(_("%6d Romulans captured %5d") %
2983 (game.state.nromrem, game.state.nromrem))
2984 if game.inkling - game.state.remkl:
2985 prout(_("%6d ordinary Klingons destroyed %5d") %
2986 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
2987 if game.incom - len(game.state.kcmdr):
2988 prout(_("%6d Klingon commanders destroyed %5d") %
2989 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
2990 if game.inscom - game.state.nscrem:
2991 prout(_("%6d Super-Commander destroyed %5d") %
2992 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
2994 prout(_("%6.2f Klingons per stardate %5d") %
2995 (game.perdate, ithperd))
2996 if game.state.starkl:
2997 prout(_("%6d stars destroyed by your action %5d") %
2998 (game.state.starkl, -5*game.state.starkl))
2999 if game.state.nplankl:
3000 prout(_("%6d planets destroyed by your action %5d") %
3001 (game.state.nplankl, -10*game.state.nplankl))
3002 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3003 prout(_("%6d inhabited planets destroyed by your action %5d") %
3004 (game.state.nworldkl, -300*game.state.nworldkl))
3005 if game.state.basekl:
3006 prout(_("%6d bases destroyed by your action %5d") %
3007 (game.state.basekl, -100*game.state.basekl))
3009 prout(_("%6d calls for help from starbase %5d") %
3010 (game.nhelp, -45*game.nhelp))
3012 prout(_("%6d casualties incurred %5d") %
3013 (game.casual, -game.casual))
3015 prout(_("%6d crew abandoned in space %5d") %
3016 (game.abandoned, -3*game.abandoned))
3018 prout(_("%6d ship(s) lost or destroyed %5d") %
3019 (klship, -100*klship))
3021 prout(_("Penalty for getting yourself killed -200"))
3023 proutn(_("Bonus for winning "))
3024 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3025 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3026 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3027 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3028 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3029 prout(" %5d" % iwon)
3031 prout(_("TOTAL SCORE %5d") % game.score)
3034 "Emit winner's commemmorative plaque."
3037 proutn(_("File or device name for your plaque: "))
3040 fp = open(winner, "w")
3043 prout(_("Invalid name."))
3045 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3047 # The 38 below must be 64 for 132-column paper
3048 nskip = 38 - len(winner)/2
3049 fp.write("\n\n\n\n")
3050 # --------DRAW ENTERPRISE PICTURE.
3051 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3052 fp.write(" EEE E : : : E\n" )
3053 fp.write(" EE EEE E : : NCC-1701 : E\n")
3054 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3055 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3056 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3057 fp.write(" EEEEEEE EEEEE E E E E\n")
3058 fp.write(" EEE E E E E\n")
3059 fp.write(" E E E E\n")
3060 fp.write(" EEEEEEEEEEEEE E E\n")
3061 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3062 fp.write(" :E : EEEE E\n")
3063 fp.write(" .-E -:----- E\n")
3064 fp.write(" :E : E\n")
3065 fp.write(" EE : EEEEEEEE\n")
3066 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3068 fp.write(_(" U. S. S. ENTERPRISE\n"))
3069 fp.write("\n\n\n\n")
3070 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3072 fp.write(_(" Starfleet Command bestows to you\n"))
3074 fp.write("%*s%s\n\n" % (nskip, "", winner))
3075 fp.write(_(" the rank of\n\n"))
3076 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3078 if game.skill == SKILL_EXPERT:
3079 fp.write(_(" Expert level\n\n"))
3080 elif game.skill == SKILL_EMERITUS:
3081 fp.write(_("Emeritus level\n\n"))
3083 fp.write(_(" Cheat level\n\n"))
3084 timestring = time.ctime()
3085 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3086 (timestring+4, timestring+20, timestring+11))
3087 fp.write(_(" Your score: %d\n\n") % game.score)
3088 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3091 # Code from io.c begins here
3093 rows = linecount = 0 # for paging
3096 fullscreen_window = None
3097 srscan_window = None
3098 report_window = None
3099 status_window = None
3100 lrscan_window = None
3101 message_window = None
3102 prompt_window = None
3107 "for some recent versions of python2, the following enables UTF8"
3108 "for the older ones we probably need to set C locale, and the python3"
3109 "has no problems at all"
3110 if sys.version_info[0] < 3:
3112 locale.setlocale(locale.LC_ALL, "")
3113 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3114 gettext.textdomain("sst")
3115 if not (game.options & OPTION_CURSES):
3116 ln_env = os.getenv("LINES")
3122 stdscr = curses.initscr()
3126 if game.options & OPTION_COLOR:
3127 curses.start_color()
3128 curses.use_default_colors()
3129 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3130 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3131 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3132 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3133 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3134 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3135 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3136 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3137 global fullscreen_window, srscan_window, report_window, status_window
3138 global lrscan_window, message_window, prompt_window
3139 (rows, columns) = stdscr.getmaxyx()
3140 fullscreen_window = stdscr
3141 srscan_window = curses.newwin(12, 25, 0, 0)
3142 report_window = curses.newwin(11, 0, 1, 25)
3143 status_window = curses.newwin(10, 0, 1, 39)
3144 lrscan_window = curses.newwin(5, 0, 0, 64)
3145 message_window = curses.newwin(0, 0, 12, 0)
3146 prompt_window = curses.newwin(1, 0, rows-2, 0)
3147 message_window.scrollok(True)
3148 setwnd(fullscreen_window)
3152 if game.options & OPTION_CURSES:
3153 stdscr.keypad(False)
3159 "Wait for user action -- OK to do nothing if on a TTY"
3160 if game.options & OPTION_CURSES:
3165 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3169 if game.skill > SKILL_FAIR:
3170 prompt = _("[CONTINUE?]")
3172 prompt = _("[PRESS ENTER TO CONTINUE]")
3174 if game.options & OPTION_CURSES:
3176 setwnd(prompt_window)
3177 prompt_window.clear()
3178 prompt_window.addstr(prompt)
3179 prompt_window.getstr()
3180 prompt_window.clear()
3181 prompt_window.refresh()
3182 setwnd(message_window)
3185 sys.stdout.write('\n')
3188 sys.stdout.write('\n' * rows)
3192 "Skip i lines. Pause game if this would cause a scrolling event."
3193 for dummy in range(i):
3194 if game.options & OPTION_CURSES:
3195 (y, x) = curwnd.getyx()
3198 except curses.error:
3203 if rows and linecount >= rows:
3206 sys.stdout.write('\n')
3209 "Utter a line with no following line feed."
3210 if game.options & OPTION_CURSES:
3211 (y, x) = curwnd.getyx()
3212 (my, mx) = curwnd.getmaxyx()
3213 if curwnd == message_window and y >= my - 2:
3219 sys.stdout.write(line)
3229 if not replayfp or replayfp.closed: # Don't slow down replays
3232 if game.options & OPTION_CURSES:
3236 if not replayfp or replayfp.closed:
3240 "Get a line of input."
3241 if game.options & OPTION_CURSES:
3242 line = curwnd.getstr() + "\n"
3245 if replayfp and not replayfp.closed:
3247 line = replayfp.readline()
3250 prout("*** Replay finished")
3253 elif line[0] != "#":
3256 line = raw_input() + "\n"
3262 "Change windows -- OK for this to be a no-op in tty mode."
3264 if game.options & OPTION_CURSES:
3266 curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window)
3269 "Clear to end of line -- can be a no-op in tty mode"
3270 if game.options & OPTION_CURSES:
3275 "Clear screen -- can be a no-op in tty mode."
3277 if game.options & OPTION_CURSES:
3283 def textcolor(color=DEFAULT):
3284 if game.options & OPTION_COLOR:
3285 if color == DEFAULT:
3287 elif color == BLACK:
3288 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3290 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3291 elif color == GREEN:
3292 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3294 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3296 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3297 elif color == MAGENTA:
3298 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3299 elif color == BROWN:
3300 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3301 elif color == LIGHTGRAY:
3302 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3303 elif color == DARKGRAY:
3304 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3305 elif color == LIGHTBLUE:
3306 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3307 elif color == LIGHTGREEN:
3308 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3309 elif color == LIGHTCYAN:
3310 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3311 elif color == LIGHTRED:
3312 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3313 elif color == LIGHTMAGENTA:
3314 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3315 elif color == YELLOW:
3316 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3317 elif color == WHITE:
3318 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3321 if game.options & OPTION_COLOR:
3322 curwnd.attron(curses.A_REVERSE)
3325 # Things past this point have policy implications.
3329 "Hook to be called after moving to redraw maps."
3330 if game.options & OPTION_CURSES:
3333 setwnd(srscan_window)
3337 setwnd(status_window)
3338 status_window.clear()
3339 status_window.move(0, 0)
3340 setwnd(report_window)
3341 report_window.clear()
3342 report_window.move(0, 0)
3344 setwnd(lrscan_window)
3345 lrscan_window.clear()
3346 lrscan_window.move(0, 0)
3347 lrscan(silent=False)
3349 def put_srscan_sym(w, sym):
3350 "Emit symbol for short-range scan."
3351 srscan_window.move(w.i+1, w.j*2+2)
3352 srscan_window.addch(sym)
3353 srscan_window.refresh()
3356 "Enemy fall down, go boom."
3357 if game.options & OPTION_CURSES:
3359 setwnd(srscan_window)
3360 srscan_window.attron(curses.A_REVERSE)
3361 put_srscan_sym(w, game.quad[w.i][w.j])
3365 srscan_window.attroff(curses.A_REVERSE)
3366 put_srscan_sym(w, game.quad[w.i][w.j])
3367 curses.delay_output(500)
3368 setwnd(message_window)
3371 "Sound and visual effects for teleportation."
3372 if game.options & OPTION_CURSES:
3374 setwnd(message_window)
3376 prouts(" . . . . . ")
3377 if game.options & OPTION_CURSES:
3378 #curses.delay_output(1000)
3382 def tracktorpedo(w, step, i, n, iquad):
3383 "Torpedo-track animation."
3384 if not game.options & OPTION_CURSES:
3388 proutn(_("Track for torpedo number %d- ") % (i+1))
3391 proutn(_("Torpedo track- "))
3392 elif step==4 or step==9:
3396 if not damaged(DSRSENS) or game.condition=="docked":
3397 if i != 0 and step == 1:
3400 if (iquad=='.') or (iquad==' '):
3401 put_srscan_sym(w, '+')
3405 put_srscan_sym(w, iquad)
3407 curwnd.attron(curses.A_REVERSE)
3408 put_srscan_sym(w, iquad)
3412 curwnd.attroff(curses.A_REVERSE)
3413 put_srscan_sym(w, iquad)
3418 "Display the current galaxy chart."
3419 if game.options & OPTION_CURSES:
3420 setwnd(message_window)
3421 message_window.clear()
3423 if game.options & OPTION_TTY:
3428 def prstat(txt, data):
3430 if game.options & OPTION_CURSES:
3432 setwnd(status_window)
3434 proutn(" " * (NSYM - len(txt)))
3437 if game.options & OPTION_CURSES:
3438 setwnd(report_window)
3440 # Code from moving.c begins here
3442 def imove(icourse=None, noattack=False):
3443 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3446 def newquadrant(noattack):
3447 # Leaving quadrant -- allow final enemy attack
3448 # Don't do it if being pushed by Nova
3449 if len(game.enemies) != 0 and not noattack:
3451 for enemy in game.enemies:
3452 finald = (w - enemy.location).distance()
3453 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3454 # Stas Sergeev added the condition
3455 # that attacks only happen if Klingons
3456 # are present and your skill is good.
3457 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3458 attack(torps_ok=False)
3461 # check for edge of galaxy
3465 if icourse.final.i < 0:
3466 icourse.final.i = -icourse.final.i
3468 if icourse.final.j < 0:
3469 icourse.final.j = -icourse.final.j
3471 if icourse.final.i >= GALSIZE*QUADSIZE:
3472 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3474 if icourse.final.j >= GALSIZE*QUADSIZE:
3475 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3483 if game.nkinks == 3:
3484 # Three strikes -- you're out!
3488 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3489 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3490 prout(_("YOU WILL BE DESTROYED."))
3491 # Compute final position in new quadrant
3492 if trbeam: # Don't bother if we are to be beamed
3494 game.quadrant = icourse.final.quadrant()
3495 game.sector = icourse.final.sector()
3497 prout(_("Entering Quadrant %s.") % game.quadrant)
3498 game.quad[game.sector.i][game.sector.j] = game.ship
3500 if game.skill>SKILL_NOVICE:
3501 attack(torps_ok=False)
3503 def check_collision(h):
3504 iquad = game.quad[h.i][h.j]
3506 # object encountered in flight path
3507 stopegy = 50.0*icourse.distance/game.optime
3508 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3509 for enemy in game.enemies:
3510 if enemy.location == game.sector:
3512 collision(rammed=False, enemy=enemy)
3516 prouts(_("***RED ALERT! RED ALERT!"))
3518 proutn("***" + crmshp())
3519 proutn(_(" pulled into black hole at Sector %s") % h)
3520 # Getting pulled into a black hole was certain
3521 # death in Almy's original. Stas Sergeev added a
3522 # possibility that you'll get timewarped instead.
3524 for m in range(NDEVICES):
3525 if game.damage[m]>0:
3527 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3528 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3538 prout(_(" encounters Tholian web at %s;") % h)
3540 prout(_(" blocked by object at %s;") % h)
3541 proutn(_("Emergency stop required "))
3542 prout(_("%2d units of energy.") % int(stopegy))
3543 game.energy -= stopegy
3544 if game.energy <= 0:
3551 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3552 game.inorbit = False
3553 # If tractor beam is to occur, don't move full distance
3554 if game.state.date+game.optime >= scheduled(FTBEAM):
3556 game.condition = "red"
3557 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3558 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3560 game.quad[game.sector.i][game.sector.j] = '.'
3561 for m in range(icourse.moves):
3563 w = icourse.sector()
3564 if icourse.origin.quadrant() != icourse.location.quadrant():
3565 newquadrant(noattack)
3567 elif check_collision(w):
3568 print "Collision detected"
3572 # We're in destination quadrant -- compute new average enemy distances
3573 game.quad[game.sector.i][game.sector.j] = game.ship
3575 for enemy in game.enemies:
3576 finald = (w-enemy.location).distance()
3577 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3578 enemy.kdist = finald
3580 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3581 attack(torps_ok=False)
3582 for enemy in game.enemies:
3583 enemy.kavgd = enemy.kdist
3586 setwnd(message_window)
3590 "Dock our ship at a starbase."
3592 if game.condition == "docked" and verbose:
3593 prout(_("Already docked."))
3596 prout(_("You must first leave standard orbit."))
3598 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3599 prout(crmshp() + _(" not adjacent to base."))
3601 game.condition = "docked"
3605 if game.energy < game.inenrg:
3606 game.energy = game.inenrg
3607 game.shield = game.inshld
3608 game.torps = game.intorps
3609 game.lsupres = game.inlsr
3610 game.state.crew = FULLCREW
3611 if not damaged(DRADIO) and \
3612 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3613 # get attack report from base
3614 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3618 def cartesian(loc1=None, loc2=None):
3620 return game.quadrant * QUADSIZE + game.sector
3622 return game.quadrant * QUADSIZE + loc1
3624 return loc1 * QUADSIZE + loc2
3626 def getcourse(isprobe):
3627 "Get a course and distance from the user."
3629 dquad = copy.copy(game.quadrant)
3630 navmode = "unspecified"
3634 if game.landed and not isprobe:
3635 prout(_("Dummy! You can't leave standard orbit until you"))
3636 proutn(_("are back aboard the ship."))
3639 while navmode == "unspecified":
3640 if damaged(DNAVSYS):
3642 prout(_("Computer damaged; manual navigation only"))
3644 prout(_("Computer damaged; manual movement only"))
3649 key = scanner.next()
3651 proutn(_("Manual or automatic- "))
3654 elif key == "IHALPHA":
3655 if scanner.sees("manual"):
3657 key = scanner.next()
3659 elif scanner.sees("automatic"):
3660 navmode = "automatic"
3661 key = scanner.next()
3669 prout(_("(Manual navigation assumed.)"))
3671 prout(_("(Manual movement assumed.)"))
3675 if navmode == "automatic":
3676 while key == "IHEOL":
3678 proutn(_("Target quadrant or quadrant§or- "))
3680 proutn(_("Destination sector or quadrant§or- "))
3683 key = scanner.next()
3687 xi = int(round(scanner.real))-1
3688 key = scanner.next()
3692 xj = int(round(scanner.real))-1
3693 key = scanner.next()
3695 # both quadrant and sector specified
3696 xk = int(round(scanner.real))-1
3697 key = scanner.next()
3701 xl = int(round(scanner.real))-1
3707 # only one pair of numbers was specified
3709 # only quadrant specified -- go to center of dest quad
3712 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3714 # only sector specified
3718 if not dquad.valid_quadrant() or not dsect.valid_sector():
3725 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3727 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3728 # the actual deltas get computed here
3729 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3730 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3732 while key == "IHEOL":
3733 proutn(_("X and Y displacements- "))
3736 key = scanner.next()
3741 delta.j = scanner.real
3742 key = scanner.next()
3746 delta.i = scanner.real
3747 # Check for zero movement
3748 if delta.i == 0 and delta.j == 0:
3751 if itemp == "verbose" and not isprobe:
3753 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3755 return course(bearing=delta.bearing(), distance=delta.distance())
3758 def __init__(self, bearing, distance, origin=None):
3759 self.distance = distance
3760 self.bearing = bearing
3762 self.origin = cartesian(game.quadrant, game.sector)
3764 self.origin = origin
3765 # The bearing() code we inherited from FORTRAN is actually computing
3766 # clockface directions!
3767 if self.bearing < 0.0:
3768 self.bearing += 12.0
3769 self.angle = ((15.0 - self.bearing) * 0.5235988)
3771 self.origin = cartesian(game.quadrant, game.sector)
3773 self.origin = cartesian(game.quadrant, origin)
3774 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
3775 bigger = max(abs(self.increment.i), abs(self.increment.j))
3776 self.increment /= bigger
3777 self.moves = int(round(10*self.distance*bigger))
3779 self.final = (self.location + self.moves*self.increment).roundtogrid()
3781 self.location = self.origin
3784 return self.location.roundtogrid() == self.final
3786 "Next step on course."
3788 self.nextlocation = self.location + self.increment
3789 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3790 self.location = self.nextlocation
3793 return self.location.quadrant()
3795 return self.location.sector()
3796 def power(self, warp):
3797 return self.distance*(warp**3)*(game.shldup+1)
3798 def time(self, warp):
3799 return 10.0*self.distance/warp**2
3802 "Move under impulse power."
3804 if damaged(DIMPULS):
3807 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3809 if game.energy > 30.0:
3811 course = getcourse(isprobe=False)
3814 power = 20.0 + 100.0*course.distance
3817 if power >= game.energy:
3818 # Insufficient power for trip
3820 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3821 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3822 if game.energy > 30:
3823 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3824 int(0.01 * (game.energy-20.0)-0.05))
3825 prout(_(" quadrants.\""))
3827 prout(_("quadrant. They are, therefore, useless.\""))
3830 # Make sure enough time is left for the trip
3831 game.optime = course.dist/0.095
3832 if game.optime >= game.state.remtime:
3833 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3834 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3835 proutn(_("we dare spend the time?\" "))
3838 # Activate impulse engines and pay the cost
3839 imove(course, noattack=False)
3843 power = 20.0 + 100.0*course.dist
3844 game.energy -= power
3845 game.optime = course.dist/0.095
3846 if game.energy <= 0:
3850 def warp(wcourse, involuntary):
3851 "ove under warp drive."
3852 blooey = False; twarp = False
3853 if not involuntary: # Not WARPX entry
3855 if game.damage[DWARPEN] > 10.0:
3858 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3860 if damaged(DWARPEN) and game.warpfac > 4.0:
3863 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3864 prout(_(" is repaired, I can only give you warp 4.\""))
3866 # Read in course and distance
3869 wcourse = getcourse(isprobe=False)
3872 # Make sure starship has enough energy for the trip
3873 # Note: this formula is slightly different from the C version,
3874 # and lets you skate a bit closer to the edge.
3875 if wcourse.power(game.warpfac) >= game.energy:
3876 # Insufficient power for trip
3879 prout(_("Engineering to bridge--"))
3880 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
3881 iwarp = (game.energy/(wcourse.dist+0.05)) ** 0.333333333
3883 prout(_("We can't do it, Captain. We don't have enough energy."))
3885 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3888 prout(_("if you'll lower the shields."))
3892 prout(_("We haven't the energy to go that far with the shields up."))
3894 # Make sure enough time is left for the trip
3895 game.optime = wcourse.time(game.warpfac)
3896 if game.optime >= 0.8*game.state.remtime:
3898 prout(_("First Officer Spock- \"Captain, I compute that such"))
3899 proutn(_(" a trip would require approximately %2.0f") %
3900 (100.0*game.optime/game.state.remtime))
3901 prout(_(" percent of our"))
3902 proutn(_(" remaining time. Are you sure this is wise?\" "))
3908 if game.warpfac > 6.0:
3909 # Decide if engine damage will occur
3910 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3911 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
3912 if prob > randreal():
3914 wcourse.distance = randreal(wcourse.distance)
3915 # Decide if time warp will occur
3916 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3918 if game.idebug and game.warpfac==10 and not twarp:
3920 proutn("=== Force time warp? ")
3924 # If time warp or engine damage, check path
3925 # If it is obstructed, don't do warp or damage
3926 look = wcourse.moves
3930 w = wcourse.sector()
3931 if not w.valid_sector():
3933 if game.quad[w.i][w.j] != '.':
3937 # Activate Warp Engines and pay the cost
3938 imove(wcourse, noattack=False)
3941 game.energy -= wcourse.power(game.warpfac)
3942 if game.energy <= 0:
3944 game.optime = wcourse.time(game.warpfac)
3948 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
3950 prout(_("Engineering to bridge--"))
3951 prout(_(" Scott here. The warp engines are damaged."))
3952 prout(_(" We'll have to reduce speed to warp 4."))
3957 "Change the warp factor."
3963 proutn(_("Warp factor- "))
3967 if game.damage[DWARPEN] > 10.0:
3968 prout(_("Warp engines inoperative."))
3970 if damaged(DWARPEN) and scanner.real > 4.0:
3971 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
3972 prout(_(" but right now we can only go warp 4.\""))
3974 if scanner.real > 10.0:
3975 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
3977 if scanner.real < 1.0:
3978 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
3980 oldfac = game.warpfac
3981 game.warpfac = scanner.real
3982 if game.warpfac <= oldfac or game.warpfac <= 6.0:
3983 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
3986 if game.warpfac < 8.00:
3987 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
3989 if game.warpfac == 10.0:
3990 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
3992 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
3996 "Cope with being tossed out of quadrant by supernova or yanked by beam."
3998 # is captain on planet?
4000 if damaged(DTRANSP):
4003 prout(_("Scotty rushes to the transporter controls."))
4005 prout(_("But with the shields up it's hopeless."))
4007 prouts(_("His desperate attempt to rescue you . . ."))
4012 prout(_("SUCCEEDS!"))
4015 proutn(_("The crystals mined were "))
4023 # Check to see if captain in shuttle craft
4028 # Inform captain of attempt to reach safety
4032 prouts(_("***RED ALERT! RED ALERT!"))
4034 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4035 prouts(_(" a supernova."))
4037 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4038 prout(_("safely out of quadrant."))
4039 if not damaged(DRADIO):
4040 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4041 # Try to use warp engines
4042 if damaged(DWARPEN):
4044 prout(_("Warp engines damaged."))
4047 game.warpfac = randreal(6.0, 8.0)
4048 prout(_("Warp factor set to %d") % int(game.warpfac))
4049 power = 0.75*game.energy
4050 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4051 dist = max(dist, randreal(math.sqrt(2)))
4052 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4053 game.optime = bugout.time(game.warpfac)
4055 game.inorbit = False
4056 warp(bugout, involuntary=True)
4058 # This is bad news, we didn't leave quadrant.
4062 prout(_("Insufficient energy to leave quadrant."))
4065 # Repeat if another snova
4066 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4068 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4069 finish(FWON) # Snova killed remaining enemy.
4072 "Let's do the time warp again."
4073 prout(_("***TIME WARP ENTERED."))
4074 if game.state.snap and withprob(0.5):
4076 prout(_("You are traveling backwards in time %d stardates.") %
4077 int(game.state.date-game.snapsht.date))
4078 game.state = game.snapsht
4079 game.state.snap = False
4080 if len(game.state.kcmdr):
4081 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4082 schedule(FBATTAK, expran(0.3*game.intime))
4083 schedule(FSNOVA, expran(0.5*game.intime))
4084 # next snapshot will be sooner
4085 schedule(FSNAP, expran(0.25*game.state.remtime))
4087 if game.state.nscrem:
4088 schedule(FSCMOVE, 0.2777)
4092 game.battle.invalidate()
4093 # Make sure Galileo is consistant -- Snapshot may have been taken
4094 # when on planet, which would give us two Galileos!
4096 for l in range(game.inplan):
4097 if game.state.planets[l].known == "shuttle_down":
4099 if game.iscraft == "onship" and game.ship=='E':
4100 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4101 game.iscraft = "offship"
4102 # Likewise, if in the original time the Galileo was abandoned, but
4103 # was on ship earlier, it would have vanished -- let's restore it.
4104 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4105 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4106 game.iscraft = "onship"
4107 # There used to be code to do the actual reconstrction here,
4108 # but the starchart is now part of the snapshotted galaxy state.
4109 prout(_("Spock has reconstructed a correct star chart from memory"))
4111 # Go forward in time
4112 game.optime = expran(0.5*game.intime)
4113 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4114 # cheat to make sure no tractor beams occur during time warp
4115 postpone(FTBEAM, game.optime)
4116 game.damage[DRADIO] += game.optime
4118 events() # Stas Sergeev added this -- do pending events
4121 "Launch deep-space probe."
4122 # New code to launch a deep space probe
4123 if game.nprobes == 0:
4126 if game.ship == 'E':
4127 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4129 prout(_("Ye Faerie Queene has no deep space probes."))
4134 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4136 if is_scheduled(FDSPROB):
4139 if damaged(DRADIO) and game.condition != "docked":
4140 prout(_("Spock- \"Records show the previous probe has not yet"))
4141 prout(_(" reached its destination.\""))
4143 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4145 key = scanner.next()
4147 if game.nprobes == 1:
4148 prout(_("1 probe left."))
4150 prout(_("%d probes left") % game.nprobes)
4151 proutn(_("Are you sure you want to fire a probe? "))
4154 game.isarmed = False
4155 if key == "IHALPHA" and scanner.token == "armed":
4157 key = scanner.next()
4158 elif key == "IHEOL":
4159 proutn(_("Arm NOVAMAX warhead? "))
4161 elif key == "IHREAL": # first element of course
4162 scanner.push(scanner.token)
4164 game.probe = getcourse(isprobe=True)
4168 schedule(FDSPROB, 0.01) # Time to move one sector
4169 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4174 "Yell for help from nearest starbase."
4175 # There's more than one way to move in this game!
4177 # Test for conditions which prevent calling for help
4178 if game.condition == "docked":
4179 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4182 prout(_("Subspace radio damaged."))
4184 if not game.state.baseq:
4185 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4188 prout(_("You must be aboard the %s.") % crmshp())
4190 # OK -- call for help from nearest starbase
4193 # There's one in this quadrant
4194 ddist = (game.base - game.sector).distance()
4197 for ibq in game.state.baseq:
4198 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4201 # Since starbase not in quadrant, set up new quadrant
4204 # dematerialize starship
4205 game.quad[game.sector.i][game.sector.j]='.'
4206 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4207 % (game.quadrant, crmshp()))
4208 game.sector.invalidate()
4209 for m in range(1, 5+1):
4210 w = game.base.scatter()
4211 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4212 # found one -- finish up
4215 if not game.sector.is_valid():
4216 prout(_("You have been lost in space..."))
4217 finish(FMATERIALIZE)
4219 # Give starbase three chances to rematerialize starship
4220 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4221 for m in range(1, 3+1):
4222 if m == 1: proutn(_("1st"))
4223 elif m == 2: proutn(_("2nd"))
4224 elif m == 3: proutn(_("3rd"))
4225 proutn(_(" attempt to re-materialize ") + crmshp())
4226 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4229 if randreal() > probf:
4233 curses.delay_output(500)
4235 game.quad[game.sector.i][game.sector.j]='?'
4238 setwnd(message_window)
4239 finish(FMATERIALIZE)
4241 game.quad[game.sector.i][game.sector.j]=game.ship
4243 prout(_("succeeds."))
4247 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4252 if game.condition=="docked":
4254 prout(_("You cannot abandon Ye Faerie Queene."))
4257 # Must take shuttle craft to exit
4258 if game.damage[DSHUTTL]==-1:
4259 prout(_("Ye Faerie Queene has no shuttle craft."))
4261 if game.damage[DSHUTTL]<0:
4262 prout(_("Shuttle craft now serving Big Macs."))
4264 if game.damage[DSHUTTL]>0:
4265 prout(_("Shuttle craft damaged."))
4268 prout(_("You must be aboard the ship."))
4270 if game.iscraft != "onship":
4271 prout(_("Shuttle craft not currently available."))
4273 # Emit abandon ship messages
4275 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4277 prouts(_("***ALL HANDS ABANDON SHIP!"))
4279 prout(_("Captain and crew escape in shuttle craft."))
4280 if not game.state.baseq:
4281 # Oops! no place to go...
4284 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4286 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4287 prout(_("Remainder of ship's complement beam down"))
4288 prout(_("to nearest habitable planet."))
4289 elif q.planet != None and not damaged(DTRANSP):
4290 prout(_("Remainder of ship's complement beam down to %s.") %
4293 prout(_("Entire crew of %d left to die in outer space.") %
4295 game.casual += game.state.crew
4296 game.abandoned += game.state.crew
4297 # If at least one base left, give 'em the Faerie Queene
4299 game.icrystl = False # crystals are lost
4300 game.nprobes = 0 # No probes
4301 prout(_("You are captured by Klingons and released to"))
4302 prout(_("the Federation in a prisoner-of-war exchange."))
4303 nb = randrange(len(game.state.baseq))
4304 # Set up quadrant and position FQ adjacient to base
4305 if not game.quadrant == game.state.baseq[nb]:
4306 game.quadrant = game.state.baseq[nb]
4307 game.sector.i = game.sector.j = 5
4310 # position next to base by trial and error
4311 game.quad[game.sector.i][game.sector.j] = '.'
4312 for l in range(QUADSIZE):
4313 game.sector = game.base.scatter()
4314 if game.sector.valid_sector() and \
4315 game.quad[game.sector.i][game.sector.j] == '.':
4318 break # found a spot
4319 game.sector.i=QUADSIZE/2
4320 game.sector.j=QUADSIZE/2
4322 # Get new commission
4323 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4324 game.state.crew = FULLCREW
4325 prout(_("Starfleet puts you in command of another ship,"))
4326 prout(_("the Faerie Queene, which is antiquated but,"))
4327 prout(_("still useable."))
4329 prout(_("The dilithium crystals have been moved."))
4331 game.iscraft = "offship" # Galileo disappears
4333 game.condition="docked"
4334 for l in range(NDEVICES):
4335 game.damage[l] = 0.0
4336 game.damage[DSHUTTL] = -1
4337 game.energy = game.inenrg = 3000.0
4338 game.shield = game.inshld = 1250.0
4339 game.torps = game.intorps = 6
4340 game.lsupres=game.inlsr=3.0
4345 # Code from planets.c begins here.
4348 "Abort a lengthy operation if an event interrupts it."
4351 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4356 "Report on (uninhabited) planets in the galaxy."
4360 prout(_("Spock- \"Planet report follows, Captain.\""))
4362 for i in range(game.inplan):
4363 if game.state.planets[i].pclass == "destroyed":
4365 if (game.state.planets[i].known != "unknown" \
4366 and not game.state.planets[i].inhabited) \
4369 if game.idebug and game.state.planets[i].known=="unknown":
4370 proutn("(Unknown) ")
4371 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4372 proutn(_(" class "))
4373 proutn(game.state.planets[i].pclass)
4375 if game.state.planets[i].crystals != "present":
4377 prout(_("dilithium crystals present."))
4378 if game.state.planets[i].known=="shuttle_down":
4379 prout(_(" Shuttle Craft Galileo on surface."))
4381 prout(_("No information available."))
4384 "Enter standard orbit."
4388 prout(_("Already in standard orbit."))
4390 if damaged(DWARPEN) and damaged(DIMPULS):
4391 prout(_("Both warp and impulse engines damaged."))
4393 if not game.plnet.is_valid():
4394 prout("There is no planet in this sector.")
4396 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4397 prout(crmshp() + _(" not adjacent to planet."))
4400 game.optime = randreal(0.02, 0.05)
4401 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4405 game.height = randreal(1400, 8600)
4406 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4411 "Examine planets in this quadrant."
4412 if damaged(DSRSENS):
4413 if game.options & OPTION_TTY:
4414 prout(_("Short range sensors damaged."))
4416 if game.iplnet == None:
4417 if game.options & OPTION_TTY:
4418 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4420 if game.iplnet.known == "unknown":
4421 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4423 prout(_(" Planet at Sector %s is of class %s.") %
4424 (game.plnet, game.iplnet.pclass))
4425 if game.iplnet.known=="shuttle_down":
4426 prout(_(" Sensors show Galileo still on surface."))
4427 proutn(_(" Readings indicate"))
4428 if game.iplnet.crystals != "present":
4430 prout(_(" dilithium crystals present.\""))
4431 if game.iplnet.known == "unknown":
4432 game.iplnet.known = "known"
4433 elif game.iplnet.inhabited:
4434 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4435 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4438 "Use the transporter."
4442 if damaged(DTRANSP):
4443 prout(_("Transporter damaged."))
4444 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4446 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4450 if not game.inorbit:
4451 prout(crmshp() + _(" not in standard orbit."))
4454 prout(_("Impossible to transport through shields."))
4456 if game.iplnet.known=="unknown":
4457 prout(_("Spock- \"Captain, we have no information on this planet"))
4458 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4459 prout(_(" you may not go down.\""))
4461 if not game.landed and game.iplnet.crystals=="absent":
4462 prout(_("Spock- \"Captain, I fail to see the logic in"))
4463 prout(_(" exploring a planet with no dilithium crystals."))
4464 proutn(_(" Are you sure this is wise?\" "))
4468 if not (game.options & OPTION_PLAIN):
4469 nrgneed = 50 * game.skill + game.height / 100.0
4470 if nrgneed > game.energy:
4471 prout(_("Engineering to bridge--"))
4472 prout(_(" Captain, we don't have enough energy for transportation."))
4474 if not game.landed and nrgneed * 2 > game.energy:
4475 prout(_("Engineering to bridge--"))
4476 prout(_(" Captain, we have enough energy only to transport you down to"))
4477 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4478 if game.iplnet.known == "shuttle_down":
4479 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4480 proutn(_(" Are you sure this is wise?\" "))
4485 # Coming from planet
4486 if game.iplnet.known=="shuttle_down":
4487 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4491 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4492 prout(_("Landing party assembled, ready to beam up."))
4494 prout(_("Kirk whips out communicator..."))
4495 prouts(_("BEEP BEEP BEEP"))
4497 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4500 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4502 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4504 prout(_("Kirk- \"Energize.\""))
4507 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4510 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4512 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4515 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4516 game.landed = not game.landed
4517 game.energy -= nrgneed
4519 prout(_("Transport complete."))
4520 if game.landed and game.iplnet.known=="shuttle_down":
4521 prout(_("The shuttle craft Galileo is here!"))
4522 if not game.landed and game.imine:
4529 "Strip-mine a world for dilithium."
4533 prout(_("Mining party not on planet."))
4535 if game.iplnet.crystals == "mined":
4536 prout(_("This planet has already been strip-mined for dilithium."))
4538 elif game.iplnet.crystals == "absent":
4539 prout(_("No dilithium crystals on this planet."))
4542 prout(_("You've already mined enough crystals for this trip."))
4544 if game.icrystl and game.cryprob == 0.05:
4545 prout(_("With all those fresh crystals aboard the ") + crmshp())
4546 prout(_("there's no reason to mine more at this time."))
4548 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4551 prout(_("Mining operation complete."))
4552 game.iplnet.crystals = "mined"
4553 game.imine = game.ididit = True
4556 "Use dilithium crystals."
4560 if not game.icrystl:
4561 prout(_("No dilithium crystals available."))
4563 if game.energy >= 1000:
4564 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4565 prout(_(" except when Condition Yellow exists."))
4567 prout(_("Spock- \"Captain, I must warn you that loading"))
4568 prout(_(" raw dilithium crystals into the ship's power"))
4569 prout(_(" system may risk a severe explosion."))
4570 proutn(_(" Are you sure this is wise?\" "))
4575 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4576 prout(_(" Mr. Spock and I will try it.\""))
4578 prout(_("Spock- \"Crystals in place, Sir."))
4579 prout(_(" Ready to activate circuit.\""))
4581 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4583 if withprob(game.cryprob):
4584 prouts(_(" \"Activating now! - - No good! It's***"))
4586 prouts(_("***RED ALERT! RED A*L********************************"))
4589 prouts(_("****************** KA-BOOM!!!! *******************"))
4593 game.energy += randreal(5000.0, 5500.0)
4594 prouts(_(" \"Activating now! - - "))
4595 prout(_("The instruments"))
4596 prout(_(" are going crazy, but I think it's"))
4597 prout(_(" going to work!! Congratulations, Sir!\""))
4602 "Use shuttlecraft for planetary jaunt."
4605 if damaged(DSHUTTL):
4606 if game.damage[DSHUTTL] == -1.0:
4607 if game.inorbit and game.iplnet.known == "shuttle_down":
4608 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4610 prout(_("Ye Faerie Queene had no shuttle craft."))
4611 elif game.damage[DSHUTTL] > 0:
4612 prout(_("The Galileo is damaged."))
4613 else: # game.damage[DSHUTTL] < 0
4614 prout(_("Shuttle craft is now serving Big Macs."))
4616 if not game.inorbit:
4617 prout(crmshp() + _(" not in standard orbit."))
4619 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4620 prout(_("Shuttle craft not currently available."))
4622 if not game.landed and game.iplnet.known=="shuttle_down":
4623 prout(_("You will have to beam down to retrieve the shuttle craft."))
4625 if game.shldup or game.condition == "docked":
4626 prout(_("Shuttle craft cannot pass through shields."))
4628 if game.iplnet.known=="unknown":
4629 prout(_("Spock- \"Captain, we have no information on this planet"))
4630 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4631 prout(_(" you may not fly down.\""))
4633 game.optime = 3.0e-5*game.height
4634 if game.optime >= 0.8*game.state.remtime:
4635 prout(_("First Officer Spock- \"Captain, I compute that such"))
4636 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4637 int(100*game.optime/game.state.remtime))
4638 prout(_("remaining time."))
4639 proutn(_("Are you sure this is wise?\" "))
4645 if game.iscraft == "onship":
4647 if not damaged(DTRANSP):
4648 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4652 proutn(_("Shuttle crew"))
4654 proutn(_("Rescue party"))
4655 prout(_(" boards Galileo and swoops toward planet surface."))
4656 game.iscraft = "offship"
4660 game.iplnet.known="shuttle_down"
4661 prout(_("Trip complete."))
4664 # Ready to go back to ship
4665 prout(_("You and your mining party board the"))
4666 prout(_("shuttle craft for the trip back to the Enterprise."))
4668 prouts(_("The short hop begins . . ."))
4670 game.iplnet.known="known"
4676 game.iscraft = "onship"
4682 prout(_("Trip complete."))
4685 # Kirk on ship and so is Galileo
4686 prout(_("Mining party assembles in the hangar deck,"))
4687 prout(_("ready to board the shuttle craft \"Galileo\"."))
4689 prouts(_("The hangar doors open; the trip begins."))
4692 game.iscraft = "offship"
4695 game.iplnet.known = "shuttle_down"
4698 prout(_("Trip complete."))
4702 "Use the big zapper."
4706 if game.ship != 'E':
4707 prout(_("Ye Faerie Queene has no death ray."))
4709 if len(game.enemies)==0:
4710 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4713 prout(_("Death Ray is damaged."))
4715 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4716 prout(_(" is highly unpredictible. Considering the alternatives,"))
4717 proutn(_(" are you sure this is wise?\" "))
4720 prout(_("Spock- \"Acknowledged.\""))
4723 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4725 prout(_("Crew scrambles in emergency preparation."))
4726 prout(_("Spock and Scotty ready the death ray and"))
4727 prout(_("prepare to channel all ship's power to the device."))
4729 prout(_("Spock- \"Preparations complete, sir.\""))
4730 prout(_("Kirk- \"Engage!\""))
4732 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4735 if game.options & OPTION_PLAIN:
4739 prouts(_("Sulu- \"Captain! It's working!\""))
4741 while len(game.enemies) > 0:
4742 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4743 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4744 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4746 if (game.options & OPTION_PLAIN) == 0:
4747 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4749 prout(_(" is still operational.\""))
4751 prout(_(" has been rendered nonfunctional.\""))
4752 game.damage[DDRAY] = 39.95
4754 r = randreal() # Pick failure method
4756 prouts(_("Sulu- \"Captain! It's working!\""))
4758 prouts(_("***RED ALERT! RED ALERT!"))
4760 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4762 prouts(_("***RED ALERT! RED A*L********************************"))
4765 prouts(_("****************** KA-BOOM!!!! *******************"))
4770 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4772 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4774 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4775 prout(_(" have apparently been transformed into strange mutations."))
4776 prout(_(" Vulcans do not seem to be affected."))
4778 prout(_("Kirk- \"Raauch! Raauch!\""))
4782 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4784 proutn(_("Spock- \"I believe the word is"))
4785 prouts(_(" *ASTONISHING*"))
4786 prout(_(" Mr. Sulu."))
4787 for i in range(QUADSIZE):
4788 for j in range(QUADSIZE):
4789 if game.quad[i][j] == '.':
4790 game.quad[i][j] = '?'
4791 prout(_(" Captain, our quadrant is now infested with"))
4792 prouts(_(" - - - - - - *THINGS*."))
4794 prout(_(" I have no logical explanation.\""))
4796 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4798 prout(_("Scotty- \"There are so many tribbles down here"))
4799 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4803 # Code from reports.c begins here
4805 def attackreport(curt):
4806 "eport status of bases under attack."
4808 if is_scheduled(FCDBAS):
4809 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4810 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4811 elif game.isatb == 1:
4812 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4813 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4815 prout(_("No Starbase is currently under attack."))
4817 if is_scheduled(FCDBAS):
4818 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4820 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4824 # report on general game status
4826 s1 = (game.thawed and _("thawed ")) or ""
4827 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4828 s3 = (None, _("novice"), _("fair"),
4829 _("good"), _("expert"), _("emeritus"))[game.skill]
4830 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4831 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4832 prout(_("No plaque is allowed."))
4834 prout(_("This is tournament game %d.") % game.tourn)
4835 prout(_("Your secret password is \"%s\"") % game.passwd)
4836 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4837 (game.inkling + game.incom + game.inscom)))
4838 if game.incom - len(game.state.kcmdr):
4839 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4840 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4841 prout(_(", but no Commanders."))
4844 if game.skill > SKILL_FAIR:
4845 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4846 if len(game.state.baseq) != game.inbase:
4848 if game.inbase-len(game.state.baseq)==1:
4849 proutn(_("has been 1 base"))
4851 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4852 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4854 prout(_("There are %d bases.") % game.inbase)
4855 if communicating() or game.iseenit:
4856 # Don't report this if not seen and
4857 # either the radio is dead or not at base!
4861 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4863 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4864 if game.ship == 'E':
4865 proutn(_("You have "))
4867 proutn("%d" % (game.nprobes))
4870 proutn(_(" deep space probe"))
4874 if communicating() and is_scheduled(FDSPROB):
4876 proutn(_("An armed deep space probe is in "))
4878 proutn(_("A deep space probe is in "))
4879 prout("Quadrant %s." % game.probec)
4881 if game.cryprob <= .05:
4882 prout(_("Dilithium crystals aboard ship... not yet used."))
4886 while game.cryprob > ai:
4889 prout(_("Dilithium crystals have been used %d time%s.") % \
4890 (i, (_("s"), "")[i==1]))
4894 "Long-range sensor scan."
4895 if damaged(DLRSENS):
4896 # Now allow base's sensors if docked
4897 if game.condition != "docked":
4899 prout(_("LONG-RANGE SENSORS DAMAGED."))
4902 prout(_("Starbase's long-range scan"))
4904 prout(_("Long-range scan"))
4905 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4908 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4909 if not Coord(x, y).valid_quadrant():
4913 if not damaged(DRADIO):
4914 game.state.galaxy[x][y].charted = True
4915 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4916 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4917 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4918 if not silent and game.state.galaxy[x][y].supernova:
4921 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4929 for i in range(NDEVICES):
4932 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4933 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4935 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4936 game.damage[i]+0.05,
4937 DOCKFAC*game.damage[i]+0.005))
4939 prout(_("All devices functional."))
4942 "Update the chart in the Enterprise's computer from galaxy data."
4943 game.lastchart = game.state.date
4944 for i in range(GALSIZE):
4945 for j in range(GALSIZE):
4946 if game.state.galaxy[i][j].charted:
4947 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
4948 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
4949 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
4952 "Display the star chart."
4954 if (game.options & OPTION_AUTOSCAN):
4956 if not damaged(DRADIO):
4958 if game.lastchart < game.state.date and game.condition == "docked":
4959 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
4961 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
4962 if game.state.date > game.lastchart:
4963 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
4964 prout(" 1 2 3 4 5 6 7 8")
4965 for i in range(GALSIZE):
4966 proutn("%d |" % (i+1))
4967 for j in range(GALSIZE):
4968 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4972 if game.state.galaxy[i][j].supernova:
4974 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
4976 elif game.state.galaxy[i][j].charted:
4977 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
4981 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4989 def sectscan(goodScan, i, j):
4990 "Light up an individual dot in a sector."
4991 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
4992 textcolor({"green":GREEN,
4996 "dead":BROWN}[game.condition])
4997 if game.quad[i][j] != game.ship:
4999 proutn("%c " % game.quad[i][j])
5005 "Emit status report lines"
5006 if not req or req == 1:
5007 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5008 % (game.state.date, game.state.remtime))
5009 if not req or req == 2:
5010 if game.condition != "docked":
5012 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5013 (game.condition.upper(), sum(map(lambda x: x > 0, game.damage))))
5014 if not req or req == 3:
5015 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5016 if not req or req == 4:
5017 if damaged(DLIFSUP):
5018 if game.condition == "docked":
5019 s = _("DAMAGED, Base provides")
5021 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5024 prstat(_("Life Support"), s)
5025 if not req or req == 5:
5026 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5027 if not req or req == 6:
5029 if game.icrystl and (game.options & OPTION_SHOWME):
5030 extra = _(" (have crystals)")
5031 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5032 if not req or req == 7:
5033 prstat(_("Torpedoes"), "%d" % (game.torps))
5034 if not req or req == 8:
5035 if damaged(DSHIELD):
5041 data = _(" %d%% %.1f units") \
5042 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5043 prstat(_("Shields"), s+data)
5044 if not req or req == 9:
5045 prstat(_("Klingons Left"), "%d" \
5046 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5047 if not req or req == 10:
5048 if game.options & OPTION_WORLDS:
5049 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5050 if plnet and plnet.inhabited:
5051 prstat(_("Major system"), plnet.name)
5053 prout(_("Sector is uninhabited"))
5054 elif not req or req == 11:
5055 attackreport(not req)
5058 "Request specified status data, a historical relic from slow TTYs."
5059 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5060 while scanner.next() == "IHEOL":
5061 proutn(_("Information desired? "))
5063 if scanner.token in requests:
5064 status(requests.index(scanner.token))
5066 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5067 prout((" date, condition, position, lsupport, warpfactor,"))
5068 prout((" energy, torpedoes, shields, klingons, system, time."))
5073 if damaged(DSRSENS):
5074 # Allow base's sensors if docked
5075 if game.condition != "docked":
5076 prout(_(" S.R. SENSORS DAMAGED!"))
5079 prout(_(" [Using Base's sensors]"))
5081 prout(_(" Short-range scan"))
5082 if goodScan and not damaged(DRADIO):
5083 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5084 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5085 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5086 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5087 prout(" 1 2 3 4 5 6 7 8 9 10")
5088 if game.condition != "docked":
5090 for i in range(QUADSIZE):
5091 proutn("%2d " % (i+1))
5092 for j in range(QUADSIZE):
5093 sectscan(goodScan, i, j)
5097 "Use computer to get estimated time of arrival for a warp jump."
5098 w1 = Coord(); w2 = Coord()
5100 if damaged(DCOMPTR):
5101 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5104 if scanner.next() != "IHREAL":
5107 proutn(_("Destination quadrant and/or sector? "))
5108 if scanner.next()!="IHREAL":
5111 w1.j = int(scanner.real-0.5)
5112 if scanner.next() != "IHREAL":
5115 w1.i = int(scanner.real-0.5)
5116 if scanner.next() == "IHREAL":
5117 w2.j = int(scanner.real-0.5)
5118 if scanner.next() != "IHREAL":
5121 w2.i = int(scanner.real-0.5)
5123 if game.quadrant.j>w1.i:
5127 if game.quadrant.i>w1.j:
5131 if not w1.valid_quadrant() or not w2.valid_sector():
5134 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5135 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5138 prout(_("Answer \"no\" if you don't know the value:"))
5141 proutn(_("Time or arrival date? "))
5142 if scanner.next()=="IHREAL":
5143 ttime = scanner.real
5144 if ttime > game.state.date:
5145 ttime -= game.state.date # Actually a star date
5146 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5147 if ttime <= 1e-10 or twarp > 10:
5148 prout(_("We'll never make it, sir."))
5155 proutn(_("Warp factor? "))
5156 if scanner.next()== "IHREAL":
5158 twarp = scanner.real
5159 if twarp<1.0 or twarp > 10.0:
5163 prout(_("Captain, certainly you can give me one of these."))
5166 ttime = (10.0*dist)/twarp**2
5167 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5168 if tpower >= game.energy:
5169 prout(_("Insufficient energy, sir."))
5170 if not game.shldup or tpower > game.energy*2.0:
5173 proutn(_("New warp factor to try? "))
5174 if scanner.next() == "IHREAL":
5176 twarp = scanner.real
5177 if twarp<1.0 or twarp > 10.0:
5185 prout(_("But if you lower your shields,"))
5186 proutn(_("remaining"))
5189 proutn(_("Remaining"))
5190 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5192 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5194 prout(_("Any warp speed is adequate."))
5196 prout(_("Minimum warp needed is %.2f,") % (twarp))
5197 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5198 if game.state.remtime < ttime:
5199 prout(_("Unfortunately, the Federation will be destroyed by then."))
5201 prout(_("You'll be taking risks at that speed, Captain"))
5202 if (game.isatb==1 and game.state.kscmdr == w1 and \
5203 scheduled(FSCDBAS)< ttime+game.state.date) or \
5204 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5205 prout(_("The starbase there will be destroyed by then."))
5206 proutn(_("New warp factor to try? "))
5207 if scanner.next() == "IHREAL":
5209 twarp = scanner.real
5210 if twarp<1.0 or twarp > 10.0:
5218 # Code from setup.c begins here
5221 "Issue a historically correct banner."
5223 prout(_("-SUPER- STAR TREK"))
5225 # From the FORTRAN original
5226 # prout(_("Latest update-21 Sept 78"))
5232 scanner.push("emsave.trk")
5233 key = scanner.next()
5235 proutn(_("File name: "))
5236 key = scanner.next()
5237 if key != "IHALPHA":
5240 if '.' not in scanner.token:
5241 scanner.token += ".trk"
5243 fp = open(scanner.token, "wb")
5245 prout(_("Can't freeze game as file %s") % scanner.token)
5247 cPickle.dump(game, fp)
5252 "Retrieve saved game."
5255 key = scanner.next()
5257 proutn(_("File name: "))
5258 key = scanner.next()
5259 if key != "IHALPHA":
5262 if '.' not in scanner.token:
5263 scanner.token += ".trk"
5265 fp = open(scanner.token, "rb")
5267 prout(_("Can't thaw game in %s") % scanner.token)
5269 game = cPickle.load(fp)
5274 # I used <http://www.memory-alpha.org> to find planets
5275 # with references in ST:TOS. Earth and the Alpha Centauri
5276 # Colony have been omitted.
5278 # Some planets marked Class G and P here will be displayed as class M
5279 # because of the way planets are generated. This is a known bug.
5282 _("Andoria (Fesoan)"), # several episodes
5283 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5284 _("Vulcan (T'Khasi)"), # many episodes
5285 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5286 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5287 _("Ardana"), # TOS: "The Cloud Minders"
5288 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5289 _("Gideon"), # TOS: "The Mark of Gideon"
5290 _("Aldebaran III"), # TOS: "The Deadly Years"
5291 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5292 _("Altair IV"), # TOS: "Amok Time
5293 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5294 _("Benecia"), # TOS: "The Conscience of the King"
5295 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5296 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5297 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5298 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5299 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5300 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5301 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5302 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5303 _("Ingraham B"), # TOS: "Operation: Annihilate"
5304 _("Janus IV"), # TOS: "The Devil in the Dark"
5305 _("Makus III"), # TOS: "The Galileo Seven"
5306 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5307 _("Omega IV"), # TOS: "The Omega Glory"
5308 _("Regulus V"), # TOS: "Amok Time
5309 _("Deneva"), # TOS: "Operation -- Annihilate!"
5310 # Worlds from BSD Trek
5311 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5312 _("Beta III"), # TOS: "The Return of the Archons"
5313 _("Triacus"), # TOS: "And the Children Shall Lead",
5314 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5316 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5317 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5318 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5319 # _("Izar"), # TOS: "Whom Gods Destroy"
5320 # _("Tiburon"), # TOS: "The Way to Eden"
5321 # _("Merak II"), # TOS: "The Cloud Minders"
5322 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5323 # _("Iotia"), # TOS: "A Piece of the Action"
5327 _("S. R. Sensors"), \
5328 _("L. R. Sensors"), \
5330 _("Photon Tubes"), \
5331 _("Life Support"), \
5332 _("Warp Engines"), \
5333 _("Impulse Engines"), \
5335 _("Subspace Radio"), \
5336 _("Shuttle Craft"), \
5338 _("Navigation System"), \
5340 _("Shield Control"), \
5346 "Prepare to play, set up cosmos."
5348 # Decide how many of everything
5350 return # frozen game
5351 # Prepare the Enterprise
5352 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5354 game.state.crew = FULLCREW
5355 game.energy = game.inenrg = 5000.0
5356 game.shield = game.inshld = 2500.0
5359 game.quadrant = randplace(GALSIZE)
5360 game.sector = randplace(QUADSIZE)
5361 game.torps = game.intorps = 10
5362 game.nprobes = randrange(2, 5)
5364 for i in range(NDEVICES):
5365 game.damage[i] = 0.0
5366 # Set up assorted game parameters
5367 game.battle = Coord()
5368 game.state.date = game.indate = 100.0 * randreal(20, 51)
5369 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5370 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5371 game.isatb = game.state.nplankl = 0
5372 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5373 game.iscraft = "onship"
5378 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5380 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5382 game.state.planets = [] # Planet information
5383 game.state.baseq = [] # Base quadrant coordinates
5384 game.state.kcmdr = [] # Commander quadrant coordinates
5385 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5387 # Starchart is functional but we've never seen it
5388 game.lastchart = FOREVER
5389 # Put stars in the galaxy
5391 for i in range(GALSIZE):
5392 for j in range(GALSIZE):
5393 k = randrange(1, QUADSIZE**2/10+1)
5395 game.state.galaxy[i][j].stars = k
5396 # Locate star bases in galaxy
5397 for i in range(game.inbase):
5400 w = randplace(GALSIZE)
5401 if not game.state.galaxy[w.i][w.j].starbase:
5404 # C version: for (j = i-1; j > 0; j--)
5405 # so it did them in the opposite order.
5406 for j in range(1, i):
5407 # Improved placement algorithm to spread out bases
5408 distq = (w - game.state.baseq[j]).distance()
5409 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5412 prout("=== Abandoning base #%d at %s" % (i, w))
5414 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5416 prout("=== Saving base #%d, close to #%d" % (i, j))
5419 game.state.baseq.append(w)
5420 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5421 # Position ordinary Klingon Battle Cruisers
5423 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5424 if klumper > MAXKLQUAD:
5428 klump = (1.0 - r*r)*klumper
5433 w = randplace(GALSIZE)
5434 if not game.state.galaxy[w.i][w.j].supernova and \
5435 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5437 game.state.galaxy[w.i][w.j].klingons += int(klump)
5440 # Position Klingon Commander Ships
5441 for i in range(game.incom):
5443 w = randplace(GALSIZE)
5444 if not welcoming(w) or w in game.state.kcmdr:
5446 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5448 game.state.galaxy[w.i][w.j].klingons += 1
5449 game.state.kcmdr.append(w)
5450 # Locate planets in galaxy
5451 for i in range(game.inplan):
5453 w = randplace(GALSIZE)
5454 if game.state.galaxy[w.i][w.j].planet == None:
5458 new.crystals = "absent"
5459 if (game.options & OPTION_WORLDS) and i < NINHAB:
5460 new.pclass = "M" # All inhabited planets are class M
5461 new.crystals = "absent"
5463 new.name = systnames[i]
5464 new.inhabited = True
5466 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5468 new.crystals = "present"
5469 new.known = "unknown"
5470 new.inhabited = False
5471 game.state.galaxy[w.i][w.j].planet = new
5472 game.state.planets.append(new)
5474 for i in range(game.state.nromrem):
5475 w = randplace(GALSIZE)
5476 game.state.galaxy[w.i][w.j].romulans += 1
5477 # Place the Super-Commander if needed
5478 if game.state.nscrem > 0:
5480 w = randplace(GALSIZE)
5483 game.state.kscmdr = w
5484 game.state.galaxy[w.i][w.j].klingons += 1
5485 # Initialize times for extraneous events
5486 schedule(FSNOVA, expran(0.5 * game.intime))
5487 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5488 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5489 schedule(FBATTAK, expran(0.3*game.intime))
5491 if game.state.nscrem:
5492 schedule(FSCMOVE, 0.2777)
5497 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5498 schedule(FDISTR, expran(1.0 + game.intime))
5503 # Place thing (in tournament game, we don't want one!)
5504 # New in SST2K: never place the Thing near a starbase.
5505 # This makes sense and avoids a special case in the old code.
5507 if game.tourn is None:
5509 thing = randplace(GALSIZE)
5510 if thing not in game.state.baseq:
5513 game.state.snap = False
5514 if game.skill == SKILL_NOVICE:
5515 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5516 prout(_("a deadly Klingon invasion force. As captain of the United"))
5517 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5518 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5519 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5520 prout(_("your mission. As you proceed you may be given more time."))
5522 prout(_("You will have %d supporting starbases.") % (game.inbase))
5523 proutn(_("Starbase locations- "))
5525 prout(_("Stardate %d.") % int(game.state.date))
5527 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5528 prout(_("An unknown number of Romulans."))
5529 if game.state.nscrem:
5530 prout(_("And one (GULP) Super-Commander."))
5531 prout(_("%d stardates.") % int(game.intime))
5532 proutn(_("%d starbases in ") % game.inbase)
5533 for i in range(game.inbase):
5534 proutn(`game.state.baseq[i]`)
5537 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5538 proutn(_(" Sector %s") % game.sector)
5540 prout(_("Good Luck!"))
5541 if game.state.nscrem:
5542 prout(_(" YOU'LL NEED IT."))
5545 setwnd(message_window)
5547 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5549 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5550 attack(torps_ok=False)
5553 "Choose your game type."
5555 game.tourn = game.length = 0
5557 game.skill = SKILL_NONE
5559 # if not scanner.inqueue: # Can start with command line options
5560 proutn(_("Would you like a regular, tournament, or saved game? "))
5562 if scanner.sees("tournament"):
5563 while scanner.next() == "IHEOL":
5564 proutn(_("Type in tournament number-"))
5565 if scanner.real == 0:
5567 continue # We don't want a blank entry
5568 game.tourn = int(round(scanner.real))
5569 random.seed(scanner.real)
5571 logfp.write("# random.seed(%d)\n" % scanner.real)
5573 if scanner.sees("saved") or scanner.sees("frozen"):
5577 if game.passwd == None:
5579 if not game.alldone:
5580 game.thawed = True # No plaque if not finished
5584 if scanner.sees("regular"):
5586 proutn(_("What is \"%s\"? ") % scanner.token)
5588 while game.length==0 or game.skill==SKILL_NONE:
5589 if scanner.next() == "IHALPHA":
5590 if scanner.sees("short"):
5592 elif scanner.sees("medium"):
5594 elif scanner.sees("long"):
5596 elif scanner.sees("novice"):
5597 game.skill = SKILL_NOVICE
5598 elif scanner.sees("fair"):
5599 game.skill = SKILL_FAIR
5600 elif scanner.sees("good"):
5601 game.skill = SKILL_GOOD
5602 elif scanner.sees("expert"):
5603 game.skill = SKILL_EXPERT
5604 elif scanner.sees("emeritus"):
5605 game.skill = SKILL_EMERITUS
5607 proutn(_("What is \""))
5608 proutn(scanner.token)
5613 proutn(_("Would you like a Short, Medium, or Long game? "))
5614 elif game.skill == SKILL_NONE:
5615 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5616 # Choose game options -- added by ESR for SST2K
5617 if scanner.next() != "IHALPHA":
5619 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5621 if scanner.sees("plain"):
5622 # Approximates the UT FORTRAN version.
5623 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5624 game.options |= OPTION_PLAIN
5625 elif scanner.sees("almy"):
5626 # Approximates Tom Almy's version.
5627 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5628 game.options |= OPTION_ALMY
5629 elif scanner.sees("fancy") or scanner.sees("\n"):
5631 elif len(scanner.token):
5632 proutn(_("What is \"%s\"?") % scanner.token)
5633 game.options &=~ OPTION_COLOR
5635 if game.passwd == "debug":
5637 prout("=== Debug mode enabled.")
5638 # Use parameters to generate initial values of things
5639 game.damfac = 0.5 * game.skill
5640 game.inbase = randrange(BASEMIN, BASEMAX+1)
5642 if game.options & OPTION_PLANETS:
5643 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5644 if game.options & OPTION_WORLDS:
5645 game.inplan += int(NINHAB)
5646 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5647 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5648 game.state.remtime = 7.0 * game.length
5649 game.intime = game.state.remtime
5650 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5651 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5652 game.state.remres = (game.inkling+4*game.incom)*game.intime
5653 game.inresor = game.state.remres
5654 if game.inkling > 50:
5655 game.state.inbase += 1
5658 def dropin(iquad=None):
5659 "Drop a feature on a random dot in the current quadrant."
5661 w = randplace(QUADSIZE)
5662 if game.quad[w.i][w.j] == '.':
5664 if iquad is not None:
5665 game.quad[w.i][w.j] = iquad
5669 "Update our alert status."
5670 game.condition = "green"
5671 if game.energy < 1000.0:
5672 game.condition = "yellow"
5673 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5674 game.condition = "red"
5676 game.condition="dead"
5679 "Drop new Klingon into current quadrant."
5680 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5683 "Sort enemies by distance so 'nearest' is meaningful."
5684 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
5687 "Set up a new state of quadrant, for when we enter or re-enter it."
5690 game.neutz = game.inorbit = game.landed = False
5691 game.ientesc = game.iseenit = False
5692 # Create a blank quadrant
5693 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5695 # Attempt to escape Super-commander, so tbeam back!
5698 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5699 # cope with supernova
5702 game.klhere = q.klingons
5703 game.irhere = q.romulans
5705 game.quad[game.sector.i][game.sector.j] = game.ship
5708 # Position ordinary Klingons
5709 for i in range(game.klhere):
5711 # If we need a commander, promote a Klingon
5712 for cmdr in game.state.kcmdr:
5713 if cmdr == game.quadrant:
5714 e = game.enemies[game.klhere-1]
5715 game.quad[e.location.i][e.location.j] = 'C'
5716 e.power = randreal(950,1350) + 50.0*game.skill
5718 # If we need a super-commander, promote a Klingon
5719 if game.quadrant == game.state.kscmdr:
5721 game.quad[e.location.i][e.location.j] = 'S'
5722 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5723 game.iscate = (game.state.remkl > 1)
5724 # Put in Romulans if needed
5725 for i in range(q.romulans):
5726 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5727 # If quadrant needs a starbase, put it in
5729 game.base = dropin('B')
5730 # If quadrant needs a planet, put it in
5732 game.iplnet = q.planet
5733 if not q.planet.inhabited:
5734 game.plnet = dropin('P')
5736 game.plnet = dropin('@')
5737 # Check for condition
5740 if game.irhere > 0 and game.klhere == 0:
5742 if not damaged(DRADIO):
5744 prout(_("LT. Uhura- \"Captain, an urgent message."))
5745 prout(_(" I'll put it on audio.\" CLICK"))
5747 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5748 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5749 # Put in THING if needed
5750 if thing == game.quadrant:
5751 Enemy(type='?', loc=dropin(),
5752 power=randreal(6000,6500.0)+250.0*game.skill)
5753 if not damaged(DSRSENS):
5755 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5756 prout(_(" Please examine your short-range scan.\""))
5757 # Decide if quadrant needs a Tholian; lighten up if skill is low
5758 if game.options & OPTION_THOLIAN:
5759 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5760 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5761 (game.skill > SKILL_GOOD and withprob(0.08)):
5764 w.i = withprob(0.5) * (QUADSIZE-1)
5765 w.j = withprob(0.5) * (QUADSIZE-1)
5766 if game.quad[w.i][w.j] == '.':
5768 game.tholian = Enemy(type='T', loc=w,
5769 power=randrange(100, 500) + 25.0*game.skill)
5770 # Reserve unoccupied corners
5771 if game.quad[0][0]=='.':
5772 game.quad[0][0] = 'X'
5773 if game.quad[0][QUADSIZE-1]=='.':
5774 game.quad[0][QUADSIZE-1] = 'X'
5775 if game.quad[QUADSIZE-1][0]=='.':
5776 game.quad[QUADSIZE-1][0] = 'X'
5777 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5778 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5780 # And finally the stars
5781 for i in range(q.stars):
5783 # Put in a few black holes
5784 for i in range(1, 3+1):
5787 # Take out X's in corners if Tholian present
5789 if game.quad[0][0]=='X':
5790 game.quad[0][0] = '.'
5791 if game.quad[0][QUADSIZE-1]=='X':
5792 game.quad[0][QUADSIZE-1] = '.'
5793 if game.quad[QUADSIZE-1][0]=='X':
5794 game.quad[QUADSIZE-1][0] = '.'
5795 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5796 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5799 "Set the self-destruct password."
5800 if game.options & OPTION_PLAIN:
5803 proutn(_("Please type in a secret password- "))
5805 game.passwd = scanner.token
5806 if game.passwd != None:
5810 game.passwd += chr(ord('a')+randrange(26))
5811 game.passwd += chr(ord('a')+randrange(26))
5812 game.passwd += chr(ord('a')+randrange(26))
5814 # Code from sst.c begins here
5817 ("SRSCAN", OPTION_TTY),
5818 ("STATUS", OPTION_TTY),
5819 ("REQUEST", OPTION_TTY),
5820 ("LRSCAN", OPTION_TTY),
5833 ("SENSORS", OPTION_PLANETS),
5834 ("ORBIT", OPTION_PLANETS),
5835 ("TRANSPORT", OPTION_PLANETS),
5836 ("MINE", OPTION_PLANETS),
5837 ("CRYSTALS", OPTION_PLANETS),
5838 ("SHUTTLE", OPTION_PLANETS),
5839 ("PLANETS", OPTION_PLANETS),
5844 ("PROBE", OPTION_PROBE),
5846 ("FREEZE", 0), # Synonym for SAVE
5852 ("SOS", 0), # Synonym for MAYDAY
5853 ("CALL", 0), # Synonym for MAYDAY
5860 "Generate a list of legal commands."
5861 prout(_("LEGAL COMMANDS ARE:"))
5863 for (key, opt) in commands:
5864 if not opt or (opt & game.options):
5865 proutn("%-12s " % key)
5867 if emitted % 5 == 4:
5872 "Browse on-line help."
5873 key = scanner.next()
5876 setwnd(prompt_window)
5877 proutn(_("Help on what command? "))
5878 key = scanner.next()
5879 setwnd(message_window)
5882 cmds = map(lambda x: x[0], commands)
5883 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
5890 cmd = scanner.token.upper()
5891 for directory in docpath:
5893 fp = open(os.path.join(directory, "sst.doc"), "r")
5898 prout(_("Spock- \"Captain, that information is missing from the"))
5899 prout(_(" computer. You need to find sst.doc and put it somewhere"))
5900 proutn(_(" in these directories: %s") % ":".join(docpath))
5902 # This used to continue: "You need to find SST.DOC and put
5903 # it in the current directory."
5906 linebuf = fp.readline()
5908 prout(_("Spock- \"Captain, there is no information on that command.\""))
5911 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5912 linebuf = linebuf[3:].strip()
5913 if cmd.upper() == linebuf:
5916 prout(_("Spock- \"Captain, I've found the following information:\""))
5919 linebuf = fp.readline()
5920 if "******" in linebuf:
5926 "Command-interpretation loop."
5927 while True: # command loop
5929 while True: # get a command
5931 game.optime = game.justin = False
5933 setwnd(prompt_window)
5936 if scanner.next() == "IHEOL":
5937 if game.options & OPTION_CURSES:
5940 elif scanner.token == "":
5944 setwnd(message_window)
5946 abandon_passed = False
5947 for (cmd, opt) in commands:
5948 # commands after ABANDON cannot be abbreviated
5949 if cmd == "ABANDON":
5950 abandon_passed = True
5951 if cmd == scanner.token.upper() or (not abandon_passed \
5952 and cmd.startswith(scanner.token.upper())):
5959 if cmd == "SRSCAN": # srscan
5961 elif cmd == "STATUS": # status
5963 elif cmd == "REQUEST": # status request
5965 elif cmd == "LRSCAN": # long range scan
5966 lrscan(silent=False)
5967 elif cmd == "PHASERS": # phasers
5971 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
5975 elif cmd == "MOVE": # move under warp
5976 warp(wcourse=None, involuntary=False)
5977 elif cmd == "SHIELDS": # shields
5978 doshield(shraise=False)
5981 game.shldchg = False
5982 elif cmd == "DOCK": # dock at starbase
5985 attack(torps_ok=False)
5986 elif cmd == "DAMAGES": # damage reports
5988 elif cmd == "CHART": # chart
5990 elif cmd == "IMPULSE": # impulse
5992 elif cmd == "REST": # rest
5996 elif cmd == "WARP": # warp
5998 elif cmd == "SCORE": # score
6000 elif cmd == "SENSORS": # sensors
6002 elif cmd == "ORBIT": # orbit
6006 elif cmd == "TRANSPORT": # transport "beam"
6008 elif cmd == "MINE": # mine
6012 elif cmd == "CRYSTALS": # crystals
6016 elif cmd == "SHUTTLE": # shuttle
6020 elif cmd == "PLANETS": # Planet list
6022 elif cmd == "REPORT": # Game Report
6024 elif cmd == "COMPUTER": # use COMPUTER!
6026 elif cmd == "COMMANDS":
6028 elif cmd == "EMEXIT": # Emergency exit
6029 clrscr() # Hide screen
6030 freeze(True) # forced save
6031 raise SystemExit,1 # And quick exit
6032 elif cmd == "PROBE":
6033 probe() # Launch probe
6036 elif cmd == "ABANDON": # Abandon Ship
6038 elif cmd == "DESTRUCT": # Self Destruct
6040 elif cmd == "SAVE": # Save Game
6043 if game.skill > SKILL_GOOD:
6044 prout(_("WARNING--Saved games produce no plaques!"))
6045 elif cmd == "DEATHRAY": # Try a desparation measure
6049 elif cmd == "DEBUGCMD": # What do we want for debug???
6051 elif cmd == "MAYDAY": # Call for help
6056 game.alldone = True # quit the game
6061 break # Game has ended
6062 if game.optime != 0.0:
6065 break # Events did us in
6066 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6069 if hitme and not game.justin:
6070 attack(torps_ok=True)
6073 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6084 "Emit the name of an enemy or feature."
6085 if type == 'R': s = _("Romulan")
6086 elif type == 'K': s = _("Klingon")
6087 elif type == 'C': s = _("Commander")
6088 elif type == 'S': s = _("Super-commander")
6089 elif type == '*': s = _("Star")
6090 elif type == 'P': s = _("Planet")
6091 elif type == 'B': s = _("Starbase")
6092 elif type == ' ': s = _("Black hole")
6093 elif type == 'T': s = _("Tholian")
6094 elif type == '#': s = _("Tholian web")
6095 elif type == '?': s = _("Stranger")
6096 elif type == '@': s = _("Inhabited World")
6097 else: s = "Unknown??"
6100 def crmena(stars, enemy, loctype, w):
6101 "Emit the name of an enemy and his location."
6105 buf += cramen(enemy) + _(" at ")
6106 if loctype == "quadrant":
6107 buf += _("Quadrant ")
6108 elif loctype == "sector":
6113 "Emit our ship name."
6114 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6117 "Emit a line of stars"
6118 prouts("******************************************************")
6122 return -avrage*math.log(1e-7 + randreal())
6124 def randplace(size):
6125 "Choose a random location."
6127 w.i = randrange(size)
6128 w.j = randrange(size)
6138 # Get a token from the user
6141 # Fill the token quue if nothing here
6142 while not self.inqueue:
6144 if curwnd==prompt_window:
6146 setwnd(message_window)
6153 self.inqueue = line.lstrip().split() + ["\n"]
6154 # From here on in it's all looking at the queue
6155 self.token = self.inqueue.pop(0)
6156 if self.token == "\n":
6160 self.real = float(self.token)
6161 self.type = "IHREAL"
6166 self.token = self.token.lower()
6167 self.type = "IHALPHA"
6170 def append(self, tok):
6171 self.inqueue.append(tok)
6172 def push(self, tok):
6173 self.inqueue.insert(0, tok)
6177 # Demand input for next scan
6179 self.real = self.token = None
6181 # compares s to item and returns true if it matches to the length of s
6182 return s.startswith(self.token)
6184 # Round token value to nearest integer
6185 return int(round(scanner.real))
6189 if scanner.type != "IHREAL":
6192 s.i = scanner.int()-1
6194 if scanner.type != "IHREAL":
6197 s.j = scanner.int()-1
6200 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6203 "Yes-or-no confirmation."
6207 if scanner.token == 'y':
6209 if scanner.token == 'n':
6212 proutn(_("Please answer with \"y\" or \"n\": "))
6215 "Complain about unparseable input."
6218 prout(_("Beg your pardon, Captain?"))
6221 "Access to the internals for debugging."
6222 proutn("Reset levels? ")
6224 if game.energy < game.inenrg:
6225 game.energy = game.inenrg
6226 game.shield = game.inshld
6227 game.torps = game.intorps
6228 game.lsupres = game.inlsr
6229 proutn("Reset damage? ")
6231 for i in range(NDEVICES):
6232 if game.damage[i] > 0.0:
6233 game.damage[i] = 0.0
6234 proutn("Toggle debug flag? ")
6236 game.idebug = not game.idebug
6238 prout("Debug output ON")
6240 prout("Debug output OFF")
6241 proutn("Cause selective damage? ")
6243 for i in range(NDEVICES):
6244 proutn("Kill %s?" % device[i])
6246 key = scanner.next()
6247 if key == "IHALPHA" and scanner.sees("y"):
6248 game.damage[i] = 10.0
6249 proutn("Examine/change events? ")
6254 FSNOVA: "Supernova ",
6257 FBATTAK: "Base Attack ",
6258 FCDBAS: "Base Destroy ",
6259 FSCMOVE: "SC Move ",
6260 FSCDBAS: "SC Base Destroy ",
6261 FDSPROB: "Probe Move ",
6262 FDISTR: "Distress Call ",
6263 FENSLV: "Enslavement ",
6264 FREPRO: "Klingon Build ",
6266 for i in range(1, NEVENTS):
6269 proutn("%.2f" % (scheduled(i)-game.state.date))
6270 if i == FENSLV or i == FREPRO:
6272 proutn(" in %s" % ev.quadrant)
6277 key = scanner.next()
6281 elif key == "IHREAL":
6282 ev = schedule(i, scanner.real)
6283 if i == FENSLV or i == FREPRO:
6285 proutn("In quadrant- ")
6286 key = scanner.next()
6287 # "IHEOL" says to leave coordinates as they are
6290 prout("Event %d canceled, no x coordinate." % (i))
6293 w.i = int(round(scanner.real))
6294 key = scanner.next()
6296 prout("Event %d canceled, no y coordinate." % (i))
6299 w.j = int(round(scanner.real))
6302 proutn("Induce supernova here? ")
6304 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6307 if __name__ == '__main__':
6308 import getopt, socket
6310 global line, thing, game
6314 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6315 if os.getenv("TERM"):
6316 game.options |= OPTION_CURSES
6318 game.options |= OPTION_TTY
6319 seed = int(time.time())
6320 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6322 for (switch, val) in options:
6325 replayfp = open(val, "r")
6327 sys.stderr.write("sst: can't open replay file %s\n" % val)
6330 line = replayfp.readline().strip()
6331 (leader, __, seed) = line.split()
6333 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6334 line = replayfp.readline().strip()
6335 arguments += line.split()[2:]
6338 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6340 game.options |= OPTION_TTY
6341 game.options &=~ OPTION_CURSES
6342 elif switch == '-s':
6344 elif switch == '-t':
6345 game.options |= OPTION_TTY
6346 game.options &=~ OPTION_CURSES
6347 elif switch == '-x':
6349 elif switch == '-V':
6350 print "SST2K", version
6353 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6355 # where to save the input in case of bugs
6356 if "TMPDIR" in os.environ:
6357 tmpdir = os.environ['TMPDIR']
6361 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6363 sys.stderr.write("sst: warning, can't open logfile\n")
6366 logfp.write("# seed %s\n" % seed)
6367 logfp.write("# options %s\n" % " ".join(arguments))
6368 logfp.write("# recorded by %s@%s on %s\n" % \
6369 (getpass.getuser(),socket.gethostname(),time.ctime()))
6371 scanner = sstscanner()
6372 map(scanner.append, arguments)
6375 while True: # Play a game
6376 setwnd(fullscreen_window)
6382 game.alldone = False
6390 if game.tourn and game.alldone:
6391 proutn(_("Do you want your score recorded?"))
6397 proutn(_("Do you want to play again? "))
6401 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6405 except KeyboardInterrupt: