3 sst.py -- Super Star Trek 2K
5 SST2K is a Python translation of a C translation of a FORTRAN
6 original dating back to 1973. Beautiful Python it is not, but it
7 works. Translation by Eric S. Raymond; original game by David Matuszek
8 and Paul Reynolds, with modifications by Don Smith, Tom Almy,
9 Stas Sergeev, and Eric S. Raymond.
11 See the doc/HACKING file in the distribution for designers notes and advice
12 on how to modify (and how not to modify!) this code.
14 import os, sys, math, curses, time, readline, cPickle, random, copy, gettext, getpass
18 docpath = (".", "../doc", "/usr/share/doc/sst")
21 return gettext.gettext(st)
23 GALSIZE = 8 # Galaxy size in quadrants
24 NINHAB = (GALSIZE * GALSIZE / 2) # Number of inhabited worlds
25 MAXUNINHAB = 10 # Maximum uninhabited worlds
26 QUADSIZE = 10 # Quadrant size in sectors
27 BASEMIN = 2 # Minimum starbases
28 BASEMAX = (GALSIZE * GALSIZE / 12) # Maximum starbases
29 MAXKLGAME = 127 # Maximum Klingons per game
30 MAXKLQUAD = 9 # Maximum Klingons per quadrant
31 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
32 FOREVER = 1e30 # Time for the indefinite future
33 MAXBURST = 3 # Max # of torps you can launch in one turn
34 MINCMDR = 10 # Minimum number of Klingon commanders
35 DOCKFAC = 0.25 # Repair faster when docked
36 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
56 class TrekError(Exception):
59 class JumpOut(Exception):
63 def __init__(self, x=None, y=None):
66 def valid_quadrant(self):
67 return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
68 def valid_sector(self):
69 return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
71 self.i = self.j = None
73 return self.i != None and self.j != None
74 def __eq__(self, other):
75 return other != None and self.i == other.i and self.j == other.j
76 def __ne__(self, other):
77 return other == None or self.i != other.i or self.j != other.j
78 def __add__(self, other):
79 return Coord(self.i+other.i, self.j+other.j)
80 def __sub__(self, other):
81 return Coord(self.i-other.i, self.j-other.j)
82 def __mul__(self, other):
83 return Coord(self.i*other, self.j*other)
84 def __rmul__(self, other):
85 return Coord(self.i*other, self.j*other)
86 def __div__(self, other):
87 return Coord(self.i/other, self.j/other)
88 def __mod__(self, other):
89 return Coord(self.i % other, self.j % other)
90 def __rdiv__(self, other):
91 return Coord(self.i/other, self.j/other)
92 def roundtogrid(self):
93 return Coord(int(round(self.i)), int(round(self.j)))
94 def distance(self, other=None):
97 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
99 return 1.90985*math.atan2(self.j, self.i)
105 s.i = self.i / abs(self.i)
109 s.j = self.j / abs(self.j)
112 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
113 return self.roundtogrid() / QUADSIZE
115 return self.roundtogrid() % QUADSIZE
118 s.i = self.i + randrange(-1, 2)
119 s.j = self.j + randrange(-1, 2)
122 if self.i == None or self.j == None:
124 return "%s - %s" % (self.i+1, self.j+1)
128 "Do not anger the Space Thingy!"
137 self.name = None # string-valued if inhabited
138 self.quadrant = Coord() # quadrant located
139 self.pclass = None # could be ""M", "N", "O", or "destroyed"
140 self.crystals = "absent"# could be "mined", "present", "absent"
141 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
142 self.inhabited = False # is it inhabites?
150 self.starbase = False
153 self.supernova = False
155 self.status = "secure" # Could be "secure", "distressed", "enslaved"
163 def fill2d(size, fillfun):
164 "Fill an empty list in 2D."
166 for i in range(size):
168 for j in range(size):
169 lst[i].append(fillfun(i, j))
174 self.snap = False # snapshot taken
175 self.crew = 0 # crew complement
176 self.remkl = 0 # remaining klingons
177 self.nscrem = 0 # remaining super commanders
178 self.starkl = 0 # destroyed stars
179 self.basekl = 0 # destroyed bases
180 self.nromrem = 0 # Romulans remaining
181 self.nplankl = 0 # destroyed uninhabited planets
182 self.nworldkl = 0 # destroyed inhabited planets
183 self.planets = [] # Planet information
184 self.date = 0.0 # stardate
185 self.remres = 0 # remaining resources
186 self.remtime = 0 # remaining time
187 self.baseq = [] # Base quadrant coordinates
188 self.kcmdr = [] # Commander quadrant coordinates
189 self.kscmdr = Coord() # Supercommander quadrant coordinates
191 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
193 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
197 self.date = None # A real number
198 self.quadrant = None # A coord structure
201 OPTION_ALL = 0xffffffff
202 OPTION_TTY = 0x00000001 # old interface
203 OPTION_CURSES = 0x00000002 # new interface
204 OPTION_IOMODES = 0x00000003 # cover both interfaces
205 OPTION_PLANETS = 0x00000004 # planets and mining
206 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
207 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
208 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
209 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
210 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
211 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
212 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
213 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
214 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
215 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
216 OPTION_PLAIN = 0x01000000 # user chose plain game
217 OPTION_ALMY = 0x02000000 # user chose Almy variant
218 OPTION_COLOR = 0x04000000 # enable color display (experimental, ESR, 2010)
237 NDEVICES = 16 # Number of devices
247 return (game.damage[dev] != 0.0)
249 return not damaged(DRADIO) or game.condition=="docked"
251 # Define future events
252 FSPY = 0 # Spy event happens always (no future[] entry)
253 # can cause SC to tractor beam Enterprise
254 FSNOVA = 1 # Supernova
255 FTBEAM = 2 # Commander tractor beams Enterprise
256 FSNAP = 3 # Snapshot for time warp
257 FBATTAK = 4 # Commander attacks base
258 FCDBAS = 5 # Commander destroys base
259 FSCMOVE = 6 # Supercommander moves (might attack base)
260 FSCDBAS = 7 # Supercommander destroys base
261 FDSPROB = 8 # Move deep space probe
262 FDISTR = 9 # Emit distress call from an inhabited world
263 FENSLV = 10 # Inhabited word is enslaved */
264 FREPRO = 11 # Klingons build a ship in an enslaved system
267 # Abstract out the event handling -- underlying data structures will change
268 # when we implement stateful events
269 def findevent(evtype):
270 return game.future[evtype]
273 def __init__(self, etype=None, loc=None, power=None):
275 self.location = Coord()
278 self.power = power # enemy energy level
279 game.enemies.append(self)
281 motion = (loc != self.location)
282 if self.location.i is not None and self.location.j is not None:
285 game.quad[self.location.i][self.location.j] = '#'
287 game.quad[self.location.i][self.location.j] = '.'
289 self.location = copy.copy(loc)
290 game.quad[self.location.i][self.location.j] = self.type
291 self.kdist = self.kavgd = (game.sector - loc).distance()
293 self.location = Coord()
294 self.kdist = self.kavgd = None
295 game.enemies.remove(self)
298 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
302 self.options = None # Game options
303 self.state = Snapshot() # A snapshot structure
304 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
305 self.quad = None # contents of our quadrant
306 self.damage = [0.0] * NDEVICES # damage encountered
307 self.future = [] # future events
311 self.future.append(Event())
312 self.passwd = None # Self Destruct password
314 self.quadrant = None # where we are in the large
315 self.sector = None # where we are in the small
316 self.tholian = None # Tholian enemy object
317 self.base = None # position of base in current quadrant
318 self.battle = None # base coordinates being attacked
319 self.plnet = None # location of planet in quadrant
320 self.gamewon = False # Finished!
321 self.ididit = False # action taken -- allows enemy to attack
322 self.alive = False # we are alive (not killed)
323 self.justin = False # just entered quadrant
324 self.shldup = False # shields are up
325 self.shldchg = False # shield is changing (affects efficiency)
326 self.iscate = False # super commander is here
327 self.ientesc = False # attempted escape from supercommander
328 self.resting = False # rest time
329 self.icraft = False # Kirk in Galileo
330 self.landed = False # party on planet (true), on ship (false)
331 self.alldone = False # game is now finished
332 self.neutz = False # Romulan Neutral Zone
333 self.isarmed = False # probe is armed
334 self.inorbit = False # orbiting a planet
335 self.imine = False # mining
336 self.icrystl = False # dilithium crystals aboard
337 self.iseenit = False # seen base attack report
338 self.thawed = False # thawed game
339 self.condition = None # "green", "yellow", "red", "docked", "dead"
340 self.iscraft = None # "onship", "offship", "removed"
341 self.skill = None # Player skill level
342 self.inkling = 0 # initial number of klingons
343 self.inbase = 0 # initial number of bases
344 self.incom = 0 # initial number of commanders
345 self.inscom = 0 # initial number of commanders
346 self.inrom = 0 # initial number of commanders
347 self.instar = 0 # initial stars
348 self.intorps = 0 # initial/max torpedoes
349 self.torps = 0 # number of torpedoes
350 self.ship = 0 # ship type -- 'E' is Enterprise
351 self.abandoned = 0 # count of crew abandoned in space
352 self.length = 0 # length of game
353 self.klhere = 0 # klingons here
354 self.casual = 0 # causalties
355 self.nhelp = 0 # calls for help
356 self.nkinks = 0 # count of energy-barrier crossings
357 self.iplnet = None # planet # in quadrant
358 self.inplan = 0 # initial planets
359 self.irhere = 0 # Romulans in quadrant
360 self.isatb = 0 # =2 if super commander is attacking base
361 self.tourn = None # tournament number
362 self.nprobes = 0 # number of probes available
363 self.inresor = 0.0 # initial resources
364 self.intime = 0.0 # initial time
365 self.inenrg = 0.0 # initial/max energy
366 self.inshld = 0.0 # initial/max shield
367 self.inlsr = 0.0 # initial life support resources
368 self.indate = 0.0 # initial date
369 self.energy = 0.0 # energy level
370 self.shield = 0.0 # shield level
371 self.warpfac = 0.0 # warp speed
372 self.lsupres = 0.0 # life support reserves
373 self.optime = 0.0 # time taken by current operation
374 self.damfac = 0.0 # damage factor
375 self.lastchart = 0.0 # time star chart was last updated
376 self.cryprob = 0.0 # probability that crystal will work
377 self.probe = None # object holding probe course info
378 self.height = 0.0 # height of orbit around planet
379 self.score = 0.0 # overall score
380 self.perdate = 0.0 # rate of kills
381 self.idebug = False # Debugging instrumentation enabled?
383 # Stas thinks this should be (C expression):
384 # game.state.remkl + len(game.state.kcmdr) > 0 ?
385 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
386 # He says the existing expression is prone to divide-by-zero errors
387 # after killing the last klingon when score is shown -- perhaps also
388 # if the only remaining klingon is SCOM.
389 game.state.remtime = game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr))
415 return random.random() < p
417 def randrange(*args):
418 return random.randrange(*args)
423 v *= args[0] # from [0, args[0])
425 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
428 # Code from ai.c begins here
431 "Would this quadrant welcome another Klingon?"
432 return iq.valid_quadrant() and \
433 not game.state.galaxy[iq.i][iq.j].supernova and \
434 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
436 def tryexit(enemy, look, irun):
437 "A bad guy attempts to bug out."
439 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
440 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
441 if not welcoming(iq):
443 if enemy.type == 'R':
444 return False # Romulans cannot escape!
446 # avoid intruding on another commander's territory
447 if enemy.type == 'C':
448 if iq in game.state.kcmdr:
450 # refuse to leave if currently attacking starbase
451 if game.battle == game.quadrant:
453 # don't leave if over 1000 units of energy
454 if enemy.power > 1000.0:
456 # emit escape message and move out of quadrant.
457 # we know this if either short or long range sensors are working
458 if not damaged(DSRSENS) or not damaged(DLRSENS) or \
459 game.condition == "docked":
460 prout(crmena(True, enemy.type, "sector", enemy.location) + \
461 (_(" escapes to Quadrant %s (and regains strength).") % iq))
462 # handle local matters related to escape
465 if game.condition != "docked":
467 # Handle global matters related to escape
468 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
469 game.state.galaxy[iq.i][iq.j].klingons += 1
470 if enemy.type == 'S':
474 schedule(FSCMOVE, 0.2777)
476 game.state.kscmdr = iq
478 for cmdr in game.state.kcmdr:
479 if cmdr == game.quadrant:
480 game.state.kcmdr.append(iq)
482 return True # success
484 # The bad-guy movement algorithm:
486 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
487 # If both are operating full strength, force is 1000. If both are damaged,
488 # force is -1000. Having shields down subtracts an additional 1000.
490 # 2. Enemy has forces equal to the energy of the attacker plus
491 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
492 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
494 # Attacker Initial energy levels (nominal):
495 # Klingon Romulan Commander Super-Commander
496 # Novice 400 700 1200
498 # Good 450 800 1300 1750
499 # Expert 475 850 1350 1875
500 # Emeritus 500 900 1400 2000
501 # VARIANCE 75 200 200 200
503 # Enemy vessels only move prior to their attack. In Novice - Good games
504 # only commanders move. In Expert games, all enemy vessels move if there
505 # is a commander present. In Emeritus games all enemy vessels move.
507 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
508 # forces are 1000 greater than Enterprise.
510 # Agressive action on average cuts the distance between the ship and
511 # the enemy to 1/4 the original.
513 # 4. At lower energy advantage, movement units are proportional to the
514 # advantage with a 650 advantage being to hold ground, 800 to move forward
515 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
517 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
518 # retreat, especially at high skill levels.
520 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
522 def movebaddy(enemy):
523 "Tactical movement for the bad guys."
524 goto = Coord(); look = Coord()
526 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
527 if game.skill >= SKILL_EXPERT:
528 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
530 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
532 mdist = int(dist1 + 0.5) # Nearest integer distance
533 # If SC, check with spy to see if should hi-tail it
534 if enemy.type=='S' and \
535 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
539 # decide whether to advance, retreat, or hold position
540 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
542 forces += 1000 # Good for enemy if shield is down!
543 if not damaged(DPHASER) or not damaged(DPHOTON):
544 if damaged(DPHASER): # phasers damaged
547 forces -= 0.2*(game.energy - 2500.0)
548 if damaged(DPHOTON): # photon torpedoes damaged
551 forces -= 50.0*game.torps
553 # phasers and photon tubes both out!
556 if forces <= 1000.0 and game.condition != "docked": # Typical situation
557 motion = ((forces + randreal(200))/150.0) - 5.0
559 if forces > 1000.0: # Very strong -- move in for kill
560 motion = (1.0 - randreal())**2 * dist1 + 1.0
561 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
562 motion -= game.skill*(2.0-randreal()**2)
564 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
565 # don't move if no motion
568 # Limit motion according to skill
569 if abs(motion) > game.skill:
574 # calculate preferred number of steps
575 nsteps = abs(int(motion))
576 if motion > 0 and nsteps > mdist:
577 nsteps = mdist # don't overshoot
578 if nsteps > QUADSIZE:
579 nsteps = QUADSIZE # This shouldn't be necessary
581 nsteps = 1 # This shouldn't be necessary
583 proutn("NSTEPS = %d:" % nsteps)
584 # Compute preferred values of delta X and Y
585 m = game.sector - enemy.location
586 if 2.0 * abs(m.i) < abs(m.j):
588 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
590 m = (motion * m).sgn()
591 goto = enemy.location
593 for ll in range(nsteps):
595 proutn(" %d" % (ll+1))
596 # Check if preferred position available
607 attempts = 0 # Settle mysterious hang problem
608 while attempts < 20 and not success:
610 if look.i < 0 or look.i >= QUADSIZE:
611 if motion < 0 and tryexit(enemy, look, irun):
613 if krawli == m.i or m.j == 0:
615 look.i = goto.i + krawli
617 elif look.j < 0 or look.j >= QUADSIZE:
618 if motion < 0 and tryexit(enemy, look, irun):
620 if krawlj == m.j or m.i == 0:
622 look.j = goto.j + krawlj
624 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
625 # See if enemy should ram ship
626 if game.quad[look.i][look.j] == game.ship and \
627 (enemy.type == 'C' or enemy.type == 'S'):
628 collision(rammed=True, enemy=enemy)
630 if krawli != m.i and m.j != 0:
631 look.i = goto.i + krawli
633 elif krawlj != m.j and m.i != 0:
634 look.j = goto.j + krawlj
637 break # we have failed
649 if not damaged(DSRSENS) or game.condition == "docked":
650 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
651 if enemy.kdist < dist1:
652 proutn(_(" advances to "))
654 proutn(_(" retreats to "))
655 prout("Sector %s." % goto)
658 "Sequence Klingon tactical movement."
661 # Figure out which Klingon is the commander (or Supercommander)
663 if game.quadrant in game.state.kcmdr:
664 for enemy in game.enemies:
665 if enemy.type == 'C':
667 if game.state.kscmdr==game.quadrant:
668 for enemy in game.enemies:
669 if enemy.type == 'S':
672 # If skill level is high, move other Klingons and Romulans too!
673 # Move these last so they can base their actions on what the
675 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
676 for enemy in game.enemies:
677 if enemy.type in ('K', 'R'):
681 def movescom(iq, avoid):
682 "Commander movement helper."
683 # Avoid quadrants with bases if we want to avoid Enterprise
684 if not welcoming(iq) or (avoid and iq in game.state.baseq):
686 if game.justin and not game.iscate:
689 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
690 game.state.kscmdr = iq
691 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
692 if game.state.kscmdr==game.quadrant:
693 # SC has scooted, remove him from current quadrant
698 for enemy in game.enemies:
699 if enemy.type == 'S':
703 if game.condition != "docked":
706 # check for a helpful planet
707 for i in range(game.inplan):
708 if game.state.planets[i].quadrant == game.state.kscmdr and \
709 game.state.planets[i].crystals == "present":
711 game.state.planets[i].pclass = "destroyed"
712 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
715 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
716 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
717 prout(_(" by the Super-commander.\""))
719 return True # looks good!
721 def supercommander():
722 "Move the Super Commander."
723 iq = Coord(); sc = Coord(); ibq = Coord(); idelta = Coord()
726 prout("== SUPERCOMMANDER")
727 # Decide on being active or passive
728 avoid = ((game.incom - len(game.state.kcmdr) + game.inkling - game.state.remkl)/(game.state.date+0.01-game.indate) < 0.1*game.skill*(game.skill+1.0) or \
729 (game.state.date-game.indate) < 3.0)
730 if not game.iscate and avoid:
731 # compute move away from Enterprise
732 idelta = game.state.kscmdr-game.quadrant
733 if idelta.distance() > 2.0:
735 idelta.i = game.state.kscmdr.j-game.quadrant.j
736 idelta.j = game.quadrant.i-game.state.kscmdr.i
738 # compute distances to starbases
739 if not game.state.baseq:
743 sc = game.state.kscmdr
744 for (i, base) in enumerate(game.state.baseq):
745 basetbl.append((i, (base - sc).distance()))
746 if game.state.baseq > 1:
747 basetbl.sort(lambda x, y: cmp(x[1], y[1]))
748 # look for nearest base without a commander, no Enterprise, and
749 # without too many Klingons, and not already under attack.
750 ifindit = iwhichb = 0
751 for (i2, base) in enumerate(game.state.baseq):
752 i = basetbl[i2][0] # bug in original had it not finding nearest
753 if base == game.quadrant or base == game.battle or not welcoming(base):
755 # if there is a commander, and no other base is appropriate,
756 # we will take the one with the commander
757 for cmdr in game.state.kcmdr:
758 if base == cmdr and ifindit != 2:
762 else: # no commander -- use this one
767 return # Nothing suitable -- wait until next time
768 ibq = game.state.baseq[iwhichb]
769 # decide how to move toward base
770 idelta = ibq - game.state.kscmdr
771 # Maximum movement is 1 quadrant in either or both axes
772 idelta = idelta.sgn()
773 # try moving in both x and y directions
774 # there was what looked like a bug in the Almy C code here,
775 # but it might be this translation is just wrong.
776 iq = game.state.kscmdr + idelta
777 if not movescom(iq, avoid):
778 # failed -- try some other maneuvers
779 if idelta.i == 0 or idelta.j == 0:
782 iq.j = game.state.kscmdr.j + 1
783 if not movescom(iq, avoid):
784 iq.j = game.state.kscmdr.j - 1
787 iq.i = game.state.kscmdr.i + 1
788 if not movescom(iq, avoid):
789 iq.i = game.state.kscmdr.i - 1
792 # try moving just in x or y
793 iq.j = game.state.kscmdr.j
794 if not movescom(iq, avoid):
795 iq.j = game.state.kscmdr.j + idelta.j
796 iq.i = game.state.kscmdr.i
799 if len(game.state.baseq) == 0:
802 for ibq in game.state.baseq:
803 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
806 return # no, don't attack base!
809 schedule(FSCDBAS, randreal(1.0, 3.0))
810 if is_scheduled(FCDBAS):
811 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
812 if not communicating():
816 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
818 prout(_(" reports that it is under attack from the Klingon Super-commander."))
819 proutn(_(" It can survive until stardate %d.\"") \
820 % int(scheduled(FSCDBAS)))
823 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
827 game.optime = 0.0 # actually finished
829 # Check for intelligence report
830 if not game.idebug and \
832 (not communicating()) or \
833 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
836 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
837 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
842 if not game.tholian or game.justin:
845 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
848 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
851 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
854 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
858 # something is wrong!
859 game.tholian.move(None)
860 prout("***Internal error: Tholian in a bad spot.")
862 # do nothing if we are blocked
863 if game.quad[tid.i][tid.j] not in ('.', '#'):
865 here = copy.copy(game.tholian.location)
866 delta = (tid - game.tholian.location).sgn()
868 while here.i != tid.i:
870 if game.quad[here.i][here.j] == '.':
871 game.tholian.move(here)
873 while here.j != tid.j:
875 if game.quad[here.i][here.j] == '.':
876 game.tholian.move(here)
877 # check to see if all holes plugged
878 for i in range(QUADSIZE):
879 if game.quad[0][i]!='#' and game.quad[0][i]!='T':
881 if game.quad[QUADSIZE-1][i]!='#' and game.quad[QUADSIZE-1][i]!='T':
883 if game.quad[i][0]!='#' and game.quad[i][0]!='T':
885 if game.quad[i][QUADSIZE-1]!='#' and game.quad[i][QUADSIZE-1]!='T':
887 # All plugged up -- Tholian splits
888 game.quad[game.tholian.location.i][game.tholian.location.j]='#'
890 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
891 game.tholian.move(None)
894 # Code from battle.c begins here
896 def doshield(shraise):
897 "Change shield status."
905 if scanner.sees("transfer"):
909 prout(_("Shields damaged and down."))
911 if scanner.sees("up"):
913 elif scanner.sees("down"):
916 proutn(_("Do you wish to change shield energy? "))
919 elif damaged(DSHIELD):
920 prout(_("Shields damaged and down."))
923 proutn(_("Shields are up. Do you want them down? "))
930 proutn(_("Shields are down. Do you want them up? "))
936 if action == "SHUP": # raise shields
938 prout(_("Shields already up."))
942 if game.condition != "docked":
944 prout(_("Shields raised."))
947 prout(_("Shields raising uses up last of energy."))
952 elif action == "SHDN":
954 prout(_("Shields already down."))
958 prout(_("Shields lowered."))
961 elif action == "NRG":
962 while scanner.next() != "IHREAL":
964 proutn(_("Energy to transfer to shields- "))
969 if nrg > game.energy:
970 prout(_("Insufficient ship energy."))
973 if game.shield+nrg >= game.inshld:
974 prout(_("Shield energy maximized."))
975 if game.shield+nrg > game.inshld:
976 prout(_("Excess energy requested returned to ship energy"))
977 game.energy -= game.inshld-game.shield
978 game.shield = game.inshld
980 if nrg < 0.0 and game.energy-nrg > game.inenrg:
981 # Prevent shield drain loophole
983 prout(_("Engineering to bridge--"))
984 prout(_(" Scott here. Power circuit problem, Captain."))
985 prout(_(" I can't drain the shields."))
988 if game.shield+nrg < 0:
989 prout(_("All shield energy transferred to ship."))
990 game.energy += game.shield
993 proutn(_("Scotty- \""))
995 prout(_("Transferring energy to shields.\""))
997 prout(_("Draining energy from shields.\""))
1003 "Choose a device to damage, at random."
1005 105, # DSRSENS: short range scanners 10.5%
1006 105, # DLRSENS: long range scanners 10.5%
1007 120, # DPHASER: phasers 12.0%
1008 120, # DPHOTON: photon torpedoes 12.0%
1009 25, # DLIFSUP: life support 2.5%
1010 65, # DWARPEN: warp drive 6.5%
1011 70, # DIMPULS: impulse engines 6.5%
1012 145, # DSHIELD: deflector shields 14.5%
1013 30, # DRADIO: subspace radio 3.0%
1014 45, # DSHUTTL: shuttle 4.5%
1015 15, # DCOMPTR: computer 1.5%
1016 20, # NAVCOMP: navigation system 2.0%
1017 75, # DTRANSP: transporter 7.5%
1018 20, # DSHCTRL: high-speed shield controller 2.0%
1019 10, # DDRAY: death ray 1.0%
1020 30, # DDSP: deep-space probes 3.0%
1022 assert(sum(weights) == 1000)
1023 idx = randrange(1000)
1025 for (i, w) in enumerate(weights):
1029 return None # we should never get here
1031 def collision(rammed, enemy):
1032 "Collision handling fot rammong events."
1033 prouts(_("***RED ALERT! RED ALERT!"))
1035 prout(_("***COLLISION IMMINENT."))
1039 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1041 proutn(_(" rammed by "))
1044 proutn(crmena(False, enemy.type, "sector", enemy.location))
1046 proutn(_(" (original position)"))
1048 deadkl(enemy.location, enemy.type, game.sector)
1049 proutn("***" + crmshp() + " heavily damaged.")
1050 icas = randrange(10, 30)
1051 prout(_("***Sickbay reports %d casualties") % icas)
1053 game.state.crew -= icas
1054 # In the pre-SST2K version, all devices got equiprobably damaged,
1055 # which was silly. Instead, pick up to half the devices at
1056 # random according to our weighting table,
1057 ncrits = randrange(NDEVICES/2)
1061 if game.damage[dev] < 0:
1063 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1064 # Damage for at least time of travel!
1065 game.damage[dev] += game.optime + extradm
1067 prout(_("***Shields are down."))
1068 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1075 def torpedo(origin, bearing, dispersion, number, nburst):
1076 "Let a photon torpedo fly"
1077 if not damaged(DSRSENS) or game.condition == "docked":
1078 setwnd(srscan_window)
1080 setwnd(message_window)
1081 ac = bearing + 0.25*dispersion # dispersion is a random variable
1082 bullseye = (15.0 - bearing)*0.5235988
1083 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1084 bumpto = Coord(0, 0)
1085 # Loop to move a single torpedo
1086 setwnd(message_window)
1087 for step in range(1, QUADSIZE*2):
1088 if not track.next(): break
1090 if not w.valid_sector():
1092 iquad=game.quad[w.i][w.j]
1093 tracktorpedo(w, step, number, nburst, iquad)
1097 if not damaged(DSRSENS) or game.condition == "docked":
1098 skip(1) # start new line after text track
1099 if iquad in ('E', 'F'): # Hit our ship
1101 prout(_("Torpedo hits %s.") % crmshp())
1102 hit = 700.0 + randreal(100) - \
1103 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1104 newcnd() # we're blown out of dock
1105 if game.landed or game.condition == "docked":
1106 return hit # Cheat if on a planet
1107 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1108 # is 143 degrees, which is almost exactly 4.8 clockface units
1109 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1111 bumpto = displacement.sector()
1112 if not bumpto.valid_sector():
1114 if game.quad[bumpto.i][bumpto.j] == ' ':
1117 if game.quad[bumpto.i][bumpto.j]!='.':
1118 # can't move into object
1120 game.sector = bumpto
1122 game.quad[w.i][w.j] = '.'
1123 game.quad[bumpto.i][bumpto.j] = iquad
1124 prout(_(" displaced by blast to Sector %s ") % bumpto)
1125 for enemy in game.enemies:
1126 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1129 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1131 if iquad in ('C', 'S') and withprob(0.05):
1132 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1133 prout(_(" torpedo neutralized."))
1135 for enemy in game.enemies:
1136 if w == enemy.location:
1138 kp = math.fabs(enemy.power)
1139 h1 = 700.0 + randrange(100) - \
1140 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1148 if enemy.power == 0:
1151 proutn(crmena(True, iquad, "sector", w))
1152 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1154 bumpto = displacement.sector()
1155 if not bumpto.valid_sector():
1156 prout(_(" damaged but not destroyed."))
1158 if game.quad[bumpto.i][bumpto.j] == ' ':
1159 prout(_(" buffeted into black hole."))
1160 deadkl(w, iquad, bumpto)
1161 if game.quad[bumpto.i][bumpto.j] != '.':
1162 prout(_(" damaged but not destroyed."))
1164 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1165 enemy.location = bumpto
1166 game.quad[w.i][w.j]='.'
1167 game.quad[bumpto.i][bumpto.j]=iquad
1168 for enemy in game.enemies:
1169 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1172 elif iquad == 'B': # Hit a base
1174 prout(_("***STARBASE DESTROYED.."))
1175 game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
1176 game.quad[w.i][w.j] = '.'
1177 game.base.invalidate()
1178 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1
1179 game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1
1180 game.state.basekl += 1
1183 elif iquad == 'P': # Hit a planet
1184 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1185 game.state.nplankl += 1
1186 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1187 game.iplnet.pclass = "destroyed"
1189 game.plnet.invalidate()
1190 game.quad[w.i][w.j] = '.'
1192 # captain perishes on planet
1195 elif iquad == '@': # Hit an inhabited world -- very bad!
1196 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1197 game.state.nworldkl += 1
1198 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1199 game.iplnet.pclass = "destroyed"
1201 game.plnet.invalidate()
1202 game.quad[w.i][w.j] = '.'
1204 # captain perishes on planet
1206 prout(_("The torpedo destroyed an inhabited planet."))
1208 elif iquad == '*': # Hit a star
1212 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1214 elif iquad == '?': # Hit a thingy
1215 if not (game.options & OPTION_THINGY) or withprob(0.3):
1217 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1219 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1221 proutn(_("Mr. Spock-"))
1222 prouts(_(" \"Fascinating!\""))
1226 # Stas Sergeev added the possibility that
1227 # you can shove the Thingy and piss it off.
1228 # It then becomes an enemy and may fire at you.
1231 elif iquad == ' ': # Black hole
1233 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1235 elif iquad == '#': # hit the web
1237 prout(_("***Torpedo absorbed by Tholian web."))
1239 elif iquad == 'T': # Hit a Tholian
1240 h1 = 700.0 + randrange(100) - \
1241 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1244 game.quad[w.i][w.j] = '.'
1249 proutn(crmena(True, 'T', "sector", w))
1251 prout(_(" survives photon blast."))
1253 prout(_(" disappears."))
1254 game.tholian.move(None)
1255 game.quad[w.i][w.j] = '#'
1260 proutn("Don't know how to handle torpedo collision with ")
1261 proutn(crmena(True, iquad, "sector", w))
1266 prout(_("Torpedo missed."))
1270 "Critical-hit resolution."
1271 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1273 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1274 proutn(_("***CRITICAL HIT--"))
1275 # Select devices and cause damage
1281 # Cheat to prevent shuttle damage unless on ship
1282 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship")):
1285 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1286 game.damage[j] += extradm
1288 for (i, j) in enumerate(cdam):
1290 if skipcount % 3 == 2 and i < len(cdam)-1:
1295 prout(_(" damaged."))
1296 if damaged(DSHIELD) and game.shldup:
1297 prout(_("***Shields knocked down."))
1300 def attack(torps_ok):
1301 # bad guy attacks us
1302 # torps_ok == False forces use of phasers in an attack
1303 # game could be over at this point, check
1308 hitmax=0.0; hittot=0.0; chgfac=1.0
1311 prout("=== ATTACK!")
1312 # Tholian gets to move before attacking
1315 # if you have just entered the RNZ, you'll get a warning
1316 if game.neutz: # The one chance not to be attacked
1319 # commanders get a chance to tac-move towards you
1320 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:
1322 # if no enemies remain after movement, we're done
1323 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing == game.quadrant and not thing.angered):
1325 # set up partial hits if attack happens during shield status change
1326 pfac = 1.0/game.inshld
1328 chgfac = 0.25 + randreal(0.5)
1330 # message verbosity control
1331 if game.skill <= SKILL_FAIR:
1333 for enemy in game.enemies:
1335 continue # too weak to attack
1336 # compute hit strength and diminish shield power
1338 # Increase chance of photon torpedos if docked or enemy energy is low
1339 if game.condition == "docked":
1341 if enemy.power < 500:
1343 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1345 # different enemies have different probabilities of throwing a torp
1346 usephasers = not torps_ok or \
1347 (enemy.type == 'K' and r > 0.0005) or \
1348 (enemy.type == 'C' and r > 0.015) or \
1349 (enemy.type == 'R' and r > 0.3) or \
1350 (enemy.type == 'S' and r > 0.07) or \
1351 (enemy.type == '?' and r > 0.05)
1352 if usephasers: # Enemy uses phasers
1353 if game.condition == "docked":
1354 continue # Don't waste the effort!
1355 attempt = True # Attempt to attack
1356 dustfac = randreal(0.8, 0.85)
1357 hit = enemy.power*math.pow(dustfac,enemy.kavgd)
1359 else: # Enemy uses photon torpedo
1360 # We should be able to make the bearing() method work here
1361 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1363 proutn(_("***TORPEDO INCOMING"))
1364 if not damaged(DSRSENS):
1365 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1368 dispersion = (randreal()+randreal())*0.5 - 0.5
1369 dispersion += 0.002*enemy.power*dispersion
1370 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1371 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1372 finish(FWON) # Klingons did themselves in!
1373 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1374 return # Supernova or finished
1377 # incoming phaser or torpedo, shields may dissipate it
1378 if game.shldup or game.shldchg or game.condition == "docked":
1379 # shields will take hits
1380 propor = pfac * game.shield
1381 if game.condition == "docked":
1385 hitsh = propor*chgfac*hit+1.0
1387 if absorb > game.shield:
1388 absorb = game.shield
1389 game.shield -= absorb
1391 # taking a hit blasts us out of a starbase dock
1392 if game.condition == "docked":
1394 # but the shields may take care of it
1395 if propor > 0.1 and hit < 0.005*game.energy:
1397 # hit from this opponent got through shields, so take damage
1399 proutn(_("%d unit hit") % int(hit))
1400 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1401 proutn(_(" on the ") + crmshp())
1402 if not damaged(DSRSENS) and usephasers:
1403 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1405 # Decide if hit is critical
1411 if game.energy <= 0:
1412 # Returning home upon your shield, not with it...
1415 if not attempt and game.condition == "docked":
1416 prout(_("***Enemies decide against attacking your ship."))
1417 percent = 100.0*pfac*game.shield+0.5
1419 # Shields fully protect ship
1420 proutn(_("Enemy attack reduces shield strength to "))
1422 # Emit message if starship suffered hit(s)
1424 proutn(_("Energy left %2d shields ") % int(game.energy))
1427 elif not damaged(DSHIELD):
1430 proutn(_("damaged, "))
1431 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1432 # Check if anyone was hurt
1433 if hitmax >= 200 or hittot >= 500:
1434 icas = randrange(int(hittot * 0.015))
1437 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1438 prout(_(" in that last attack.\""))
1440 game.state.crew -= icas
1441 # After attack, reset average distance to enemies
1442 for enemy in game.enemies:
1443 enemy.kavgd = enemy.kdist
1447 def deadkl(w, etype, mv):
1448 "Kill a Klingon, Tholian, Romulan, or Thingy."
1449 # Added mv to allow enemy to "move" before dying
1450 proutn(crmena(True, etype, "sector", mv))
1451 # Decide what kind of enemy it is and update appropriately
1453 # Chalk up a Romulan
1454 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1456 game.state.nromrem -= 1
1465 # Killed some type of Klingon
1466 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1469 game.state.kcmdr.remove(game.quadrant)
1471 if game.state.kcmdr:
1472 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1473 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1476 game.state.remkl -= 1
1478 game.state.nscrem -= 1
1479 game.state.kscmdr.invalidate()
1484 # For each kind of enemy, finish message to player
1485 prout(_(" destroyed."))
1486 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1489 # Remove enemy ship from arrays describing local conditions
1490 for e in game.enemies:
1497 "Return None if target is invalid, otherwise return a course angle."
1498 if not w.valid_sector():
1502 # FIXME: C code this was translated from is wacky -- why the sign reversal?
1503 delta.j = (w.j - game.sector.j)
1504 delta.i = (game.sector.i - w.i)
1505 if delta == Coord(0, 0):
1507 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1508 prout(_(" I recommend an immediate review of"))
1509 prout(_(" the Captain's psychological profile.\""))
1512 return delta.bearing()
1515 "Launch photon torpedo salvo."
1518 if damaged(DPHOTON):
1519 prout(_("Photon tubes damaged."))
1523 prout(_("No torpedoes left."))
1526 # First, get torpedo count
1529 if scanner.token == "IHALPHA":
1532 elif scanner.token == "IHEOL" or not scanner.waiting():
1533 prout(_("%d torpedoes left.") % game.torps)
1535 proutn(_("Number of torpedoes to fire- "))
1536 continue # Go back around to get a number
1537 else: # key == "IHREAL"
1539 if n <= 0: # abort command
1544 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1547 scanner.chew() # User requested more torps than available
1548 continue # Go back around
1549 break # All is good, go to next stage
1553 key = scanner.next()
1554 if i == 0 and key == "IHEOL":
1555 break # no coordinate waiting, we will try prompting
1556 if i == 1 and key == "IHEOL":
1557 # direct all torpedoes at one target
1559 target.append(target[0])
1560 tcourse.append(tcourse[0])
1563 scanner.push(scanner.token)
1564 target.append(scanner.getcoord())
1565 if target[-1] == None:
1567 tcourse.append(targetcheck(target[-1]))
1568 if tcourse[-1] == None:
1571 if len(target) == 0:
1572 # prompt for each one
1574 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1576 target.append(scanner.getcoord())
1577 if target[-1] == None:
1579 tcourse.append(targetcheck(target[-1]))
1580 if tcourse[-1] == None:
1583 # Loop for moving <n> torpedoes
1585 if game.condition != "docked":
1587 dispersion = (randreal()+randreal())*0.5 -0.5
1588 if math.fabs(dispersion) >= 0.47:
1590 dispersion *= randreal(1.2, 2.2)
1592 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1594 prouts(_("***TORPEDO MISFIRES."))
1597 prout(_(" Remainder of burst aborted."))
1599 prout(_("***Photon tubes damaged by misfire."))
1600 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1602 if game.shldup or game.condition == "docked":
1603 dispersion *= 1.0 + 0.0001*game.shield
1604 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1605 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1607 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1611 "Check for phasers overheating."
1613 checkburn = (rpow-1500.0)*0.00038
1614 if withprob(checkburn):
1615 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1616 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1618 def checkshctrl(rpow):
1619 "Check shield control."
1622 prout(_("Shields lowered."))
1624 # Something bad has happened
1625 prouts(_("***RED ALERT! RED ALERT!"))
1627 hit = rpow*game.shield/game.inshld
1628 game.energy -= rpow+hit*0.8
1629 game.shield -= hit*0.2
1630 if game.energy <= 0.0:
1631 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1636 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1638 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1639 icas = randrange(int(hit*0.012))
1644 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1645 prout(_(" %d casualties so far.\"") % icas)
1647 game.state.crew -= icas
1649 prout(_("Phaser energy dispersed by shields."))
1650 prout(_("Enemy unaffected."))
1655 "Register a phaser hit on Klingons and Romulans."
1659 for (k, wham) in enumerate(hits):
1662 dustfac = randreal(0.9, 1.0)
1663 hit = wham*math.pow(dustfac,game.enemies[kk].kdist)
1664 kpini = game.enemies[kk].power
1665 kp = math.fabs(kpini)
1666 if PHASEFAC*hit < kp:
1668 if game.enemies[kk].power < 0:
1669 game.enemies[kk].power -= -kp
1671 game.enemies[kk].power -= kp
1672 kpow = game.enemies[kk].power
1673 w = game.enemies[kk].location
1675 if not damaged(DSRSENS):
1677 proutn(_("%d unit hit on ") % int(hit))
1679 proutn(_("Very small hit on "))
1680 ienm = game.quad[w.i][w.j]
1683 proutn(crmena(False, ienm, "sector", w))
1687 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1691 kk -= 1 # don't do the increment
1693 else: # decide whether or not to emasculate klingon
1694 if kpow>0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1695 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1696 prout(_(" has just lost its firepower.\""))
1697 game.enemies[kk].power = -kpow
1702 "Fire phasers at bad guys."
1704 kz = 0; k = 1; irec=0 # Cheating inhibitor
1705 ifast = False; no = False; itarg = True; msgflag = True; rpow=0
1709 # SR sensors and Computer are needed for automode
1710 if damaged(DSRSENS) or damaged(DCOMPTR):
1712 if game.condition == "docked":
1713 prout(_("Phasers can't be fired through base shields."))
1716 if damaged(DPHASER):
1717 prout(_("Phaser control damaged."))
1721 if damaged(DSHCTRL):
1722 prout(_("High speed shield control damaged."))
1725 if game.energy <= 200.0:
1726 prout(_("Insufficient energy to activate high-speed shield control."))
1729 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1731 # Original code so convoluted, I re-did it all
1732 # (That was Tom Almy talking about the C code, I think -- ESR)
1733 while automode=="NOTSET":
1735 if key == "IHALPHA":
1736 if scanner.sees("manual"):
1737 if len(game.enemies)==0:
1738 prout(_("There is no enemy present to select."))
1741 automode="AUTOMATIC"
1744 key = scanner.next()
1745 elif scanner.sees("automatic"):
1746 if (not itarg) and len(game.enemies) != 0:
1747 automode = "FORCEMAN"
1749 if len(game.enemies)==0:
1750 prout(_("Energy will be expended into space."))
1751 automode = "AUTOMATIC"
1752 key = scanner.next()
1753 elif scanner.sees("no"):
1758 elif key == "IHREAL":
1759 if len(game.enemies)==0:
1760 prout(_("Energy will be expended into space."))
1761 automode = "AUTOMATIC"
1763 automode = "FORCEMAN"
1765 automode = "AUTOMATIC"
1768 if len(game.enemies)==0:
1769 prout(_("Energy will be expended into space."))
1770 automode = "AUTOMATIC"
1772 automode = "FORCEMAN"
1774 proutn(_("Manual or automatic? "))
1779 if automode == "AUTOMATIC":
1780 if key == "IHALPHA" and scanner.sees("no"):
1782 key = scanner.next()
1783 if key != "IHREAL" and len(game.enemies) != 0:
1784 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1789 for i in range(len(game.enemies)):
1790 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1792 proutn(_("%d units required. ") % irec)
1794 proutn(_("Units to fire= "))
1795 key = scanner.next()
1800 proutn(_("Energy available= %.2f") % avail)
1803 if not rpow > avail:
1810 if key == "IHALPHA" and scanner.sees("no"):
1813 game.energy -= 200 # Go and do it!
1814 if checkshctrl(rpow):
1819 if len(game.enemies):
1822 for i in range(len(game.enemies)):
1826 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))
1827 over = randreal(1.01, 1.06) * hits[i]
1829 powrem -= hits[i] + over
1830 if powrem <= 0 and temp < hits[i]:
1839 if extra > 0 and not game.alldone:
1841 proutn(_("*** Tholian web absorbs "))
1842 if len(game.enemies)>0:
1843 proutn(_("excess "))
1844 prout(_("phaser energy."))
1846 prout(_("%d expended on empty space.") % int(extra))
1847 elif automode == "FORCEMAN":
1850 if damaged(DCOMPTR):
1851 prout(_("Battle computer damaged, manual fire only."))
1854 prouts(_("---WORKING---"))
1856 prout(_("Short-range-sensors-damaged"))
1857 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1858 prout(_("Manual-fire-must-be-used"))
1860 elif automode == "MANUAL":
1862 for k in range(len(game.enemies)):
1863 aim = game.enemies[k].location
1864 ienm = game.quad[aim.i][aim.j]
1866 proutn(_("Energy available= %.2f") % (avail-0.006))
1870 if damaged(DSRSENS) and \
1871 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1872 prout(cramen(ienm) + _(" can't be located without short range scan."))
1875 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
1880 if itarg and k > kz:
1881 irec=(abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9,game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1884 if not damaged(DCOMPTR):
1889 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1890 key = scanner.next()
1891 if key == "IHALPHA" and scanner.sees("no"):
1893 key = scanner.next()
1895 if key == "IHALPHA":
1899 if k == 1: # Let me say I'm baffled by this
1902 if scanner.real < 0:
1906 hits[k] = scanner.real
1907 rpow += scanner.real
1908 # If total requested is too much, inform and start over
1910 prout(_("Available energy exceeded -- try again."))
1913 key = scanner.next() # scan for next value
1916 # zero energy -- abort
1919 if key == "IHALPHA" and scanner.sees("no"):
1924 game.energy -= 200.0
1925 if checkshctrl(rpow):
1929 # Say shield raised or malfunction, if necessary
1936 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1937 prouts(_(" CLICK CLICK POP . . ."))
1938 prout(_(" No response, sir!"))
1941 prout(_("Shields raised."))
1946 # Code from events,c begins here.
1948 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1949 # event of each type active at any given time. Mostly these means we can
1950 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1951 # BSD Trek, from which we swiped the idea, can have up to 5.
1953 def unschedule(evtype):
1954 "Remove an event from the schedule."
1955 game.future[evtype].date = FOREVER
1956 return game.future[evtype]
1958 def is_scheduled(evtype):
1959 "Is an event of specified type scheduled."
1960 return game.future[evtype].date != FOREVER
1962 def scheduled(evtype):
1963 "When will this event happen?"
1964 return game.future[evtype].date
1966 def schedule(evtype, offset):
1967 "Schedule an event of specified type."
1968 game.future[evtype].date = game.state.date + offset
1969 return game.future[evtype]
1971 def postpone(evtype, offset):
1972 "Postpone a scheduled event."
1973 game.future[evtype].date += offset
1976 "Rest period is interrupted by event."
1979 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
1981 game.resting = False
1987 "Run through the event queue looking for things to do."
1989 fintim = game.state.date + game.optime
1993 w = Coord(); hold = Coord()
1994 ev = Event(); ev2 = Event()
1996 def tractorbeam(yank):
1997 "Tractor-beaming cases merge here."
1999 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2001 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2002 # If Kirk & Co. screwing around on planet, handle
2003 atover(True) # atover(true) is Grab
2006 if game.icraft: # Caught in Galileo?
2009 # Check to see if shuttle is aboard
2010 if game.iscraft == "offship":
2013 prout(_("Galileo, left on the planet surface, is captured"))
2014 prout(_("by aliens and made into a flying McDonald's."))
2015 game.damage[DSHUTTL] = -10
2016 game.iscraft = "removed"
2018 prout(_("Galileo, left on the planet surface, is well hidden."))
2020 game.quadrant = game.state.kscmdr
2022 game.quadrant = game.state.kcmdr[i]
2023 game.sector = randplace(QUADSIZE)
2024 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2025 % (game.quadrant, game.sector))
2027 prout(_("(Remainder of rest/repair period cancelled.)"))
2028 game.resting = False
2030 if not damaged(DSHIELD) and game.shield > 0:
2031 doshield(shraise=True) # raise shields
2032 game.shldchg = False
2034 prout(_("(Shields not currently useable.)"))
2036 # Adjust finish time to time of tractor beaming
2037 fintim = game.state.date+game.optime
2038 attack(torps_ok=False)
2039 if not game.state.kcmdr:
2042 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2045 "Code merges here for any commander destroying a starbase."
2046 # Not perfect, but will have to do
2047 # Handle case where base is in same quadrant as starship
2048 if game.battle == game.quadrant:
2049 game.state.chart[game.battle.i][game.battle.j].starbase = False
2050 game.quad[game.base.i][game.base.j] = '.'
2051 game.base.invalidate()
2054 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2055 elif game.state.baseq and communicating():
2056 # Get word via subspace radio
2059 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2060 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2062 prout(_("the Klingon Super-Commander"))
2064 prout(_("a Klingon Commander"))
2065 game.state.chart[game.battle.i][game.battle.j].starbase = False
2066 # Remove Starbase from galaxy
2067 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2068 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2070 # reinstate a commander's base attack
2074 game.battle.invalidate()
2076 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2077 for i in range(1, NEVENTS):
2078 if i == FSNOVA: proutn("=== Supernova ")
2079 elif i == FTBEAM: proutn("=== T Beam ")
2080 elif i == FSNAP: proutn("=== Snapshot ")
2081 elif i == FBATTAK: proutn("=== Base Attack ")
2082 elif i == FCDBAS: proutn("=== Base Destroy ")
2083 elif i == FSCMOVE: proutn("=== SC Move ")
2084 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2085 elif i == FDSPROB: proutn("=== Probe Move ")
2086 elif i == FDISTR: proutn("=== Distress Call ")
2087 elif i == FENSLV: proutn("=== Enslavement ")
2088 elif i == FREPRO: proutn("=== Klingon Build ")
2090 prout("%.2f" % (scheduled(i)))
2093 radio_was_broken = damaged(DRADIO)
2096 # Select earliest extraneous event, evcode==0 if no events
2101 for l in range(1, NEVENTS):
2102 if game.future[l].date < datemin:
2105 prout("== Event %d fires" % evcode)
2106 datemin = game.future[l].date
2107 xtime = datemin-game.state.date
2108 game.state.date = datemin
2109 # Decrement Federation resources and recompute remaining time
2110 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2112 if game.state.remtime <= 0:
2115 # Any crew left alive?
2116 if game.state.crew <=0:
2119 # Is life support adequate?
2120 if damaged(DLIFSUP) and game.condition != "docked":
2121 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2124 game.lsupres -= xtime
2125 if game.damage[DLIFSUP] <= xtime:
2126 game.lsupres = game.inlsr
2129 if game.condition == "docked":
2131 # Don't fix Deathray here
2132 for l in range(NDEVICES):
2133 if game.damage[l] > 0.0 and l != DDRAY:
2134 if game.damage[l]-repair > 0.0:
2135 game.damage[l] -= repair
2137 game.damage[l] = 0.0
2138 # If radio repaired, update star chart and attack reports
2139 if radio_was_broken and not damaged(DRADIO):
2140 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2141 prout(_(" surveillance reports are coming in."))
2143 if not game.iseenit:
2147 prout(_(" The star chart is now up to date.\""))
2149 # Cause extraneous event EVCODE to occur
2150 game.optime -= xtime
2151 if evcode == FSNOVA: # Supernova
2154 schedule(FSNOVA, expran(0.5*game.intime))
2155 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2157 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2158 if game.state.nscrem == 0 or \
2159 ictbeam or istract or \
2160 game.condition=="docked" or game.isatb==1 or game.iscate:
2162 if game.ientesc or \
2163 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2164 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2165 (damaged(DSHIELD) and \
2166 (game.energy < 2500 or damaged(DPHASER)) and \
2167 (game.torps < 5 or damaged(DPHOTON))):
2169 istract = ictbeam = True
2170 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2173 elif evcode == FTBEAM: # Tractor beam
2174 if not game.state.kcmdr:
2177 i = randrange(len(game.state.kcmdr))
2178 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2179 if istract or game.condition == "docked" or yank == 0:
2180 # Drats! Have to reschedule
2182 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2186 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2187 game.snapsht = copy.deepcopy(game.state)
2188 game.state.snap = True
2189 schedule(FSNAP, expran(0.5 * game.intime))
2190 elif evcode == FBATTAK: # Commander attacks starbase
2191 if not game.state.kcmdr or not game.state.baseq:
2197 for ibq in game.state.baseq:
2198 for cmdr in game.state.kcmdr:
2199 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2202 # no match found -- try later
2203 schedule(FBATTAK, expran(0.3*game.intime))
2208 # commander + starbase combination found -- launch attack
2210 schedule(FCDBAS, randreal(1.0, 4.0))
2211 if game.isatb: # extra time if SC already attacking
2212 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2213 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2214 game.iseenit = False
2215 if not communicating():
2216 continue # No warning :-(
2220 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2221 prout(_(" reports that it is under attack and that it can"))
2222 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2225 elif evcode == FSCDBAS: # Supercommander destroys base
2228 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2229 continue # WAS RETURN!
2231 game.battle = game.state.kscmdr
2233 elif evcode == FCDBAS: # Commander succeeds in destroying base
2234 if evcode == FCDBAS:
2236 if not game.state.baseq() \
2237 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2238 game.battle.invalidate()
2240 # find the lucky pair
2241 for cmdr in game.state.kcmdr:
2242 if cmdr == game.battle:
2245 # No action to take after all
2248 elif evcode == FSCMOVE: # Supercommander moves
2249 schedule(FSCMOVE, 0.2777)
2250 if not game.ientesc and not istract and game.isatb != 1 and \
2251 (not game.iscate or not game.justin):
2253 elif evcode == FDSPROB: # Move deep space probe
2254 schedule(FDSPROB, 0.01)
2255 if not game.probe.next():
2256 if not game.probe.quadrant().valid_quadrant() or \
2257 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2258 # Left galaxy or ran into supernova
2262 proutn(_("Lt. Uhura- \"The deep space probe "))
2263 if not game.probe.quadrant().valid_quadrant():
2264 prout(_("has left the galaxy.\""))
2266 prout(_("is no longer transmitting.\""))
2272 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2273 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2275 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2276 chp.klingons = pdest.klingons
2277 chp.starbase = pdest.starbase
2278 chp.stars = pdest.stars
2279 pdest.charted = True
2280 game.probe.moves -= 1 # One less to travel
2281 if game.probe.arrived() and game.isarmed and pdest.stars:
2282 supernova(game.probe) # fire in the hole!
2284 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2286 elif evcode == FDISTR: # inhabited system issues distress call
2288 # try a whole bunch of times to find something suitable
2289 for i in range(100):
2290 # need a quadrant which is not the current one,
2291 # which has some stars which are inhabited and
2292 # not already under attack, which is not
2293 # supernova'ed, and which has some Klingons in it
2294 w = randplace(GALSIZE)
2295 q = game.state.galaxy[w.i][w.j]
2296 if not (game.quadrant == w or q.planet == None or \
2297 not q.planet.inhabited or \
2298 q.supernova or q.status!="secure" or q.klingons<=0):
2301 # can't seem to find one; ignore this call
2303 prout("=== Couldn't find location for distress event.")
2305 # got one!! Schedule its enslavement
2306 ev = schedule(FENSLV, expran(game.intime))
2308 q.status = "distressed"
2309 # tell the captain about it if we can
2311 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2313 prout(_("by a Klingon invasion fleet."))
2316 elif evcode == FENSLV: # starsystem is enslaved
2317 ev = unschedule(FENSLV)
2318 # see if current distress call still active
2319 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2323 q.status = "enslaved"
2325 # play stork and schedule the first baby
2326 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2327 ev2.quadrant = ev.quadrant
2329 # report the disaster if we can
2331 prout(_("Uhura- We've lost contact with starsystem %s") % \
2333 prout(_("in Quadrant %s.\n") % ev.quadrant)
2334 elif evcode == FREPRO: # Klingon reproduces
2335 # If we ever switch to a real event queue, we'll need to
2336 # explicitly retrieve and restore the x and y.
2337 ev = schedule(FREPRO, expran(1.0 * game.intime))
2338 # see if current distress call still active
2339 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2343 if game.state.remkl >=MAXKLGAME:
2344 continue # full right now
2345 # reproduce one Klingon
2348 if game.klhere >= MAXKLQUAD:
2350 # this quadrant not ok, pick an adjacent one
2351 for m.i in range(w.i - 1, w.i + 2):
2352 for m.j in range(w.j - 1, w.j + 2):
2353 if not m.valid_quadrant():
2355 q = game.state.galaxy[m.i][m.j]
2356 # check for this quad ok (not full & no snova)
2357 if q.klingons >= MAXKLQUAD or q.supernova:
2361 continue # search for eligible quadrant failed
2365 game.state.remkl += 1
2367 if game.quadrant == w:
2369 game.enemies.append(newkling())
2370 # recompute time left
2373 if game.quadrant == w:
2374 prout(_("Spock- sensors indicate the Klingons have"))
2375 prout(_("launched a warship from %s.") % q.planet)
2377 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2378 if q.planet != None:
2379 proutn(_("near %s ") % q.planet)
2380 prout(_("in Quadrant %s.") % w)
2386 key = scanner.next()
2389 proutn(_("How long? "))
2394 origTime = delay = scanner.real
2397 if delay >= game.state.remtime or len(game.enemies) != 0:
2398 proutn(_("Are you sure? "))
2401 # Alternate resting periods (events) with attacks
2405 game.resting = False
2406 if not game.resting:
2407 prout(_("%d stardates left.") % int(game.state.remtime))
2409 temp = game.optime = delay
2410 if len(game.enemies):
2411 rtime = randreal(1.0, 2.0)
2415 if game.optime < delay:
2416 attack(torps_ok=False)
2424 # Repair Deathray if long rest at starbase
2425 if origTime-delay >= 9.99 and game.condition == "docked":
2426 game.damage[DDRAY] = 0.0
2427 # leave if quadrant supernovas
2428 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2430 game.resting = False
2435 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2436 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2438 # Wow! We've supernova'ed
2439 supernova(game.quadrant)
2441 # handle initial nova
2442 game.quad[nov.i][nov.j] = '.'
2443 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2444 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2445 game.state.starkl += 1
2446 # Set up queue to recursively trigger adjacent stars
2452 for offset.i in range(-1, 1+1):
2453 for offset.j in range(-1, 1+1):
2454 if offset.j==0 and offset.i==0:
2456 neighbor = start + offset
2457 if not neighbor.valid_sector():
2459 iquad = game.quad[neighbor.i][neighbor.j]
2460 # Empty space ends reaction
2461 if iquad in ('.', '?', ' ', 'T', '#'):
2463 elif iquad == '*': # Affect another star
2465 # This star supernovas
2466 supernova(game.quadrant)
2469 hits.append(neighbor)
2470 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2471 game.state.starkl += 1
2472 proutn(crmena(True, '*', "sector", neighbor))
2474 game.quad[neighbor.i][neighbor.j] = '.'
2476 elif iquad in ('P', '@'): # Destroy planet
2477 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2479 game.state.nplankl += 1
2481 game.state.worldkl += 1
2482 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2483 game.iplnet.pclass = "destroyed"
2485 game.plnet.invalidate()
2489 game.quad[neighbor.i][neighbor.j] = '.'
2490 elif iquad == 'B': # Destroy base
2491 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2492 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2493 game.base.invalidate()
2494 game.state.basekl += 1
2496 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2497 game.quad[neighbor.i][neighbor.j] = '.'
2498 elif iquad in ('E', 'F'): # Buffet ship
2499 prout(_("***Starship buffeted by nova."))
2501 if game.shield >= 2000.0:
2502 game.shield -= 2000.0
2504 diff = 2000.0 - game.shield
2508 prout(_("***Shields knocked out."))
2509 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2511 game.energy -= 2000.0
2512 if game.energy <= 0:
2515 # add in course nova contributes to kicking starship
2516 bump += (game.sector-hits[-1]).sgn()
2517 elif iquad == 'K': # kill klingon
2518 deadkl(neighbor, iquad, neighbor)
2519 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2520 for ll in range(len(game.enemies)):
2521 if game.enemies[ll].location == neighbor:
2523 game.enemies[ll].power -= 800.0 # If firepower is lost, die
2524 if game.enemies[ll].power <= 0.0:
2525 deadkl(neighbor, iquad, neighbor)
2527 newc = neighbor + neighbor - hits[-1]
2528 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2529 if not newc.valid_sector():
2530 # can't leave quadrant
2533 iquad1 = game.quad[newc.i][newc.j]
2535 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2537 deadkl(neighbor, iquad, newc)
2540 # can't move into something else
2543 proutn(_(", buffeted to Sector %s") % newc)
2544 game.quad[neighbor.i][neighbor.j] = '.'
2545 game.quad[newc.i][newc.j] = iquad
2546 game.enemies[ll].move(newc)
2547 # Starship affected by nova -- kick it away.
2549 direc = ncourse[3*(bump.i+1)+bump.j+2]
2554 scourse = course(bearing=direc, distance=dist)
2555 game.optime = scourse.time(warp=4)
2557 prout(_("Force of nova displaces starship."))
2558 imove(scourse, noattack=True)
2559 game.optime = scourse.time(warp=4)
2563 "Star goes supernova."
2568 # Scheduled supernova -- select star at random.
2571 for nq.i in range(GALSIZE):
2572 for nq.j in range(GALSIZE):
2573 stars += game.state.galaxy[nq.i][nq.j].stars
2575 return # nothing to supernova exists
2576 num = randrange(stars) + 1
2577 for nq.i in range(GALSIZE):
2578 for nq.j in range(GALSIZE):
2579 num -= game.state.galaxy[nq.i][nq.j].stars
2585 proutn("=== Super nova here?")
2588 if not nq == game.quadrant or game.justin:
2589 # it isn't here, or we just entered (treat as enroute)
2592 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2593 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2596 # we are in the quadrant!
2597 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2598 for ns.i in range(QUADSIZE):
2599 for ns.j in range(QUADSIZE):
2600 if game.quad[ns.i][ns.j]=='*':
2607 prouts(_("***RED ALERT! RED ALERT!"))
2609 prout(_("***Incipient supernova detected at Sector %s") % ns)
2610 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2611 proutn(_("Emergency override attempts t"))
2612 prouts("***************")
2616 # destroy any Klingons in supernovaed quadrant
2617 kldead = game.state.galaxy[nq.i][nq.j].klingons
2618 game.state.galaxy[nq.i][nq.j].klingons = 0
2619 if nq == game.state.kscmdr:
2620 # did in the Supercommander!
2621 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2625 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2626 comkills = len(game.state.kcmdr) - len(survivors)
2627 game.state.kcmdr = survivors
2629 if not game.state.kcmdr:
2631 game.state.remkl -= kldead
2632 # destroy Romulans and planets in supernovaed quadrant
2633 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2634 game.state.galaxy[nq.i][nq.j].romulans = 0
2635 game.state.nromrem -= nrmdead
2637 for loop in range(game.inplan):
2638 if game.state.planets[loop].quadrant == nq:
2639 game.state.planets[loop].pclass = "destroyed"
2641 # Destroy any base in supernovaed quadrant
2642 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2643 # If starship caused supernova, tally up destruction
2645 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2646 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2647 game.state.nplankl += npdead
2648 # mark supernova in galaxy and in star chart
2649 if game.quadrant == nq or communicating():
2650 game.state.galaxy[nq.i][nq.j].supernova = True
2651 # If supernova destroys last Klingons give special message
2652 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2655 prout(_("Lucky you!"))
2656 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2659 # if some Klingons remain, continue or die in supernova
2664 # Code from finish.c ends here.
2667 "Self-destruct maneuver. Finish with a BANG!"
2669 if damaged(DCOMPTR):
2670 prout(_("Computer damaged; cannot execute destruct sequence."))
2672 prouts(_("---WORKING---")); skip(1)
2673 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2674 prouts(" 10"); skip(1)
2675 prouts(" 9"); skip(1)
2676 prouts(" 8"); skip(1)
2677 prouts(" 7"); skip(1)
2678 prouts(" 6"); skip(1)
2680 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2682 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2684 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2687 if game.passwd != scanner.token:
2688 prouts(_("PASSWORD-REJECTED;"))
2690 prouts(_("CONTINUITY-EFFECTED"))
2693 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2694 prouts(" 5"); skip(1)
2695 prouts(" 4"); skip(1)
2696 prouts(" 3"); skip(1)
2697 prouts(" 2"); skip(1)
2698 prouts(" 1"); skip(1)
2700 prouts(_("GOODBYE-CRUEL-WORLD"))
2708 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2712 if len(game.enemies) != 0:
2713 whammo = 25.0 * game.energy
2714 for l in range(len(game.enemies)):
2715 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2716 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2720 "Compute our rate of kils over time."
2721 elapsed = game.state.date - game.indate
2722 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2725 starting = (game.inkling + game.incom + game.inscom)
2726 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2727 return (starting - remaining)/elapsed
2731 badpt = 5.0*game.state.starkl + \
2733 10.0*game.state.nplankl + \
2734 300*game.state.nworldkl + \
2736 100.0*game.state.basekl +\
2738 if game.ship == 'F':
2740 elif game.ship == None:
2745 # end the game, with appropriate notfications
2749 prout(_("It is stardate %.1f.") % game.state.date)
2751 if ifin == FWON: # Game has been won
2752 if game.state.nromrem != 0:
2753 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2756 prout(_("You have smashed the Klingon invasion fleet and saved"))
2757 prout(_("the Federation."))
2762 badpt = 0.0 # Close enough!
2763 # killsPerDate >= RateMax
2764 if game.state.date-game.indate < 5.0 or \
2765 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2767 prout(_("In fact, you have done so well that Starfleet Command"))
2768 if game.skill == SKILL_NOVICE:
2769 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2770 elif game.skill == SKILL_FAIR:
2771 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2772 elif game.skill == SKILL_GOOD:
2773 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2774 elif game.skill == SKILL_EXPERT:
2775 prout(_("promotes you to Commodore Emeritus."))
2777 prout(_("Now that you think you're really good, try playing"))
2778 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2779 elif game.skill == SKILL_EMERITUS:
2781 proutn(_("Computer- "))
2782 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2784 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2786 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2788 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2790 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2792 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2794 prout(_("Now you can retire and write your own Star Trek game!"))
2796 elif game.skill >= SKILL_EXPERT:
2797 if game.thawed and not game.idebug:
2798 prout(_("You cannot get a citation, so..."))
2800 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2804 # Only grant long life if alive (original didn't!)
2806 prout(_("LIVE LONG AND PROSPER."))
2811 elif ifin == FDEPLETE: # Federation Resources Depleted
2812 prout(_("Your time has run out and the Federation has been"))
2813 prout(_("conquered. Your starship is now Klingon property,"))
2814 prout(_("and you are put on trial as a war criminal. On the"))
2815 proutn(_("basis of your record, you are "))
2816 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2817 prout(_("acquitted."))
2819 prout(_("LIVE LONG AND PROSPER."))
2821 prout(_("found guilty and"))
2822 prout(_("sentenced to death by slow torture."))
2826 elif ifin == FLIFESUP:
2827 prout(_("Your life support reserves have run out, and"))
2828 prout(_("you die of thirst, starvation, and asphyxiation."))
2829 prout(_("Your starship is a derelict in space."))
2831 prout(_("Your energy supply is exhausted."))
2833 prout(_("Your starship is a derelict in space."))
2834 elif ifin == FBATTLE:
2835 prout(_("The %s has been destroyed in battle.") % crmshp())
2837 prout(_("Dulce et decorum est pro patria mori."))
2839 prout(_("You have made three attempts to cross the negative energy"))
2840 prout(_("barrier which surrounds the galaxy."))
2842 prout(_("Your navigation is abominable."))
2845 prout(_("Your starship has been destroyed by a nova."))
2846 prout(_("That was a great shot."))
2848 elif ifin == FSNOVAED:
2849 prout(_("The %s has been fried by a supernova.") % crmshp())
2850 prout(_("...Not even cinders remain..."))
2851 elif ifin == FABANDN:
2852 prout(_("You have been captured by the Klingons. If you still"))
2853 prout(_("had a starbase to be returned to, you would have been"))
2854 prout(_("repatriated and given another chance. Since you have"))
2855 prout(_("no starbases, you will be mercilessly tortured to death."))
2856 elif ifin == FDILITHIUM:
2857 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2858 elif ifin == FMATERIALIZE:
2859 prout(_("Starbase was unable to re-materialize your starship."))
2860 prout(_("Sic transit gloria mundi"))
2861 elif ifin == FPHASER:
2862 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2864 prout(_("You and your landing party have been"))
2865 prout(_("converted to energy, disipating through space."))
2866 elif ifin == FMINING:
2867 prout(_("You are left with your landing party on"))
2868 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2870 prout(_("They are very fond of \"Captain Kirk\" soup."))
2872 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2873 elif ifin == FDPLANET:
2874 prout(_("You and your mining party perish."))
2876 prout(_("That was a great shot."))
2879 prout(_("The Galileo is instantly annihilated by the supernova."))
2880 prout(_("You and your mining party are atomized."))
2882 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2883 prout(_("joins the Romulans, wreaking terror on the Federation."))
2884 elif ifin == FPNOVA:
2885 prout(_("You and your mining party are atomized."))
2887 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2888 prout(_("joins the Romulans, wreaking terror on the Federation."))
2889 elif ifin == FSTRACTOR:
2890 prout(_("The shuttle craft Galileo is also caught,"))
2891 prout(_("and breaks up under the strain."))
2893 prout(_("Your debris is scattered for millions of miles."))
2894 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2896 prout(_("The mutants attack and kill Spock."))
2897 prout(_("Your ship is captured by Klingons, and"))
2898 prout(_("your crew is put on display in a Klingon zoo."))
2899 elif ifin == FTRIBBLE:
2900 prout(_("Tribbles consume all remaining water,"))
2901 prout(_("food, and oxygen on your ship."))
2903 prout(_("You die of thirst, starvation, and asphyxiation."))
2904 prout(_("Your starship is a derelict in space."))
2906 prout(_("Your ship is drawn to the center of the black hole."))
2907 prout(_("You are crushed into extremely dense matter."))
2909 prout(_("Your last crew member has died."))
2910 if game.ship == 'F':
2912 elif game.ship == 'E':
2915 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2916 goodies = game.state.remres/game.inresor
2917 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2918 if goodies/baddies >= randreal(1.0, 1.5):
2919 prout(_("As a result of your actions, a treaty with the Klingon"))
2920 prout(_("Empire has been signed. The terms of the treaty are"))
2921 if goodies/baddies >= randreal(3.0):
2922 prout(_("favorable to the Federation."))
2924 prout(_("Congratulations!"))
2926 prout(_("highly unfavorable to the Federation."))
2928 prout(_("The Federation will be destroyed."))
2930 prout(_("Since you took the last Klingon with you, you are a"))
2931 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2932 prout(_("statue in your memory. Rest in peace, and try not"))
2933 prout(_("to think about pigeons."))
2938 "Compute player's score."
2939 timused = game.state.date - game.indate
2940 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2942 game.perdate = killrate()
2943 ithperd = 500*game.perdate + 0.5
2946 iwon = 100*game.skill
2947 if game.ship == 'E':
2949 elif game.ship == 'F':
2953 game.score = 10*(game.inkling - game.state.remkl) \
2954 + 50*(game.incom - len(game.state.kcmdr)) \
2956 + 20*(game.inrom - game.state.nromrem) \
2957 + 200*(game.inscom - game.state.nscrem) \
2958 - game.state.nromrem \
2963 prout(_("Your score --"))
2964 if game.inrom - game.state.nromrem:
2965 prout(_("%6d Romulans destroyed %5d") %
2966 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
2967 if game.state.nromrem and game.gamewon:
2968 prout(_("%6d Romulans captured %5d") %
2969 (game.state.nromrem, game.state.nromrem))
2970 if game.inkling - game.state.remkl:
2971 prout(_("%6d ordinary Klingons destroyed %5d") %
2972 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
2973 if game.incom - len(game.state.kcmdr):
2974 prout(_("%6d Klingon commanders destroyed %5d") %
2975 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
2976 if game.inscom - game.state.nscrem:
2977 prout(_("%6d Super-Commander destroyed %5d") %
2978 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
2980 prout(_("%6.2f Klingons per stardate %5d") %
2981 (game.perdate, ithperd))
2982 if game.state.starkl:
2983 prout(_("%6d stars destroyed by your action %5d") %
2984 (game.state.starkl, -5*game.state.starkl))
2985 if game.state.nplankl:
2986 prout(_("%6d planets destroyed by your action %5d") %
2987 (game.state.nplankl, -10*game.state.nplankl))
2988 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
2989 prout(_("%6d inhabited planets destroyed by your action %5d") %
2990 (game.state.nworldkl, -300*game.state.nworldkl))
2991 if game.state.basekl:
2992 prout(_("%6d bases destroyed by your action %5d") %
2993 (game.state.basekl, -100*game.state.basekl))
2995 prout(_("%6d calls for help from starbase %5d") %
2996 (game.nhelp, -45*game.nhelp))
2998 prout(_("%6d casualties incurred %5d") %
2999 (game.casual, -game.casual))
3001 prout(_("%6d crew abandoned in space %5d") %
3002 (game.abandoned, -3*game.abandoned))
3004 prout(_("%6d ship(s) lost or destroyed %5d") %
3005 (klship, -100*klship))
3007 prout(_("Penalty for getting yourself killed -200"))
3009 proutn(_("Bonus for winning "))
3010 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3011 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3012 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3013 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3014 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3015 prout(" %5d" % iwon)
3017 prout(_("TOTAL SCORE %5d") % game.score)
3020 "Emit winner's commemmorative plaque."
3023 proutn(_("File or device name for your plaque: "))
3026 fp = open(winner, "w")
3029 prout(_("Invalid name."))
3031 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3033 # The 38 below must be 64 for 132-column paper
3034 nskip = 38 - len(winner)/2
3035 fp.write("\n\n\n\n")
3036 # --------DRAW ENTERPRISE PICTURE.
3037 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3038 fp.write(" EEE E : : : E\n" )
3039 fp.write(" EE EEE E : : NCC-1701 : E\n")
3040 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3041 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3042 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3043 fp.write(" EEEEEEE EEEEE E E E E\n")
3044 fp.write(" EEE E E E E\n")
3045 fp.write(" E E E E\n")
3046 fp.write(" EEEEEEEEEEEEE E E\n")
3047 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3048 fp.write(" :E : EEEE E\n")
3049 fp.write(" .-E -:----- E\n")
3050 fp.write(" :E : E\n")
3051 fp.write(" EE : EEEEEEEE\n")
3052 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3054 fp.write(_(" U. S. S. ENTERPRISE\n"))
3055 fp.write("\n\n\n\n")
3056 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3058 fp.write(_(" Starfleet Command bestows to you\n"))
3060 fp.write("%*s%s\n\n" % (nskip, "", winner))
3061 fp.write(_(" the rank of\n\n"))
3062 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3064 if game.skill == SKILL_EXPERT:
3065 fp.write(_(" Expert level\n\n"))
3066 elif game.skill == SKILL_EMERITUS:
3067 fp.write(_("Emeritus level\n\n"))
3069 fp.write(_(" Cheat level\n\n"))
3070 timestring = time.ctime()
3071 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3072 (timestring+4, timestring+20, timestring+11))
3073 fp.write(_(" Your score: %d\n\n") % game.score)
3074 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3077 # Code from io.c begins here
3079 rows = linecount = 0 # for paging
3082 fullscreen_window = None
3083 srscan_window = None
3084 report_window = None
3085 status_window = None
3086 lrscan_window = None
3087 message_window = None
3088 prompt_window = None
3093 "for some recent versions of python2, the following enables UTF8"
3094 "for the older ones we probably need to set C locale, and the python3"
3095 "has no problems at all"
3096 if sys.version_info[0] < 3:
3098 locale.setlocale(locale.LC_ALL, "")
3099 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3100 gettext.textdomain("sst")
3101 if not (game.options & OPTION_CURSES):
3102 ln_env = os.getenv("LINES")
3108 stdscr = curses.initscr()
3112 if game.options & OPTION_COLOR:
3113 curses.start_color()
3114 curses.use_default_colors()
3115 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3116 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3117 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3118 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3119 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3120 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3121 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3122 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3123 global fullscreen_window, srscan_window, report_window, status_window
3124 global lrscan_window, message_window, prompt_window
3125 (rows, columns) = stdscr.getmaxyx()
3126 fullscreen_window = stdscr
3127 srscan_window = curses.newwin(12, 25, 0, 0)
3128 report_window = curses.newwin(11, 0, 1, 25)
3129 status_window = curses.newwin(10, 0, 1, 39)
3130 lrscan_window = curses.newwin(5, 0, 0, 64)
3131 message_window = curses.newwin(0, 0, 12, 0)
3132 prompt_window = curses.newwin(1, 0, rows-2, 0)
3133 message_window.scrollok(True)
3134 setwnd(fullscreen_window)
3138 if game.options & OPTION_CURSES:
3139 stdscr.keypad(False)
3145 "Wait for user action -- OK to do nothing if on a TTY"
3146 if game.options & OPTION_CURSES:
3151 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3155 if game.skill > SKILL_FAIR:
3156 prompt = _("[CONTINUE?]")
3158 prompt = _("[PRESS ENTER TO CONTINUE]")
3160 if game.options & OPTION_CURSES:
3162 setwnd(prompt_window)
3163 prompt_window.clear()
3164 prompt_window.addstr(prompt)
3165 prompt_window.getstr()
3166 prompt_window.clear()
3167 prompt_window.refresh()
3168 setwnd(message_window)
3171 sys.stdout.write('\n')
3174 sys.stdout.write('\n' * rows)
3178 "Skip i lines. Pause game if this would cause a scrolling event."
3179 for dummy in range(i):
3180 if game.options & OPTION_CURSES:
3181 (y, x) = curwnd.getyx()
3184 except curses.error:
3189 if rows and linecount >= rows:
3192 sys.stdout.write('\n')
3195 "Utter a line with no following line feed."
3196 if game.options & OPTION_CURSES:
3197 (y, x) = curwnd.getyx()
3198 (my, mx) = curwnd.getmaxyx()
3199 if curwnd == message_window and y >= my - 2:
3205 sys.stdout.write(line)
3215 if not replayfp or replayfp.closed: # Don't slow down replays
3218 if game.options & OPTION_CURSES:
3222 if not replayfp or replayfp.closed:
3226 "Get a line of input."
3227 if game.options & OPTION_CURSES:
3228 line = curwnd.getstr() + "\n"
3231 if replayfp and not replayfp.closed:
3233 line = replayfp.readline()
3236 prout("*** Replay finished")
3239 elif line[0] != "#":
3242 line = raw_input() + "\n"
3248 "Change windows -- OK for this to be a no-op in tty mode."
3250 if game.options & OPTION_CURSES:
3252 curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window)
3255 "Clear to end of line -- can be a no-op in tty mode"
3256 if game.options & OPTION_CURSES:
3261 "Clear screen -- can be a no-op in tty mode."
3263 if game.options & OPTION_CURSES:
3269 def textcolor(color=DEFAULT):
3270 if game.options & OPTION_COLOR:
3271 if color == DEFAULT:
3273 elif color == BLACK:
3274 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3276 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3277 elif color == GREEN:
3278 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3280 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3282 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3283 elif color == MAGENTA:
3284 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3285 elif color == BROWN:
3286 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3287 elif color == LIGHTGRAY:
3288 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3289 elif color == DARKGRAY:
3290 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3291 elif color == LIGHTBLUE:
3292 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3293 elif color == LIGHTGREEN:
3294 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3295 elif color == LIGHTCYAN:
3296 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3297 elif color == LIGHTRED:
3298 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3299 elif color == LIGHTMAGENTA:
3300 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3301 elif color == YELLOW:
3302 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3303 elif color == WHITE:
3304 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3307 if game.options & OPTION_COLOR:
3308 curwnd.attron(curses.A_REVERSE)
3311 # Things past this point have policy implications.
3315 "Hook to be called after moving to redraw maps."
3316 if game.options & OPTION_CURSES:
3319 setwnd(srscan_window)
3323 setwnd(status_window)
3324 status_window.clear()
3325 status_window.move(0, 0)
3326 setwnd(report_window)
3327 report_window.clear()
3328 report_window.move(0, 0)
3330 setwnd(lrscan_window)
3331 lrscan_window.clear()
3332 lrscan_window.move(0, 0)
3333 lrscan(silent=False)
3335 def put_srscan_sym(w, sym):
3336 "Emit symbol for short-range scan."
3337 srscan_window.move(w.i+1, w.j*2+2)
3338 srscan_window.addch(sym)
3339 srscan_window.refresh()
3342 "Enemy fall down, go boom."
3343 if game.options & OPTION_CURSES:
3345 setwnd(srscan_window)
3346 srscan_window.attron(curses.A_REVERSE)
3347 put_srscan_sym(w, game.quad[w.i][w.j])
3351 srscan_window.attroff(curses.A_REVERSE)
3352 put_srscan_sym(w, game.quad[w.i][w.j])
3353 curses.delay_output(500)
3354 setwnd(message_window)
3357 "Sound and visual effects for teleportation."
3358 if game.options & OPTION_CURSES:
3360 setwnd(message_window)
3362 prouts(" . . . . . ")
3363 if game.options & OPTION_CURSES:
3364 #curses.delay_output(1000)
3368 def tracktorpedo(w, step, i, n, iquad):
3369 "Torpedo-track animation."
3370 if not game.options & OPTION_CURSES:
3374 proutn(_("Track for torpedo number %d- ") % (i+1))
3377 proutn(_("Torpedo track- "))
3378 elif step==4 or step==9:
3382 if not damaged(DSRSENS) or game.condition=="docked":
3383 if i != 0 and step == 1:
3386 if (iquad=='.') or (iquad==' '):
3387 put_srscan_sym(w, '+')
3391 put_srscan_sym(w, iquad)
3393 curwnd.attron(curses.A_REVERSE)
3394 put_srscan_sym(w, iquad)
3398 curwnd.attroff(curses.A_REVERSE)
3399 put_srscan_sym(w, iquad)
3404 "Display the current galaxy chart."
3405 if game.options & OPTION_CURSES:
3406 setwnd(message_window)
3407 message_window.clear()
3409 if game.options & OPTION_TTY:
3414 def prstat(txt, data):
3416 if game.options & OPTION_CURSES:
3418 setwnd(status_window)
3420 proutn(" " * (NSYM - len(txt)))
3423 if game.options & OPTION_CURSES:
3424 setwnd(report_window)
3426 # Code from moving.c begins here
3428 def imove(icourse=None, noattack=False):
3429 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3432 def newquadrant(noattack):
3433 # Leaving quadrant -- allow final enemy attack
3434 # Don't do it if being pushed by Nova
3435 if len(game.enemies) != 0 and not noattack:
3437 for enemy in game.enemies:
3438 finald = (w - enemy.location).distance()
3439 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3440 # Stas Sergeev added the condition
3441 # that attacks only happen if Klingons
3442 # are present and your skill is good.
3443 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3444 attack(torps_ok=False)
3447 # check for edge of galaxy
3451 if icourse.final.i < 0:
3452 icourse.final.i = -icourse.final.i
3454 if icourse.final.j < 0:
3455 icourse.final.j = -icourse.final.j
3457 if icourse.final.i >= GALSIZE*QUADSIZE:
3458 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3460 if icourse.final.j >= GALSIZE*QUADSIZE:
3461 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3469 if game.nkinks == 3:
3470 # Three strikes -- you're out!
3474 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3475 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3476 prout(_("YOU WILL BE DESTROYED."))
3477 # Compute final position in new quadrant
3478 if trbeam: # Don't bother if we are to be beamed
3480 game.quadrant = icourse.final.quadrant()
3481 game.sector = icourse.final.sector()
3483 prout(_("Entering Quadrant %s.") % game.quadrant)
3484 game.quad[game.sector.i][game.sector.j] = game.ship
3486 if game.skill>SKILL_NOVICE:
3487 attack(torps_ok=False)
3489 def check_collision(h):
3490 iquad = game.quad[h.i][h.j]
3492 # object encountered in flight path
3493 stopegy = 50.0*icourse.distance/game.optime
3494 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3495 for enemy in game.enemies:
3496 if enemy.location == game.sector:
3498 collision(rammed=False, enemy=enemy)
3502 prouts(_("***RED ALERT! RED ALERT!"))
3504 proutn("***" + crmshp())
3505 proutn(_(" pulled into black hole at Sector %s") % h)
3506 # Getting pulled into a black hole was certain
3507 # death in Almy's original. Stas Sergeev added a
3508 # possibility that you'll get timewarped instead.
3510 for m in range(NDEVICES):
3511 if game.damage[m]>0:
3513 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3514 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3524 prout(_(" encounters Tholian web at %s;") % h)
3526 prout(_(" blocked by object at %s;") % h)
3527 proutn(_("Emergency stop required "))
3528 prout(_("%2d units of energy.") % int(stopegy))
3529 game.energy -= stopegy
3530 if game.energy <= 0:
3537 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3538 game.inorbit = False
3539 # If tractor beam is to occur, don't move full distance
3540 if game.state.date+game.optime >= scheduled(FTBEAM):
3542 game.condition = "red"
3543 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3544 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3546 game.quad[game.sector.i][game.sector.j] = '.'
3547 for m in range(icourse.moves):
3549 w = icourse.sector()
3550 if icourse.origin.quadrant() != icourse.location.quadrant():
3551 newquadrant(noattack)
3553 elif check_collision(w):
3554 print "Collision detected"
3558 # We're in destination quadrant -- compute new average enemy distances
3559 game.quad[game.sector.i][game.sector.j] = game.ship
3561 for enemy in game.enemies:
3562 finald = (w-enemy.location).distance()
3563 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3564 enemy.kdist = finald
3566 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3567 attack(torps_ok=False)
3568 for enemy in game.enemies:
3569 enemy.kavgd = enemy.kdist
3572 setwnd(message_window)
3576 "Dock our ship at a starbase."
3578 if game.condition == "docked" and verbose:
3579 prout(_("Already docked."))
3582 prout(_("You must first leave standard orbit."))
3584 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3585 prout(crmshp() + _(" not adjacent to base."))
3587 game.condition = "docked"
3591 if game.energy < game.inenrg:
3592 game.energy = game.inenrg
3593 game.shield = game.inshld
3594 game.torps = game.intorps
3595 game.lsupres = game.inlsr
3596 game.state.crew = FULLCREW
3597 if not damaged(DRADIO) and \
3598 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3599 # get attack report from base
3600 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3604 def cartesian(loc1=None, loc2=None):
3606 return game.quadrant * QUADSIZE + game.sector
3608 return game.quadrant * QUADSIZE + loc1
3610 return loc1 * QUADSIZE + loc2
3612 def getcourse(isprobe):
3613 "Get a course and distance from the user."
3615 dquad = copy.copy(game.quadrant)
3616 navmode = "unspecified"
3620 if game.landed and not isprobe:
3621 prout(_("Dummy! You can't leave standard orbit until you"))
3622 proutn(_("are back aboard the ship."))
3625 while navmode == "unspecified":
3626 if damaged(DNAVSYS):
3628 prout(_("Computer damaged; manual navigation only"))
3630 prout(_("Computer damaged; manual movement only"))
3635 key = scanner.next()
3637 proutn(_("Manual or automatic- "))
3640 elif key == "IHALPHA":
3641 if scanner.sees("manual"):
3643 key = scanner.next()
3645 elif scanner.sees("automatic"):
3646 navmode = "automatic"
3647 key = scanner.next()
3655 prout(_("(Manual navigation assumed.)"))
3657 prout(_("(Manual movement assumed.)"))
3661 if navmode == "automatic":
3662 while key == "IHEOL":
3664 proutn(_("Target quadrant or quadrant§or- "))
3666 proutn(_("Destination sector or quadrant§or- "))
3669 key = scanner.next()
3673 xi = int(round(scanner.real))-1
3674 key = scanner.next()
3678 xj = int(round(scanner.real))-1
3679 key = scanner.next()
3681 # both quadrant and sector specified
3682 xk = int(round(scanner.real))-1
3683 key = scanner.next()
3687 xl = int(round(scanner.real))-1
3693 # only one pair of numbers was specified
3695 # only quadrant specified -- go to center of dest quad
3698 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3700 # only sector specified
3704 if not dquad.valid_quadrant() or not dsect.valid_sector():
3711 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3713 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3714 # the actual deltas get computed here
3715 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3716 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3718 while key == "IHEOL":
3719 proutn(_("X and Y displacements- "))
3722 key = scanner.next()
3727 delta.j = scanner.real
3728 key = scanner.next()
3732 delta.i = scanner.real
3733 # Check for zero movement
3734 if delta.i == 0 and delta.j == 0:
3737 if itemp == "verbose" and not isprobe:
3739 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3741 return course(bearing=delta.bearing(), distance=delta.distance())
3744 def __init__(self, bearing, distance, origin=None):
3745 self.distance = distance
3746 self.bearing = bearing
3748 self.origin = cartesian(game.quadrant, game.sector)
3750 self.origin = origin
3751 # The bearing() code we inherited from FORTRAN is actually computing
3752 # clockface directions!
3753 if self.bearing < 0.0:
3754 self.bearing += 12.0
3755 self.angle = ((15.0 - self.bearing) * 0.5235988)
3757 self.origin = cartesian(game.quadrant, game.sector)
3759 self.origin = cartesian(game.quadrant, origin)
3760 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
3761 bigger = max(abs(self.increment.i), abs(self.increment.j))
3762 self.increment /= bigger
3763 self.moves = int(round(10*self.distance*bigger))
3765 self.final = (self.location + self.moves*self.increment).roundtogrid()
3767 self.location = self.origin
3770 return self.location.roundtogrid() == self.final
3772 "Next step on course."
3774 self.nextlocation = self.location + self.increment
3775 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3776 self.location = self.nextlocation
3779 return self.location.quadrant()
3781 return self.location.sector()
3782 def power(self, warp):
3783 return self.distance*(warp**3)*(game.shldup+1)
3784 def time(self, warp):
3785 return 10.0*self.distance/warp**2
3788 "Move under impulse power."
3790 if damaged(DIMPULS):
3793 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3795 if game.energy > 30.0:
3797 course = getcourse(isprobe=False)
3800 power = 20.0 + 100.0*course.distance
3803 if power >= game.energy:
3804 # Insufficient power for trip
3806 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3807 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3808 if game.energy > 30:
3809 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3810 int(0.01 * (game.energy-20.0)-0.05))
3811 prout(_(" quadrants.\""))
3813 prout(_("quadrant. They are, therefore, useless.\""))
3816 # Make sure enough time is left for the trip
3817 game.optime = course.dist/0.095
3818 if game.optime >= game.state.remtime:
3819 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3820 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3821 proutn(_("we dare spend the time?\" "))
3824 # Activate impulse engines and pay the cost
3825 imove(course, noattack=False)
3829 power = 20.0 + 100.0*course.dist
3830 game.energy -= power
3831 game.optime = course.dist/0.095
3832 if game.energy <= 0:
3836 def warp(wcourse, involuntary):
3837 "ove under warp drive."
3838 blooey = False; twarp = False
3839 if not involuntary: # Not WARPX entry
3841 if game.damage[DWARPEN] > 10.0:
3844 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3846 if damaged(DWARPEN) and game.warpfac > 4.0:
3849 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3850 prout(_(" is repaired, I can only give you warp 4.\""))
3852 # Read in course and distance
3855 wcourse = getcourse(isprobe=False)
3858 # Make sure starship has enough energy for the trip
3859 # Note: this formula is slightly different from the C version,
3860 # and lets you skate a bit closer to the edge.
3861 if wcourse.power(game.warpfac) >= game.energy:
3862 # Insufficient power for trip
3865 prout(_("Engineering to bridge--"))
3866 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
3867 iwarp = (game.energy/(wcourse.dist+0.05)) ** 0.333333333
3869 prout(_("We can't do it, Captain. We don't have enough energy."))
3871 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3874 prout(_("if you'll lower the shields."))
3878 prout(_("We haven't the energy to go that far with the shields up."))
3880 # Make sure enough time is left for the trip
3881 game.optime = wcourse.time(game.warpfac)
3882 if game.optime >= 0.8*game.state.remtime:
3884 prout(_("First Officer Spock- \"Captain, I compute that such"))
3885 proutn(_(" a trip would require approximately %2.0f") %
3886 (100.0*game.optime/game.state.remtime))
3887 prout(_(" percent of our"))
3888 proutn(_(" remaining time. Are you sure this is wise?\" "))
3894 if game.warpfac > 6.0:
3895 # Decide if engine damage will occur
3896 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3897 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
3898 if prob > randreal():
3900 wcourse.distance = randreal(wcourse.distance)
3901 # Decide if time warp will occur
3902 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3904 if game.idebug and game.warpfac==10 and not twarp:
3906 proutn("=== Force time warp? ")
3910 # If time warp or engine damage, check path
3911 # If it is obstructed, don't do warp or damage
3912 look = wcourse.moves
3916 w = wcourse.sector()
3917 if not w.valid_sector():
3919 if game.quad[w.i][w.j] != '.':
3923 # Activate Warp Engines and pay the cost
3924 imove(wcourse, noattack=False)
3927 game.energy -= wcourse.power(game.warpfac)
3928 if game.energy <= 0:
3930 game.optime = wcourse.time(game.warpfac)
3934 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
3936 prout(_("Engineering to bridge--"))
3937 prout(_(" Scott here. The warp engines are damaged."))
3938 prout(_(" We'll have to reduce speed to warp 4."))
3943 "Change the warp factor."
3949 proutn(_("Warp factor- "))
3953 if game.damage[DWARPEN] > 10.0:
3954 prout(_("Warp engines inoperative."))
3956 if damaged(DWARPEN) and scanner.real > 4.0:
3957 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
3958 prout(_(" but right now we can only go warp 4.\""))
3960 if scanner.real > 10.0:
3961 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
3963 if scanner.real < 1.0:
3964 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
3966 oldfac = game.warpfac
3967 game.warpfac = scanner.real
3968 if game.warpfac <= oldfac or game.warpfac <= 6.0:
3969 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
3972 if game.warpfac < 8.00:
3973 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
3975 if game.warpfac == 10.0:
3976 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
3978 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
3982 "Cope with being tossed out of quadrant by supernova or yanked by beam."
3984 # is captain on planet?
3986 if damaged(DTRANSP):
3989 prout(_("Scotty rushes to the transporter controls."))
3991 prout(_("But with the shields up it's hopeless."))
3993 prouts(_("His desperate attempt to rescue you . . ."))
3998 prout(_("SUCCEEDS!"))
4001 proutn(_("The crystals mined were "))
4009 # Check to see if captain in shuttle craft
4014 # Inform captain of attempt to reach safety
4018 prouts(_("***RED ALERT! RED ALERT!"))
4020 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4021 prouts(_(" a supernova."))
4023 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4024 prout(_("safely out of quadrant."))
4025 if not damaged(DRADIO):
4026 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4027 # Try to use warp engines
4028 if damaged(DWARPEN):
4030 prout(_("Warp engines damaged."))
4033 game.warpfac = randreal(6.0, 8.0)
4034 prout(_("Warp factor set to %d") % int(game.warpfac))
4035 power = 0.75*game.energy
4036 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4037 dist = max(dist, randreal(math.sqrt(2)))
4038 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4039 game.optime = bugout.time(game.warpfac)
4041 game.inorbit = False
4042 warp(bugout, involuntary=True)
4044 # This is bad news, we didn't leave quadrant.
4048 prout(_("Insufficient energy to leave quadrant."))
4051 # Repeat if another snova
4052 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4054 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4055 finish(FWON) # Snova killed remaining enemy.
4058 "Let's do the time warp again."
4059 prout(_("***TIME WARP ENTERED."))
4060 if game.state.snap and withprob(0.5):
4062 prout(_("You are traveling backwards in time %d stardates.") %
4063 int(game.state.date-game.snapsht.date))
4064 game.state = game.snapsht
4065 game.state.snap = False
4066 if len(game.state.kcmdr):
4067 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4068 schedule(FBATTAK, expran(0.3*game.intime))
4069 schedule(FSNOVA, expran(0.5*game.intime))
4070 # next snapshot will be sooner
4071 schedule(FSNAP, expran(0.25*game.state.remtime))
4073 if game.state.nscrem:
4074 schedule(FSCMOVE, 0.2777)
4078 game.battle.invalidate()
4079 # Make sure Galileo is consistant -- Snapshot may have been taken
4080 # when on planet, which would give us two Galileos!
4082 for l in range(game.inplan):
4083 if game.state.planets[l].known == "shuttle_down":
4085 if game.iscraft == "onship" and game.ship=='E':
4086 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4087 game.iscraft = "offship"
4088 # Likewise, if in the original time the Galileo was abandoned, but
4089 # was on ship earlier, it would have vanished -- let's restore it.
4090 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4091 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4092 game.iscraft = "onship"
4093 # There used to be code to do the actual reconstrction here,
4094 # but the starchart is now part of the snapshotted galaxy state.
4095 prout(_("Spock has reconstructed a correct star chart from memory"))
4097 # Go forward in time
4098 game.optime = expran(0.5*game.intime)
4099 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4100 # cheat to make sure no tractor beams occur during time warp
4101 postpone(FTBEAM, game.optime)
4102 game.damage[DRADIO] += game.optime
4104 events() # Stas Sergeev added this -- do pending events
4107 "Launch deep-space probe."
4108 # New code to launch a deep space probe
4109 if game.nprobes == 0:
4112 if game.ship == 'E':
4113 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4115 prout(_("Ye Faerie Queene has no deep space probes."))
4120 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4122 if is_scheduled(FDSPROB):
4125 if damaged(DRADIO) and game.condition != "docked":
4126 prout(_("Spock- \"Records show the previous probe has not yet"))
4127 prout(_(" reached its destination.\""))
4129 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4131 key = scanner.next()
4133 if game.nprobes == 1:
4134 prout(_("1 probe left."))
4136 prout(_("%d probes left") % game.nprobes)
4137 proutn(_("Are you sure you want to fire a probe? "))
4140 game.isarmed = False
4141 if key == "IHALPHA" and scanner.token == "armed":
4143 key = scanner.next()
4144 elif key == "IHEOL":
4145 proutn(_("Arm NOVAMAX warhead? "))
4147 elif key == "IHREAL": # first element of course
4148 scanner.push(scanner.token)
4150 game.probe = getcourse(isprobe=True)
4154 schedule(FDSPROB, 0.01) # Time to move one sector
4155 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4160 "Yell for help from nearest starbase."
4161 # There's more than one way to move in this game!
4163 # Test for conditions which prevent calling for help
4164 if game.condition == "docked":
4165 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4168 prout(_("Subspace radio damaged."))
4170 if not game.state.baseq:
4171 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4174 prout(_("You must be aboard the %s.") % crmshp())
4176 # OK -- call for help from nearest starbase
4179 # There's one in this quadrant
4180 ddist = (game.base - game.sector).distance()
4183 for ibq in game.state.baseq:
4184 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4187 # Since starbase not in quadrant, set up new quadrant
4190 # dematerialize starship
4191 game.quad[game.sector.i][game.sector.j]='.'
4192 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4193 % (game.quadrant, crmshp()))
4194 game.sector.invalidate()
4195 for m in range(1, 5+1):
4196 w = game.base.scatter()
4197 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4198 # found one -- finish up
4201 if not game.sector.is_valid():
4202 prout(_("You have been lost in space..."))
4203 finish(FMATERIALIZE)
4205 # Give starbase three chances to rematerialize starship
4206 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4207 for m in range(1, 3+1):
4208 if m == 1: proutn(_("1st"))
4209 elif m == 2: proutn(_("2nd"))
4210 elif m == 3: proutn(_("3rd"))
4211 proutn(_(" attempt to re-materialize ") + crmshp())
4212 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4215 if randreal() > probf:
4219 curses.delay_output(500)
4221 game.quad[game.sector.i][game.sector.j]='?'
4224 setwnd(message_window)
4225 finish(FMATERIALIZE)
4227 game.quad[game.sector.i][game.sector.j]=game.ship
4229 prout(_("succeeds."))
4233 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4238 if game.condition=="docked":
4240 prout(_("You cannot abandon Ye Faerie Queene."))
4243 # Must take shuttle craft to exit
4244 if game.damage[DSHUTTL]==-1:
4245 prout(_("Ye Faerie Queene has no shuttle craft."))
4247 if game.damage[DSHUTTL]<0:
4248 prout(_("Shuttle craft now serving Big Macs."))
4250 if game.damage[DSHUTTL]>0:
4251 prout(_("Shuttle craft damaged."))
4254 prout(_("You must be aboard the ship."))
4256 if game.iscraft != "onship":
4257 prout(_("Shuttle craft not currently available."))
4259 # Emit abandon ship messages
4261 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4263 prouts(_("***ALL HANDS ABANDON SHIP!"))
4265 prout(_("Captain and crew escape in shuttle craft."))
4266 if not game.state.baseq:
4267 # Oops! no place to go...
4270 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4272 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4273 prout(_("Remainder of ship's complement beam down"))
4274 prout(_("to nearest habitable planet."))
4275 elif q.planet != None and not damaged(DTRANSP):
4276 prout(_("Remainder of ship's complement beam down to %s.") %
4279 prout(_("Entire crew of %d left to die in outer space.") %
4281 game.casual += game.state.crew
4282 game.abandoned += game.state.crew
4283 # If at least one base left, give 'em the Faerie Queene
4285 game.icrystl = False # crystals are lost
4286 game.nprobes = 0 # No probes
4287 prout(_("You are captured by Klingons and released to"))
4288 prout(_("the Federation in a prisoner-of-war exchange."))
4289 nb = randrange(len(game.state.baseq))
4290 # Set up quadrant and position FQ adjacient to base
4291 if not game.quadrant == game.state.baseq[nb]:
4292 game.quadrant = game.state.baseq[nb]
4293 game.sector.i = game.sector.j = 5
4296 # position next to base by trial and error
4297 game.quad[game.sector.i][game.sector.j] = '.'
4298 for l in range(QUADSIZE):
4299 game.sector = game.base.scatter()
4300 if game.sector.valid_sector() and \
4301 game.quad[game.sector.i][game.sector.j] == '.':
4304 break # found a spot
4305 game.sector.i=QUADSIZE/2
4306 game.sector.j=QUADSIZE/2
4308 # Get new commission
4309 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4310 game.state.crew = FULLCREW
4311 prout(_("Starfleet puts you in command of another ship,"))
4312 prout(_("the Faerie Queene, which is antiquated but,"))
4313 prout(_("still useable."))
4315 prout(_("The dilithium crystals have been moved."))
4317 game.iscraft = "offship" # Galileo disappears
4319 game.condition="docked"
4320 for l in range(NDEVICES):
4321 game.damage[l] = 0.0
4322 game.damage[DSHUTTL] = -1
4323 game.energy = game.inenrg = 3000.0
4324 game.shield = game.inshld = 1250.0
4325 game.torps = game.intorps = 6
4326 game.lsupres=game.inlsr=3.0
4331 # Code from planets.c begins here.
4334 "Abort a lengthy operation if an event interrupts it."
4337 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4342 "Report on (uninhabited) planets in the galaxy."
4346 prout(_("Spock- \"Planet report follows, Captain.\""))
4348 for i in range(game.inplan):
4349 if game.state.planets[i].pclass == "destroyed":
4351 if (game.state.planets[i].known != "unknown" \
4352 and not game.state.planets[i].inhabited) \
4355 if game.idebug and game.state.planets[i].known=="unknown":
4356 proutn("(Unknown) ")
4357 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4358 proutn(_(" class "))
4359 proutn(game.state.planets[i].pclass)
4361 if game.state.planets[i].crystals != "present":
4363 prout(_("dilithium crystals present."))
4364 if game.state.planets[i].known=="shuttle_down":
4365 prout(_(" Shuttle Craft Galileo on surface."))
4367 prout(_("No information available."))
4370 "Enter standard orbit."
4374 prout(_("Already in standard orbit."))
4376 if damaged(DWARPEN) and damaged(DIMPULS):
4377 prout(_("Both warp and impulse engines damaged."))
4379 if not game.plnet.is_valid():
4380 prout("There is no planet in this sector.")
4382 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4383 prout(crmshp() + _(" not adjacent to planet."))
4386 game.optime = randreal(0.02, 0.05)
4387 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4391 game.height = randreal(1400, 8600)
4392 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4397 "Examine planets in this quadrant."
4398 if damaged(DSRSENS):
4399 if game.options & OPTION_TTY:
4400 prout(_("Short range sensors damaged."))
4402 if game.iplnet == None:
4403 if game.options & OPTION_TTY:
4404 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4406 if game.iplnet.known == "unknown":
4407 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4409 prout(_(" Planet at Sector %s is of class %s.") %
4410 (game.plnet, game.iplnet.pclass))
4411 if game.iplnet.known=="shuttle_down":
4412 prout(_(" Sensors show Galileo still on surface."))
4413 proutn(_(" Readings indicate"))
4414 if game.iplnet.crystals != "present":
4416 prout(_(" dilithium crystals present.\""))
4417 if game.iplnet.known == "unknown":
4418 game.iplnet.known = "known"
4419 elif game.iplnet.inhabited:
4420 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4421 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4424 "Use the transporter."
4428 if damaged(DTRANSP):
4429 prout(_("Transporter damaged."))
4430 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4432 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4436 if not game.inorbit:
4437 prout(crmshp() + _(" not in standard orbit."))
4440 prout(_("Impossible to transport through shields."))
4442 if game.iplnet.known=="unknown":
4443 prout(_("Spock- \"Captain, we have no information on this planet"))
4444 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4445 prout(_(" you may not go down.\""))
4447 if not game.landed and game.iplnet.crystals=="absent":
4448 prout(_("Spock- \"Captain, I fail to see the logic in"))
4449 prout(_(" exploring a planet with no dilithium crystals."))
4450 proutn(_(" Are you sure this is wise?\" "))
4454 if not (game.options & OPTION_PLAIN):
4455 nrgneed = 50 * game.skill + game.height / 100.0
4456 if nrgneed > game.energy:
4457 prout(_("Engineering to bridge--"))
4458 prout(_(" Captain, we don't have enough energy for transportation."))
4460 if not game.landed and nrgneed * 2 > game.energy:
4461 prout(_("Engineering to bridge--"))
4462 prout(_(" Captain, we have enough energy only to transport you down to"))
4463 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4464 if game.iplnet.known == "shuttle_down":
4465 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4466 proutn(_(" Are you sure this is wise?\" "))
4471 # Coming from planet
4472 if game.iplnet.known=="shuttle_down":
4473 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4477 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4478 prout(_("Landing party assembled, ready to beam up."))
4480 prout(_("Kirk whips out communicator..."))
4481 prouts(_("BEEP BEEP BEEP"))
4483 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4486 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4488 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4490 prout(_("Kirk- \"Energize.\""))
4493 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4496 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4498 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4501 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4502 game.landed = not game.landed
4503 game.energy -= nrgneed
4505 prout(_("Transport complete."))
4506 if game.landed and game.iplnet.known=="shuttle_down":
4507 prout(_("The shuttle craft Galileo is here!"))
4508 if not game.landed and game.imine:
4515 "Strip-mine a world for dilithium."
4519 prout(_("Mining party not on planet."))
4521 if game.iplnet.crystals == "mined":
4522 prout(_("This planet has already been strip-mined for dilithium."))
4524 elif game.iplnet.crystals == "absent":
4525 prout(_("No dilithium crystals on this planet."))
4528 prout(_("You've already mined enough crystals for this trip."))
4530 if game.icrystl and game.cryprob == 0.05:
4531 prout(_("With all those fresh crystals aboard the ") + crmshp())
4532 prout(_("there's no reason to mine more at this time."))
4534 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4537 prout(_("Mining operation complete."))
4538 game.iplnet.crystals = "mined"
4539 game.imine = game.ididit = True
4542 "Use dilithium crystals."
4546 if not game.icrystl:
4547 prout(_("No dilithium crystals available."))
4549 if game.energy >= 1000:
4550 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4551 prout(_(" except when Condition Yellow exists."))
4553 prout(_("Spock- \"Captain, I must warn you that loading"))
4554 prout(_(" raw dilithium crystals into the ship's power"))
4555 prout(_(" system may risk a severe explosion."))
4556 proutn(_(" Are you sure this is wise?\" "))
4561 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4562 prout(_(" Mr. Spock and I will try it.\""))
4564 prout(_("Spock- \"Crystals in place, Sir."))
4565 prout(_(" Ready to activate circuit.\""))
4567 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4569 if withprob(game.cryprob):
4570 prouts(_(" \"Activating now! - - No good! It's***"))
4572 prouts(_("***RED ALERT! RED A*L********************************"))
4575 prouts(_("****************** KA-BOOM!!!! *******************"))
4579 game.energy += randreal(5000.0, 5500.0)
4580 prouts(_(" \"Activating now! - - "))
4581 prout(_("The instruments"))
4582 prout(_(" are going crazy, but I think it's"))
4583 prout(_(" going to work!! Congratulations, Sir!\""))
4588 "Use shuttlecraft for planetary jaunt."
4591 if damaged(DSHUTTL):
4592 if game.damage[DSHUTTL] == -1.0:
4593 if game.inorbit and game.iplnet.known == "shuttle_down":
4594 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4596 prout(_("Ye Faerie Queene had no shuttle craft."))
4597 elif game.damage[DSHUTTL] > 0:
4598 prout(_("The Galileo is damaged."))
4599 else: # game.damage[DSHUTTL] < 0
4600 prout(_("Shuttle craft is now serving Big Macs."))
4602 if not game.inorbit:
4603 prout(crmshp() + _(" not in standard orbit."))
4605 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4606 prout(_("Shuttle craft not currently available."))
4608 if not game.landed and game.iplnet.known=="shuttle_down":
4609 prout(_("You will have to beam down to retrieve the shuttle craft."))
4611 if game.shldup or game.condition == "docked":
4612 prout(_("Shuttle craft cannot pass through shields."))
4614 if game.iplnet.known=="unknown":
4615 prout(_("Spock- \"Captain, we have no information on this planet"))
4616 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4617 prout(_(" you may not fly down.\""))
4619 game.optime = 3.0e-5*game.height
4620 if game.optime >= 0.8*game.state.remtime:
4621 prout(_("First Officer Spock- \"Captain, I compute that such"))
4622 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4623 int(100*game.optime/game.state.remtime))
4624 prout(_("remaining time."))
4625 proutn(_("Are you sure this is wise?\" "))
4631 if game.iscraft == "onship":
4633 if not damaged(DTRANSP):
4634 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4638 proutn(_("Shuttle crew"))
4640 proutn(_("Rescue party"))
4641 prout(_(" boards Galileo and swoops toward planet surface."))
4642 game.iscraft = "offship"
4646 game.iplnet.known="shuttle_down"
4647 prout(_("Trip complete."))
4650 # Ready to go back to ship
4651 prout(_("You and your mining party board the"))
4652 prout(_("shuttle craft for the trip back to the Enterprise."))
4654 prouts(_("The short hop begins . . ."))
4656 game.iplnet.known="known"
4662 game.iscraft = "onship"
4668 prout(_("Trip complete."))
4671 # Kirk on ship and so is Galileo
4672 prout(_("Mining party assembles in the hangar deck,"))
4673 prout(_("ready to board the shuttle craft \"Galileo\"."))
4675 prouts(_("The hangar doors open; the trip begins."))
4678 game.iscraft = "offship"
4681 game.iplnet.known = "shuttle_down"
4684 prout(_("Trip complete."))
4688 "Use the big zapper."
4692 if game.ship != 'E':
4693 prout(_("Ye Faerie Queene has no death ray."))
4695 if len(game.enemies)==0:
4696 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4699 prout(_("Death Ray is damaged."))
4701 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4702 prout(_(" is highly unpredictible. Considering the alternatives,"))
4703 proutn(_(" are you sure this is wise?\" "))
4706 prout(_("Spock- \"Acknowledged.\""))
4709 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4711 prout(_("Crew scrambles in emergency preparation."))
4712 prout(_("Spock and Scotty ready the death ray and"))
4713 prout(_("prepare to channel all ship's power to the device."))
4715 prout(_("Spock- \"Preparations complete, sir.\""))
4716 prout(_("Kirk- \"Engage!\""))
4718 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4721 if game.options & OPTION_PLAIN:
4725 prouts(_("Sulu- \"Captain! It's working!\""))
4727 while len(game.enemies) > 0:
4728 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4729 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4730 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4732 if (game.options & OPTION_PLAIN) == 0:
4733 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4735 prout(_(" is still operational.\""))
4737 prout(_(" has been rendered nonfunctional.\""))
4738 game.damage[DDRAY] = 39.95
4740 r = randreal() # Pick failure method
4742 prouts(_("Sulu- \"Captain! It's working!\""))
4744 prouts(_("***RED ALERT! RED ALERT!"))
4746 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4748 prouts(_("***RED ALERT! RED A*L********************************"))
4751 prouts(_("****************** KA-BOOM!!!! *******************"))
4756 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4758 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4760 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4761 prout(_(" have apparently been transformed into strange mutations."))
4762 prout(_(" Vulcans do not seem to be affected."))
4764 prout(_("Kirk- \"Raauch! Raauch!\""))
4768 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4770 proutn(_("Spock- \"I believe the word is"))
4771 prouts(_(" *ASTONISHING*"))
4772 prout(_(" Mr. Sulu."))
4773 for i in range(QUADSIZE):
4774 for j in range(QUADSIZE):
4775 if game.quad[i][j] == '.':
4776 game.quad[i][j] = '?'
4777 prout(_(" Captain, our quadrant is now infested with"))
4778 prouts(_(" - - - - - - *THINGS*."))
4780 prout(_(" I have no logical explanation.\""))
4782 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4784 prout(_("Scotty- \"There are so many tribbles down here"))
4785 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4789 # Code from reports.c begins here
4791 def attackreport(curt):
4792 "eport status of bases under attack."
4794 if is_scheduled(FCDBAS):
4795 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4796 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4797 elif game.isatb == 1:
4798 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4799 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4801 prout(_("No Starbase is currently under attack."))
4803 if is_scheduled(FCDBAS):
4804 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4806 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4810 # report on general game status
4812 s1 = (game.thawed and _("thawed ")) or ""
4813 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4814 s3 = (None, _("novice"), _("fair"),
4815 _("good"), _("expert"), _("emeritus"))[game.skill]
4816 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4817 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4818 prout(_("No plaque is allowed."))
4820 prout(_("This is tournament game %d.") % game.tourn)
4821 prout(_("Your secret password is \"%s\"") % game.passwd)
4822 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4823 (game.inkling + game.incom + game.inscom)))
4824 if game.incom - len(game.state.kcmdr):
4825 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4826 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4827 prout(_(", but no Commanders."))
4830 if game.skill > SKILL_FAIR:
4831 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4832 if len(game.state.baseq) != game.inbase:
4834 if game.inbase-len(game.state.baseq)==1:
4835 proutn(_("has been 1 base"))
4837 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4838 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4840 prout(_("There are %d bases.") % game.inbase)
4841 if communicating() or game.iseenit:
4842 # Don't report this if not seen and
4843 # either the radio is dead or not at base!
4847 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4849 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4850 if game.ship == 'E':
4851 proutn(_("You have "))
4853 proutn("%d" % (game.nprobes))
4856 proutn(_(" deep space probe"))
4860 if communicating() and is_scheduled(FDSPROB):
4862 proutn(_("An armed deep space probe is in "))
4864 proutn(_("A deep space probe is in "))
4865 prout("Quadrant %s." % game.probec)
4867 if game.cryprob <= .05:
4868 prout(_("Dilithium crystals aboard ship... not yet used."))
4872 while game.cryprob > ai:
4875 prout(_("Dilithium crystals have been used %d time%s.") % \
4876 (i, (_("s"), "")[i==1]))
4880 "Long-range sensor scan."
4881 if damaged(DLRSENS):
4882 # Now allow base's sensors if docked
4883 if game.condition != "docked":
4885 prout(_("LONG-RANGE SENSORS DAMAGED."))
4888 prout(_("Starbase's long-range scan"))
4890 prout(_("Long-range scan"))
4891 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4894 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4895 if not Coord(x, y).valid_quadrant():
4899 if not damaged(DRADIO):
4900 game.state.galaxy[x][y].charted = True
4901 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4902 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4903 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4904 if not silent and game.state.galaxy[x][y].supernova:
4907 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4915 for i in range(NDEVICES):
4918 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4919 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4921 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4922 game.damage[i]+0.05,
4923 DOCKFAC*game.damage[i]+0.005))
4925 prout(_("All devices functional."))
4928 "Update the chart in the Enterprise's computer from galaxy data."
4929 game.lastchart = game.state.date
4930 for i in range(GALSIZE):
4931 for j in range(GALSIZE):
4932 if game.state.galaxy[i][j].charted:
4933 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
4934 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
4935 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
4938 "Display the star chart."
4940 if (game.options & OPTION_AUTOSCAN):
4942 if not damaged(DRADIO):
4944 if game.lastchart < game.state.date and game.condition == "docked":
4945 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
4947 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
4948 if game.state.date > game.lastchart:
4949 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
4950 prout(" 1 2 3 4 5 6 7 8")
4951 for i in range(GALSIZE):
4952 proutn("%d |" % (i+1))
4953 for j in range(GALSIZE):
4954 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4958 if game.state.galaxy[i][j].supernova:
4960 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
4962 elif game.state.galaxy[i][j].charted:
4963 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
4967 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4975 def sectscan(goodScan, i, j):
4976 "Light up an individual dot in a sector."
4977 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
4978 textcolor({"green":GREEN,
4982 "dead":BROWN}[game.condition])
4983 if game.quad[i][j] != game.ship:
4985 proutn("%c " % game.quad[i][j])
4991 "Emit status report lines"
4992 if not req or req == 1:
4993 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
4994 % (game.state.date, game.state.remtime))
4995 if not req or req == 2:
4996 if game.condition != "docked":
4998 prstat(_("Condition"), _("%s, %i DAMAGES") % \
4999 (game.condition.upper(), sum(map(lambda x: x > 0, game.damage))))
5000 if not req or req == 3:
5001 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5002 if not req or req == 4:
5003 if damaged(DLIFSUP):
5004 if game.condition == "docked":
5005 s = _("DAMAGED, Base provides")
5007 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5010 prstat(_("Life Support"), s)
5011 if not req or req == 5:
5012 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5013 if not req or req == 6:
5015 if game.icrystl and (game.options & OPTION_SHOWME):
5016 extra = _(" (have crystals)")
5017 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5018 if not req or req == 7:
5019 prstat(_("Torpedoes"), "%d" % (game.torps))
5020 if not req or req == 8:
5021 if damaged(DSHIELD):
5027 data = _(" %d%% %.1f units") \
5028 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5029 prstat(_("Shields"), s+data)
5030 if not req or req == 9:
5031 prstat(_("Klingons Left"), "%d" \
5032 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5033 if not req or req == 10:
5034 if game.options & OPTION_WORLDS:
5035 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5036 if plnet and plnet.inhabited:
5037 prstat(_("Major system"), plnet.name)
5039 prout(_("Sector is uninhabited"))
5040 elif not req or req == 11:
5041 attackreport(not req)
5044 "Request specified status data, a historical relic from slow TTYs."
5045 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5046 while scanner.next() == "IHEOL":
5047 proutn(_("Information desired? "))
5049 if scanner.token in requests:
5050 status(requests.index(scanner.token))
5052 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5053 prout((" date, condition, position, lsupport, warpfactor,"))
5054 prout((" energy, torpedoes, shields, klingons, system, time."))
5059 if damaged(DSRSENS):
5060 # Allow base's sensors if docked
5061 if game.condition != "docked":
5062 prout(_(" S.R. SENSORS DAMAGED!"))
5065 prout(_(" [Using Base's sensors]"))
5067 prout(_(" Short-range scan"))
5068 if goodScan and not damaged(DRADIO):
5069 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5070 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5071 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5072 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5073 prout(" 1 2 3 4 5 6 7 8 9 10")
5074 if game.condition != "docked":
5076 for i in range(QUADSIZE):
5077 proutn("%2d " % (i+1))
5078 for j in range(QUADSIZE):
5079 sectscan(goodScan, i, j)
5083 "Use computer to get estimated time of arrival for a warp jump."
5084 w1 = Coord(); w2 = Coord()
5086 if damaged(DCOMPTR):
5087 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5090 if scanner.next() != "IHREAL":
5093 proutn(_("Destination quadrant and/or sector? "))
5094 if scanner.next()!="IHREAL":
5097 w1.j = int(scanner.real-0.5)
5098 if scanner.next() != "IHREAL":
5101 w1.i = int(scanner.real-0.5)
5102 if scanner.next() == "IHREAL":
5103 w2.j = int(scanner.real-0.5)
5104 if scanner.next() != "IHREAL":
5107 w2.i = int(scanner.real-0.5)
5109 if game.quadrant.j>w1.i:
5113 if game.quadrant.i>w1.j:
5117 if not w1.valid_quadrant() or not w2.valid_sector():
5120 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5121 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5124 prout(_("Answer \"no\" if you don't know the value:"))
5127 proutn(_("Time or arrival date? "))
5128 if scanner.next()=="IHREAL":
5129 ttime = scanner.real
5130 if ttime > game.state.date:
5131 ttime -= game.state.date # Actually a star date
5132 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5133 if ttime <= 1e-10 or twarp > 10:
5134 prout(_("We'll never make it, sir."))
5141 proutn(_("Warp factor? "))
5142 if scanner.next()== "IHREAL":
5144 twarp = scanner.real
5145 if twarp<1.0 or twarp > 10.0:
5149 prout(_("Captain, certainly you can give me one of these."))
5152 ttime = (10.0*dist)/twarp**2
5153 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5154 if tpower >= game.energy:
5155 prout(_("Insufficient energy, sir."))
5156 if not game.shldup or tpower > game.energy*2.0:
5159 proutn(_("New warp factor to try? "))
5160 if scanner.next() == "IHREAL":
5162 twarp = scanner.real
5163 if twarp<1.0 or twarp > 10.0:
5171 prout(_("But if you lower your shields,"))
5172 proutn(_("remaining"))
5175 proutn(_("Remaining"))
5176 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5178 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5180 prout(_("Any warp speed is adequate."))
5182 prout(_("Minimum warp needed is %.2f,") % (twarp))
5183 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5184 if game.state.remtime < ttime:
5185 prout(_("Unfortunately, the Federation will be destroyed by then."))
5187 prout(_("You'll be taking risks at that speed, Captain"))
5188 if (game.isatb==1 and game.state.kscmdr == w1 and \
5189 scheduled(FSCDBAS)< ttime+game.state.date) or \
5190 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5191 prout(_("The starbase there will be destroyed by then."))
5192 proutn(_("New warp factor to try? "))
5193 if scanner.next() == "IHREAL":
5195 twarp = scanner.real
5196 if twarp<1.0 or twarp > 10.0:
5204 # Code from setup.c begins here
5207 "Issue a historically correct banner."
5209 prout(_("-SUPER- STAR TREK"))
5211 # From the FORTRAN original
5212 # prout(_("Latest update-21 Sept 78"))
5218 scanner.push("emsave.trk")
5219 key = scanner.next()
5221 proutn(_("File name: "))
5222 key = scanner.next()
5223 if key != "IHALPHA":
5226 if '.' not in scanner.token:
5227 scanner.token += ".trk"
5229 fp = open(scanner.token, "wb")
5231 prout(_("Can't freeze game as file %s") % scanner.token)
5233 cPickle.dump(game, fp)
5238 "Retrieve saved game."
5241 key = scanner.next()
5243 proutn(_("File name: "))
5244 key = scanner.next()
5245 if key != "IHALPHA":
5248 if '.' not in scanner.token:
5249 scanner.token += ".trk"
5251 fp = open(scanner.token, "rb")
5253 prout(_("Can't thaw game in %s") % scanner.token)
5255 game = cPickle.load(fp)
5260 # I used <http://www.memory-alpha.org> to find planets
5261 # with references in ST:TOS. Earth and the Alpha Centauri
5262 # Colony have been omitted.
5264 # Some planets marked Class G and P here will be displayed as class M
5265 # because of the way planets are generated. This is a known bug.
5268 _("Andoria (Fesoan)"), # several episodes
5269 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5270 _("Vulcan (T'Khasi)"), # many episodes
5271 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5272 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5273 _("Ardana"), # TOS: "The Cloud Minders"
5274 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5275 _("Gideon"), # TOS: "The Mark of Gideon"
5276 _("Aldebaran III"), # TOS: "The Deadly Years"
5277 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5278 _("Altair IV"), # TOS: "Amok Time
5279 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5280 _("Benecia"), # TOS: "The Conscience of the King"
5281 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5282 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5283 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5284 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5285 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5286 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5287 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5288 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5289 _("Ingraham B"), # TOS: "Operation: Annihilate"
5290 _("Janus IV"), # TOS: "The Devil in the Dark"
5291 _("Makus III"), # TOS: "The Galileo Seven"
5292 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5293 _("Omega IV"), # TOS: "The Omega Glory"
5294 _("Regulus V"), # TOS: "Amok Time
5295 _("Deneva"), # TOS: "Operation -- Annihilate!"
5296 # Worlds from BSD Trek
5297 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5298 _("Beta III"), # TOS: "The Return of the Archons"
5299 _("Triacus"), # TOS: "And the Children Shall Lead",
5300 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5302 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5303 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5304 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5305 # _("Izar"), # TOS: "Whom Gods Destroy"
5306 # _("Tiburon"), # TOS: "The Way to Eden"
5307 # _("Merak II"), # TOS: "The Cloud Minders"
5308 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5309 # _("Iotia"), # TOS: "A Piece of the Action"
5313 _("S. R. Sensors"), \
5314 _("L. R. Sensors"), \
5316 _("Photon Tubes"), \
5317 _("Life Support"), \
5318 _("Warp Engines"), \
5319 _("Impulse Engines"), \
5321 _("Subspace Radio"), \
5322 _("Shuttle Craft"), \
5324 _("Navigation System"), \
5326 _("Shield Control"), \
5332 "Prepare to play, set up cosmos."
5334 # Decide how many of everything
5336 return # frozen game
5337 # Prepare the Enterprise
5338 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5340 game.state.crew = FULLCREW
5341 game.energy = game.inenrg = 5000.0
5342 game.shield = game.inshld = 2500.0
5345 game.quadrant = randplace(GALSIZE)
5346 game.sector = randplace(QUADSIZE)
5347 game.torps = game.intorps = 10
5348 game.nprobes = randrange(2, 5)
5350 for i in range(NDEVICES):
5351 game.damage[i] = 0.0
5352 # Set up assorted game parameters
5353 game.battle = Coord()
5354 game.state.date = game.indate = 100.0 * randreal(20, 51)
5355 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5356 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5357 game.isatb = game.state.nplankl = 0
5358 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5359 game.iscraft = "onship"
5364 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5366 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5368 game.state.planets = [] # Planet information
5369 game.state.baseq = [] # Base quadrant coordinates
5370 game.state.kcmdr = [] # Commander quadrant coordinates
5371 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5373 # Starchart is functional but we've never seen it
5374 game.lastchart = FOREVER
5375 # Put stars in the galaxy
5377 for i in range(GALSIZE):
5378 for j in range(GALSIZE):
5379 k = randrange(1, QUADSIZE**2/10+1)
5381 game.state.galaxy[i][j].stars = k
5382 # Locate star bases in galaxy
5383 for i in range(game.inbase):
5386 w = randplace(GALSIZE)
5387 if not game.state.galaxy[w.i][w.j].starbase:
5390 # C version: for (j = i-1; j > 0; j--)
5391 # so it did them in the opposite order.
5392 for j in range(1, i):
5393 # Improved placement algorithm to spread out bases
5394 distq = (w - game.state.baseq[j]).distance()
5395 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5398 prout("=== Abandoning base #%d at %s" % (i, w))
5400 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5402 prout("=== Saving base #%d, close to #%d" % (i, j))
5405 game.state.baseq.append(w)
5406 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5407 # Position ordinary Klingon Battle Cruisers
5409 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5410 if klumper > MAXKLQUAD:
5414 klump = (1.0 - r*r)*klumper
5419 w = randplace(GALSIZE)
5420 if not game.state.galaxy[w.i][w.j].supernova and \
5421 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5423 game.state.galaxy[w.i][w.j].klingons += int(klump)
5426 # Position Klingon Commander Ships
5427 for i in range(game.incom):
5429 w = randplace(GALSIZE)
5430 if not welcoming(w) or w in game.state.kcmdr:
5432 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5434 game.state.galaxy[w.i][w.j].klingons += 1
5435 game.state.kcmdr.append(w)
5436 # Locate planets in galaxy
5437 for i in range(game.inplan):
5439 w = randplace(GALSIZE)
5440 if game.state.galaxy[w.i][w.j].planet == None:
5444 new.crystals = "absent"
5445 if (game.options & OPTION_WORLDS) and i < NINHAB:
5446 new.pclass = "M" # All inhabited planets are class M
5447 new.crystals = "absent"
5449 new.name = systnames[i]
5450 new.inhabited = True
5452 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5454 new.crystals = "present"
5455 new.known = "unknown"
5456 new.inhabited = False
5457 game.state.galaxy[w.i][w.j].planet = new
5458 game.state.planets.append(new)
5460 for i in range(game.state.nromrem):
5461 w = randplace(GALSIZE)
5462 game.state.galaxy[w.i][w.j].romulans += 1
5463 # Place the Super-Commander if needed
5464 if game.state.nscrem > 0:
5466 w = randplace(GALSIZE)
5469 game.state.kscmdr = w
5470 game.state.galaxy[w.i][w.j].klingons += 1
5471 # Initialize times for extraneous events
5472 schedule(FSNOVA, expran(0.5 * game.intime))
5473 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5474 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5475 schedule(FBATTAK, expran(0.3*game.intime))
5477 if game.state.nscrem:
5478 schedule(FSCMOVE, 0.2777)
5483 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5484 schedule(FDISTR, expran(1.0 + game.intime))
5489 # Place thing (in tournament game, we don't want one!)
5490 # New in SST2K: never place the Thing near a starbase.
5491 # This makes sense and avoids a special case in the old code.
5493 if game.tourn is None:
5495 thing = randplace(GALSIZE)
5496 if thing not in game.state.baseq:
5499 game.state.snap = False
5500 if game.skill == SKILL_NOVICE:
5501 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5502 prout(_("a deadly Klingon invasion force. As captain of the United"))
5503 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5504 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5505 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5506 prout(_("your mission. As you proceed you may be given more time."))
5508 prout(_("You will have %d supporting starbases.") % (game.inbase))
5509 proutn(_("Starbase locations- "))
5511 prout(_("Stardate %d.") % int(game.state.date))
5513 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5514 prout(_("An unknown number of Romulans."))
5515 if game.state.nscrem:
5516 prout(_("And one (GULP) Super-Commander."))
5517 prout(_("%d stardates.") % int(game.intime))
5518 proutn(_("%d starbases in ") % game.inbase)
5519 for i in range(game.inbase):
5520 proutn(`game.state.baseq[i]`)
5523 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5524 proutn(_(" Sector %s") % game.sector)
5526 prout(_("Good Luck!"))
5527 if game.state.nscrem:
5528 prout(_(" YOU'LL NEED IT."))
5531 setwnd(message_window)
5533 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5535 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5536 attack(torps_ok=False)
5539 "Choose your game type."
5541 game.tourn = game.length = 0
5543 game.skill = SKILL_NONE
5545 # if not scanner.inqueue: # Can start with command line options
5546 proutn(_("Would you like a regular, tournament, or saved game? "))
5548 if scanner.sees("tournament"):
5549 while scanner.next() == "IHEOL":
5550 proutn(_("Type in tournament number-"))
5551 if scanner.real == 0:
5553 continue # We don't want a blank entry
5554 game.tourn = int(round(scanner.real))
5555 random.seed(scanner.real)
5557 logfp.write("# random.seed(%d)\n" % scanner.real)
5559 if scanner.sees("saved") or scanner.sees("frozen"):
5563 if game.passwd == None:
5565 if not game.alldone:
5566 game.thawed = True # No plaque if not finished
5570 if scanner.sees("regular"):
5572 proutn(_("What is \"%s\"? ") % scanner.token)
5574 while game.length==0 or game.skill==SKILL_NONE:
5575 if scanner.next() == "IHALPHA":
5576 if scanner.sees("short"):
5578 elif scanner.sees("medium"):
5580 elif scanner.sees("long"):
5582 elif scanner.sees("novice"):
5583 game.skill = SKILL_NOVICE
5584 elif scanner.sees("fair"):
5585 game.skill = SKILL_FAIR
5586 elif scanner.sees("good"):
5587 game.skill = SKILL_GOOD
5588 elif scanner.sees("expert"):
5589 game.skill = SKILL_EXPERT
5590 elif scanner.sees("emeritus"):
5591 game.skill = SKILL_EMERITUS
5593 proutn(_("What is \""))
5594 proutn(scanner.token)
5599 proutn(_("Would you like a Short, Medium, or Long game? "))
5600 elif game.skill == SKILL_NONE:
5601 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5602 # Choose game options -- added by ESR for SST2K
5603 if scanner.next() != "IHALPHA":
5605 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5607 if scanner.sees("plain"):
5608 # Approximates the UT FORTRAN version.
5609 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5610 game.options |= OPTION_PLAIN
5611 elif scanner.sees("almy"):
5612 # Approximates Tom Almy's version.
5613 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5614 game.options |= OPTION_ALMY
5615 elif scanner.sees("fancy") or scanner.sees("\n"):
5617 elif len(scanner.token):
5618 proutn(_("What is \"%s\"?") % scanner.token)
5619 game.options &=~ OPTION_COLOR
5621 if game.passwd == "debug":
5623 prout("=== Debug mode enabled.")
5624 # Use parameters to generate initial values of things
5625 game.damfac = 0.5 * game.skill
5626 game.inbase = randrange(BASEMIN, BASEMAX+1)
5628 if game.options & OPTION_PLANETS:
5629 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5630 if game.options & OPTION_WORLDS:
5631 game.inplan += int(NINHAB)
5632 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5633 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5634 game.state.remtime = 7.0 * game.length
5635 game.intime = game.state.remtime
5636 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5637 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5638 game.state.remres = (game.inkling+4*game.incom)*game.intime
5639 game.inresor = game.state.remres
5640 if game.inkling > 50:
5641 game.state.inbase += 1
5644 def dropin(iquad=None):
5645 "Drop a feature on a random dot in the current quadrant."
5647 w = randplace(QUADSIZE)
5648 if game.quad[w.i][w.j] == '.':
5650 if iquad is not None:
5651 game.quad[w.i][w.j] = iquad
5655 "Update our alert status."
5656 game.condition = "green"
5657 if game.energy < 1000.0:
5658 game.condition = "yellow"
5659 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5660 game.condition = "red"
5662 game.condition="dead"
5665 "Drop new Klingon into current quadrant."
5666 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5669 "Sort enemies by distance so 'nearest' is meaningful."
5670 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
5673 "Set up a new state of quadrant, for when we enter or re-enter it."
5676 game.neutz = game.inorbit = game.landed = False
5677 game.ientesc = game.iseenit = False
5678 # Create a blank quadrant
5679 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5681 # Attempt to escape Super-commander, so tbeam back!
5684 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5685 # cope with supernova
5688 game.klhere = q.klingons
5689 game.irhere = q.romulans
5691 game.quad[game.sector.i][game.sector.j] = game.ship
5694 # Position ordinary Klingons
5695 for i in range(game.klhere):
5697 # If we need a commander, promote a Klingon
5698 for cmdr in game.state.kcmdr:
5699 if cmdr == game.quadrant:
5700 e = game.enemies[game.klhere-1]
5701 game.quad[e.location.i][e.location.j] = 'C'
5702 e.power = randreal(950,1350) + 50.0*game.skill
5704 # If we need a super-commander, promote a Klingon
5705 if game.quadrant == game.state.kscmdr:
5707 game.quad[e.location.i][e.location.j] = 'S'
5708 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5709 game.iscate = (game.state.remkl > 1)
5710 # Put in Romulans if needed
5711 for i in range(q.romulans):
5712 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5713 # If quadrant needs a starbase, put it in
5715 game.base = dropin('B')
5716 # If quadrant needs a planet, put it in
5718 game.iplnet = q.planet
5719 if not q.planet.inhabited:
5720 game.plnet = dropin('P')
5722 game.plnet = dropin('@')
5723 # Check for condition
5726 if game.irhere > 0 and game.klhere == 0:
5728 if not damaged(DRADIO):
5730 prout(_("LT. Uhura- \"Captain, an urgent message."))
5731 prout(_(" I'll put it on audio.\" CLICK"))
5733 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5734 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5735 # Put in THING if needed
5736 if thing == game.quadrant:
5737 Enemy(type='?', loc=dropin(),
5738 power=randreal(6000,6500.0)+250.0*game.skill)
5739 if not damaged(DSRSENS):
5741 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5742 prout(_(" Please examine your short-range scan.\""))
5743 # Decide if quadrant needs a Tholian; lighten up if skill is low
5744 if game.options & OPTION_THOLIAN:
5745 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5746 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5747 (game.skill > SKILL_GOOD and withprob(0.08)):
5750 w.i = withprob(0.5) * (QUADSIZE-1)
5751 w.j = withprob(0.5) * (QUADSIZE-1)
5752 if game.quad[w.i][w.j] == '.':
5754 game.tholian = Enemy(type='T', loc=w,
5755 power=randrange(100, 500) + 25.0*game.skill)
5756 # Reserve unoccupied corners
5757 if game.quad[0][0]=='.':
5758 game.quad[0][0] = 'X'
5759 if game.quad[0][QUADSIZE-1]=='.':
5760 game.quad[0][QUADSIZE-1] = 'X'
5761 if game.quad[QUADSIZE-1][0]=='.':
5762 game.quad[QUADSIZE-1][0] = 'X'
5763 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5764 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5766 # And finally the stars
5767 for i in range(q.stars):
5769 # Put in a few black holes
5770 for i in range(1, 3+1):
5773 # Take out X's in corners if Tholian present
5775 if game.quad[0][0]=='X':
5776 game.quad[0][0] = '.'
5777 if game.quad[0][QUADSIZE-1]=='X':
5778 game.quad[0][QUADSIZE-1] = '.'
5779 if game.quad[QUADSIZE-1][0]=='X':
5780 game.quad[QUADSIZE-1][0] = '.'
5781 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5782 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5785 "Set the self-destruct password."
5786 if game.options & OPTION_PLAIN:
5789 proutn(_("Please type in a secret password- "))
5791 game.passwd = scanner.token
5792 if game.passwd != None:
5796 game.passwd += chr(ord('a')+randrange(26))
5797 game.passwd += chr(ord('a')+randrange(26))
5798 game.passwd += chr(ord('a')+randrange(26))
5800 # Code from sst.c begins here
5803 ("SRSCAN", OPTION_TTY),
5804 ("STATUS", OPTION_TTY),
5805 ("REQUEST", OPTION_TTY),
5806 ("LRSCAN", OPTION_TTY),
5819 ("SENSORS", OPTION_PLANETS),
5820 ("ORBIT", OPTION_PLANETS),
5821 ("TRANSPORT", OPTION_PLANETS),
5822 ("MINE", OPTION_PLANETS),
5823 ("CRYSTALS", OPTION_PLANETS),
5824 ("SHUTTLE", OPTION_PLANETS),
5825 ("PLANETS", OPTION_PLANETS),
5830 ("PROBE", OPTION_PROBE),
5832 ("FREEZE", 0), # Synonym for SAVE
5838 ("SOS", 0), # Synonym for MAYDAY
5839 ("CALL", 0), # Synonym for MAYDAY
5846 "Generate a list of legal commands."
5847 prout(_("LEGAL COMMANDS ARE:"))
5849 for (key, opt) in commands:
5850 if not opt or (opt & game.options):
5851 proutn("%-12s " % key)
5853 if emitted % 5 == 4:
5858 "Browse on-line help."
5859 key = scanner.next()
5862 setwnd(prompt_window)
5863 proutn(_("Help on what command? "))
5864 key = scanner.next()
5865 setwnd(message_window)
5868 cmds = map(lambda x: x[0], commands)
5869 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
5876 cmd = scanner.token.upper()
5877 for directory in docpath:
5879 fp = open(os.path.join(directory, "sst.doc"), "r")
5884 prout(_("Spock- \"Captain, that information is missing from the"))
5885 prout(_(" computer. You need to find sst.doc and put it somewhere"))
5886 proutn(_(" in these directories: %s") % ":".join(docpath))
5888 # This used to continue: "You need to find SST.DOC and put
5889 # it in the current directory."
5892 linebuf = fp.readline()
5894 prout(_("Spock- \"Captain, there is no information on that command.\""))
5897 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5898 linebuf = linebuf[3:].strip()
5899 if cmd.upper() == linebuf:
5902 prout(_("Spock- \"Captain, I've found the following information:\""))
5905 linebuf = fp.readline()
5906 if "******" in linebuf:
5912 "Command-interpretation loop."
5913 while True: # command loop
5915 while True: # get a command
5917 game.optime = game.justin = False
5919 setwnd(prompt_window)
5922 if scanner.next() == "IHEOL":
5923 if game.options & OPTION_CURSES:
5926 elif scanner.token == "":
5930 setwnd(message_window)
5932 abandon_passed = False
5933 for (cmd, opt) in commands:
5934 # commands after ABANDON cannot be abbreviated
5935 if cmd == "ABANDON":
5936 abandon_passed = True
5937 if cmd == scanner.token.upper() or (not abandon_passed \
5938 and cmd.startswith(scanner.token.upper())):
5945 if cmd == "SRSCAN": # srscan
5947 elif cmd == "STATUS": # status
5949 elif cmd == "REQUEST": # status request
5951 elif cmd == "LRSCAN": # long range scan
5952 lrscan(silent=False)
5953 elif cmd == "PHASERS": # phasers
5957 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
5961 elif cmd == "MOVE": # move under warp
5962 warp(wcourse=None, involuntary=False)
5963 elif cmd == "SHIELDS": # shields
5964 doshield(shraise=False)
5967 game.shldchg = False
5968 elif cmd == "DOCK": # dock at starbase
5971 attack(torps_ok=False)
5972 elif cmd == "DAMAGES": # damage reports
5974 elif cmd == "CHART": # chart
5976 elif cmd == "IMPULSE": # impulse
5978 elif cmd == "REST": # rest
5982 elif cmd == "WARP": # warp
5984 elif cmd == "SCORE": # score
5986 elif cmd == "SENSORS": # sensors
5988 elif cmd == "ORBIT": # orbit
5992 elif cmd == "TRANSPORT": # transport "beam"
5994 elif cmd == "MINE": # mine
5998 elif cmd == "CRYSTALS": # crystals
6002 elif cmd == "SHUTTLE": # shuttle
6006 elif cmd == "PLANETS": # Planet list
6008 elif cmd == "REPORT": # Game Report
6010 elif cmd == "COMPUTER": # use COMPUTER!
6012 elif cmd == "COMMANDS":
6014 elif cmd == "EMEXIT": # Emergency exit
6015 clrscr() # Hide screen
6016 freeze(True) # forced save
6017 raise SystemExit,1 # And quick exit
6018 elif cmd == "PROBE":
6019 probe() # Launch probe
6022 elif cmd == "ABANDON": # Abandon Ship
6024 elif cmd == "DESTRUCT": # Self Destruct
6026 elif cmd == "SAVE": # Save Game
6029 if game.skill > SKILL_GOOD:
6030 prout(_("WARNING--Saved games produce no plaques!"))
6031 elif cmd == "DEATHRAY": # Try a desparation measure
6035 elif cmd == "DEBUGCMD": # What do we want for debug???
6037 elif cmd == "MAYDAY": # Call for help
6042 game.alldone = True # quit the game
6047 break # Game has ended
6048 if game.optime != 0.0:
6051 break # Events did us in
6052 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6055 if hitme and not game.justin:
6056 attack(torps_ok=True)
6059 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6070 "Emit the name of an enemy or feature."
6071 if type == 'R': s = _("Romulan")
6072 elif type == 'K': s = _("Klingon")
6073 elif type == 'C': s = _("Commander")
6074 elif type == 'S': s = _("Super-commander")
6075 elif type == '*': s = _("Star")
6076 elif type == 'P': s = _("Planet")
6077 elif type == 'B': s = _("Starbase")
6078 elif type == ' ': s = _("Black hole")
6079 elif type == 'T': s = _("Tholian")
6080 elif type == '#': s = _("Tholian web")
6081 elif type == '?': s = _("Stranger")
6082 elif type == '@': s = _("Inhabited World")
6083 else: s = "Unknown??"
6086 def crmena(stars, enemy, loctype, w):
6087 "Emit the name of an enemy and his location."
6091 buf += cramen(enemy) + _(" at ")
6092 if loctype == "quadrant":
6093 buf += _("Quadrant ")
6094 elif loctype == "sector":
6099 "Emit our ship name."
6100 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6103 "Emit a line of stars"
6104 prouts("******************************************************")
6108 return -avrage*math.log(1e-7 + randreal())
6110 def randplace(size):
6111 "Choose a random location."
6113 w.i = randrange(size)
6114 w.j = randrange(size)
6124 # Get a token from the user
6127 # Fill the token quue if nothing here
6128 while not self.inqueue:
6130 if curwnd==prompt_window:
6132 setwnd(message_window)
6139 self.inqueue = line.lstrip().split() + ["\n"]
6140 # From here on in it's all looking at the queue
6141 self.token = self.inqueue.pop(0)
6142 if self.token == "\n":
6146 self.real = float(self.token)
6147 self.type = "IHREAL"
6152 self.token = self.token.lower()
6153 self.type = "IHALPHA"
6156 def append(self, tok):
6157 self.inqueue.append(tok)
6158 def push(self, tok):
6159 self.inqueue.insert(0, tok)
6163 # Demand input for next scan
6165 self.real = self.token = None
6167 # compares s to item and returns true if it matches to the length of s
6168 return s.startswith(self.token)
6170 # Round token value to nearest integer
6171 return int(round(scanner.real))
6175 if scanner.type != "IHREAL":
6178 s.i = scanner.int()-1
6180 if scanner.type != "IHREAL":
6183 s.j = scanner.int()-1
6186 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6189 "Yes-or-no confirmation."
6193 if scanner.token == 'y':
6195 if scanner.token == 'n':
6198 proutn(_("Please answer with \"y\" or \"n\": "))
6201 "Complain about unparseable input."
6204 prout(_("Beg your pardon, Captain?"))
6207 "Access to the internals for debugging."
6208 proutn("Reset levels? ")
6210 if game.energy < game.inenrg:
6211 game.energy = game.inenrg
6212 game.shield = game.inshld
6213 game.torps = game.intorps
6214 game.lsupres = game.inlsr
6215 proutn("Reset damage? ")
6217 for i in range(NDEVICES):
6218 if game.damage[i] > 0.0:
6219 game.damage[i] = 0.0
6220 proutn("Toggle debug flag? ")
6222 game.idebug = not game.idebug
6224 prout("Debug output ON")
6226 prout("Debug output OFF")
6227 proutn("Cause selective damage? ")
6229 for i in range(NDEVICES):
6230 proutn("Kill %s?" % device[i])
6232 key = scanner.next()
6233 if key == "IHALPHA" and scanner.sees("y"):
6234 game.damage[i] = 10.0
6235 proutn("Examine/change events? ")
6240 FSNOVA: "Supernova ",
6243 FBATTAK: "Base Attack ",
6244 FCDBAS: "Base Destroy ",
6245 FSCMOVE: "SC Move ",
6246 FSCDBAS: "SC Base Destroy ",
6247 FDSPROB: "Probe Move ",
6248 FDISTR: "Distress Call ",
6249 FENSLV: "Enslavement ",
6250 FREPRO: "Klingon Build ",
6252 for i in range(1, NEVENTS):
6255 proutn("%.2f" % (scheduled(i)-game.state.date))
6256 if i == FENSLV or i == FREPRO:
6258 proutn(" in %s" % ev.quadrant)
6263 key = scanner.next()
6267 elif key == "IHREAL":
6268 ev = schedule(i, scanner.real)
6269 if i == FENSLV or i == FREPRO:
6271 proutn("In quadrant- ")
6272 key = scanner.next()
6273 # "IHEOL" says to leave coordinates as they are
6276 prout("Event %d canceled, no x coordinate." % (i))
6279 w.i = int(round(scanner.real))
6280 key = scanner.next()
6282 prout("Event %d canceled, no y coordinate." % (i))
6285 w.j = int(round(scanner.real))
6288 proutn("Induce supernova here? ")
6290 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6293 if __name__ == '__main__':
6294 import getopt, socket
6296 global line, thing, game
6300 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6301 if os.getenv("TERM"):
6302 game.options |= OPTION_CURSES
6304 game.options |= OPTION_TTY
6305 seed = int(time.time())
6306 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6307 for (switch, val) in options:
6310 replayfp = open(val, "r")
6312 sys.stderr.write("sst: can't open replay file %s\n" % val)
6315 line = replayfp.readline().strip()
6316 (leader, key, seed) = line.split()
6318 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6319 line = replayfp.readline().strip()
6320 arguments += line.split()[2:]
6322 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6324 game.options |= OPTION_TTY
6325 game.options &=~ OPTION_CURSES
6326 elif switch == '-s':
6328 elif switch == '-t':
6329 game.options |= OPTION_TTY
6330 game.options &=~ OPTION_CURSES
6331 elif switch == '-x':
6333 elif switch == '-V':
6334 print "SST2K", version
6337 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6339 # where to save the input in case of bugs
6340 if "TMPDIR" in os.environ:
6341 tmpdir = os.environ['TMPDIR']
6345 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6347 sys.stderr.write("sst: warning, can't open logfile\n")
6350 logfp.write("# seed %s\n" % seed)
6351 logfp.write("# options %s\n" % " ".join(arguments))
6352 logfp.write("# recorded by %s@%s on %s\n" % \
6353 (getpass.getuser(),socket.gethostname(),time.ctime()))
6355 scanner = sstscanner()
6356 map(scanner.append, arguments)
6359 while True: # Play a game
6360 setwnd(fullscreen_window)
6366 game.alldone = False
6372 if game.tourn and game.alldone:
6373 proutn(_("Do you want your score recorded?"))
6379 proutn(_("Do you want to play again? "))
6383 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6387 except KeyboardInterrupt: