3 sst.py -- Super Star Trek 2K
5 SST2K is a Python translation of a C translation of a FORTRAN
6 original dating back to 1973. Beautiful Python it is not, but it
7 works. Translation by Eric S. Raymond; original game by David Matuszek
8 and Paul Reynolds, with modifications by Don Smith, Tom Almy,
9 Stas Sergeev, and Eric S. Raymond.
11 See the doc/HACKING file in the distribution for designers notes and advice
12 on how to modify (and how not to modify!) this code.
14 import os, sys, math, curses, time, readline, cPickle, random, copy, gettext, getpass
18 docpath = (".", "../doc", "/usr/share/doc/sst")
21 return gettext.gettext(st)
23 GALSIZE = 8 # Galaxy size in quadrants
24 NINHAB = (GALSIZE * GALSIZE / 2) # Number of inhabited worlds
25 MAXUNINHAB = 10 # Maximum uninhabited worlds
26 QUADSIZE = 10 # Quadrant size in sectors
27 BASEMIN = 2 # Minimum starbases
28 BASEMAX = (GALSIZE * GALSIZE / 12) # Maximum starbases
29 MAXKLGAME = 127 # Maximum Klingons per game
30 MAXKLQUAD = 9 # Maximum Klingons per quadrant
31 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
32 FOREVER = 1e30 # Time for the indefinite future
33 MAXBURST = 3 # Max # of torps you can launch in one turn
34 MINCMDR = 10 # Minimum number of Klingon commanders
35 DOCKFAC = 0.25 # Repair faster when docked
36 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
56 class TrekError(Exception):
59 class JumpOut(Exception):
63 def __init__(self, x=None, y=None):
66 def valid_quadrant(self):
67 return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
68 def valid_sector(self):
69 return self.i >= 0 and self.i < QUADSIZE and self.j >= 0 and self.j < QUADSIZE
71 self.i = self.j = None
73 return self.i != None and self.j != None
74 def __eq__(self, other):
75 return other != None and self.i == other.i and self.j == other.j
76 def __ne__(self, other):
77 return other == None or self.i != other.i or self.j != other.j
78 def __add__(self, other):
79 return Coord(self.i+other.i, self.j+other.j)
80 def __sub__(self, other):
81 return Coord(self.i-other.i, self.j-other.j)
82 def __mul__(self, other):
83 return Coord(self.i*other, self.j*other)
84 def __rmul__(self, other):
85 return Coord(self.i*other, self.j*other)
86 def __div__(self, other):
87 return Coord(self.i/other, self.j/other)
88 def __mod__(self, other):
89 return Coord(self.i % other, self.j % other)
90 def __rdiv__(self, other):
91 return Coord(self.i/other, self.j/other)
92 def roundtogrid(self):
93 return Coord(int(round(self.i)), int(round(self.j)))
94 def distance(self, other=None):
97 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
99 return 1.90985*math.atan2(self.j, self.i)
105 s.i = self.i / abs(self.i)
109 s.j = self.j / abs(self.j)
112 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
113 return self.roundtogrid() / QUADSIZE
115 return self.roundtogrid() % QUADSIZE
118 s.i = self.i + randrange(-1, 2)
119 s.j = self.j + randrange(-1, 2)
122 if self.i == None or self.j == None:
124 return "%s - %s" % (self.i+1, self.j+1)
128 "Do not anger the Space Thingy!"
137 self.name = None # string-valued if inhabited
138 self.quadrant = Coord() # quadrant located
139 self.pclass = None # could be ""M", "N", "O", or "destroyed"
140 self.crystals = "absent"# could be "mined", "present", "absent"
141 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
142 self.inhabited = False # is it inhabites?
150 self.starbase = False
153 self.supernova = False
155 self.status = "secure" # Could be "secure", "distressed", "enslaved"
163 def fill2d(size, fillfun):
164 "Fill an empty list in 2D."
166 for i in range(size):
168 for j in range(size):
169 lst[i].append(fillfun(i, j))
174 self.snap = False # snapshot taken
175 self.crew = 0 # crew complement
176 self.remkl = 0 # remaining klingons
177 self.nscrem = 0 # remaining super commanders
178 self.starkl = 0 # destroyed stars
179 self.basekl = 0 # destroyed bases
180 self.nromrem = 0 # Romulans remaining
181 self.nplankl = 0 # destroyed uninhabited planets
182 self.nworldkl = 0 # destroyed inhabited planets
183 self.planets = [] # Planet information
184 self.date = 0.0 # stardate
185 self.remres = 0 # remaining resources
186 self.remtime = 0 # remaining time
187 self.baseq = [] # Base quadrant coordinates
188 self.kcmdr = [] # Commander quadrant coordinates
189 self.kscmdr = Coord() # Supercommander quadrant coordinates
191 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
193 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
197 self.date = None # A real number
198 self.quadrant = None # A coord structure
201 OPTION_ALL = 0xffffffff
202 OPTION_TTY = 0x00000001 # old interface
203 OPTION_CURSES = 0x00000002 # new interface
204 OPTION_IOMODES = 0x00000003 # cover both interfaces
205 OPTION_PLANETS = 0x00000004 # planets and mining
206 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
207 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
208 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
209 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
210 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
211 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
212 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
213 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
214 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
215 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
216 OPTION_PLAIN = 0x01000000 # user chose plain game
217 OPTION_ALMY = 0x02000000 # user chose Almy variant
218 OPTION_COLOR = 0x04000000 # enable color display (experimental, ESR, 2010)
237 NDEVICES = 16 # Number of devices
247 return (game.damage[dev] != 0.0)
249 return not damaged(DRADIO) or game.condition=="docked"
251 # Define future events
252 FSPY = 0 # Spy event happens always (no future[] entry)
253 # can cause SC to tractor beam Enterprise
254 FSNOVA = 1 # Supernova
255 FTBEAM = 2 # Commander tractor beams Enterprise
256 FSNAP = 3 # Snapshot for time warp
257 FBATTAK = 4 # Commander attacks base
258 FCDBAS = 5 # Commander destroys base
259 FSCMOVE = 6 # Supercommander moves (might attack base)
260 FSCDBAS = 7 # Supercommander destroys base
261 FDSPROB = 8 # Move deep space probe
262 FDISTR = 9 # Emit distress call from an inhabited world
263 FENSLV = 10 # Inhabited word is enslaved */
264 FREPRO = 11 # Klingons build a ship in an enslaved system
267 # Abstract out the event handling -- underlying data structures will change
268 # when we implement stateful events
269 def findevent(evtype):
270 return game.future[evtype]
273 def __init__(self, etype=None, loc=None, power=None):
275 self.location = Coord()
278 self.power = power # enemy energy level
279 game.enemies.append(self)
281 motion = (loc != self.location)
282 if self.location.i is not None and self.location.j is not None:
285 game.quad[self.location.i][self.location.j] = '#'
287 game.quad[self.location.i][self.location.j] = '.'
289 self.location = copy.copy(loc)
290 game.quad[self.location.i][self.location.j] = self.type
291 self.kdist = self.kavgd = (game.sector - loc).distance()
293 self.location = Coord()
294 self.kdist = self.kavgd = None
295 game.enemies.remove(self)
298 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
302 self.options = None # Game options
303 self.state = Snapshot() # A snapshot structure
304 self.snapsht = Snapshot() # Last snapshot taken for time-travel purposes
305 self.quad = None # contents of our quadrant
306 self.damage = [0.0] * NDEVICES # damage encountered
307 self.future = [] # future events
311 self.future.append(Event())
312 self.passwd = None # Self Destruct password
314 self.quadrant = None # where we are in the large
315 self.sector = None # where we are in the small
316 self.tholian = None # Tholian enemy object
317 self.base = None # position of base in current quadrant
318 self.battle = None # base coordinates being attacked
319 self.plnet = None # location of planet in quadrant
320 self.gamewon = False # Finished!
321 self.ididit = False # action taken -- allows enemy to attack
322 self.alive = False # we are alive (not killed)
323 self.justin = False # just entered quadrant
324 self.shldup = False # shields are up
325 self.shldchg = False # shield is changing (affects efficiency)
326 self.iscate = False # super commander is here
327 self.ientesc = False # attempted escape from supercommander
328 self.resting = False # rest time
329 self.icraft = False # Kirk in Galileo
330 self.landed = False # party on planet (true), on ship (false)
331 self.alldone = False # game is now finished
332 self.neutz = False # Romulan Neutral Zone
333 self.isarmed = False # probe is armed
334 self.inorbit = False # orbiting a planet
335 self.imine = False # mining
336 self.icrystl = False # dilithium crystals aboard
337 self.iseenit = False # seen base attack report
338 self.thawed = False # thawed game
339 self.condition = None # "green", "yellow", "red", "docked", "dead"
340 self.iscraft = None # "onship", "offship", "removed"
341 self.skill = None # Player skill level
342 self.inkling = 0 # initial number of klingons
343 self.inbase = 0 # initial number of bases
344 self.incom = 0 # initial number of commanders
345 self.inscom = 0 # initial number of commanders
346 self.inrom = 0 # initial number of commanders
347 self.instar = 0 # initial stars
348 self.intorps = 0 # initial/max torpedoes
349 self.torps = 0 # number of torpedoes
350 self.ship = 0 # ship type -- 'E' is Enterprise
351 self.abandoned = 0 # count of crew abandoned in space
352 self.length = 0 # length of game
353 self.klhere = 0 # klingons here
354 self.casual = 0 # causalties
355 self.nhelp = 0 # calls for help
356 self.nkinks = 0 # count of energy-barrier crossings
357 self.iplnet = None # planet # in quadrant
358 self.inplan = 0 # initial planets
359 self.irhere = 0 # Romulans in quadrant
360 self.isatb = 0 # =2 if super commander is attacking base
361 self.tourn = None # tournament number
362 self.nprobes = 0 # number of probes available
363 self.inresor = 0.0 # initial resources
364 self.intime = 0.0 # initial time
365 self.inenrg = 0.0 # initial/max energy
366 self.inshld = 0.0 # initial/max shield
367 self.inlsr = 0.0 # initial life support resources
368 self.indate = 0.0 # initial date
369 self.energy = 0.0 # energy level
370 self.shield = 0.0 # shield level
371 self.warpfac = 0.0 # warp speed
372 self.lsupres = 0.0 # life support reserves
373 self.optime = 0.0 # time taken by current operation
374 self.damfac = 0.0 # damage factor
375 self.lastchart = 0.0 # time star chart was last updated
376 self.cryprob = 0.0 # probability that crystal will work
377 self.probe = None # object holding probe course info
378 self.height = 0.0 # height of orbit around planet
379 self.score = 0.0 # overall score
380 self.perdate = 0.0 # rate of kills
381 self.idebug = False # Debugging instrumentation enabled?
383 # Stas thinks this should be (C expression):
384 # game.state.remkl + len(game.state.kcmdr) > 0 ?
385 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
386 # He says the existing expression is prone to divide-by-zero errors
387 # after killing the last klingon when score is shown -- perhaps also
388 # if the only remaining klingon is SCOM.
389 game.state.remtime = game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr))
415 return random.random() < p
417 def randrange(*args):
418 return random.randrange(*args)
423 v *= args[0] # from [0, args[0])
425 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
428 # Code from ai.c begins here
431 "Would this quadrant welcome another Klingon?"
432 return iq.valid_quadrant() and \
433 not game.state.galaxy[iq.i][iq.j].supernova and \
434 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
436 def tryexit(enemy, look, irun):
437 "A bad guy attempts to bug out."
439 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
440 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
441 if not welcoming(iq):
443 if enemy.type == 'R':
444 return False # Romulans cannot escape!
446 # avoid intruding on another commander's territory
447 if enemy.type == 'C':
448 if iq in game.state.kcmdr:
450 # refuse to leave if currently attacking starbase
451 if game.battle == game.quadrant:
453 # don't leave if over 1000 units of energy
454 if enemy.power > 1000.0:
456 # emit escape message and move out of quadrant.
457 # we know this if either short or long range sensors are working
458 if not damaged(DSRSENS) or not damaged(DLRSENS) or \
459 game.condition == "docked":
460 prout(crmena(True, enemy.type, "sector", enemy.location) + \
461 (_(" escapes to Quadrant %s (and regains strength).") % iq))
462 # handle local matters related to escape
465 if game.condition != "docked":
467 # Handle global matters related to escape
468 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
469 game.state.galaxy[iq.i][iq.j].klingons += 1
470 if enemy.type == 'S':
474 schedule(FSCMOVE, 0.2777)
476 game.state.kscmdr = iq
478 for cmdr in game.state.kcmdr:
479 if cmdr == game.quadrant:
480 game.state.kcmdr.append(iq)
482 return True # success
484 # The bad-guy movement algorithm:
486 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
487 # If both are operating full strength, force is 1000. If both are damaged,
488 # force is -1000. Having shields down subtracts an additional 1000.
490 # 2. Enemy has forces equal to the energy of the attacker plus
491 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
492 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
494 # Attacker Initial energy levels (nominal):
495 # Klingon Romulan Commander Super-Commander
496 # Novice 400 700 1200
498 # Good 450 800 1300 1750
499 # Expert 475 850 1350 1875
500 # Emeritus 500 900 1400 2000
501 # VARIANCE 75 200 200 200
503 # Enemy vessels only move prior to their attack. In Novice - Good games
504 # only commanders move. In Expert games, all enemy vessels move if there
505 # is a commander present. In Emeritus games all enemy vessels move.
507 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
508 # forces are 1000 greater than Enterprise.
510 # Agressive action on average cuts the distance between the ship and
511 # the enemy to 1/4 the original.
513 # 4. At lower energy advantage, movement units are proportional to the
514 # advantage with a 650 advantage being to hold ground, 800 to move forward
515 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
517 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
518 # retreat, especially at high skill levels.
520 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
522 def movebaddy(enemy):
523 "Tactical movement for the bad guys."
527 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
528 if game.skill >= SKILL_EXPERT:
529 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
531 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
533 mdist = int(dist1 + 0.5) # Nearest integer distance
534 # If SC, check with spy to see if should hi-tail it
535 if enemy.type == 'S' and \
536 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
540 # decide whether to advance, retreat, or hold position
541 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
543 forces += 1000 # Good for enemy if shield is down!
544 if not damaged(DPHASER) or not damaged(DPHOTON):
545 if damaged(DPHASER): # phasers damaged
548 forces -= 0.2*(game.energy - 2500.0)
549 if damaged(DPHOTON): # photon torpedoes damaged
552 forces -= 50.0*game.torps
554 # phasers and photon tubes both out!
557 if forces <= 1000.0 and game.condition != "docked": # Typical situation
558 motion = ((forces + randreal(200))/150.0) - 5.0
560 if forces > 1000.0: # Very strong -- move in for kill
561 motion = (1.0 - randreal())**2 * dist1 + 1.0
562 if game.condition == "docked" and (game.options & OPTION_BASE): # protected by base -- back off !
563 motion -= game.skill*(2.0-randreal()**2)
565 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
566 # don't move if no motion
569 # Limit motion according to skill
570 if abs(motion) > game.skill:
575 # calculate preferred number of steps
576 nsteps = abs(int(motion))
577 if motion > 0 and nsteps > mdist:
578 nsteps = mdist # don't overshoot
579 if nsteps > QUADSIZE:
580 nsteps = QUADSIZE # This shouldn't be necessary
582 nsteps = 1 # This shouldn't be necessary
584 proutn("NSTEPS = %d:" % nsteps)
585 # Compute preferred values of delta X and Y
586 m = game.sector - enemy.location
587 if 2.0 * abs(m.i) < abs(m.j):
589 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
591 m = (motion * m).sgn()
592 goto = enemy.location
594 for ll in range(nsteps):
596 proutn(" %d" % (ll+1))
597 # Check if preferred position available
608 attempts = 0 # Settle mysterious hang problem
609 while attempts < 20 and not success:
611 if look.i < 0 or look.i >= QUADSIZE:
612 if motion < 0 and tryexit(enemy, look, irun):
614 if krawli == m.i or m.j == 0:
616 look.i = goto.i + krawli
618 elif look.j < 0 or look.j >= QUADSIZE:
619 if motion < 0 and tryexit(enemy, look, irun):
621 if krawlj == m.j or m.i == 0:
623 look.j = goto.j + krawlj
625 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
626 # See if enemy should ram ship
627 if game.quad[look.i][look.j] == game.ship and \
628 (enemy.type == 'C' or enemy.type == 'S'):
629 collision(rammed=True, enemy=enemy)
631 if krawli != m.i and m.j != 0:
632 look.i = goto.i + krawli
634 elif krawlj != m.j and m.i != 0:
635 look.j = goto.j + krawlj
638 break # we have failed
650 if not damaged(DSRSENS) or game.condition == "docked":
651 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
652 if enemy.kdist < dist1:
653 proutn(_(" advances to "))
655 proutn(_(" retreats to "))
656 prout("Sector %s." % goto)
659 "Sequence Klingon tactical movement."
662 # Figure out which Klingon is the commander (or Supercommander)
664 if game.quadrant in game.state.kcmdr:
665 for enemy in game.enemies:
666 if enemy.type == 'C':
668 if game.state.kscmdr == game.quadrant:
669 for enemy in game.enemies:
670 if enemy.type == 'S':
673 # If skill level is high, move other Klingons and Romulans too!
674 # Move these last so they can base their actions on what the
676 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
677 for enemy in game.enemies:
678 if enemy.type in ('K', 'R'):
682 def movescom(iq, avoid):
683 "Commander movement helper."
684 # Avoid quadrants with bases if we want to avoid Enterprise
685 if not welcoming(iq) or (avoid and iq in game.state.baseq):
687 if game.justin and not game.iscate:
690 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
691 game.state.kscmdr = iq
692 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
693 if game.state.kscmdr == game.quadrant:
694 # SC has scooted, remove him from current quadrant
699 for enemy in game.enemies:
700 if enemy.type == 'S':
704 if game.condition != "docked":
707 # check for a helpful planet
708 for i in range(game.inplan):
709 if game.state.planets[i].quadrant == game.state.kscmdr and \
710 game.state.planets[i].crystals == "present":
712 game.state.planets[i].pclass = "destroyed"
713 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
716 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
717 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
718 prout(_(" by the Super-commander.\""))
720 return True # looks good!
722 def supercommander():
723 "Move the Super Commander."
730 prout("== SUPERCOMMANDER")
731 # Decide on being active or passive
732 avoid = ((game.incom - len(game.state.kcmdr) + game.inkling - game.state.remkl)/(game.state.date+0.01-game.indate) < 0.1*game.skill*(game.skill+1.0) or \
733 (game.state.date-game.indate) < 3.0)
734 if not game.iscate and avoid:
735 # compute move away from Enterprise
736 idelta = game.state.kscmdr-game.quadrant
737 if idelta.distance() > 2.0:
739 idelta.i = game.state.kscmdr.j-game.quadrant.j
740 idelta.j = game.quadrant.i-game.state.kscmdr.i
742 # compute distances to starbases
743 if not game.state.baseq:
747 sc = game.state.kscmdr
748 for (i, base) in enumerate(game.state.baseq):
749 basetbl.append((i, (base - sc).distance()))
750 if game.state.baseq > 1:
751 basetbl.sort(lambda x, y: cmp(x[1], y[1]))
752 # look for nearest base without a commander, no Enterprise, and
753 # without too many Klingons, and not already under attack.
754 ifindit = iwhichb = 0
755 for (i2, base) in enumerate(game.state.baseq):
756 i = basetbl[i2][0] # bug in original had it not finding nearest
757 if base == game.quadrant or base == game.battle or not welcoming(base):
759 # if there is a commander, and no other base is appropriate,
760 # we will take the one with the commander
761 for cmdr in game.state.kcmdr:
762 if base == cmdr and ifindit != 2:
766 else: # no commander -- use this one
771 return # Nothing suitable -- wait until next time
772 ibq = game.state.baseq[iwhichb]
773 # decide how to move toward base
774 idelta = ibq - game.state.kscmdr
775 # Maximum movement is 1 quadrant in either or both axes
776 idelta = idelta.sgn()
777 # try moving in both x and y directions
778 # there was what looked like a bug in the Almy C code here,
779 # but it might be this translation is just wrong.
780 iq = game.state.kscmdr + idelta
781 if not movescom(iq, avoid):
782 # failed -- try some other maneuvers
783 if idelta.i == 0 or idelta.j == 0:
786 iq.j = game.state.kscmdr.j + 1
787 if not movescom(iq, avoid):
788 iq.j = game.state.kscmdr.j - 1
791 iq.i = game.state.kscmdr.i + 1
792 if not movescom(iq, avoid):
793 iq.i = game.state.kscmdr.i - 1
796 # try moving just in x or y
797 iq.j = game.state.kscmdr.j
798 if not movescom(iq, avoid):
799 iq.j = game.state.kscmdr.j + idelta.j
800 iq.i = game.state.kscmdr.i
803 if len(game.state.baseq) == 0:
806 for ibq in game.state.baseq:
807 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
810 return # no, don't attack base!
813 schedule(FSCDBAS, randreal(1.0, 3.0))
814 if is_scheduled(FCDBAS):
815 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
816 if not communicating():
820 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
822 prout(_(" reports that it is under attack from the Klingon Super-commander."))
823 proutn(_(" It can survive until stardate %d.\"") \
824 % int(scheduled(FSCDBAS)))
827 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
831 game.optime = 0.0 # actually finished
833 # Check for intelligence report
834 if not game.idebug and \
836 (not communicating()) or \
837 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
840 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
841 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
846 if not game.tholian or game.justin:
849 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
852 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
855 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
858 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
862 # something is wrong!
863 game.tholian.move(None)
864 prout("***Internal error: Tholian in a bad spot.")
866 # do nothing if we are blocked
867 if game.quad[tid.i][tid.j] not in ('.', '#'):
869 here = copy.copy(game.tholian.location)
870 delta = (tid - game.tholian.location).sgn()
872 while here.i != tid.i:
874 if game.quad[here.i][here.j] == '.':
875 game.tholian.move(here)
877 while here.j != tid.j:
879 if game.quad[here.i][here.j] == '.':
880 game.tholian.move(here)
881 # check to see if all holes plugged
882 for i in range(QUADSIZE):
883 if game.quad[0][i] != '#' and game.quad[0][i] != 'T':
885 if game.quad[QUADSIZE-1][i] != '#' and game.quad[QUADSIZE-1][i] != 'T':
887 if game.quad[i][0] != '#' and game.quad[i][0] != 'T':
889 if game.quad[i][QUADSIZE-1] != '#' and game.quad[i][QUADSIZE-1] != 'T':
891 # All plugged up -- Tholian splits
892 game.quad[game.tholian.location.i][game.tholian.location.j] = '#'
894 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
895 game.tholian.move(None)
898 # Code from battle.c begins here
900 def doshield(shraise):
901 "Change shield status."
909 if scanner.sees("transfer"):
913 prout(_("Shields damaged and down."))
915 if scanner.sees("up"):
917 elif scanner.sees("down"):
920 proutn(_("Do you wish to change shield energy? "))
923 elif damaged(DSHIELD):
924 prout(_("Shields damaged and down."))
927 proutn(_("Shields are up. Do you want them down? "))
934 proutn(_("Shields are down. Do you want them up? "))
940 if action == "SHUP": # raise shields
942 prout(_("Shields already up."))
946 if game.condition != "docked":
948 prout(_("Shields raised."))
951 prout(_("Shields raising uses up last of energy."))
956 elif action == "SHDN":
958 prout(_("Shields already down."))
962 prout(_("Shields lowered."))
965 elif action == "NRG":
966 while scanner.next() != "IHREAL":
968 proutn(_("Energy to transfer to shields- "))
973 if nrg > game.energy:
974 prout(_("Insufficient ship energy."))
977 if game.shield+nrg >= game.inshld:
978 prout(_("Shield energy maximized."))
979 if game.shield+nrg > game.inshld:
980 prout(_("Excess energy requested returned to ship energy"))
981 game.energy -= game.inshld-game.shield
982 game.shield = game.inshld
984 if nrg < 0.0 and game.energy-nrg > game.inenrg:
985 # Prevent shield drain loophole
987 prout(_("Engineering to bridge--"))
988 prout(_(" Scott here. Power circuit problem, Captain."))
989 prout(_(" I can't drain the shields."))
992 if game.shield+nrg < 0:
993 prout(_("All shield energy transferred to ship."))
994 game.energy += game.shield
997 proutn(_("Scotty- \""))
999 prout(_("Transferring energy to shields.\""))
1001 prout(_("Draining energy from shields.\""))
1007 "Choose a device to damage, at random."
1009 105, # DSRSENS: short range scanners 10.5%
1010 105, # DLRSENS: long range scanners 10.5%
1011 120, # DPHASER: phasers 12.0%
1012 120, # DPHOTON: photon torpedoes 12.0%
1013 25, # DLIFSUP: life support 2.5%
1014 65, # DWARPEN: warp drive 6.5%
1015 70, # DIMPULS: impulse engines 6.5%
1016 145, # DSHIELD: deflector shields 14.5%
1017 30, # DRADIO: subspace radio 3.0%
1018 45, # DSHUTTL: shuttle 4.5%
1019 15, # DCOMPTR: computer 1.5%
1020 20, # NAVCOMP: navigation system 2.0%
1021 75, # DTRANSP: transporter 7.5%
1022 20, # DSHCTRL: high-speed shield controller 2.0%
1023 10, # DDRAY: death ray 1.0%
1024 30, # DDSP: deep-space probes 3.0%
1026 assert(sum(weights) == 1000)
1027 idx = randrange(1000)
1029 for (i, w) in enumerate(weights):
1033 return None # we should never get here
1035 def collision(rammed, enemy):
1036 "Collision handling fot rammong events."
1037 prouts(_("***RED ALERT! RED ALERT!"))
1039 prout(_("***COLLISION IMMINENT."))
1043 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1045 proutn(_(" rammed by "))
1048 proutn(crmena(False, enemy.type, "sector", enemy.location))
1050 proutn(_(" (original position)"))
1052 deadkl(enemy.location, enemy.type, game.sector)
1053 proutn("***" + crmshp() + " heavily damaged.")
1054 icas = randrange(10, 30)
1055 prout(_("***Sickbay reports %d casualties") % icas)
1057 game.state.crew -= icas
1058 # In the pre-SST2K version, all devices got equiprobably damaged,
1059 # which was silly. Instead, pick up to half the devices at
1060 # random according to our weighting table,
1061 ncrits = randrange(NDEVICES/2)
1065 if game.damage[dev] < 0:
1067 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1068 # Damage for at least time of travel!
1069 game.damage[dev] += game.optime + extradm
1071 prout(_("***Shields are down."))
1072 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1079 def torpedo(origin, bearing, dispersion, number, nburst):
1080 "Let a photon torpedo fly"
1081 if not damaged(DSRSENS) or game.condition == "docked":
1082 setwnd(srscan_window)
1084 setwnd(message_window)
1085 ac = bearing + 0.25*dispersion # dispersion is a random variable
1086 bullseye = (15.0 - bearing)*0.5235988
1087 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1088 bumpto = Coord(0, 0)
1089 # Loop to move a single torpedo
1090 setwnd(message_window)
1091 for step in range(1, QUADSIZE*2):
1092 if not track.next():
1095 if not w.valid_sector():
1097 iquad = game.quad[w.i][w.j]
1098 tracktorpedo(w, step, number, nburst, iquad)
1102 if not damaged(DSRSENS) or game.condition == "docked":
1103 skip(1) # start new line after text track
1104 if iquad in ('E', 'F'): # Hit our ship
1106 prout(_("Torpedo hits %s.") % crmshp())
1107 hit = 700.0 + randreal(100) - \
1108 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1109 newcnd() # we're blown out of dock
1110 if game.landed or game.condition == "docked":
1111 return hit # Cheat if on a planet
1112 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1113 # is 143 degrees, which is almost exactly 4.8 clockface units
1114 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1116 bumpto = displacement.sector()
1117 if not bumpto.valid_sector():
1119 if game.quad[bumpto.i][bumpto.j] == ' ':
1122 if game.quad[bumpto.i][bumpto.j] != '.':
1123 # can't move into object
1125 game.sector = bumpto
1127 game.quad[w.i][w.j] = '.'
1128 game.quad[bumpto.i][bumpto.j] = iquad
1129 prout(_(" displaced by blast to Sector %s ") % bumpto)
1130 for enemy in game.enemies:
1131 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1134 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1136 if iquad in ('C', 'S') and withprob(0.05):
1137 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1138 prout(_(" torpedo neutralized."))
1140 for enemy in game.enemies:
1141 if w == enemy.location:
1143 kp = math.fabs(enemy.power)
1144 h1 = 700.0 + randrange(100) - \
1145 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1153 if enemy.power == 0:
1156 proutn(crmena(True, iquad, "sector", w))
1157 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1159 bumpto = displacement.sector()
1160 if not bumpto.valid_sector():
1161 prout(_(" damaged but not destroyed."))
1163 if game.quad[bumpto.i][bumpto.j] == ' ':
1164 prout(_(" buffeted into black hole."))
1165 deadkl(w, iquad, bumpto)
1166 if game.quad[bumpto.i][bumpto.j] != '.':
1167 prout(_(" damaged but not destroyed."))
1169 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1170 enemy.location = bumpto
1171 game.quad[w.i][w.j] = '.'
1172 game.quad[bumpto.i][bumpto.j] = iquad
1173 for enemy in game.enemies:
1174 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1177 elif iquad == 'B': # Hit a base
1179 prout(_("***STARBASE DESTROYED.."))
1180 game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
1181 game.quad[w.i][w.j] = '.'
1182 game.base.invalidate()
1183 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1
1184 game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1
1185 game.state.basekl += 1
1188 elif iquad == 'P': # Hit a planet
1189 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1190 game.state.nplankl += 1
1191 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1192 game.iplnet.pclass = "destroyed"
1194 game.plnet.invalidate()
1195 game.quad[w.i][w.j] = '.'
1197 # captain perishes on planet
1200 elif iquad == '@': # Hit an inhabited world -- very bad!
1201 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1202 game.state.nworldkl += 1
1203 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1204 game.iplnet.pclass = "destroyed"
1206 game.plnet.invalidate()
1207 game.quad[w.i][w.j] = '.'
1209 # captain perishes on planet
1211 prout(_("The torpedo destroyed an inhabited planet."))
1213 elif iquad == '*': # Hit a star
1217 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1219 elif iquad == '?': # Hit a thingy
1220 if not (game.options & OPTION_THINGY) or withprob(0.3):
1222 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1224 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1226 proutn(_("Mr. Spock-"))
1227 prouts(_(" \"Fascinating!\""))
1231 # Stas Sergeev added the possibility that
1232 # you can shove the Thingy and piss it off.
1233 # It then becomes an enemy and may fire at you.
1236 elif iquad == ' ': # Black hole
1238 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1240 elif iquad == '#': # hit the web
1242 prout(_("***Torpedo absorbed by Tholian web."))
1244 elif iquad == 'T': # Hit a Tholian
1245 h1 = 700.0 + randrange(100) - \
1246 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1249 game.quad[w.i][w.j] = '.'
1254 proutn(crmena(True, 'T', "sector", w))
1256 prout(_(" survives photon blast."))
1258 prout(_(" disappears."))
1259 game.tholian.move(None)
1260 game.quad[w.i][w.j] = '#'
1265 proutn("Don't know how to handle torpedo collision with ")
1266 proutn(crmena(True, iquad, "sector", w))
1271 prout(_("Torpedo missed."))
1275 "Critical-hit resolution."
1276 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1278 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1279 proutn(_("***CRITICAL HIT--"))
1280 # Select devices and cause damage
1286 # Cheat to prevent shuttle damage unless on ship
1287 if not (game.damage[j]<0.0 or (j == DSHUTTL and game.iscraft != "onship")):
1290 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1291 game.damage[j] += extradm
1293 for (i, j) in enumerate(cdam):
1295 if skipcount % 3 == 2 and i < len(cdam)-1:
1300 prout(_(" damaged."))
1301 if damaged(DSHIELD) and game.shldup:
1302 prout(_("***Shields knocked down."))
1305 def attack(torps_ok):
1306 # bad guy attacks us
1307 # torps_ok == False forces use of phasers in an attack
1308 # game could be over at this point, check
1318 prout("=== ATTACK!")
1319 # Tholian gets to move before attacking
1322 # if you have just entered the RNZ, you'll get a warning
1323 if game.neutz: # The one chance not to be attacked
1326 # commanders get a chance to tac-move towards you
1327 if (((game.quadrant in game.state.kcmdr or game.state.kscmdr == game.quadrant) and not game.justin) or game.skill == SKILL_EMERITUS) and torps_ok:
1329 # if no enemies remain after movement, we're done
1330 if len(game.enemies) == 0 or (len(game.enemies) == 1 and thing == game.quadrant and not thing.angered):
1332 # set up partial hits if attack happens during shield status change
1333 pfac = 1.0/game.inshld
1335 chgfac = 0.25 + randreal(0.5)
1337 # message verbosity control
1338 if game.skill <= SKILL_FAIR:
1340 for enemy in game.enemies:
1342 continue # too weak to attack
1343 # compute hit strength and diminish shield power
1345 # Increase chance of photon torpedos if docked or enemy energy is low
1346 if game.condition == "docked":
1348 if enemy.power < 500:
1350 if enemy.type == 'T' or (enemy.type == '?' and not thing.angered):
1352 # different enemies have different probabilities of throwing a torp
1353 usephasers = not torps_ok or \
1354 (enemy.type == 'K' and r > 0.0005) or \
1355 (enemy.type == 'C' and r > 0.015) or \
1356 (enemy.type == 'R' and r > 0.3) or \
1357 (enemy.type == 'S' and r > 0.07) or \
1358 (enemy.type == '?' and r > 0.05)
1359 if usephasers: # Enemy uses phasers
1360 if game.condition == "docked":
1361 continue # Don't waste the effort!
1362 attempt = True # Attempt to attack
1363 dustfac = randreal(0.8, 0.85)
1364 hit = enemy.power*math.pow(dustfac,enemy.kavgd)
1366 else: # Enemy uses photon torpedo
1367 # We should be able to make the bearing() method work here
1368 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1370 proutn(_("***TORPEDO INCOMING"))
1371 if not damaged(DSRSENS):
1372 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1375 dispersion = (randreal()+randreal())*0.5 - 0.5
1376 dispersion += 0.002*enemy.power*dispersion
1377 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1378 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1379 finish(FWON) # Klingons did themselves in!
1380 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1381 return # Supernova or finished
1384 # incoming phaser or torpedo, shields may dissipate it
1385 if game.shldup or game.shldchg or game.condition == "docked":
1386 # shields will take hits
1387 propor = pfac * game.shield
1388 if game.condition == "docked":
1392 hitsh = propor*chgfac*hit+1.0
1394 if absorb > game.shield:
1395 absorb = game.shield
1396 game.shield -= absorb
1398 # taking a hit blasts us out of a starbase dock
1399 if game.condition == "docked":
1401 # but the shields may take care of it
1402 if propor > 0.1 and hit < 0.005*game.energy:
1404 # hit from this opponent got through shields, so take damage
1406 proutn(_("%d unit hit") % int(hit))
1407 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1408 proutn(_(" on the ") + crmshp())
1409 if not damaged(DSRSENS) and usephasers:
1410 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1412 # Decide if hit is critical
1418 if game.energy <= 0:
1419 # Returning home upon your shield, not with it...
1422 if not attempt and game.condition == "docked":
1423 prout(_("***Enemies decide against attacking your ship."))
1424 percent = 100.0*pfac*game.shield+0.5
1426 # Shields fully protect ship
1427 proutn(_("Enemy attack reduces shield strength to "))
1429 # Emit message if starship suffered hit(s)
1431 proutn(_("Energy left %2d shields ") % int(game.energy))
1434 elif not damaged(DSHIELD):
1437 proutn(_("damaged, "))
1438 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1439 # Check if anyone was hurt
1440 if hitmax >= 200 or hittot >= 500:
1441 icas = randrange(int(hittot * 0.015))
1444 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1445 prout(_(" in that last attack.\""))
1447 game.state.crew -= icas
1448 # After attack, reset average distance to enemies
1449 for enemy in game.enemies:
1450 enemy.kavgd = enemy.kdist
1454 def deadkl(w, etype, mv):
1455 "Kill a Klingon, Tholian, Romulan, or Thingy."
1456 # Added mv to allow enemy to "move" before dying
1457 proutn(crmena(True, etype, "sector", mv))
1458 # Decide what kind of enemy it is and update appropriately
1460 # Chalk up a Romulan
1461 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1463 game.state.nromrem -= 1
1472 # Killed some type of Klingon
1473 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1476 game.state.kcmdr.remove(game.quadrant)
1478 if game.state.kcmdr:
1479 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1480 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1483 game.state.remkl -= 1
1485 game.state.nscrem -= 1
1486 game.state.kscmdr.invalidate()
1491 # For each kind of enemy, finish message to player
1492 prout(_(" destroyed."))
1493 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
1496 # Remove enemy ship from arrays describing local conditions
1497 for e in game.enemies:
1504 "Return None if target is invalid, otherwise return a course angle."
1505 if not w.valid_sector():
1509 # C code this was translated from is wacky -- why the sign reversal?
1510 delta.j = (w.j - game.sector.j)
1511 delta.i = (game.sector.i - w.i)
1512 if delta == Coord(0, 0):
1514 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1515 prout(_(" I recommend an immediate review of"))
1516 prout(_(" the Captain's psychological profile.\""))
1519 return delta.bearing()
1522 "Launch photon torpedo salvo."
1525 if damaged(DPHOTON):
1526 prout(_("Photon tubes damaged."))
1530 prout(_("No torpedoes left."))
1533 # First, get torpedo count
1536 if scanner.token == "IHALPHA":
1539 elif scanner.token == "IHEOL" or not scanner.waiting():
1540 prout(_("%d torpedoes left.") % game.torps)
1542 proutn(_("Number of torpedoes to fire- "))
1543 continue # Go back around to get a number
1544 else: # key == "IHREAL"
1546 if n <= 0: # abort command
1551 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1554 scanner.chew() # User requested more torps than available
1555 continue # Go back around
1556 break # All is good, go to next stage
1560 key = scanner.next()
1561 if i == 0 and key == "IHEOL":
1562 break # no coordinate waiting, we will try prompting
1563 if i == 1 and key == "IHEOL":
1564 # direct all torpedoes at one target
1566 target.append(target[0])
1567 tcourse.append(tcourse[0])
1570 scanner.push(scanner.token)
1571 target.append(scanner.getcoord())
1572 if target[-1] == None:
1574 tcourse.append(targetcheck(target[-1]))
1575 if tcourse[-1] == None:
1578 if len(target) == 0:
1579 # prompt for each one
1581 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1583 target.append(scanner.getcoord())
1584 if target[-1] == None:
1586 tcourse.append(targetcheck(target[-1]))
1587 if tcourse[-1] == None:
1590 # Loop for moving <n> torpedoes
1592 if game.condition != "docked":
1594 dispersion = (randreal()+randreal())*0.5 -0.5
1595 if math.fabs(dispersion) >= 0.47:
1597 dispersion *= randreal(1.2, 2.2)
1599 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1601 prouts(_("***TORPEDO MISFIRES."))
1604 prout(_(" Remainder of burst aborted."))
1606 prout(_("***Photon tubes damaged by misfire."))
1607 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1609 if game.shldup or game.condition == "docked":
1610 dispersion *= 1.0 + 0.0001*game.shield
1611 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1612 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1614 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1618 "Check for phasers overheating."
1620 checkburn = (rpow-1500.0)*0.00038
1621 if withprob(checkburn):
1622 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1623 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1625 def checkshctrl(rpow):
1626 "Check shield control."
1629 prout(_("Shields lowered."))
1631 # Something bad has happened
1632 prouts(_("***RED ALERT! RED ALERT!"))
1634 hit = rpow*game.shield/game.inshld
1635 game.energy -= rpow+hit*0.8
1636 game.shield -= hit*0.2
1637 if game.energy <= 0.0:
1638 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1643 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1645 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1646 icas = randrange(int(hit*0.012))
1651 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1652 prout(_(" %d casualties so far.\"") % icas)
1654 game.state.crew -= icas
1656 prout(_("Phaser energy dispersed by shields."))
1657 prout(_("Enemy unaffected."))
1662 "Register a phaser hit on Klingons and Romulans."
1666 for (k, wham) in enumerate(hits):
1669 dustfac = randreal(0.9, 1.0)
1670 hit = wham*math.pow(dustfac,game.enemies[kk].kdist)
1671 kpini = game.enemies[kk].power
1672 kp = math.fabs(kpini)
1673 if PHASEFAC*hit < kp:
1675 if game.enemies[kk].power < 0:
1676 game.enemies[kk].power -= -kp
1678 game.enemies[kk].power -= kp
1679 kpow = game.enemies[kk].power
1680 w = game.enemies[kk].location
1682 if not damaged(DSRSENS):
1684 proutn(_("%d unit hit on ") % int(hit))
1686 proutn(_("Very small hit on "))
1687 ienm = game.quad[w.i][w.j]
1690 proutn(crmena(False, ienm, "sector", w))
1694 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1698 kk -= 1 # don't do the increment
1700 else: # decide whether or not to emasculate klingon
1701 if kpow > 0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1702 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1703 prout(_(" has just lost its firepower.\""))
1704 game.enemies[kk].power = -kpow
1709 "Fire phasers at bad guys."
1711 kz = 0; k = 1; irec=0 # Cheating inhibitor
1712 ifast = False; no = False; itarg = True; msgflag = True; rpow=0
1716 # SR sensors and Computer are needed for automode
1717 if damaged(DSRSENS) or damaged(DCOMPTR):
1719 if game.condition == "docked":
1720 prout(_("Phasers can't be fired through base shields."))
1723 if damaged(DPHASER):
1724 prout(_("Phaser control damaged."))
1728 if damaged(DSHCTRL):
1729 prout(_("High speed shield control damaged."))
1732 if game.energy <= 200.0:
1733 prout(_("Insufficient energy to activate high-speed shield control."))
1736 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1738 # Original code so convoluted, I re-did it all
1739 # (That was Tom Almy talking about the C code, I think -- ESR)
1740 while automode=="NOTSET":
1742 if key == "IHALPHA":
1743 if scanner.sees("manual"):
1744 if len(game.enemies)==0:
1745 prout(_("There is no enemy present to select."))
1748 automode="AUTOMATIC"
1751 key = scanner.next()
1752 elif scanner.sees("automatic"):
1753 if (not itarg) and len(game.enemies) != 0:
1754 automode = "FORCEMAN"
1756 if len(game.enemies)==0:
1757 prout(_("Energy will be expended into space."))
1758 automode = "AUTOMATIC"
1759 key = scanner.next()
1760 elif scanner.sees("no"):
1765 elif key == "IHREAL":
1766 if len(game.enemies)==0:
1767 prout(_("Energy will be expended into space."))
1768 automode = "AUTOMATIC"
1770 automode = "FORCEMAN"
1772 automode = "AUTOMATIC"
1775 if len(game.enemies)==0:
1776 prout(_("Energy will be expended into space."))
1777 automode = "AUTOMATIC"
1779 automode = "FORCEMAN"
1781 proutn(_("Manual or automatic? "))
1786 if automode == "AUTOMATIC":
1787 if key == "IHALPHA" and scanner.sees("no"):
1789 key = scanner.next()
1790 if key != "IHREAL" and len(game.enemies) != 0:
1791 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1796 for i in range(len(game.enemies)):
1797 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1799 proutn(_("%d units required. ") % irec)
1801 proutn(_("Units to fire= "))
1802 key = scanner.next()
1807 proutn(_("Energy available= %.2f") % avail)
1810 if not rpow > avail:
1817 if key == "IHALPHA" and scanner.sees("no"):
1820 game.energy -= 200 # Go and do it!
1821 if checkshctrl(rpow):
1826 if len(game.enemies):
1829 for i in range(len(game.enemies)):
1833 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))
1834 over = randreal(1.01, 1.06) * hits[i]
1836 powrem -= hits[i] + over
1837 if powrem <= 0 and temp < hits[i]:
1846 if extra > 0 and not game.alldone:
1848 proutn(_("*** Tholian web absorbs "))
1849 if len(game.enemies)>0:
1850 proutn(_("excess "))
1851 prout(_("phaser energy."))
1853 prout(_("%d expended on empty space.") % int(extra))
1854 elif automode == "FORCEMAN":
1857 if damaged(DCOMPTR):
1858 prout(_("Battle computer damaged, manual fire only."))
1861 prouts(_("---WORKING---"))
1863 prout(_("Short-range-sensors-damaged"))
1864 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1865 prout(_("Manual-fire-must-be-used"))
1867 elif automode == "MANUAL":
1869 for k in range(len(game.enemies)):
1870 aim = game.enemies[k].location
1871 ienm = game.quad[aim.i][aim.j]
1873 proutn(_("Energy available= %.2f") % (avail-0.006))
1877 if damaged(DSRSENS) and \
1878 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1879 prout(cramen(ienm) + _(" can't be located without short range scan."))
1882 hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
1887 if itarg and k > kz:
1888 irec=(abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9,game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1891 if not damaged(DCOMPTR):
1896 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1897 key = scanner.next()
1898 if key == "IHALPHA" and scanner.sees("no"):
1900 key = scanner.next()
1902 if key == "IHALPHA":
1906 if k == 1: # Let me say I'm baffled by this
1909 if scanner.real < 0:
1913 hits[k] = scanner.real
1914 rpow += scanner.real
1915 # If total requested is too much, inform and start over
1917 prout(_("Available energy exceeded -- try again."))
1920 key = scanner.next() # scan for next value
1923 # zero energy -- abort
1926 if key == "IHALPHA" and scanner.sees("no"):
1931 game.energy -= 200.0
1932 if checkshctrl(rpow):
1936 # Say shield raised or malfunction, if necessary
1943 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1944 prouts(_(" CLICK CLICK POP . . ."))
1945 prout(_(" No response, sir!"))
1948 prout(_("Shields raised."))
1953 # Code from events,c begins here.
1955 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1956 # event of each type active at any given time. Mostly these means we can
1957 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1958 # BSD Trek, from which we swiped the idea, can have up to 5.
1960 def unschedule(evtype):
1961 "Remove an event from the schedule."
1962 game.future[evtype].date = FOREVER
1963 return game.future[evtype]
1965 def is_scheduled(evtype):
1966 "Is an event of specified type scheduled."
1967 return game.future[evtype].date != FOREVER
1969 def scheduled(evtype):
1970 "When will this event happen?"
1971 return game.future[evtype].date
1973 def schedule(evtype, offset):
1974 "Schedule an event of specified type."
1975 game.future[evtype].date = game.state.date + offset
1976 return game.future[evtype]
1978 def postpone(evtype, offset):
1979 "Postpone a scheduled event."
1980 game.future[evtype].date += offset
1983 "Rest period is interrupted by event."
1986 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
1988 game.resting = False
1994 "Run through the event queue looking for things to do."
1996 fintim = game.state.date + game.optime
2000 w = Coord(); hold = Coord()
2001 ev = Event(); ev2 = Event()
2003 def tractorbeam(yank):
2004 "Tractor-beaming cases merge here."
2006 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2008 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
2009 # If Kirk & Co. screwing around on planet, handle
2010 atover(True) # atover(true) is Grab
2013 if game.icraft: # Caught in Galileo?
2016 # Check to see if shuttle is aboard
2017 if game.iscraft == "offship":
2020 prout(_("Galileo, left on the planet surface, is captured"))
2021 prout(_("by aliens and made into a flying McDonald's."))
2022 game.damage[DSHUTTL] = -10
2023 game.iscraft = "removed"
2025 prout(_("Galileo, left on the planet surface, is well hidden."))
2027 game.quadrant = game.state.kscmdr
2029 game.quadrant = game.state.kcmdr[i]
2030 game.sector = randplace(QUADSIZE)
2031 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2032 % (game.quadrant, game.sector))
2034 prout(_("(Remainder of rest/repair period cancelled.)"))
2035 game.resting = False
2037 if not damaged(DSHIELD) and game.shield > 0:
2038 doshield(shraise=True) # raise shields
2039 game.shldchg = False
2041 prout(_("(Shields not currently useable.)"))
2043 # Adjust finish time to time of tractor beaming
2044 fintim = game.state.date+game.optime
2045 attack(torps_ok=False)
2046 if not game.state.kcmdr:
2049 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2052 "Code merges here for any commander destroying a starbase."
2053 # Not perfect, but will have to do
2054 # Handle case where base is in same quadrant as starship
2055 if game.battle == game.quadrant:
2056 game.state.chart[game.battle.i][game.battle.j].starbase = False
2057 game.quad[game.base.i][game.base.j] = '.'
2058 game.base.invalidate()
2061 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2062 elif game.state.baseq and communicating():
2063 # Get word via subspace radio
2066 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2067 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2069 prout(_("the Klingon Super-Commander"))
2071 prout(_("a Klingon Commander"))
2072 game.state.chart[game.battle.i][game.battle.j].starbase = False
2073 # Remove Starbase from galaxy
2074 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2075 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2077 # reinstate a commander's base attack
2081 game.battle.invalidate()
2083 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2084 for i in range(1, NEVENTS):
2085 if i == FSNOVA: proutn("=== Supernova ")
2086 elif i == FTBEAM: proutn("=== T Beam ")
2087 elif i == FSNAP: proutn("=== Snapshot ")
2088 elif i == FBATTAK: proutn("=== Base Attack ")
2089 elif i == FCDBAS: proutn("=== Base Destroy ")
2090 elif i == FSCMOVE: proutn("=== SC Move ")
2091 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2092 elif i == FDSPROB: proutn("=== Probe Move ")
2093 elif i == FDISTR: proutn("=== Distress Call ")
2094 elif i == FENSLV: proutn("=== Enslavement ")
2095 elif i == FREPRO: proutn("=== Klingon Build ")
2097 prout("%.2f" % (scheduled(i)))
2100 radio_was_broken = damaged(DRADIO)
2103 # Select earliest extraneous event, evcode==0 if no events
2108 for l in range(1, NEVENTS):
2109 if game.future[l].date < datemin:
2112 prout("== Event %d fires" % evcode)
2113 datemin = game.future[l].date
2114 xtime = datemin-game.state.date
2115 game.state.date = datemin
2116 # Decrement Federation resources and recompute remaining time
2117 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2119 if game.state.remtime <= 0:
2122 # Any crew left alive?
2123 if game.state.crew <=0:
2126 # Is life support adequate?
2127 if damaged(DLIFSUP) and game.condition != "docked":
2128 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2131 game.lsupres -= xtime
2132 if game.damage[DLIFSUP] <= xtime:
2133 game.lsupres = game.inlsr
2136 if game.condition == "docked":
2138 # Don't fix Deathray here
2139 for l in range(NDEVICES):
2140 if game.damage[l] > 0.0 and l != DDRAY:
2141 if game.damage[l]-repair > 0.0:
2142 game.damage[l] -= repair
2144 game.damage[l] = 0.0
2145 # If radio repaired, update star chart and attack reports
2146 if radio_was_broken and not damaged(DRADIO):
2147 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2148 prout(_(" surveillance reports are coming in."))
2150 if not game.iseenit:
2154 prout(_(" The star chart is now up to date.\""))
2156 # Cause extraneous event EVCODE to occur
2157 game.optime -= xtime
2158 if evcode == FSNOVA: # Supernova
2161 schedule(FSNOVA, expran(0.5*game.intime))
2162 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2164 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2165 if game.state.nscrem == 0 or \
2166 ictbeam or istract or \
2167 game.condition=="docked" or game.isatb==1 or game.iscate:
2169 if game.ientesc or \
2170 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2171 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2172 (damaged(DSHIELD) and \
2173 (game.energy < 2500 or damaged(DPHASER)) and \
2174 (game.torps < 5 or damaged(DPHOTON))):
2176 istract = ictbeam = True
2177 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2180 elif evcode == FTBEAM: # Tractor beam
2181 if not game.state.kcmdr:
2184 i = randrange(len(game.state.kcmdr))
2185 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2186 if istract or game.condition == "docked" or yank == 0:
2187 # Drats! Have to reschedule
2189 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2193 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2194 game.snapsht = copy.deepcopy(game.state)
2195 game.state.snap = True
2196 schedule(FSNAP, expran(0.5 * game.intime))
2197 elif evcode == FBATTAK: # Commander attacks starbase
2198 if not game.state.kcmdr or not game.state.baseq:
2204 for ibq in game.state.baseq:
2205 for cmdr in game.state.kcmdr:
2206 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2209 # no match found -- try later
2210 schedule(FBATTAK, expran(0.3*game.intime))
2215 # commander + starbase combination found -- launch attack
2217 schedule(FCDBAS, randreal(1.0, 4.0))
2218 if game.isatb: # extra time if SC already attacking
2219 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2220 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2221 game.iseenit = False
2222 if not communicating():
2223 continue # No warning :-(
2227 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2228 prout(_(" reports that it is under attack and that it can"))
2229 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2232 elif evcode == FSCDBAS: # Supercommander destroys base
2235 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2236 continue # WAS RETURN!
2238 game.battle = game.state.kscmdr
2240 elif evcode == FCDBAS: # Commander succeeds in destroying base
2241 if evcode == FCDBAS:
2243 if not game.state.baseq() \
2244 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2245 game.battle.invalidate()
2247 # find the lucky pair
2248 for cmdr in game.state.kcmdr:
2249 if cmdr == game.battle:
2252 # No action to take after all
2255 elif evcode == FSCMOVE: # Supercommander moves
2256 schedule(FSCMOVE, 0.2777)
2257 if not game.ientesc and not istract and game.isatb != 1 and \
2258 (not game.iscate or not game.justin):
2260 elif evcode == FDSPROB: # Move deep space probe
2261 schedule(FDSPROB, 0.01)
2262 if not game.probe.next():
2263 if not game.probe.quadrant().valid_quadrant() or \
2264 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2265 # Left galaxy or ran into supernova
2269 proutn(_("Lt. Uhura- \"The deep space probe "))
2270 if not game.probe.quadrant().valid_quadrant():
2271 prout(_("has left the galaxy.\""))
2273 prout(_("is no longer transmitting.\""))
2279 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2280 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2282 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2283 chp.klingons = pdest.klingons
2284 chp.starbase = pdest.starbase
2285 chp.stars = pdest.stars
2286 pdest.charted = True
2287 game.probe.moves -= 1 # One less to travel
2288 if game.probe.arrived() and game.isarmed and pdest.stars:
2289 supernova(game.probe) # fire in the hole!
2291 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2293 elif evcode == FDISTR: # inhabited system issues distress call
2295 # try a whole bunch of times to find something suitable
2296 for i in range(100):
2297 # need a quadrant which is not the current one,
2298 # which has some stars which are inhabited and
2299 # not already under attack, which is not
2300 # supernova'ed, and which has some Klingons in it
2301 w = randplace(GALSIZE)
2302 q = game.state.galaxy[w.i][w.j]
2303 if not (game.quadrant == w or q.planet == None or \
2304 not q.planet.inhabited or \
2305 q.supernova or q.status!="secure" or q.klingons<=0):
2308 # can't seem to find one; ignore this call
2310 prout("=== Couldn't find location for distress event.")
2312 # got one!! Schedule its enslavement
2313 ev = schedule(FENSLV, expran(game.intime))
2315 q.status = "distressed"
2316 # tell the captain about it if we can
2318 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2320 prout(_("by a Klingon invasion fleet."))
2323 elif evcode == FENSLV: # starsystem is enslaved
2324 ev = unschedule(FENSLV)
2325 # see if current distress call still active
2326 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2330 q.status = "enslaved"
2332 # play stork and schedule the first baby
2333 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2334 ev2.quadrant = ev.quadrant
2336 # report the disaster if we can
2338 prout(_("Uhura- We've lost contact with starsystem %s") % \
2340 prout(_("in Quadrant %s.\n") % ev.quadrant)
2341 elif evcode == FREPRO: # Klingon reproduces
2342 # If we ever switch to a real event queue, we'll need to
2343 # explicitly retrieve and restore the x and y.
2344 ev = schedule(FREPRO, expran(1.0 * game.intime))
2345 # see if current distress call still active
2346 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2350 if game.state.remkl >=MAXKLGAME:
2351 continue # full right now
2352 # reproduce one Klingon
2355 if game.klhere >= MAXKLQUAD:
2357 # this quadrant not ok, pick an adjacent one
2358 for m.i in range(w.i - 1, w.i + 2):
2359 for m.j in range(w.j - 1, w.j + 2):
2360 if not m.valid_quadrant():
2362 q = game.state.galaxy[m.i][m.j]
2363 # check for this quad ok (not full & no snova)
2364 if q.klingons >= MAXKLQUAD or q.supernova:
2368 continue # search for eligible quadrant failed
2372 game.state.remkl += 1
2374 if game.quadrant == w:
2376 game.enemies.append(newkling())
2377 # recompute time left
2380 if game.quadrant == w:
2381 prout(_("Spock- sensors indicate the Klingons have"))
2382 prout(_("launched a warship from %s.") % q.planet)
2384 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2385 if q.planet != None:
2386 proutn(_("near %s ") % q.planet)
2387 prout(_("in Quadrant %s.") % w)
2393 key = scanner.next()
2396 proutn(_("How long? "))
2401 origTime = delay = scanner.real
2404 if delay >= game.state.remtime or len(game.enemies) != 0:
2405 proutn(_("Are you sure? "))
2408 # Alternate resting periods (events) with attacks
2412 game.resting = False
2413 if not game.resting:
2414 prout(_("%d stardates left.") % int(game.state.remtime))
2416 temp = game.optime = delay
2417 if len(game.enemies):
2418 rtime = randreal(1.0, 2.0)
2422 if game.optime < delay:
2423 attack(torps_ok=False)
2431 # Repair Deathray if long rest at starbase
2432 if origTime-delay >= 9.99 and game.condition == "docked":
2433 game.damage[DDRAY] = 0.0
2434 # leave if quadrant supernovas
2435 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2437 game.resting = False
2442 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2443 newc = Coord(); neighbor = Coord(); bump = Coord(0, 0)
2445 # Wow! We've supernova'ed
2446 supernova(game.quadrant)
2448 # handle initial nova
2449 game.quad[nov.i][nov.j] = '.'
2450 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2451 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2452 game.state.starkl += 1
2453 # Set up queue to recursively trigger adjacent stars
2459 for offset.i in range(-1, 1+1):
2460 for offset.j in range(-1, 1+1):
2461 if offset.j==0 and offset.i==0:
2463 neighbor = start + offset
2464 if not neighbor.valid_sector():
2466 iquad = game.quad[neighbor.i][neighbor.j]
2467 # Empty space ends reaction
2468 if iquad in ('.', '?', ' ', 'T', '#'):
2470 elif iquad == '*': # Affect another star
2472 # This star supernovas
2473 supernova(game.quadrant)
2476 hits.append(neighbor)
2477 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2478 game.state.starkl += 1
2479 proutn(crmena(True, '*', "sector", neighbor))
2481 game.quad[neighbor.i][neighbor.j] = '.'
2483 elif iquad in ('P', '@'): # Destroy planet
2484 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2486 game.state.nplankl += 1
2488 game.state.worldkl += 1
2489 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2490 game.iplnet.pclass = "destroyed"
2492 game.plnet.invalidate()
2496 game.quad[neighbor.i][neighbor.j] = '.'
2497 elif iquad == 'B': # Destroy base
2498 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2499 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2500 game.base.invalidate()
2501 game.state.basekl += 1
2503 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2504 game.quad[neighbor.i][neighbor.j] = '.'
2505 elif iquad in ('E', 'F'): # Buffet ship
2506 prout(_("***Starship buffeted by nova."))
2508 if game.shield >= 2000.0:
2509 game.shield -= 2000.0
2511 diff = 2000.0 - game.shield
2515 prout(_("***Shields knocked out."))
2516 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2518 game.energy -= 2000.0
2519 if game.energy <= 0:
2522 # add in course nova contributes to kicking starship
2523 bump += (game.sector-hits[-1]).sgn()
2524 elif iquad == 'K': # kill klingon
2525 deadkl(neighbor, iquad, neighbor)
2526 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2527 for ll in range(len(game.enemies)):
2528 if game.enemies[ll].location == neighbor:
2530 game.enemies[ll].power -= 800.0 # If firepower is lost, die
2531 if game.enemies[ll].power <= 0.0:
2532 deadkl(neighbor, iquad, neighbor)
2534 newc = neighbor + neighbor - hits[-1]
2535 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2536 if not newc.valid_sector():
2537 # can't leave quadrant
2540 iquad1 = game.quad[newc.i][newc.j]
2542 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2544 deadkl(neighbor, iquad, newc)
2547 # can't move into something else
2550 proutn(_(", buffeted to Sector %s") % newc)
2551 game.quad[neighbor.i][neighbor.j] = '.'
2552 game.quad[newc.i][newc.j] = iquad
2553 game.enemies[ll].move(newc)
2554 # Starship affected by nova -- kick it away.
2556 direc = ncourse[3*(bump.i+1)+bump.j+2]
2561 scourse = course(bearing=direc, distance=dist)
2562 game.optime = scourse.time(warp=4)
2564 prout(_("Force of nova displaces starship."))
2565 imove(scourse, noattack=True)
2566 game.optime = scourse.time(warp=4)
2570 "Star goes supernova."
2575 # Scheduled supernova -- select star at random.
2578 for nq.i in range(GALSIZE):
2579 for nq.j in range(GALSIZE):
2580 stars += game.state.galaxy[nq.i][nq.j].stars
2582 return # nothing to supernova exists
2583 num = randrange(stars) + 1
2584 for nq.i in range(GALSIZE):
2585 for nq.j in range(GALSIZE):
2586 num -= game.state.galaxy[nq.i][nq.j].stars
2592 proutn("=== Super nova here?")
2595 if not nq == game.quadrant or game.justin:
2596 # it isn't here, or we just entered (treat as enroute)
2599 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2600 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2603 # we are in the quadrant!
2604 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2605 for ns.i in range(QUADSIZE):
2606 for ns.j in range(QUADSIZE):
2607 if game.quad[ns.i][ns.j]=='*':
2614 prouts(_("***RED ALERT! RED ALERT!"))
2616 prout(_("***Incipient supernova detected at Sector %s") % ns)
2617 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2618 proutn(_("Emergency override attempts t"))
2619 prouts("***************")
2623 # destroy any Klingons in supernovaed quadrant
2624 kldead = game.state.galaxy[nq.i][nq.j].klingons
2625 game.state.galaxy[nq.i][nq.j].klingons = 0
2626 if nq == game.state.kscmdr:
2627 # did in the Supercommander!
2628 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2632 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2633 comkills = len(game.state.kcmdr) - len(survivors)
2634 game.state.kcmdr = survivors
2636 if not game.state.kcmdr:
2638 game.state.remkl -= kldead
2639 # destroy Romulans and planets in supernovaed quadrant
2640 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2641 game.state.galaxy[nq.i][nq.j].romulans = 0
2642 game.state.nromrem -= nrmdead
2644 for loop in range(game.inplan):
2645 if game.state.planets[loop].quadrant == nq:
2646 game.state.planets[loop].pclass = "destroyed"
2648 # Destroy any base in supernovaed quadrant
2649 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2650 # If starship caused supernova, tally up destruction
2652 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2653 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2654 game.state.nplankl += npdead
2655 # mark supernova in galaxy and in star chart
2656 if game.quadrant == nq or communicating():
2657 game.state.galaxy[nq.i][nq.j].supernova = True
2658 # If supernova destroys last Klingons give special message
2659 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2662 prout(_("Lucky you!"))
2663 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2666 # if some Klingons remain, continue or die in supernova
2671 # Code from finish.c ends here.
2674 "Self-destruct maneuver. Finish with a BANG!"
2676 if damaged(DCOMPTR):
2677 prout(_("Computer damaged; cannot execute destruct sequence."))
2679 prouts(_("---WORKING---")); skip(1)
2680 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2681 prouts(" 10"); skip(1)
2682 prouts(" 9"); skip(1)
2683 prouts(" 8"); skip(1)
2684 prouts(" 7"); skip(1)
2685 prouts(" 6"); skip(1)
2687 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2689 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2691 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2694 if game.passwd != scanner.token:
2695 prouts(_("PASSWORD-REJECTED;"))
2697 prouts(_("CONTINUITY-EFFECTED"))
2700 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2701 prouts(" 5"); skip(1)
2702 prouts(" 4"); skip(1)
2703 prouts(" 3"); skip(1)
2704 prouts(" 2"); skip(1)
2705 prouts(" 1"); skip(1)
2707 prouts(_("GOODBYE-CRUEL-WORLD"))
2715 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2719 if len(game.enemies) != 0:
2720 whammo = 25.0 * game.energy
2721 for l in range(len(game.enemies)):
2722 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2723 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2727 "Compute our rate of kils over time."
2728 elapsed = game.state.date - game.indate
2729 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2732 starting = (game.inkling + game.incom + game.inscom)
2733 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2734 return (starting - remaining)/elapsed
2738 badpt = 5.0*game.state.starkl + \
2740 10.0*game.state.nplankl + \
2741 300*game.state.nworldkl + \
2743 100.0*game.state.basekl +\
2745 if game.ship == 'F':
2747 elif game.ship == None:
2752 # end the game, with appropriate notfications
2756 prout(_("It is stardate %.1f.") % game.state.date)
2758 if ifin == FWON: # Game has been won
2759 if game.state.nromrem != 0:
2760 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2763 prout(_("You have smashed the Klingon invasion fleet and saved"))
2764 prout(_("the Federation."))
2769 badpt = 0.0 # Close enough!
2770 # killsPerDate >= RateMax
2771 if game.state.date-game.indate < 5.0 or \
2772 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2774 prout(_("In fact, you have done so well that Starfleet Command"))
2775 if game.skill == SKILL_NOVICE:
2776 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2777 elif game.skill == SKILL_FAIR:
2778 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2779 elif game.skill == SKILL_GOOD:
2780 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2781 elif game.skill == SKILL_EXPERT:
2782 prout(_("promotes you to Commodore Emeritus."))
2784 prout(_("Now that you think you're really good, try playing"))
2785 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2786 elif game.skill == SKILL_EMERITUS:
2788 proutn(_("Computer- "))
2789 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2791 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2793 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2795 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2797 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2799 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2801 prout(_("Now you can retire and write your own Star Trek game!"))
2803 elif game.skill >= SKILL_EXPERT:
2804 if game.thawed and not game.idebug:
2805 prout(_("You cannot get a citation, so..."))
2807 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2811 # Only grant long life if alive (original didn't!)
2813 prout(_("LIVE LONG AND PROSPER."))
2818 elif ifin == FDEPLETE: # Federation Resources Depleted
2819 prout(_("Your time has run out and the Federation has been"))
2820 prout(_("conquered. Your starship is now Klingon property,"))
2821 prout(_("and you are put on trial as a war criminal. On the"))
2822 proutn(_("basis of your record, you are "))
2823 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2824 prout(_("acquitted."))
2826 prout(_("LIVE LONG AND PROSPER."))
2828 prout(_("found guilty and"))
2829 prout(_("sentenced to death by slow torture."))
2833 elif ifin == FLIFESUP:
2834 prout(_("Your life support reserves have run out, and"))
2835 prout(_("you die of thirst, starvation, and asphyxiation."))
2836 prout(_("Your starship is a derelict in space."))
2838 prout(_("Your energy supply is exhausted."))
2840 prout(_("Your starship is a derelict in space."))
2841 elif ifin == FBATTLE:
2842 prout(_("The %s has been destroyed in battle.") % crmshp())
2844 prout(_("Dulce et decorum est pro patria mori."))
2846 prout(_("You have made three attempts to cross the negative energy"))
2847 prout(_("barrier which surrounds the galaxy."))
2849 prout(_("Your navigation is abominable."))
2852 prout(_("Your starship has been destroyed by a nova."))
2853 prout(_("That was a great shot."))
2855 elif ifin == FSNOVAED:
2856 prout(_("The %s has been fried by a supernova.") % crmshp())
2857 prout(_("...Not even cinders remain..."))
2858 elif ifin == FABANDN:
2859 prout(_("You have been captured by the Klingons. If you still"))
2860 prout(_("had a starbase to be returned to, you would have been"))
2861 prout(_("repatriated and given another chance. Since you have"))
2862 prout(_("no starbases, you will be mercilessly tortured to death."))
2863 elif ifin == FDILITHIUM:
2864 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2865 elif ifin == FMATERIALIZE:
2866 prout(_("Starbase was unable to re-materialize your starship."))
2867 prout(_("Sic transit gloria mundi"))
2868 elif ifin == FPHASER:
2869 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2871 prout(_("You and your landing party have been"))
2872 prout(_("converted to energy, disipating through space."))
2873 elif ifin == FMINING:
2874 prout(_("You are left with your landing party on"))
2875 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2877 prout(_("They are very fond of \"Captain Kirk\" soup."))
2879 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2880 elif ifin == FDPLANET:
2881 prout(_("You and your mining party perish."))
2883 prout(_("That was a great shot."))
2886 prout(_("The Galileo is instantly annihilated by the supernova."))
2887 prout(_("You and your mining party are atomized."))
2889 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2890 prout(_("joins the Romulans, wreaking terror on the Federation."))
2891 elif ifin == FPNOVA:
2892 prout(_("You and your mining party are atomized."))
2894 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2895 prout(_("joins the Romulans, wreaking terror on the Federation."))
2896 elif ifin == FSTRACTOR:
2897 prout(_("The shuttle craft Galileo is also caught,"))
2898 prout(_("and breaks up under the strain."))
2900 prout(_("Your debris is scattered for millions of miles."))
2901 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2903 prout(_("The mutants attack and kill Spock."))
2904 prout(_("Your ship is captured by Klingons, and"))
2905 prout(_("your crew is put on display in a Klingon zoo."))
2906 elif ifin == FTRIBBLE:
2907 prout(_("Tribbles consume all remaining water,"))
2908 prout(_("food, and oxygen on your ship."))
2910 prout(_("You die of thirst, starvation, and asphyxiation."))
2911 prout(_("Your starship is a derelict in space."))
2913 prout(_("Your ship is drawn to the center of the black hole."))
2914 prout(_("You are crushed into extremely dense matter."))
2916 prout(_("Your last crew member has died."))
2917 if game.ship == 'F':
2919 elif game.ship == 'E':
2922 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2923 goodies = game.state.remres/game.inresor
2924 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2925 if goodies/baddies >= randreal(1.0, 1.5):
2926 prout(_("As a result of your actions, a treaty with the Klingon"))
2927 prout(_("Empire has been signed. The terms of the treaty are"))
2928 if goodies/baddies >= randreal(3.0):
2929 prout(_("favorable to the Federation."))
2931 prout(_("Congratulations!"))
2933 prout(_("highly unfavorable to the Federation."))
2935 prout(_("The Federation will be destroyed."))
2937 prout(_("Since you took the last Klingon with you, you are a"))
2938 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2939 prout(_("statue in your memory. Rest in peace, and try not"))
2940 prout(_("to think about pigeons."))
2945 "Compute player's score."
2946 timused = game.state.date - game.indate
2947 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2949 game.perdate = killrate()
2950 ithperd = 500*game.perdate + 0.5
2953 iwon = 100*game.skill
2954 if game.ship == 'E':
2956 elif game.ship == 'F':
2960 game.score = 10*(game.inkling - game.state.remkl) \
2961 + 50*(game.incom - len(game.state.kcmdr)) \
2963 + 20*(game.inrom - game.state.nromrem) \
2964 + 200*(game.inscom - game.state.nscrem) \
2965 - game.state.nromrem \
2970 prout(_("Your score --"))
2971 if game.inrom - game.state.nromrem:
2972 prout(_("%6d Romulans destroyed %5d") %
2973 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
2974 if game.state.nromrem and game.gamewon:
2975 prout(_("%6d Romulans captured %5d") %
2976 (game.state.nromrem, game.state.nromrem))
2977 if game.inkling - game.state.remkl:
2978 prout(_("%6d ordinary Klingons destroyed %5d") %
2979 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
2980 if game.incom - len(game.state.kcmdr):
2981 prout(_("%6d Klingon commanders destroyed %5d") %
2982 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
2983 if game.inscom - game.state.nscrem:
2984 prout(_("%6d Super-Commander destroyed %5d") %
2985 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
2987 prout(_("%6.2f Klingons per stardate %5d") %
2988 (game.perdate, ithperd))
2989 if game.state.starkl:
2990 prout(_("%6d stars destroyed by your action %5d") %
2991 (game.state.starkl, -5*game.state.starkl))
2992 if game.state.nplankl:
2993 prout(_("%6d planets destroyed by your action %5d") %
2994 (game.state.nplankl, -10*game.state.nplankl))
2995 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
2996 prout(_("%6d inhabited planets destroyed by your action %5d") %
2997 (game.state.nworldkl, -300*game.state.nworldkl))
2998 if game.state.basekl:
2999 prout(_("%6d bases destroyed by your action %5d") %
3000 (game.state.basekl, -100*game.state.basekl))
3002 prout(_("%6d calls for help from starbase %5d") %
3003 (game.nhelp, -45*game.nhelp))
3005 prout(_("%6d casualties incurred %5d") %
3006 (game.casual, -game.casual))
3008 prout(_("%6d crew abandoned in space %5d") %
3009 (game.abandoned, -3*game.abandoned))
3011 prout(_("%6d ship(s) lost or destroyed %5d") %
3012 (klship, -100*klship))
3014 prout(_("Penalty for getting yourself killed -200"))
3016 proutn(_("Bonus for winning "))
3017 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3018 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3019 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3020 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3021 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3022 prout(" %5d" % iwon)
3024 prout(_("TOTAL SCORE %5d") % game.score)
3027 "Emit winner's commemmorative plaque."
3030 proutn(_("File or device name for your plaque: "))
3033 fp = open(winner, "w")
3036 prout(_("Invalid name."))
3038 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3040 # The 38 below must be 64 for 132-column paper
3041 nskip = 38 - len(winner)/2
3042 fp.write("\n\n\n\n")
3043 # --------DRAW ENTERPRISE PICTURE.
3044 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3045 fp.write(" EEE E : : : E\n" )
3046 fp.write(" EE EEE E : : NCC-1701 : E\n")
3047 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3048 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3049 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3050 fp.write(" EEEEEEE EEEEE E E E E\n")
3051 fp.write(" EEE E E E E\n")
3052 fp.write(" E E E E\n")
3053 fp.write(" EEEEEEEEEEEEE E E\n")
3054 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3055 fp.write(" :E : EEEE E\n")
3056 fp.write(" .-E -:----- E\n")
3057 fp.write(" :E : E\n")
3058 fp.write(" EE : EEEEEEEE\n")
3059 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3061 fp.write(_(" U. S. S. ENTERPRISE\n"))
3062 fp.write("\n\n\n\n")
3063 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3065 fp.write(_(" Starfleet Command bestows to you\n"))
3067 fp.write("%*s%s\n\n" % (nskip, "", winner))
3068 fp.write(_(" the rank of\n\n"))
3069 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3071 if game.skill == SKILL_EXPERT:
3072 fp.write(_(" Expert level\n\n"))
3073 elif game.skill == SKILL_EMERITUS:
3074 fp.write(_("Emeritus level\n\n"))
3076 fp.write(_(" Cheat level\n\n"))
3077 timestring = time.ctime()
3078 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3079 (timestring+4, timestring+20, timestring+11))
3080 fp.write(_(" Your score: %d\n\n") % game.score)
3081 fp.write(_(" Klingons per stardate: %.2f\n") % game.perdate)
3084 # Code from io.c begins here
3086 rows = linecount = 0 # for paging
3089 fullscreen_window = None
3090 srscan_window = None
3091 report_window = None
3092 status_window = None
3093 lrscan_window = None
3094 message_window = None
3095 prompt_window = None
3100 "for some recent versions of python2, the following enables UTF8"
3101 "for the older ones we probably need to set C locale, and the python3"
3102 "has no problems at all"
3103 if sys.version_info[0] < 3:
3105 locale.setlocale(locale.LC_ALL, "")
3106 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3107 gettext.textdomain("sst")
3108 if not (game.options & OPTION_CURSES):
3109 ln_env = os.getenv("LINES")
3115 stdscr = curses.initscr()
3119 if game.options & OPTION_COLOR:
3120 curses.start_color()
3121 curses.use_default_colors()
3122 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1)
3123 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1)
3124 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1)
3125 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1)
3126 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1)
3127 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1)
3128 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1)
3129 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1)
3130 global fullscreen_window, srscan_window, report_window, status_window
3131 global lrscan_window, message_window, prompt_window
3132 (rows, columns) = stdscr.getmaxyx()
3133 fullscreen_window = stdscr
3134 srscan_window = curses.newwin(12, 25, 0, 0)
3135 report_window = curses.newwin(11, 0, 1, 25)
3136 status_window = curses.newwin(10, 0, 1, 39)
3137 lrscan_window = curses.newwin(5, 0, 0, 64)
3138 message_window = curses.newwin(0, 0, 12, 0)
3139 prompt_window = curses.newwin(1, 0, rows-2, 0)
3140 message_window.scrollok(True)
3141 setwnd(fullscreen_window)
3145 if game.options & OPTION_CURSES:
3146 stdscr.keypad(False)
3152 "Wait for user action -- OK to do nothing if on a TTY"
3153 if game.options & OPTION_CURSES:
3158 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3162 if game.skill > SKILL_FAIR:
3163 prompt = _("[CONTINUE?]")
3165 prompt = _("[PRESS ENTER TO CONTINUE]")
3167 if game.options & OPTION_CURSES:
3169 setwnd(prompt_window)
3170 prompt_window.clear()
3171 prompt_window.addstr(prompt)
3172 prompt_window.getstr()
3173 prompt_window.clear()
3174 prompt_window.refresh()
3175 setwnd(message_window)
3178 sys.stdout.write('\n')
3181 sys.stdout.write('\n' * rows)
3185 "Skip i lines. Pause game if this would cause a scrolling event."
3186 for dummy in range(i):
3187 if game.options & OPTION_CURSES:
3188 (y, x) = curwnd.getyx()
3191 except curses.error:
3196 if rows and linecount >= rows:
3199 sys.stdout.write('\n')
3202 "Utter a line with no following line feed."
3203 if game.options & OPTION_CURSES:
3204 (y, x) = curwnd.getyx()
3205 (my, mx) = curwnd.getmaxyx()
3206 if curwnd == message_window and y >= my - 2:
3212 sys.stdout.write(line)
3222 if not replayfp or replayfp.closed: # Don't slow down replays
3225 if game.options & OPTION_CURSES:
3229 if not replayfp or replayfp.closed:
3233 "Get a line of input."
3234 if game.options & OPTION_CURSES:
3235 line = curwnd.getstr() + "\n"
3238 if replayfp and not replayfp.closed:
3240 line = replayfp.readline()
3243 prout("*** Replay finished")
3246 elif line[0] != "#":
3249 line = raw_input() + "\n"
3255 "Change windows -- OK for this to be a no-op in tty mode."
3257 if game.options & OPTION_CURSES:
3259 curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window)
3262 "Clear to end of line -- can be a no-op in tty mode"
3263 if game.options & OPTION_CURSES:
3268 "Clear screen -- can be a no-op in tty mode."
3270 if game.options & OPTION_CURSES:
3276 def textcolor(color=DEFAULT):
3277 if game.options & OPTION_COLOR:
3278 if color == DEFAULT:
3280 elif color == BLACK:
3281 curwnd.attron(curses.color_pair(curses.COLOR_BLACK))
3283 curwnd.attron(curses.color_pair(curses.COLOR_BLUE))
3284 elif color == GREEN:
3285 curwnd.attron(curses.color_pair(curses.COLOR_GREEN))
3287 curwnd.attron(curses.color_pair(curses.COLOR_CYAN))
3289 curwnd.attron(curses.color_pair(curses.COLOR_RED))
3290 elif color == MAGENTA:
3291 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA))
3292 elif color == BROWN:
3293 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW))
3294 elif color == LIGHTGRAY:
3295 curwnd.attron(curses.color_pair(curses.COLOR_WHITE))
3296 elif color == DARKGRAY:
3297 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD)
3298 elif color == LIGHTBLUE:
3299 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD)
3300 elif color == LIGHTGREEN:
3301 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD)
3302 elif color == LIGHTCYAN:
3303 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD)
3304 elif color == LIGHTRED:
3305 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD)
3306 elif color == LIGHTMAGENTA:
3307 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD)
3308 elif color == YELLOW:
3309 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD)
3310 elif color == WHITE:
3311 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD)
3314 if game.options & OPTION_COLOR:
3315 curwnd.attron(curses.A_REVERSE)
3318 # Things past this point have policy implications.
3322 "Hook to be called after moving to redraw maps."
3323 if game.options & OPTION_CURSES:
3326 setwnd(srscan_window)
3330 setwnd(status_window)
3331 status_window.clear()
3332 status_window.move(0, 0)
3333 setwnd(report_window)
3334 report_window.clear()
3335 report_window.move(0, 0)
3337 setwnd(lrscan_window)
3338 lrscan_window.clear()
3339 lrscan_window.move(0, 0)
3340 lrscan(silent=False)
3342 def put_srscan_sym(w, sym):
3343 "Emit symbol for short-range scan."
3344 srscan_window.move(w.i+1, w.j*2+2)
3345 srscan_window.addch(sym)
3346 srscan_window.refresh()
3349 "Enemy fall down, go boom."
3350 if game.options & OPTION_CURSES:
3352 setwnd(srscan_window)
3353 srscan_window.attron(curses.A_REVERSE)
3354 put_srscan_sym(w, game.quad[w.i][w.j])
3358 srscan_window.attroff(curses.A_REVERSE)
3359 put_srscan_sym(w, game.quad[w.i][w.j])
3360 curses.delay_output(500)
3361 setwnd(message_window)
3364 "Sound and visual effects for teleportation."
3365 if game.options & OPTION_CURSES:
3367 setwnd(message_window)
3369 prouts(" . . . . . ")
3370 if game.options & OPTION_CURSES:
3371 #curses.delay_output(1000)
3375 def tracktorpedo(w, step, i, n, iquad):
3376 "Torpedo-track animation."
3377 if not game.options & OPTION_CURSES:
3381 proutn(_("Track for torpedo number %d- ") % (i+1))
3384 proutn(_("Torpedo track- "))
3385 elif step==4 or step==9:
3389 if not damaged(DSRSENS) or game.condition=="docked":
3390 if i != 0 and step == 1:
3393 if (iquad=='.') or (iquad==' '):
3394 put_srscan_sym(w, '+')
3398 put_srscan_sym(w, iquad)
3400 curwnd.attron(curses.A_REVERSE)
3401 put_srscan_sym(w, iquad)
3405 curwnd.attroff(curses.A_REVERSE)
3406 put_srscan_sym(w, iquad)
3411 "Display the current galaxy chart."
3412 if game.options & OPTION_CURSES:
3413 setwnd(message_window)
3414 message_window.clear()
3416 if game.options & OPTION_TTY:
3421 def prstat(txt, data):
3423 if game.options & OPTION_CURSES:
3425 setwnd(status_window)
3427 proutn(" " * (NSYM - len(txt)))
3430 if game.options & OPTION_CURSES:
3431 setwnd(report_window)
3433 # Code from moving.c begins here
3435 def imove(icourse=None, noattack=False):
3436 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3439 def newquadrant(noattack):
3440 # Leaving quadrant -- allow final enemy attack
3441 # Don't do it if being pushed by Nova
3442 if len(game.enemies) != 0 and not noattack:
3444 for enemy in game.enemies:
3445 finald = (w - enemy.location).distance()
3446 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3447 # Stas Sergeev added the condition
3448 # that attacks only happen if Klingons
3449 # are present and your skill is good.
3450 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3451 attack(torps_ok=False)
3454 # check for edge of galaxy
3458 if icourse.final.i < 0:
3459 icourse.final.i = -icourse.final.i
3461 if icourse.final.j < 0:
3462 icourse.final.j = -icourse.final.j
3464 if icourse.final.i >= GALSIZE*QUADSIZE:
3465 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3467 if icourse.final.j >= GALSIZE*QUADSIZE:
3468 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3476 if game.nkinks == 3:
3477 # Three strikes -- you're out!
3481 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3482 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3483 prout(_("YOU WILL BE DESTROYED."))
3484 # Compute final position in new quadrant
3485 if trbeam: # Don't bother if we are to be beamed
3487 game.quadrant = icourse.final.quadrant()
3488 game.sector = icourse.final.sector()
3490 prout(_("Entering Quadrant %s.") % game.quadrant)
3491 game.quad[game.sector.i][game.sector.j] = game.ship
3493 if game.skill>SKILL_NOVICE:
3494 attack(torps_ok=False)
3496 def check_collision(h):
3497 iquad = game.quad[h.i][h.j]
3499 # object encountered in flight path
3500 stopegy = 50.0*icourse.distance/game.optime
3501 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3502 for enemy in game.enemies:
3503 if enemy.location == game.sector:
3505 collision(rammed=False, enemy=enemy)
3509 prouts(_("***RED ALERT! RED ALERT!"))
3511 proutn("***" + crmshp())
3512 proutn(_(" pulled into black hole at Sector %s") % h)
3513 # Getting pulled into a black hole was certain
3514 # death in Almy's original. Stas Sergeev added a
3515 # possibility that you'll get timewarped instead.
3517 for m in range(NDEVICES):
3518 if game.damage[m]>0:
3520 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3521 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3531 prout(_(" encounters Tholian web at %s;") % h)
3533 prout(_(" blocked by object at %s;") % h)
3534 proutn(_("Emergency stop required "))
3535 prout(_("%2d units of energy.") % int(stopegy))
3536 game.energy -= stopegy
3537 if game.energy <= 0:
3544 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3545 game.inorbit = False
3546 # If tractor beam is to occur, don't move full distance
3547 if game.state.date+game.optime >= scheduled(FTBEAM):
3549 game.condition = "red"
3550 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3551 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3553 game.quad[game.sector.i][game.sector.j] = '.'
3554 for m in range(icourse.moves):
3556 w = icourse.sector()
3557 if icourse.origin.quadrant() != icourse.location.quadrant():
3558 newquadrant(noattack)
3560 elif check_collision(w):
3561 print "Collision detected"
3565 # We're in destination quadrant -- compute new average enemy distances
3566 game.quad[game.sector.i][game.sector.j] = game.ship
3568 for enemy in game.enemies:
3569 finald = (w-enemy.location).distance()
3570 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3571 enemy.kdist = finald
3573 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3574 attack(torps_ok=False)
3575 for enemy in game.enemies:
3576 enemy.kavgd = enemy.kdist
3579 setwnd(message_window)
3583 "Dock our ship at a starbase."
3585 if game.condition == "docked" and verbose:
3586 prout(_("Already docked."))
3589 prout(_("You must first leave standard orbit."))
3591 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3592 prout(crmshp() + _(" not adjacent to base."))
3594 game.condition = "docked"
3598 if game.energy < game.inenrg:
3599 game.energy = game.inenrg
3600 game.shield = game.inshld
3601 game.torps = game.intorps
3602 game.lsupres = game.inlsr
3603 game.state.crew = FULLCREW
3604 if not damaged(DRADIO) and \
3605 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3606 # get attack report from base
3607 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3611 def cartesian(loc1=None, loc2=None):
3613 return game.quadrant * QUADSIZE + game.sector
3615 return game.quadrant * QUADSIZE + loc1
3617 return loc1 * QUADSIZE + loc2
3619 def getcourse(isprobe):
3620 "Get a course and distance from the user."
3622 dquad = copy.copy(game.quadrant)
3623 navmode = "unspecified"
3627 if game.landed and not isprobe:
3628 prout(_("Dummy! You can't leave standard orbit until you"))
3629 proutn(_("are back aboard the ship."))
3632 while navmode == "unspecified":
3633 if damaged(DNAVSYS):
3635 prout(_("Computer damaged; manual navigation only"))
3637 prout(_("Computer damaged; manual movement only"))
3642 key = scanner.next()
3644 proutn(_("Manual or automatic- "))
3647 elif key == "IHALPHA":
3648 if scanner.sees("manual"):
3650 key = scanner.next()
3652 elif scanner.sees("automatic"):
3653 navmode = "automatic"
3654 key = scanner.next()
3662 prout(_("(Manual navigation assumed.)"))
3664 prout(_("(Manual movement assumed.)"))
3668 if navmode == "automatic":
3669 while key == "IHEOL":
3671 proutn(_("Target quadrant or quadrant§or- "))
3673 proutn(_("Destination sector or quadrant§or- "))
3676 key = scanner.next()
3680 xi = int(round(scanner.real))-1
3681 key = scanner.next()
3685 xj = int(round(scanner.real))-1
3686 key = scanner.next()
3688 # both quadrant and sector specified
3689 xk = int(round(scanner.real))-1
3690 key = scanner.next()
3694 xl = int(round(scanner.real))-1
3700 # only one pair of numbers was specified
3702 # only quadrant specified -- go to center of dest quad
3705 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3707 # only sector specified
3711 if not dquad.valid_quadrant() or not dsect.valid_sector():
3718 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3720 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3721 # the actual deltas get computed here
3722 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3723 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3725 while key == "IHEOL":
3726 proutn(_("X and Y displacements- "))
3729 key = scanner.next()
3734 delta.j = scanner.real
3735 key = scanner.next()
3739 delta.i = scanner.real
3740 # Check for zero movement
3741 if delta.i == 0 and delta.j == 0:
3744 if itemp == "verbose" and not isprobe:
3746 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3748 return course(bearing=delta.bearing(), distance=delta.distance())
3751 def __init__(self, bearing, distance, origin=None):
3752 self.distance = distance
3753 self.bearing = bearing
3755 self.origin = cartesian(game.quadrant, game.sector)
3757 self.origin = origin
3758 # The bearing() code we inherited from FORTRAN is actually computing
3759 # clockface directions!
3760 if self.bearing < 0.0:
3761 self.bearing += 12.0
3762 self.angle = ((15.0 - self.bearing) * 0.5235988)
3764 self.origin = cartesian(game.quadrant, game.sector)
3766 self.origin = cartesian(game.quadrant, origin)
3767 self.increment = Coord(-math.sin(self.angle), math.cos(self.angle))
3768 bigger = max(abs(self.increment.i), abs(self.increment.j))
3769 self.increment /= bigger
3770 self.moves = int(round(10*self.distance*bigger))
3772 self.final = (self.location + self.moves*self.increment).roundtogrid()
3774 self.location = self.origin
3777 return self.location.roundtogrid() == self.final
3779 "Next step on course."
3781 self.nextlocation = self.location + self.increment
3782 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3783 self.location = self.nextlocation
3786 return self.location.quadrant()
3788 return self.location.sector()
3789 def power(self, warp):
3790 return self.distance*(warp**3)*(game.shldup+1)
3791 def time(self, warp):
3792 return 10.0*self.distance/warp**2
3795 "Move under impulse power."
3797 if damaged(DIMPULS):
3800 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3802 if game.energy > 30.0:
3804 course = getcourse(isprobe=False)
3807 power = 20.0 + 100.0*course.distance
3810 if power >= game.energy:
3811 # Insufficient power for trip
3813 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3814 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3815 if game.energy > 30:
3816 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3817 int(0.01 * (game.energy-20.0)-0.05))
3818 prout(_(" quadrants.\""))
3820 prout(_("quadrant. They are, therefore, useless.\""))
3823 # Make sure enough time is left for the trip
3824 game.optime = course.dist/0.095
3825 if game.optime >= game.state.remtime:
3826 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3827 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3828 proutn(_("we dare spend the time?\" "))
3831 # Activate impulse engines and pay the cost
3832 imove(course, noattack=False)
3836 power = 20.0 + 100.0*course.dist
3837 game.energy -= power
3838 game.optime = course.dist/0.095
3839 if game.energy <= 0:
3843 def warp(wcourse, involuntary):
3844 "ove under warp drive."
3845 blooey = False; twarp = False
3846 if not involuntary: # Not WARPX entry
3848 if game.damage[DWARPEN] > 10.0:
3851 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3853 if damaged(DWARPEN) and game.warpfac > 4.0:
3856 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3857 prout(_(" is repaired, I can only give you warp 4.\""))
3859 # Read in course and distance
3862 wcourse = getcourse(isprobe=False)
3865 # Make sure starship has enough energy for the trip
3866 # Note: this formula is slightly different from the C version,
3867 # and lets you skate a bit closer to the edge.
3868 if wcourse.power(game.warpfac) >= game.energy:
3869 # Insufficient power for trip
3872 prout(_("Engineering to bridge--"))
3873 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
3874 iwarp = (game.energy/(wcourse.dist+0.05)) ** 0.333333333
3876 prout(_("We can't do it, Captain. We don't have enough energy."))
3878 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3881 prout(_("if you'll lower the shields."))
3885 prout(_("We haven't the energy to go that far with the shields up."))
3887 # Make sure enough time is left for the trip
3888 game.optime = wcourse.time(game.warpfac)
3889 if game.optime >= 0.8*game.state.remtime:
3891 prout(_("First Officer Spock- \"Captain, I compute that such"))
3892 proutn(_(" a trip would require approximately %2.0f") %
3893 (100.0*game.optime/game.state.remtime))
3894 prout(_(" percent of our"))
3895 proutn(_(" remaining time. Are you sure this is wise?\" "))
3901 if game.warpfac > 6.0:
3902 # Decide if engine damage will occur
3903 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3904 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
3905 if prob > randreal():
3907 wcourse.distance = randreal(wcourse.distance)
3908 # Decide if time warp will occur
3909 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3911 if game.idebug and game.warpfac==10 and not twarp:
3913 proutn("=== Force time warp? ")
3917 # If time warp or engine damage, check path
3918 # If it is obstructed, don't do warp or damage
3919 look = wcourse.moves
3923 w = wcourse.sector()
3924 if not w.valid_sector():
3926 if game.quad[w.i][w.j] != '.':
3930 # Activate Warp Engines and pay the cost
3931 imove(wcourse, noattack=False)
3934 game.energy -= wcourse.power(game.warpfac)
3935 if game.energy <= 0:
3937 game.optime = wcourse.time(game.warpfac)
3941 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
3943 prout(_("Engineering to bridge--"))
3944 prout(_(" Scott here. The warp engines are damaged."))
3945 prout(_(" We'll have to reduce speed to warp 4."))
3950 "Change the warp factor."
3956 proutn(_("Warp factor- "))
3960 if game.damage[DWARPEN] > 10.0:
3961 prout(_("Warp engines inoperative."))
3963 if damaged(DWARPEN) and scanner.real > 4.0:
3964 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
3965 prout(_(" but right now we can only go warp 4.\""))
3967 if scanner.real > 10.0:
3968 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
3970 if scanner.real < 1.0:
3971 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
3973 oldfac = game.warpfac
3974 game.warpfac = scanner.real
3975 if game.warpfac <= oldfac or game.warpfac <= 6.0:
3976 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
3979 if game.warpfac < 8.00:
3980 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
3982 if game.warpfac == 10.0:
3983 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
3985 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
3989 "Cope with being tossed out of quadrant by supernova or yanked by beam."
3991 # is captain on planet?
3993 if damaged(DTRANSP):
3996 prout(_("Scotty rushes to the transporter controls."))
3998 prout(_("But with the shields up it's hopeless."))
4000 prouts(_("His desperate attempt to rescue you . . ."))
4005 prout(_("SUCCEEDS!"))
4008 proutn(_("The crystals mined were "))
4016 # Check to see if captain in shuttle craft
4021 # Inform captain of attempt to reach safety
4025 prouts(_("***RED ALERT! RED ALERT!"))
4027 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4028 prouts(_(" a supernova."))
4030 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4031 prout(_("safely out of quadrant."))
4032 if not damaged(DRADIO):
4033 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4034 # Try to use warp engines
4035 if damaged(DWARPEN):
4037 prout(_("Warp engines damaged."))
4040 game.warpfac = randreal(6.0, 8.0)
4041 prout(_("Warp factor set to %d") % int(game.warpfac))
4042 power = 0.75*game.energy
4043 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4044 dist = max(dist, randreal(math.sqrt(2)))
4045 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4046 game.optime = bugout.time(game.warpfac)
4048 game.inorbit = False
4049 warp(bugout, involuntary=True)
4051 # This is bad news, we didn't leave quadrant.
4055 prout(_("Insufficient energy to leave quadrant."))
4058 # Repeat if another snova
4059 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4061 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4062 finish(FWON) # Snova killed remaining enemy.
4065 "Let's do the time warp again."
4066 prout(_("***TIME WARP ENTERED."))
4067 if game.state.snap and withprob(0.5):
4069 prout(_("You are traveling backwards in time %d stardates.") %
4070 int(game.state.date-game.snapsht.date))
4071 game.state = game.snapsht
4072 game.state.snap = False
4073 if len(game.state.kcmdr):
4074 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4075 schedule(FBATTAK, expran(0.3*game.intime))
4076 schedule(FSNOVA, expran(0.5*game.intime))
4077 # next snapshot will be sooner
4078 schedule(FSNAP, expran(0.25*game.state.remtime))
4080 if game.state.nscrem:
4081 schedule(FSCMOVE, 0.2777)
4085 game.battle.invalidate()
4086 # Make sure Galileo is consistant -- Snapshot may have been taken
4087 # when on planet, which would give us two Galileos!
4089 for l in range(game.inplan):
4090 if game.state.planets[l].known == "shuttle_down":
4092 if game.iscraft == "onship" and game.ship=='E':
4093 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4094 game.iscraft = "offship"
4095 # Likewise, if in the original time the Galileo was abandoned, but
4096 # was on ship earlier, it would have vanished -- let's restore it.
4097 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4098 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4099 game.iscraft = "onship"
4100 # There used to be code to do the actual reconstrction here,
4101 # but the starchart is now part of the snapshotted galaxy state.
4102 prout(_("Spock has reconstructed a correct star chart from memory"))
4104 # Go forward in time
4105 game.optime = expran(0.5*game.intime)
4106 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4107 # cheat to make sure no tractor beams occur during time warp
4108 postpone(FTBEAM, game.optime)
4109 game.damage[DRADIO] += game.optime
4111 events() # Stas Sergeev added this -- do pending events
4114 "Launch deep-space probe."
4115 # New code to launch a deep space probe
4116 if game.nprobes == 0:
4119 if game.ship == 'E':
4120 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4122 prout(_("Ye Faerie Queene has no deep space probes."))
4127 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4129 if is_scheduled(FDSPROB):
4132 if damaged(DRADIO) and game.condition != "docked":
4133 prout(_("Spock- \"Records show the previous probe has not yet"))
4134 prout(_(" reached its destination.\""))
4136 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4138 key = scanner.next()
4140 if game.nprobes == 1:
4141 prout(_("1 probe left."))
4143 prout(_("%d probes left") % game.nprobes)
4144 proutn(_("Are you sure you want to fire a probe? "))
4147 game.isarmed = False
4148 if key == "IHALPHA" and scanner.token == "armed":
4150 key = scanner.next()
4151 elif key == "IHEOL":
4152 proutn(_("Arm NOVAMAX warhead? "))
4154 elif key == "IHREAL": # first element of course
4155 scanner.push(scanner.token)
4157 game.probe = getcourse(isprobe=True)
4161 schedule(FDSPROB, 0.01) # Time to move one sector
4162 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4167 "Yell for help from nearest starbase."
4168 # There's more than one way to move in this game!
4170 # Test for conditions which prevent calling for help
4171 if game.condition == "docked":
4172 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4175 prout(_("Subspace radio damaged."))
4177 if not game.state.baseq:
4178 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4181 prout(_("You must be aboard the %s.") % crmshp())
4183 # OK -- call for help from nearest starbase
4186 # There's one in this quadrant
4187 ddist = (game.base - game.sector).distance()
4190 for ibq in game.state.baseq:
4191 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4194 # Since starbase not in quadrant, set up new quadrant
4197 # dematerialize starship
4198 game.quad[game.sector.i][game.sector.j]='.'
4199 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4200 % (game.quadrant, crmshp()))
4201 game.sector.invalidate()
4202 for m in range(1, 5+1):
4203 w = game.base.scatter()
4204 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4205 # found one -- finish up
4208 if not game.sector.is_valid():
4209 prout(_("You have been lost in space..."))
4210 finish(FMATERIALIZE)
4212 # Give starbase three chances to rematerialize starship
4213 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4214 for m in range(1, 3+1):
4215 if m == 1: proutn(_("1st"))
4216 elif m == 2: proutn(_("2nd"))
4217 elif m == 3: proutn(_("3rd"))
4218 proutn(_(" attempt to re-materialize ") + crmshp())
4219 game.quad[game.sector.i][game.sector.j]=('-','o','O')[m-1]
4222 if randreal() > probf:
4226 curses.delay_output(500)
4228 game.quad[game.sector.i][game.sector.j]='?'
4231 setwnd(message_window)
4232 finish(FMATERIALIZE)
4234 game.quad[game.sector.i][game.sector.j]=game.ship
4236 prout(_("succeeds."))
4240 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4245 if game.condition=="docked":
4247 prout(_("You cannot abandon Ye Faerie Queene."))
4250 # Must take shuttle craft to exit
4251 if game.damage[DSHUTTL]==-1:
4252 prout(_("Ye Faerie Queene has no shuttle craft."))
4254 if game.damage[DSHUTTL]<0:
4255 prout(_("Shuttle craft now serving Big Macs."))
4257 if game.damage[DSHUTTL]>0:
4258 prout(_("Shuttle craft damaged."))
4261 prout(_("You must be aboard the ship."))
4263 if game.iscraft != "onship":
4264 prout(_("Shuttle craft not currently available."))
4266 # Emit abandon ship messages
4268 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4270 prouts(_("***ALL HANDS ABANDON SHIP!"))
4272 prout(_("Captain and crew escape in shuttle craft."))
4273 if not game.state.baseq:
4274 # Oops! no place to go...
4277 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4279 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4280 prout(_("Remainder of ship's complement beam down"))
4281 prout(_("to nearest habitable planet."))
4282 elif q.planet != None and not damaged(DTRANSP):
4283 prout(_("Remainder of ship's complement beam down to %s.") %
4286 prout(_("Entire crew of %d left to die in outer space.") %
4288 game.casual += game.state.crew
4289 game.abandoned += game.state.crew
4290 # If at least one base left, give 'em the Faerie Queene
4292 game.icrystl = False # crystals are lost
4293 game.nprobes = 0 # No probes
4294 prout(_("You are captured by Klingons and released to"))
4295 prout(_("the Federation in a prisoner-of-war exchange."))
4296 nb = randrange(len(game.state.baseq))
4297 # Set up quadrant and position FQ adjacient to base
4298 if not game.quadrant == game.state.baseq[nb]:
4299 game.quadrant = game.state.baseq[nb]
4300 game.sector.i = game.sector.j = 5
4303 # position next to base by trial and error
4304 game.quad[game.sector.i][game.sector.j] = '.'
4305 for l in range(QUADSIZE):
4306 game.sector = game.base.scatter()
4307 if game.sector.valid_sector() and \
4308 game.quad[game.sector.i][game.sector.j] == '.':
4311 break # found a spot
4312 game.sector.i=QUADSIZE/2
4313 game.sector.j=QUADSIZE/2
4315 # Get new commission
4316 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4317 game.state.crew = FULLCREW
4318 prout(_("Starfleet puts you in command of another ship,"))
4319 prout(_("the Faerie Queene, which is antiquated but,"))
4320 prout(_("still useable."))
4322 prout(_("The dilithium crystals have been moved."))
4324 game.iscraft = "offship" # Galileo disappears
4326 game.condition="docked"
4327 for l in range(NDEVICES):
4328 game.damage[l] = 0.0
4329 game.damage[DSHUTTL] = -1
4330 game.energy = game.inenrg = 3000.0
4331 game.shield = game.inshld = 1250.0
4332 game.torps = game.intorps = 6
4333 game.lsupres=game.inlsr=3.0
4338 # Code from planets.c begins here.
4341 "Abort a lengthy operation if an event interrupts it."
4344 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4349 "Report on (uninhabited) planets in the galaxy."
4353 prout(_("Spock- \"Planet report follows, Captain.\""))
4355 for i in range(game.inplan):
4356 if game.state.planets[i].pclass == "destroyed":
4358 if (game.state.planets[i].known != "unknown" \
4359 and not game.state.planets[i].inhabited) \
4362 if game.idebug and game.state.planets[i].known=="unknown":
4363 proutn("(Unknown) ")
4364 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4365 proutn(_(" class "))
4366 proutn(game.state.planets[i].pclass)
4368 if game.state.planets[i].crystals != "present":
4370 prout(_("dilithium crystals present."))
4371 if game.state.planets[i].known=="shuttle_down":
4372 prout(_(" Shuttle Craft Galileo on surface."))
4374 prout(_("No information available."))
4377 "Enter standard orbit."
4381 prout(_("Already in standard orbit."))
4383 if damaged(DWARPEN) and damaged(DIMPULS):
4384 prout(_("Both warp and impulse engines damaged."))
4386 if not game.plnet.is_valid():
4387 prout("There is no planet in this sector.")
4389 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4390 prout(crmshp() + _(" not adjacent to planet."))
4393 game.optime = randreal(0.02, 0.05)
4394 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4398 game.height = randreal(1400, 8600)
4399 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4404 "Examine planets in this quadrant."
4405 if damaged(DSRSENS):
4406 if game.options & OPTION_TTY:
4407 prout(_("Short range sensors damaged."))
4409 if game.iplnet == None:
4410 if game.options & OPTION_TTY:
4411 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4413 if game.iplnet.known == "unknown":
4414 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4416 prout(_(" Planet at Sector %s is of class %s.") %
4417 (game.plnet, game.iplnet.pclass))
4418 if game.iplnet.known=="shuttle_down":
4419 prout(_(" Sensors show Galileo still on surface."))
4420 proutn(_(" Readings indicate"))
4421 if game.iplnet.crystals != "present":
4423 prout(_(" dilithium crystals present.\""))
4424 if game.iplnet.known == "unknown":
4425 game.iplnet.known = "known"
4426 elif game.iplnet.inhabited:
4427 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4428 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4431 "Use the transporter."
4435 if damaged(DTRANSP):
4436 prout(_("Transporter damaged."))
4437 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4439 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4443 if not game.inorbit:
4444 prout(crmshp() + _(" not in standard orbit."))
4447 prout(_("Impossible to transport through shields."))
4449 if game.iplnet.known=="unknown":
4450 prout(_("Spock- \"Captain, we have no information on this planet"))
4451 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4452 prout(_(" you may not go down.\""))
4454 if not game.landed and game.iplnet.crystals=="absent":
4455 prout(_("Spock- \"Captain, I fail to see the logic in"))
4456 prout(_(" exploring a planet with no dilithium crystals."))
4457 proutn(_(" Are you sure this is wise?\" "))
4461 if not (game.options & OPTION_PLAIN):
4462 nrgneed = 50 * game.skill + game.height / 100.0
4463 if nrgneed > game.energy:
4464 prout(_("Engineering to bridge--"))
4465 prout(_(" Captain, we don't have enough energy for transportation."))
4467 if not game.landed and nrgneed * 2 > game.energy:
4468 prout(_("Engineering to bridge--"))
4469 prout(_(" Captain, we have enough energy only to transport you down to"))
4470 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4471 if game.iplnet.known == "shuttle_down":
4472 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4473 proutn(_(" Are you sure this is wise?\" "))
4478 # Coming from planet
4479 if game.iplnet.known=="shuttle_down":
4480 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4484 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4485 prout(_("Landing party assembled, ready to beam up."))
4487 prout(_("Kirk whips out communicator..."))
4488 prouts(_("BEEP BEEP BEEP"))
4490 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4493 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4495 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4497 prout(_("Kirk- \"Energize.\""))
4500 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4503 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4505 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4508 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4509 game.landed = not game.landed
4510 game.energy -= nrgneed
4512 prout(_("Transport complete."))
4513 if game.landed and game.iplnet.known=="shuttle_down":
4514 prout(_("The shuttle craft Galileo is here!"))
4515 if not game.landed and game.imine:
4522 "Strip-mine a world for dilithium."
4526 prout(_("Mining party not on planet."))
4528 if game.iplnet.crystals == "mined":
4529 prout(_("This planet has already been strip-mined for dilithium."))
4531 elif game.iplnet.crystals == "absent":
4532 prout(_("No dilithium crystals on this planet."))
4535 prout(_("You've already mined enough crystals for this trip."))
4537 if game.icrystl and game.cryprob == 0.05:
4538 prout(_("With all those fresh crystals aboard the ") + crmshp())
4539 prout(_("there's no reason to mine more at this time."))
4541 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4544 prout(_("Mining operation complete."))
4545 game.iplnet.crystals = "mined"
4546 game.imine = game.ididit = True
4549 "Use dilithium crystals."
4553 if not game.icrystl:
4554 prout(_("No dilithium crystals available."))
4556 if game.energy >= 1000:
4557 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4558 prout(_(" except when Condition Yellow exists."))
4560 prout(_("Spock- \"Captain, I must warn you that loading"))
4561 prout(_(" raw dilithium crystals into the ship's power"))
4562 prout(_(" system may risk a severe explosion."))
4563 proutn(_(" Are you sure this is wise?\" "))
4568 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4569 prout(_(" Mr. Spock and I will try it.\""))
4571 prout(_("Spock- \"Crystals in place, Sir."))
4572 prout(_(" Ready to activate circuit.\""))
4574 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4576 if withprob(game.cryprob):
4577 prouts(_(" \"Activating now! - - No good! It's***"))
4579 prouts(_("***RED ALERT! RED A*L********************************"))
4582 prouts(_("****************** KA-BOOM!!!! *******************"))
4586 game.energy += randreal(5000.0, 5500.0)
4587 prouts(_(" \"Activating now! - - "))
4588 prout(_("The instruments"))
4589 prout(_(" are going crazy, but I think it's"))
4590 prout(_(" going to work!! Congratulations, Sir!\""))
4595 "Use shuttlecraft for planetary jaunt."
4598 if damaged(DSHUTTL):
4599 if game.damage[DSHUTTL] == -1.0:
4600 if game.inorbit and game.iplnet.known == "shuttle_down":
4601 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4603 prout(_("Ye Faerie Queene had no shuttle craft."))
4604 elif game.damage[DSHUTTL] > 0:
4605 prout(_("The Galileo is damaged."))
4606 else: # game.damage[DSHUTTL] < 0
4607 prout(_("Shuttle craft is now serving Big Macs."))
4609 if not game.inorbit:
4610 prout(crmshp() + _(" not in standard orbit."))
4612 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4613 prout(_("Shuttle craft not currently available."))
4615 if not game.landed and game.iplnet.known=="shuttle_down":
4616 prout(_("You will have to beam down to retrieve the shuttle craft."))
4618 if game.shldup or game.condition == "docked":
4619 prout(_("Shuttle craft cannot pass through shields."))
4621 if game.iplnet.known=="unknown":
4622 prout(_("Spock- \"Captain, we have no information on this planet"))
4623 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4624 prout(_(" you may not fly down.\""))
4626 game.optime = 3.0e-5*game.height
4627 if game.optime >= 0.8*game.state.remtime:
4628 prout(_("First Officer Spock- \"Captain, I compute that such"))
4629 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4630 int(100*game.optime/game.state.remtime))
4631 prout(_("remaining time."))
4632 proutn(_("Are you sure this is wise?\" "))
4638 if game.iscraft == "onship":
4640 if not damaged(DTRANSP):
4641 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4645 proutn(_("Shuttle crew"))
4647 proutn(_("Rescue party"))
4648 prout(_(" boards Galileo and swoops toward planet surface."))
4649 game.iscraft = "offship"
4653 game.iplnet.known="shuttle_down"
4654 prout(_("Trip complete."))
4657 # Ready to go back to ship
4658 prout(_("You and your mining party board the"))
4659 prout(_("shuttle craft for the trip back to the Enterprise."))
4661 prouts(_("The short hop begins . . ."))
4663 game.iplnet.known="known"
4669 game.iscraft = "onship"
4675 prout(_("Trip complete."))
4678 # Kirk on ship and so is Galileo
4679 prout(_("Mining party assembles in the hangar deck,"))
4680 prout(_("ready to board the shuttle craft \"Galileo\"."))
4682 prouts(_("The hangar doors open; the trip begins."))
4685 game.iscraft = "offship"
4688 game.iplnet.known = "shuttle_down"
4691 prout(_("Trip complete."))
4695 "Use the big zapper."
4699 if game.ship != 'E':
4700 prout(_("Ye Faerie Queene has no death ray."))
4702 if len(game.enemies)==0:
4703 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4706 prout(_("Death Ray is damaged."))
4708 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4709 prout(_(" is highly unpredictible. Considering the alternatives,"))
4710 proutn(_(" are you sure this is wise?\" "))
4713 prout(_("Spock- \"Acknowledged.\""))
4716 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4718 prout(_("Crew scrambles in emergency preparation."))
4719 prout(_("Spock and Scotty ready the death ray and"))
4720 prout(_("prepare to channel all ship's power to the device."))
4722 prout(_("Spock- \"Preparations complete, sir.\""))
4723 prout(_("Kirk- \"Engage!\""))
4725 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4728 if game.options & OPTION_PLAIN:
4732 prouts(_("Sulu- \"Captain! It's working!\""))
4734 while len(game.enemies) > 0:
4735 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4736 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4737 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4739 if (game.options & OPTION_PLAIN) == 0:
4740 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4742 prout(_(" is still operational.\""))
4744 prout(_(" has been rendered nonfunctional.\""))
4745 game.damage[DDRAY] = 39.95
4747 r = randreal() # Pick failure method
4749 prouts(_("Sulu- \"Captain! It's working!\""))
4751 prouts(_("***RED ALERT! RED ALERT!"))
4753 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4755 prouts(_("***RED ALERT! RED A*L********************************"))
4758 prouts(_("****************** KA-BOOM!!!! *******************"))
4763 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4765 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4767 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4768 prout(_(" have apparently been transformed into strange mutations."))
4769 prout(_(" Vulcans do not seem to be affected."))
4771 prout(_("Kirk- \"Raauch! Raauch!\""))
4775 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4777 proutn(_("Spock- \"I believe the word is"))
4778 prouts(_(" *ASTONISHING*"))
4779 prout(_(" Mr. Sulu."))
4780 for i in range(QUADSIZE):
4781 for j in range(QUADSIZE):
4782 if game.quad[i][j] == '.':
4783 game.quad[i][j] = '?'
4784 prout(_(" Captain, our quadrant is now infested with"))
4785 prouts(_(" - - - - - - *THINGS*."))
4787 prout(_(" I have no logical explanation.\""))
4789 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4791 prout(_("Scotty- \"There are so many tribbles down here"))
4792 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4796 # Code from reports.c begins here
4798 def attackreport(curt):
4799 "eport status of bases under attack."
4801 if is_scheduled(FCDBAS):
4802 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4803 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4804 elif game.isatb == 1:
4805 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4806 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4808 prout(_("No Starbase is currently under attack."))
4810 if is_scheduled(FCDBAS):
4811 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4813 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4817 # report on general game status
4819 s1 = (game.thawed and _("thawed ")) or ""
4820 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4821 s3 = (None, _("novice"), _("fair"),
4822 _("good"), _("expert"), _("emeritus"))[game.skill]
4823 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4824 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4825 prout(_("No plaque is allowed."))
4827 prout(_("This is tournament game %d.") % game.tourn)
4828 prout(_("Your secret password is \"%s\"") % game.passwd)
4829 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4830 (game.inkling + game.incom + game.inscom)))
4831 if game.incom - len(game.state.kcmdr):
4832 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4833 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4834 prout(_(", but no Commanders."))
4837 if game.skill > SKILL_FAIR:
4838 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4839 if len(game.state.baseq) != game.inbase:
4841 if game.inbase-len(game.state.baseq)==1:
4842 proutn(_("has been 1 base"))
4844 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4845 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4847 prout(_("There are %d bases.") % game.inbase)
4848 if communicating() or game.iseenit:
4849 # Don't report this if not seen and
4850 # either the radio is dead or not at base!
4854 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4856 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4857 if game.ship == 'E':
4858 proutn(_("You have "))
4860 proutn("%d" % (game.nprobes))
4863 proutn(_(" deep space probe"))
4867 if communicating() and is_scheduled(FDSPROB):
4869 proutn(_("An armed deep space probe is in "))
4871 proutn(_("A deep space probe is in "))
4872 prout("Quadrant %s." % game.probec)
4874 if game.cryprob <= .05:
4875 prout(_("Dilithium crystals aboard ship... not yet used."))
4879 while game.cryprob > ai:
4882 prout(_("Dilithium crystals have been used %d time%s.") % \
4883 (i, (_("s"), "")[i==1]))
4887 "Long-range sensor scan."
4888 if damaged(DLRSENS):
4889 # Now allow base's sensors if docked
4890 if game.condition != "docked":
4892 prout(_("LONG-RANGE SENSORS DAMAGED."))
4895 prout(_("Starbase's long-range scan"))
4897 prout(_("Long-range scan"))
4898 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4901 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4902 if not Coord(x, y).valid_quadrant():
4906 if not damaged(DRADIO):
4907 game.state.galaxy[x][y].charted = True
4908 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4909 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4910 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4911 if not silent and game.state.galaxy[x][y].supernova:
4914 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4922 for i in range(NDEVICES):
4925 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4926 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4928 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4929 game.damage[i]+0.05,
4930 DOCKFAC*game.damage[i]+0.005))
4932 prout(_("All devices functional."))
4935 "Update the chart in the Enterprise's computer from galaxy data."
4936 game.lastchart = game.state.date
4937 for i in range(GALSIZE):
4938 for j in range(GALSIZE):
4939 if game.state.galaxy[i][j].charted:
4940 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
4941 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
4942 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
4945 "Display the star chart."
4947 if (game.options & OPTION_AUTOSCAN):
4949 if not damaged(DRADIO):
4951 if game.lastchart < game.state.date and game.condition == "docked":
4952 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
4954 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
4955 if game.state.date > game.lastchart:
4956 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
4957 prout(" 1 2 3 4 5 6 7 8")
4958 for i in range(GALSIZE):
4959 proutn("%d |" % (i+1))
4960 for j in range(GALSIZE):
4961 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4965 if game.state.galaxy[i][j].supernova:
4967 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
4969 elif game.state.galaxy[i][j].charted:
4970 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
4974 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4982 def sectscan(goodScan, i, j):
4983 "Light up an individual dot in a sector."
4984 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
4985 textcolor({"green":GREEN,
4989 "dead":BROWN}[game.condition])
4990 if game.quad[i][j] != game.ship:
4992 proutn("%c " % game.quad[i][j])
4998 "Emit status report lines"
4999 if not req or req == 1:
5000 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5001 % (game.state.date, game.state.remtime))
5002 if not req or req == 2:
5003 if game.condition != "docked":
5005 prstat(_("Condition"), _("%s, %i DAMAGES") % \
5006 (game.condition.upper(), sum(map(lambda x: x > 0, game.damage))))
5007 if not req or req == 3:
5008 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5009 if not req or req == 4:
5010 if damaged(DLIFSUP):
5011 if game.condition == "docked":
5012 s = _("DAMAGED, Base provides")
5014 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
5017 prstat(_("Life Support"), s)
5018 if not req or req == 5:
5019 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
5020 if not req or req == 6:
5022 if game.icrystl and (game.options & OPTION_SHOWME):
5023 extra = _(" (have crystals)")
5024 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
5025 if not req or req == 7:
5026 prstat(_("Torpedoes"), "%d" % (game.torps))
5027 if not req or req == 8:
5028 if damaged(DSHIELD):
5034 data = _(" %d%% %.1f units") \
5035 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5036 prstat(_("Shields"), s+data)
5037 if not req or req == 9:
5038 prstat(_("Klingons Left"), "%d" \
5039 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5040 if not req or req == 10:
5041 if game.options & OPTION_WORLDS:
5042 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5043 if plnet and plnet.inhabited:
5044 prstat(_("Major system"), plnet.name)
5046 prout(_("Sector is uninhabited"))
5047 elif not req or req == 11:
5048 attackreport(not req)
5051 "Request specified status data, a historical relic from slow TTYs."
5052 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5053 while scanner.next() == "IHEOL":
5054 proutn(_("Information desired? "))
5056 if scanner.token in requests:
5057 status(requests.index(scanner.token))
5059 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5060 prout((" date, condition, position, lsupport, warpfactor,"))
5061 prout((" energy, torpedoes, shields, klingons, system, time."))
5066 if damaged(DSRSENS):
5067 # Allow base's sensors if docked
5068 if game.condition != "docked":
5069 prout(_(" S.R. SENSORS DAMAGED!"))
5072 prout(_(" [Using Base's sensors]"))
5074 prout(_(" Short-range scan"))
5075 if goodScan and not damaged(DRADIO):
5076 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5077 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5078 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5079 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5080 prout(" 1 2 3 4 5 6 7 8 9 10")
5081 if game.condition != "docked":
5083 for i in range(QUADSIZE):
5084 proutn("%2d " % (i+1))
5085 for j in range(QUADSIZE):
5086 sectscan(goodScan, i, j)
5090 "Use computer to get estimated time of arrival for a warp jump."
5091 w1 = Coord(); w2 = Coord()
5093 if damaged(DCOMPTR):
5094 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5097 if scanner.next() != "IHREAL":
5100 proutn(_("Destination quadrant and/or sector? "))
5101 if scanner.next()!="IHREAL":
5104 w1.j = int(scanner.real-0.5)
5105 if scanner.next() != "IHREAL":
5108 w1.i = int(scanner.real-0.5)
5109 if scanner.next() == "IHREAL":
5110 w2.j = int(scanner.real-0.5)
5111 if scanner.next() != "IHREAL":
5114 w2.i = int(scanner.real-0.5)
5116 if game.quadrant.j>w1.i:
5120 if game.quadrant.i>w1.j:
5124 if not w1.valid_quadrant() or not w2.valid_sector():
5127 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5128 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5131 prout(_("Answer \"no\" if you don't know the value:"))
5134 proutn(_("Time or arrival date? "))
5135 if scanner.next()=="IHREAL":
5136 ttime = scanner.real
5137 if ttime > game.state.date:
5138 ttime -= game.state.date # Actually a star date
5139 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5140 if ttime <= 1e-10 or twarp > 10:
5141 prout(_("We'll never make it, sir."))
5148 proutn(_("Warp factor? "))
5149 if scanner.next()== "IHREAL":
5151 twarp = scanner.real
5152 if twarp<1.0 or twarp > 10.0:
5156 prout(_("Captain, certainly you can give me one of these."))
5159 ttime = (10.0*dist)/twarp**2
5160 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5161 if tpower >= game.energy:
5162 prout(_("Insufficient energy, sir."))
5163 if not game.shldup or tpower > game.energy*2.0:
5166 proutn(_("New warp factor to try? "))
5167 if scanner.next() == "IHREAL":
5169 twarp = scanner.real
5170 if twarp<1.0 or twarp > 10.0:
5178 prout(_("But if you lower your shields,"))
5179 proutn(_("remaining"))
5182 proutn(_("Remaining"))
5183 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5185 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5187 prout(_("Any warp speed is adequate."))
5189 prout(_("Minimum warp needed is %.2f,") % (twarp))
5190 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5191 if game.state.remtime < ttime:
5192 prout(_("Unfortunately, the Federation will be destroyed by then."))
5194 prout(_("You'll be taking risks at that speed, Captain"))
5195 if (game.isatb==1 and game.state.kscmdr == w1 and \
5196 scheduled(FSCDBAS)< ttime+game.state.date) or \
5197 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5198 prout(_("The starbase there will be destroyed by then."))
5199 proutn(_("New warp factor to try? "))
5200 if scanner.next() == "IHREAL":
5202 twarp = scanner.real
5203 if twarp<1.0 or twarp > 10.0:
5211 # Code from setup.c begins here
5214 "Issue a historically correct banner."
5216 prout(_("-SUPER- STAR TREK"))
5218 # From the FORTRAN original
5219 # prout(_("Latest update-21 Sept 78"))
5225 scanner.push("emsave.trk")
5226 key = scanner.next()
5228 proutn(_("File name: "))
5229 key = scanner.next()
5230 if key != "IHALPHA":
5233 if '.' not in scanner.token:
5234 scanner.token += ".trk"
5236 fp = open(scanner.token, "wb")
5238 prout(_("Can't freeze game as file %s") % scanner.token)
5240 cPickle.dump(game, fp)
5245 "Retrieve saved game."
5248 key = scanner.next()
5250 proutn(_("File name: "))
5251 key = scanner.next()
5252 if key != "IHALPHA":
5255 if '.' not in scanner.token:
5256 scanner.token += ".trk"
5258 fp = open(scanner.token, "rb")
5260 prout(_("Can't thaw game in %s") % scanner.token)
5262 game = cPickle.load(fp)
5267 # I used <http://www.memory-alpha.org> to find planets
5268 # with references in ST:TOS. Earth and the Alpha Centauri
5269 # Colony have been omitted.
5271 # Some planets marked Class G and P here will be displayed as class M
5272 # because of the way planets are generated. This is a known bug.
5275 _("Andoria (Fesoan)"), # several episodes
5276 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5277 _("Vulcan (T'Khasi)"), # many episodes
5278 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5279 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5280 _("Ardana"), # TOS: "The Cloud Minders"
5281 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5282 _("Gideon"), # TOS: "The Mark of Gideon"
5283 _("Aldebaran III"), # TOS: "The Deadly Years"
5284 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5285 _("Altair IV"), # TOS: "Amok Time
5286 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5287 _("Benecia"), # TOS: "The Conscience of the King"
5288 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5289 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5290 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5291 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5292 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5293 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5294 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5295 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5296 _("Ingraham B"), # TOS: "Operation: Annihilate"
5297 _("Janus IV"), # TOS: "The Devil in the Dark"
5298 _("Makus III"), # TOS: "The Galileo Seven"
5299 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5300 _("Omega IV"), # TOS: "The Omega Glory"
5301 _("Regulus V"), # TOS: "Amok Time
5302 _("Deneva"), # TOS: "Operation -- Annihilate!"
5303 # Worlds from BSD Trek
5304 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5305 _("Beta III"), # TOS: "The Return of the Archons"
5306 _("Triacus"), # TOS: "And the Children Shall Lead",
5307 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5309 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5310 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5311 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5312 # _("Izar"), # TOS: "Whom Gods Destroy"
5313 # _("Tiburon"), # TOS: "The Way to Eden"
5314 # _("Merak II"), # TOS: "The Cloud Minders"
5315 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5316 # _("Iotia"), # TOS: "A Piece of the Action"
5320 _("S. R. Sensors"), \
5321 _("L. R. Sensors"), \
5323 _("Photon Tubes"), \
5324 _("Life Support"), \
5325 _("Warp Engines"), \
5326 _("Impulse Engines"), \
5328 _("Subspace Radio"), \
5329 _("Shuttle Craft"), \
5331 _("Navigation System"), \
5333 _("Shield Control"), \
5339 "Prepare to play, set up cosmos."
5341 # Decide how many of everything
5343 return # frozen game
5344 # Prepare the Enterprise
5345 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5347 game.state.crew = FULLCREW
5348 game.energy = game.inenrg = 5000.0
5349 game.shield = game.inshld = 2500.0
5352 game.quadrant = randplace(GALSIZE)
5353 game.sector = randplace(QUADSIZE)
5354 game.torps = game.intorps = 10
5355 game.nprobes = randrange(2, 5)
5357 for i in range(NDEVICES):
5358 game.damage[i] = 0.0
5359 # Set up assorted game parameters
5360 game.battle = Coord()
5361 game.state.date = game.indate = 100.0 * randreal(20, 51)
5362 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5363 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5364 game.isatb = game.state.nplankl = 0
5365 game.state.starkl = game.state.basekl = game.state.nworldkl = 0
5366 game.iscraft = "onship"
5371 game.state.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: Quadrant())
5373 game.state.chart = fill2d(GALSIZE, lambda i_unused, j_unused: Page())
5375 game.state.planets = [] # Planet information
5376 game.state.baseq = [] # Base quadrant coordinates
5377 game.state.kcmdr = [] # Commander quadrant coordinates
5378 game.statekscmdr = Coord() # Supercommander quadrant coordinates
5380 # Starchart is functional but we've never seen it
5381 game.lastchart = FOREVER
5382 # Put stars in the galaxy
5384 for i in range(GALSIZE):
5385 for j in range(GALSIZE):
5386 k = randrange(1, QUADSIZE**2/10+1)
5388 game.state.galaxy[i][j].stars = k
5389 # Locate star bases in galaxy
5390 for i in range(game.inbase):
5393 w = randplace(GALSIZE)
5394 if not game.state.galaxy[w.i][w.j].starbase:
5397 # C version: for (j = i-1; j > 0; j--)
5398 # so it did them in the opposite order.
5399 for j in range(1, i):
5400 # Improved placement algorithm to spread out bases
5401 distq = (w - game.state.baseq[j]).distance()
5402 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5405 prout("=== Abandoning base #%d at %s" % (i, w))
5407 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5409 prout("=== Saving base #%d, close to #%d" % (i, j))
5412 game.state.baseq.append(w)
5413 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5414 # Position ordinary Klingon Battle Cruisers
5416 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5417 if klumper > MAXKLQUAD:
5421 klump = (1.0 - r*r)*klumper
5426 w = randplace(GALSIZE)
5427 if not game.state.galaxy[w.i][w.j].supernova and \
5428 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5430 game.state.galaxy[w.i][w.j].klingons += int(klump)
5433 # Position Klingon Commander Ships
5434 for i in range(game.incom):
5436 w = randplace(GALSIZE)
5437 if not welcoming(w) or w in game.state.kcmdr:
5439 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5441 game.state.galaxy[w.i][w.j].klingons += 1
5442 game.state.kcmdr.append(w)
5443 # Locate planets in galaxy
5444 for i in range(game.inplan):
5446 w = randplace(GALSIZE)
5447 if game.state.galaxy[w.i][w.j].planet == None:
5451 new.crystals = "absent"
5452 if (game.options & OPTION_WORLDS) and i < NINHAB:
5453 new.pclass = "M" # All inhabited planets are class M
5454 new.crystals = "absent"
5456 new.name = systnames[i]
5457 new.inhabited = True
5459 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5461 new.crystals = "present"
5462 new.known = "unknown"
5463 new.inhabited = False
5464 game.state.galaxy[w.i][w.j].planet = new
5465 game.state.planets.append(new)
5467 for i in range(game.state.nromrem):
5468 w = randplace(GALSIZE)
5469 game.state.galaxy[w.i][w.j].romulans += 1
5470 # Place the Super-Commander if needed
5471 if game.state.nscrem > 0:
5473 w = randplace(GALSIZE)
5476 game.state.kscmdr = w
5477 game.state.galaxy[w.i][w.j].klingons += 1
5478 # Initialize times for extraneous events
5479 schedule(FSNOVA, expran(0.5 * game.intime))
5480 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5481 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5482 schedule(FBATTAK, expran(0.3*game.intime))
5484 if game.state.nscrem:
5485 schedule(FSCMOVE, 0.2777)
5490 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5491 schedule(FDISTR, expran(1.0 + game.intime))
5496 # Place thing (in tournament game, we don't want one!)
5497 # New in SST2K: never place the Thing near a starbase.
5498 # This makes sense and avoids a special case in the old code.
5500 if game.tourn is None:
5502 thing = randplace(GALSIZE)
5503 if thing not in game.state.baseq:
5506 game.state.snap = False
5507 if game.skill == SKILL_NOVICE:
5508 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5509 prout(_("a deadly Klingon invasion force. As captain of the United"))
5510 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5511 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5512 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5513 prout(_("your mission. As you proceed you may be given more time."))
5515 prout(_("You will have %d supporting starbases.") % (game.inbase))
5516 proutn(_("Starbase locations- "))
5518 prout(_("Stardate %d.") % int(game.state.date))
5520 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5521 prout(_("An unknown number of Romulans."))
5522 if game.state.nscrem:
5523 prout(_("And one (GULP) Super-Commander."))
5524 prout(_("%d stardates.") % int(game.intime))
5525 proutn(_("%d starbases in ") % game.inbase)
5526 for i in range(game.inbase):
5527 proutn(`game.state.baseq[i]`)
5530 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5531 proutn(_(" Sector %s") % game.sector)
5533 prout(_("Good Luck!"))
5534 if game.state.nscrem:
5535 prout(_(" YOU'LL NEED IT."))
5538 setwnd(message_window)
5540 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5542 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5543 attack(torps_ok=False)
5546 "Choose your game type."
5548 game.tourn = game.length = 0
5550 game.skill = SKILL_NONE
5552 # if not scanner.inqueue: # Can start with command line options
5553 proutn(_("Would you like a regular, tournament, or saved game? "))
5555 if scanner.sees("tournament"):
5556 while scanner.next() == "IHEOL":
5557 proutn(_("Type in tournament number-"))
5558 if scanner.real == 0:
5560 continue # We don't want a blank entry
5561 game.tourn = int(round(scanner.real))
5562 random.seed(scanner.real)
5564 logfp.write("# random.seed(%d)\n" % scanner.real)
5566 if scanner.sees("saved") or scanner.sees("frozen"):
5570 if game.passwd == None:
5572 if not game.alldone:
5573 game.thawed = True # No plaque if not finished
5577 if scanner.sees("regular"):
5579 proutn(_("What is \"%s\"? ") % scanner.token)
5581 while game.length==0 or game.skill==SKILL_NONE:
5582 if scanner.next() == "IHALPHA":
5583 if scanner.sees("short"):
5585 elif scanner.sees("medium"):
5587 elif scanner.sees("long"):
5589 elif scanner.sees("novice"):
5590 game.skill = SKILL_NOVICE
5591 elif scanner.sees("fair"):
5592 game.skill = SKILL_FAIR
5593 elif scanner.sees("good"):
5594 game.skill = SKILL_GOOD
5595 elif scanner.sees("expert"):
5596 game.skill = SKILL_EXPERT
5597 elif scanner.sees("emeritus"):
5598 game.skill = SKILL_EMERITUS
5600 proutn(_("What is \""))
5601 proutn(scanner.token)
5606 proutn(_("Would you like a Short, Medium, or Long game? "))
5607 elif game.skill == SKILL_NONE:
5608 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5609 # Choose game options -- added by ESR for SST2K
5610 if scanner.next() != "IHALPHA":
5612 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5614 if scanner.sees("plain"):
5615 # Approximates the UT FORTRAN version.
5616 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5617 game.options |= OPTION_PLAIN
5618 elif scanner.sees("almy"):
5619 # Approximates Tom Almy's version.
5620 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5621 game.options |= OPTION_ALMY
5622 elif scanner.sees("fancy") or scanner.sees("\n"):
5624 elif len(scanner.token):
5625 proutn(_("What is \"%s\"?") % scanner.token)
5626 game.options &=~ OPTION_COLOR
5628 if game.passwd == "debug":
5630 prout("=== Debug mode enabled.")
5631 # Use parameters to generate initial values of things
5632 game.damfac = 0.5 * game.skill
5633 game.inbase = randrange(BASEMIN, BASEMAX+1)
5635 if game.options & OPTION_PLANETS:
5636 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5637 if game.options & OPTION_WORLDS:
5638 game.inplan += int(NINHAB)
5639 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5640 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5641 game.state.remtime = 7.0 * game.length
5642 game.intime = game.state.remtime
5643 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5644 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5645 game.state.remres = (game.inkling+4*game.incom)*game.intime
5646 game.inresor = game.state.remres
5647 if game.inkling > 50:
5648 game.state.inbase += 1
5651 def dropin(iquad=None):
5652 "Drop a feature on a random dot in the current quadrant."
5654 w = randplace(QUADSIZE)
5655 if game.quad[w.i][w.j] == '.':
5657 if iquad is not None:
5658 game.quad[w.i][w.j] = iquad
5662 "Update our alert status."
5663 game.condition = "green"
5664 if game.energy < 1000.0:
5665 game.condition = "yellow"
5666 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5667 game.condition = "red"
5669 game.condition="dead"
5672 "Drop new Klingon into current quadrant."
5673 return Enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5676 "Sort enemies by distance so 'nearest' is meaningful."
5677 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
5680 "Set up a new state of quadrant, for when we enter or re-enter it."
5683 game.neutz = game.inorbit = game.landed = False
5684 game.ientesc = game.iseenit = False
5685 # Create a blank quadrant
5686 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5688 # Attempt to escape Super-commander, so tbeam back!
5691 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5692 # cope with supernova
5695 game.klhere = q.klingons
5696 game.irhere = q.romulans
5698 game.quad[game.sector.i][game.sector.j] = game.ship
5701 # Position ordinary Klingons
5702 for i in range(game.klhere):
5704 # If we need a commander, promote a Klingon
5705 for cmdr in game.state.kcmdr:
5706 if cmdr == game.quadrant:
5707 e = game.enemies[game.klhere-1]
5708 game.quad[e.location.i][e.location.j] = 'C'
5709 e.power = randreal(950,1350) + 50.0*game.skill
5711 # If we need a super-commander, promote a Klingon
5712 if game.quadrant == game.state.kscmdr:
5714 game.quad[e.location.i][e.location.j] = 'S'
5715 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5716 game.iscate = (game.state.remkl > 1)
5717 # Put in Romulans if needed
5718 for i in range(q.romulans):
5719 Enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5720 # If quadrant needs a starbase, put it in
5722 game.base = dropin('B')
5723 # If quadrant needs a planet, put it in
5725 game.iplnet = q.planet
5726 if not q.planet.inhabited:
5727 game.plnet = dropin('P')
5729 game.plnet = dropin('@')
5730 # Check for condition
5733 if game.irhere > 0 and game.klhere == 0:
5735 if not damaged(DRADIO):
5737 prout(_("LT. Uhura- \"Captain, an urgent message."))
5738 prout(_(" I'll put it on audio.\" CLICK"))
5740 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5741 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5742 # Put in THING if needed
5743 if thing == game.quadrant:
5744 Enemy(type='?', loc=dropin(),
5745 power=randreal(6000,6500.0)+250.0*game.skill)
5746 if not damaged(DSRSENS):
5748 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5749 prout(_(" Please examine your short-range scan.\""))
5750 # Decide if quadrant needs a Tholian; lighten up if skill is low
5751 if game.options & OPTION_THOLIAN:
5752 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5753 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5754 (game.skill > SKILL_GOOD and withprob(0.08)):
5757 w.i = withprob(0.5) * (QUADSIZE-1)
5758 w.j = withprob(0.5) * (QUADSIZE-1)
5759 if game.quad[w.i][w.j] == '.':
5761 game.tholian = Enemy(type='T', loc=w,
5762 power=randrange(100, 500) + 25.0*game.skill)
5763 # Reserve unoccupied corners
5764 if game.quad[0][0]=='.':
5765 game.quad[0][0] = 'X'
5766 if game.quad[0][QUADSIZE-1]=='.':
5767 game.quad[0][QUADSIZE-1] = 'X'
5768 if game.quad[QUADSIZE-1][0]=='.':
5769 game.quad[QUADSIZE-1][0] = 'X'
5770 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5771 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5773 # And finally the stars
5774 for i in range(q.stars):
5776 # Put in a few black holes
5777 for i in range(1, 3+1):
5780 # Take out X's in corners if Tholian present
5782 if game.quad[0][0]=='X':
5783 game.quad[0][0] = '.'
5784 if game.quad[0][QUADSIZE-1]=='X':
5785 game.quad[0][QUADSIZE-1] = '.'
5786 if game.quad[QUADSIZE-1][0]=='X':
5787 game.quad[QUADSIZE-1][0] = '.'
5788 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5789 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5792 "Set the self-destruct password."
5793 if game.options & OPTION_PLAIN:
5796 proutn(_("Please type in a secret password- "))
5798 game.passwd = scanner.token
5799 if game.passwd != None:
5803 game.passwd += chr(ord('a')+randrange(26))
5804 game.passwd += chr(ord('a')+randrange(26))
5805 game.passwd += chr(ord('a')+randrange(26))
5807 # Code from sst.c begins here
5810 ("SRSCAN", OPTION_TTY),
5811 ("STATUS", OPTION_TTY),
5812 ("REQUEST", OPTION_TTY),
5813 ("LRSCAN", OPTION_TTY),
5826 ("SENSORS", OPTION_PLANETS),
5827 ("ORBIT", OPTION_PLANETS),
5828 ("TRANSPORT", OPTION_PLANETS),
5829 ("MINE", OPTION_PLANETS),
5830 ("CRYSTALS", OPTION_PLANETS),
5831 ("SHUTTLE", OPTION_PLANETS),
5832 ("PLANETS", OPTION_PLANETS),
5837 ("PROBE", OPTION_PROBE),
5839 ("FREEZE", 0), # Synonym for SAVE
5845 ("SOS", 0), # Synonym for MAYDAY
5846 ("CALL", 0), # Synonym for MAYDAY
5853 "Generate a list of legal commands."
5854 prout(_("LEGAL COMMANDS ARE:"))
5856 for (key, opt) in commands:
5857 if not opt or (opt & game.options):
5858 proutn("%-12s " % key)
5860 if emitted % 5 == 4:
5865 "Browse on-line help."
5866 key = scanner.next()
5869 setwnd(prompt_window)
5870 proutn(_("Help on what command? "))
5871 key = scanner.next()
5872 setwnd(message_window)
5875 cmds = map(lambda x: x[0], commands)
5876 if scanner.token.upper() in cmds or scanner.token.upper() == "ABBREV":
5883 cmd = scanner.token.upper()
5884 for directory in docpath:
5886 fp = open(os.path.join(directory, "sst.doc"), "r")
5891 prout(_("Spock- \"Captain, that information is missing from the"))
5892 prout(_(" computer. You need to find sst.doc and put it somewhere"))
5893 proutn(_(" in these directories: %s") % ":".join(docpath))
5895 # This used to continue: "You need to find SST.DOC and put
5896 # it in the current directory."
5899 linebuf = fp.readline()
5901 prout(_("Spock- \"Captain, there is no information on that command.\""))
5904 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5905 linebuf = linebuf[3:].strip()
5906 if cmd.upper() == linebuf:
5909 prout(_("Spock- \"Captain, I've found the following information:\""))
5912 linebuf = fp.readline()
5913 if "******" in linebuf:
5919 "Command-interpretation loop."
5920 while True: # command loop
5922 while True: # get a command
5924 game.optime = game.justin = False
5926 setwnd(prompt_window)
5929 if scanner.next() == "IHEOL":
5930 if game.options & OPTION_CURSES:
5933 elif scanner.token == "":
5937 setwnd(message_window)
5939 abandon_passed = False
5940 for (cmd, opt) in commands:
5941 # commands after ABANDON cannot be abbreviated
5942 if cmd == "ABANDON":
5943 abandon_passed = True
5944 if cmd == scanner.token.upper() or (not abandon_passed \
5945 and cmd.startswith(scanner.token.upper())):
5952 if cmd == "SRSCAN": # srscan
5954 elif cmd == "STATUS": # status
5956 elif cmd == "REQUEST": # status request
5958 elif cmd == "LRSCAN": # long range scan
5959 lrscan(silent=False)
5960 elif cmd == "PHASERS": # phasers
5964 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
5968 elif cmd == "MOVE": # move under warp
5969 warp(wcourse=None, involuntary=False)
5970 elif cmd == "SHIELDS": # shields
5971 doshield(shraise=False)
5974 game.shldchg = False
5975 elif cmd == "DOCK": # dock at starbase
5978 attack(torps_ok=False)
5979 elif cmd == "DAMAGES": # damage reports
5981 elif cmd == "CHART": # chart
5983 elif cmd == "IMPULSE": # impulse
5985 elif cmd == "REST": # rest
5989 elif cmd == "WARP": # warp
5991 elif cmd == "SCORE": # score
5993 elif cmd == "SENSORS": # sensors
5995 elif cmd == "ORBIT": # orbit
5999 elif cmd == "TRANSPORT": # transport "beam"
6001 elif cmd == "MINE": # mine
6005 elif cmd == "CRYSTALS": # crystals
6009 elif cmd == "SHUTTLE": # shuttle
6013 elif cmd == "PLANETS": # Planet list
6015 elif cmd == "REPORT": # Game Report
6017 elif cmd == "COMPUTER": # use COMPUTER!
6019 elif cmd == "COMMANDS":
6021 elif cmd == "EMEXIT": # Emergency exit
6022 clrscr() # Hide screen
6023 freeze(True) # forced save
6024 raise SystemExit,1 # And quick exit
6025 elif cmd == "PROBE":
6026 probe() # Launch probe
6029 elif cmd == "ABANDON": # Abandon Ship
6031 elif cmd == "DESTRUCT": # Self Destruct
6033 elif cmd == "SAVE": # Save Game
6036 if game.skill > SKILL_GOOD:
6037 prout(_("WARNING--Saved games produce no plaques!"))
6038 elif cmd == "DEATHRAY": # Try a desparation measure
6042 elif cmd == "DEBUGCMD": # What do we want for debug???
6044 elif cmd == "MAYDAY": # Call for help
6049 game.alldone = True # quit the game
6054 break # Game has ended
6055 if game.optime != 0.0:
6058 break # Events did us in
6059 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6062 if hitme and not game.justin:
6063 attack(torps_ok=True)
6066 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6077 "Emit the name of an enemy or feature."
6078 if type == 'R': s = _("Romulan")
6079 elif type == 'K': s = _("Klingon")
6080 elif type == 'C': s = _("Commander")
6081 elif type == 'S': s = _("Super-commander")
6082 elif type == '*': s = _("Star")
6083 elif type == 'P': s = _("Planet")
6084 elif type == 'B': s = _("Starbase")
6085 elif type == ' ': s = _("Black hole")
6086 elif type == 'T': s = _("Tholian")
6087 elif type == '#': s = _("Tholian web")
6088 elif type == '?': s = _("Stranger")
6089 elif type == '@': s = _("Inhabited World")
6090 else: s = "Unknown??"
6093 def crmena(stars, enemy, loctype, w):
6094 "Emit the name of an enemy and his location."
6098 buf += cramen(enemy) + _(" at ")
6099 if loctype == "quadrant":
6100 buf += _("Quadrant ")
6101 elif loctype == "sector":
6106 "Emit our ship name."
6107 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6110 "Emit a line of stars"
6111 prouts("******************************************************")
6115 return -avrage*math.log(1e-7 + randreal())
6117 def randplace(size):
6118 "Choose a random location."
6120 w.i = randrange(size)
6121 w.j = randrange(size)
6131 # Get a token from the user
6134 # Fill the token quue if nothing here
6135 while not self.inqueue:
6137 if curwnd==prompt_window:
6139 setwnd(message_window)
6146 self.inqueue = line.lstrip().split() + ["\n"]
6147 # From here on in it's all looking at the queue
6148 self.token = self.inqueue.pop(0)
6149 if self.token == "\n":
6153 self.real = float(self.token)
6154 self.type = "IHREAL"
6159 self.token = self.token.lower()
6160 self.type = "IHALPHA"
6163 def append(self, tok):
6164 self.inqueue.append(tok)
6165 def push(self, tok):
6166 self.inqueue.insert(0, tok)
6170 # Demand input for next scan
6172 self.real = self.token = None
6174 # compares s to item and returns true if it matches to the length of s
6175 return s.startswith(self.token)
6177 # Round token value to nearest integer
6178 return int(round(scanner.real))
6182 if scanner.type != "IHREAL":
6185 s.i = scanner.int()-1
6187 if scanner.type != "IHREAL":
6190 s.j = scanner.int()-1
6193 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6196 "Yes-or-no confirmation."
6200 if scanner.token == 'y':
6202 if scanner.token == 'n':
6205 proutn(_("Please answer with \"y\" or \"n\": "))
6208 "Complain about unparseable input."
6211 prout(_("Beg your pardon, Captain?"))
6214 "Access to the internals for debugging."
6215 proutn("Reset levels? ")
6217 if game.energy < game.inenrg:
6218 game.energy = game.inenrg
6219 game.shield = game.inshld
6220 game.torps = game.intorps
6221 game.lsupres = game.inlsr
6222 proutn("Reset damage? ")
6224 for i in range(NDEVICES):
6225 if game.damage[i] > 0.0:
6226 game.damage[i] = 0.0
6227 proutn("Toggle debug flag? ")
6229 game.idebug = not game.idebug
6231 prout("Debug output ON")
6233 prout("Debug output OFF")
6234 proutn("Cause selective damage? ")
6236 for i in range(NDEVICES):
6237 proutn("Kill %s?" % device[i])
6239 key = scanner.next()
6240 if key == "IHALPHA" and scanner.sees("y"):
6241 game.damage[i] = 10.0
6242 proutn("Examine/change events? ")
6247 FSNOVA: "Supernova ",
6250 FBATTAK: "Base Attack ",
6251 FCDBAS: "Base Destroy ",
6252 FSCMOVE: "SC Move ",
6253 FSCDBAS: "SC Base Destroy ",
6254 FDSPROB: "Probe Move ",
6255 FDISTR: "Distress Call ",
6256 FENSLV: "Enslavement ",
6257 FREPRO: "Klingon Build ",
6259 for i in range(1, NEVENTS):
6262 proutn("%.2f" % (scheduled(i)-game.state.date))
6263 if i == FENSLV or i == FREPRO:
6265 proutn(" in %s" % ev.quadrant)
6270 key = scanner.next()
6274 elif key == "IHREAL":
6275 ev = schedule(i, scanner.real)
6276 if i == FENSLV or i == FREPRO:
6278 proutn("In quadrant- ")
6279 key = scanner.next()
6280 # "IHEOL" says to leave coordinates as they are
6283 prout("Event %d canceled, no x coordinate." % (i))
6286 w.i = int(round(scanner.real))
6287 key = scanner.next()
6289 prout("Event %d canceled, no y coordinate." % (i))
6292 w.j = int(round(scanner.real))
6295 proutn("Induce supernova here? ")
6297 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6300 if __name__ == '__main__':
6301 import getopt, socket
6303 global line, thing, game
6307 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6308 if os.getenv("TERM"):
6309 game.options |= OPTION_CURSES
6311 game.options |= OPTION_TTY
6312 seed = int(time.time())
6313 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6314 for (switch, val) in options:
6317 replayfp = open(val, "r")
6319 sys.stderr.write("sst: can't open replay file %s\n" % val)
6322 line = replayfp.readline().strip()
6323 (leader, key, seed) = line.split()
6325 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6326 line = replayfp.readline().strip()
6327 arguments += line.split()[2:]
6329 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6331 game.options |= OPTION_TTY
6332 game.options &=~ OPTION_CURSES
6333 elif switch == '-s':
6335 elif switch == '-t':
6336 game.options |= OPTION_TTY
6337 game.options &=~ OPTION_CURSES
6338 elif switch == '-x':
6340 elif switch == '-V':
6341 print "SST2K", version
6344 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6346 # where to save the input in case of bugs
6347 if "TMPDIR" in os.environ:
6348 tmpdir = os.environ['TMPDIR']
6352 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6354 sys.stderr.write("sst: warning, can't open logfile\n")
6357 logfp.write("# seed %s\n" % seed)
6358 logfp.write("# options %s\n" % " ".join(arguments))
6359 logfp.write("# recorded by %s@%s on %s\n" % \
6360 (getpass.getuser(),socket.gethostname(),time.ctime()))
6362 scanner = sstscanner()
6363 map(scanner.append, arguments)
6366 while True: # Play a game
6367 setwnd(fullscreen_window)
6373 game.alldone = False
6379 if game.tourn and game.alldone:
6380 proutn(_("Do you want your score recorded?"))
6386 proutn(_("Do you want to play again? "))
6390 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6394 except KeyboardInterrupt: