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")
20 def _(str): return gettext.gettext(str)
22 GALSIZE = 8 # Galaxy size in quadrants
23 NINHAB = (GALSIZE * GALSIZE / 2) # Number of inhabited worlds
24 MAXUNINHAB = 10 # Maximum uninhabited worlds
25 QUADSIZE = 10 # Quadrant size in sectors
26 BASEMIN = 2 # Minimum starbases
27 BASEMAX = (GALSIZE * GALSIZE / 12) # Maximum starbases
28 MAXKLGAME = 127 # Maximum Klingons per game
29 MAXKLQUAD = 9 # Maximum Klingons per quadrant
30 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
31 FOREVER = 1e30 # Time for the indefinite future
32 MAXBURST = 3 # Max # of torps you can launch in one turn
33 MINCMDR = 10 # Minimum number of Klingon commanders
34 DOCKFAC = 0.25 # Repair faster when docked
35 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
55 class TrekError(Exception):
58 class JumpOut(Exception):
62 def __init__(self, x=None, y=None):
65 def valid_quadrant(self):
66 return self.i>=0 and self.i<GALSIZE and self.j>=0 and self.j<GALSIZE
67 def valid_sector(self):
68 return self.i>=0 and self.i<QUADSIZE and self.j>=0 and self.j<QUADSIZE
70 self.i = self.j = None
72 return self.i != None and self.j != None
73 def __eq__(self, other):
74 return other != None and self.i == other.i and self.j == other.j
75 def __ne__(self, other):
76 return other == None or self.i != other.i or self.j != other.j
77 def __add__(self, other):
78 return coord(self.i+other.i, self.j+other.j)
79 def __sub__(self, other):
80 return coord(self.i-other.i, self.j-other.j)
81 def __mul__(self, other):
82 return coord(self.i*other, self.j*other)
83 def __rmul__(self, other):
84 return coord(self.i*other, self.j*other)
85 def __div__(self, other):
86 return coord(self.i/other, self.j/other)
87 def __mod__(self, other):
88 return coord(self.i % other, self.j % other)
89 def __rdiv__(self, other):
90 return coord(self.i/other, self.j/other)
91 def roundtogrid(self):
92 return coord(int(round(self.i)), int(round(self.j)))
93 def distance(self, other=None):
94 if not other: other = coord(0, 0)
95 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
97 return 1.90985*math.atan2(self.j, self.i)
103 s.i = self.i / abs(self.i)
107 s.j = self.j / abs(self.j)
110 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
111 return self.roundtogrid() / QUADSIZE
113 return self.roundtogrid() % QUADSIZE
116 s.i = self.i + randrange(-1, 2)
117 s.j = self.j + randrange(-1, 2)
120 if self.i == None or self.j == None:
122 return "%s - %s" % (self.i+1, self.j+1)
127 self.name = None # string-valued if inhabited
128 self.quadrant = coord() # quadrant located
129 self.pclass = None # could be ""M", "N", "O", or "destroyed"
130 self.crystals = "absent"# could be "mined", "present", "absent"
131 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
132 self.inhabited = False # is it inhabites?
140 self.starbase = False
143 self.supernova = False
145 self.status = "secure" # Could be "secure", "distressed", "enslaved"
153 def fill2d(size, fillfun):
154 "Fill an empty list in 2D."
156 for i in range(size):
158 for j in range(size):
159 lst[i].append(fillfun(i, j))
164 self.snap = False # snapshot taken
165 self.crew = 0 # crew complement
166 self.remkl = 0 # remaining klingons
167 self.nscrem = 0 # remaining super commanders
168 self.starkl = 0 # destroyed stars
169 self.basekl = 0 # destroyed bases
170 self.nromrem = 0 # Romulans remaining
171 self.nplankl = 0 # destroyed uninhabited planets
172 self.nworldkl = 0 # destroyed inhabited planets
173 self.planets = [] # Planet information
174 self.date = 0.0 # stardate
175 self.remres = 0 # remaining resources
176 self.remtime = 0 # remaining time
177 self.baseq = [] # Base quadrant coordinates
178 self.kcmdr = [] # Commander quadrant coordinates
179 self.kscmdr = coord() # Supercommander quadrant coordinates
181 self.galaxy = fill2d(GALSIZE, lambda i_unused, j_unused: quadrant())
183 self.chart = fill2d(GALSIZE, lambda i_unused, j_unused: page())
187 self.date = None # A real number
188 self.quadrant = None # A coord structure
191 OPTION_ALL = 0xffffffff
192 OPTION_TTY = 0x00000001 # old interface
193 OPTION_CURSES = 0x00000002 # new interface
194 OPTION_IOMODES = 0x00000003 # cover both interfaces
195 OPTION_PLANETS = 0x00000004 # planets and mining
196 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
197 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
198 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
199 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
200 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
201 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
202 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
203 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
204 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
205 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
206 OPTION_PLAIN = 0x01000000 # user chose plain game
207 OPTION_ALMY = 0x02000000 # user chose Almy variant
208 OPTION_COLOR = 0x04000000 # enable color display (experimental, ESR, 2010)
227 NDEVICES= 16 # Number of devices
236 def damaged(dev): return (game.damage[dev] != 0.0)
237 def communicating(): return not damaged(DRADIO) or game.condition=="docked"
239 # Define future events
240 FSPY = 0 # Spy event happens always (no future[] entry)
241 # can cause SC to tractor beam Enterprise
242 FSNOVA = 1 # Supernova
243 FTBEAM = 2 # Commander tractor beams Enterprise
244 FSNAP = 3 # Snapshot for time warp
245 FBATTAK = 4 # Commander attacks base
246 FCDBAS = 5 # Commander destroys base
247 FSCMOVE = 6 # Supercommander moves (might attack base)
248 FSCDBAS = 7 # Supercommander destroys base
249 FDSPROB = 8 # Move deep space probe
250 FDISTR = 9 # Emit distress call from an inhabited world
251 FENSLV = 10 # Inhabited word is enslaved */
252 FREPRO = 11 # Klingons build a ship in an enslaved system
255 # Abstract out the event handling -- underlying data structures will change
256 # when we implement stateful events
257 def findevent(evtype): return game.future[evtype]
260 def __init__(self, type=None, loc=None, power=None):
262 self.location = coord()
265 self.power = power # enemy energy level
266 game.enemies.append(self)
268 motion = (loc != self.location)
269 if self.location.i is not None and self.location.j is not None:
272 game.quad[self.location.i][self.location.j] = '#'
274 game.quad[self.location.i][self.location.j] = '.'
276 self.location = copy.copy(loc)
277 game.quad[self.location.i][self.location.j] = self.type
278 self.kdist = self.kavgd = (game.sector - loc).distance()
280 self.location = coord()
281 self.kdist = self.kavgd = None
282 game.enemies.remove(self)
285 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
289 self.options = None # Game options
290 self.state = snapshot() # A snapshot structure
291 self.snapsht = snapshot() # Last snapshot taken for time-travel purposes
292 self.quad = None # contents of our quadrant
293 self.damage = [0.0] * NDEVICES # damage encountered
294 self.future = [] # future events
298 self.future.append(event())
299 self.passwd = None; # Self Destruct password
301 self.quadrant = None # where we are in the large
302 self.sector = None # where we are in the small
303 self.tholian = None # Tholian enemy object
304 self.base = None # position of base in current quadrant
305 self.battle = None # base coordinates being attacked
306 self.plnet = None # location of planet in quadrant
307 self.gamewon = False # Finished!
308 self.ididit = False # action taken -- allows enemy to attack
309 self.alive = False # we are alive (not killed)
310 self.justin = False # just entered quadrant
311 self.shldup = False # shields are up
312 self.shldchg = False # shield is changing (affects efficiency)
313 self.iscate = False # super commander is here
314 self.ientesc = False # attempted escape from supercommander
315 self.resting = False # rest time
316 self.icraft = False # Kirk in Galileo
317 self.landed = False # party on planet (true), on ship (false)
318 self.alldone = False # game is now finished
319 self.neutz = False # Romulan Neutral Zone
320 self.isarmed = False # probe is armed
321 self.inorbit = False # orbiting a planet
322 self.imine = False # mining
323 self.icrystl = False # dilithium crystals aboard
324 self.iseenit = False # seen base attack report
325 self.thawed = False # thawed game
326 self.condition = None # "green", "yellow", "red", "docked", "dead"
327 self.iscraft = None # "onship", "offship", "removed"
328 self.skill = None # Player skill level
329 self.inkling = 0 # initial number of klingons
330 self.inbase = 0 # initial number of bases
331 self.incom = 0 # initial number of commanders
332 self.inscom = 0 # initial number of commanders
333 self.inrom = 0 # initial number of commanders
334 self.instar = 0 # initial stars
335 self.intorps = 0 # initial/max torpedoes
336 self.torps = 0 # number of torpedoes
337 self.ship = 0 # ship type -- 'E' is Enterprise
338 self.abandoned = 0 # count of crew abandoned in space
339 self.length = 0 # length of game
340 self.klhere = 0 # klingons here
341 self.casual = 0 # causalties
342 self.nhelp = 0 # calls for help
343 self.nkinks = 0 # count of energy-barrier crossings
344 self.iplnet = None # planet # in quadrant
345 self.inplan = 0 # initial planets
346 self.irhere = 0 # Romulans in quadrant
347 self.isatb = 0 # =2 if super commander is attacking base
348 self.tourn = None # tournament number
349 self.nprobes = 0 # number of probes available
350 self.inresor = 0.0 # initial resources
351 self.intime = 0.0 # initial time
352 self.inenrg = 0.0 # initial/max energy
353 self.inshld = 0.0 # initial/max shield
354 self.inlsr = 0.0 # initial life support resources
355 self.indate = 0.0 # initial date
356 self.energy = 0.0 # energy level
357 self.shield = 0.0 # shield level
358 self.warpfac = 0.0 # warp speed
359 self.lsupres = 0.0 # life support reserves
360 self.optime = 0.0 # time taken by current operation
361 self.damfac = 0.0 # damage factor
362 self.lastchart = 0.0 # time star chart was last updated
363 self.cryprob = 0.0 # probability that crystal will work
364 self.probe = None # object holding probe course info
365 self.height = 0.0 # height of orbit around planet
366 self.idebug = False # Debugging instrumentation enabled?
368 # Stas thinks this should be (C expression):
369 # game.state.remkl + len(game.state.kcmdr) > 0 ?
370 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
371 # He says the existing expression is prone to divide-by-zero errors
372 # after killing the last klingon when score is shown -- perhaps also
373 # if the only remaining klingon is SCOM.
374 game.state.remtime = game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr))
400 return random.random() < p
402 def randrange(*args):
403 return random.randrange(*args)
408 v *= args[0] # from [0, args[0])
410 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
413 # Code from ai.c begins here
416 "Would this quadrant welcome another Klingon?"
417 return iq.valid_quadrant() and \
418 not game.state.galaxy[iq.i][iq.j].supernova and \
419 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
421 def tryexit(enemy, look, irun):
422 "A bad guy attempts to bug out."
424 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
425 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
426 if not welcoming(iq):
428 if enemy.type == 'R':
429 return False; # Romulans cannot escape!
431 # avoid intruding on another commander's territory
432 if enemy.type == 'C':
433 if iq in game.state.kcmdr:
435 # refuse to leave if currently attacking starbase
436 if game.battle == game.quadrant:
438 # don't leave if over 1000 units of energy
439 if enemy.power > 1000.0:
441 # emit escape message and move out of quadrant.
442 # we know this if either short or long range sensors are working
443 if not damaged(DSRSENS) or not damaged(DLRSENS) or \
444 game.condition == "docked":
445 prout(crmena(True, enemy.type, "sector", enemy.location) + \
446 (_(" escapes to Quadrant %s (and regains strength).") % iq))
447 # handle local matters related to escape
450 if game.condition != "docked":
452 # Handle global matters related to escape
453 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
454 game.state.galaxy[iq.i][iq.j].klingons += 1
459 schedule(FSCMOVE, 0.2777)
463 for cmdr in game.state.kcmdr:
464 if cmdr == game.quadrant:
465 game.state.kcmdr.append(iq)
467 return True; # success
469 # The bad-guy movement algorithm:
471 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
472 # If both are operating full strength, force is 1000. If both are damaged,
473 # force is -1000. Having shields down subtracts an additional 1000.
475 # 2. Enemy has forces equal to the energy of the attacker plus
476 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
477 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
479 # Attacker Initial energy levels (nominal):
480 # Klingon Romulan Commander Super-Commander
481 # Novice 400 700 1200
483 # Good 450 800 1300 1750
484 # Expert 475 850 1350 1875
485 # Emeritus 500 900 1400 2000
486 # VARIANCE 75 200 200 200
488 # Enemy vessels only move prior to their attack. In Novice - Good games
489 # only commanders move. In Expert games, all enemy vessels move if there
490 # is a commander present. In Emeritus games all enemy vessels move.
492 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
493 # forces are 1000 greater than Enterprise.
495 # Agressive action on average cuts the distance between the ship and
496 # the enemy to 1/4 the original.
498 # 4. At lower energy advantage, movement units are proportional to the
499 # advantage with a 650 advantage being to hold ground, 800 to move forward
500 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
502 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
503 # retreat, especially at high skill levels.
505 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
507 def movebaddy(enemy):
508 "Tactical movement for the bad guys."
509 goto = coord(); look = coord()
511 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
512 if game.skill >= SKILL_EXPERT:
513 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
515 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
517 mdist = int(dist1 + 0.5); # Nearest integer distance
518 # If SC, check with spy to see if should hi-tail it
519 if enemy.type=='S' and \
520 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
524 # decide whether to advance, retreat, or hold position
525 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
527 forces += 1000; # Good for enemy if shield is down!
528 if not damaged(DPHASER) or not damaged(DPHOTON):
529 if damaged(DPHASER): # phasers damaged
532 forces -= 0.2*(game.energy - 2500.0)
533 if damaged(DPHOTON): # photon torpedoes damaged
536 forces -= 50.0*game.torps
538 # phasers and photon tubes both out!
541 if forces <= 1000.0 and game.condition != "docked": # Typical situation
542 motion = ((forces + randreal(200))/150.0) - 5.0
544 if forces > 1000.0: # Very strong -- move in for kill
545 motion = (1.0 - randreal())**2 * dist1 + 1.0
546 if game.condition=="docked" and (game.options & OPTION_BASE): # protected by base -- back off !
547 motion -= game.skill*(2.0-randreal()**2)
549 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
550 # don't move if no motion
553 # Limit motion according to skill
554 if abs(motion) > game.skill:
559 # calculate preferred number of steps
560 nsteps = abs(int(motion))
561 if motion > 0 and nsteps > mdist:
562 nsteps = mdist; # don't overshoot
563 if nsteps > QUADSIZE:
564 nsteps = QUADSIZE; # This shouldn't be necessary
566 nsteps = 1; # This shouldn't be necessary
568 proutn("NSTEPS = %d:" % nsteps)
569 # Compute preferred values of delta X and Y
570 m = game.sector - enemy.location
571 if 2.0 * abs(m.i) < abs(m.j):
573 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
575 m = (motion * m).sgn()
576 goto = enemy.location
578 for ll in range(nsteps):
580 proutn(" %d" % (ll+1))
581 # Check if preferred position available
592 attempts = 0; # Settle mysterious hang problem
593 while attempts < 20 and not success:
595 if look.i < 0 or look.i >= QUADSIZE:
596 if motion < 0 and tryexit(enemy, look, irun):
598 if krawli == m.i or m.j == 0:
600 look.i = goto.i + krawli
602 elif look.j < 0 or look.j >= QUADSIZE:
603 if motion < 0 and tryexit(enemy, look, irun):
605 if krawlj == m.j or m.i == 0:
607 look.j = goto.j + krawlj
609 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
610 # See if enemy should ram ship
611 if game.quad[look.i][look.j] == game.ship and \
612 (enemy.type == 'C' or enemy.type == 'S'):
613 collision(rammed=True, enemy=enemy)
615 if krawli != m.i and m.j != 0:
616 look.i = goto.i + krawli
618 elif krawlj != m.j and m.i != 0:
619 look.j = goto.j + krawlj
622 break; # we have failed
634 if not damaged(DSRSENS) or game.condition == "docked":
635 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
636 if enemy.kdist < dist1:
637 proutn(_(" advances to "))
639 proutn(_(" retreats to "))
640 prout("Sector %s." % goto)
643 "Sequence Klingon tactical movement."
646 # Figure out which Klingon is the commander (or Supercommander)
648 if game.quadrant in game.state.kcmdr:
649 for enemy in game.enemies:
650 if enemy.type == 'C':
652 if game.state.kscmdr==game.quadrant:
653 for enemy in game.enemies:
654 if enemy.type == 'S':
657 # If skill level is high, move other Klingons and Romulans too!
658 # Move these last so they can base their actions on what the
660 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
661 for enemy in game.enemies:
662 if enemy.type in ('K', 'R'):
664 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
666 def movescom(iq, avoid):
667 "Commander movement helper."
668 # Avoid quadrants with bases if we want to avoid Enterprise
669 if not welcoming(iq) or (avoid and iq in game.state.baseq):
671 if game.justin and not game.iscate:
674 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
675 game.state.kscmdr = iq
676 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
677 if game.state.kscmdr==game.quadrant:
678 # SC has scooted, remove him from current quadrant
683 for enemy in game.enemies:
684 if enemy.type == 'S':
688 if game.condition != "docked":
690 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
691 # check for a helpful planet
692 for i in range(game.inplan):
693 if game.state.planets[i].quadrant == game.state.kscmdr and \
694 game.state.planets[i].crystals == "present":
696 game.state.planets[i].pclass = "destroyed"
697 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
700 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
701 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
702 prout(_(" by the Super-commander.\""))
704 return True; # looks good!
706 def supercommander():
707 "Move the Super Commander."
708 iq = coord(); sc = coord(); ibq = coord(); idelta = coord()
711 prout("== SUPERCOMMANDER")
712 # Decide on being active or passive
713 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 \
714 (game.state.date-game.indate) < 3.0)
715 if not game.iscate and avoid:
716 # compute move away from Enterprise
717 idelta = game.state.kscmdr-game.quadrant
718 if idelta.distance() > 2.0:
720 idelta.i = game.state.kscmdr.j-game.quadrant.j
721 idelta.j = game.quadrant.i-game.state.kscmdr.i
723 # compute distances to starbases
724 if not game.state.baseq:
728 sc = game.state.kscmdr
729 for base in game.state.baseq:
730 basetbl.append((i, (base - sc).distance()))
731 if game.state.baseq > 1:
732 basetbl.sort(lambda x, y: cmp(x[1], y[1]))
733 # look for nearest base without a commander, no Enterprise, and
734 # without too many Klingons, and not already under attack.
735 ifindit = iwhichb = 0
736 for (i2, base) in enumerate(game.state.baseq):
737 i = basetbl[i2][0]; # bug in original had it not finding nearest
738 if base==game.quadrant or base==game.battle or not welcoming(base):
740 # if there is a commander, and no other base is appropriate,
741 # we will take the one with the commander
742 for cmdr in game.state.kcmdr:
743 if base == cmdr and ifindit != 2:
747 else: # no commander -- use this one
752 return # Nothing suitable -- wait until next time
753 ibq = game.state.baseq[iwhichb]
754 # decide how to move toward base
755 idelta = ibq - game.state.kscmdr
756 # Maximum movement is 1 quadrant in either or both axes
757 idelta = idelta.sgn()
758 # try moving in both x and y directions
759 # there was what looked like a bug in the Almy C code here,
760 # but it might be this translation is just wrong.
761 iq = game.state.kscmdr + idelta
762 if not movescom(iq, avoid):
763 # failed -- try some other maneuvers
764 if idelta.i==0 or idelta.j==0:
767 iq.j = game.state.kscmdr.j + 1
768 if not movescom(iq, avoid):
769 iq.j = game.state.kscmdr.j - 1
772 iq.i = game.state.kscmdr.i + 1
773 if not movescom(iq, avoid):
774 iq.i = game.state.kscmdr.i - 1
777 # try moving just in x or y
778 iq.j = game.state.kscmdr.j
779 if not movescom(iq, avoid):
780 iq.j = game.state.kscmdr.j + idelta.j
781 iq.i = game.state.kscmdr.i
784 if len(game.state.baseq) == 0:
787 for ibq in game.state.baseq:
788 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
791 return # no, don't attack base!
794 schedule(FSCDBAS, randreal(1.0, 3.0))
795 if is_scheduled(FCDBAS):
796 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
797 if not communicating():
801 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
803 prout(_(" reports that it is under attack from the Klingon Super-commander."))
804 proutn(_(" It can survive until stardate %d.\"") \
805 % int(scheduled(FSCDBAS)))
808 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
812 game.optime = 0.0; # actually finished
814 # Check for intelligence report
815 if not game.idebug and \
817 (not communicating()) or \
818 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
821 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
822 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
827 if not game.tholian or game.justin:
830 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
831 tid.i = 0; tid.j = QUADSIZE-1
832 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
833 tid.i = QUADSIZE-1; tid.j = QUADSIZE-1
834 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
835 tid.i = QUADSIZE-1; tid.j = 0
836 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
839 # something is wrong!
840 game.tholian.move(None)
841 prout("***Internal error: Tholian in a bad spot.")
843 # do nothing if we are blocked
844 if game.quad[tid.i][tid.j] not in ('.', '#'):
846 here = copy.copy(game.tholian.location)
847 delta = (tid - game.tholian.location).sgn()
849 while here.i != tid.i:
851 if game.quad[here.i][here.j]=='.':
852 game.tholian.move(here)
854 while here.j != tid.j:
856 if game.quad[here.i][here.j]=='.':
857 game.tholian.move(here)
858 # check to see if all holes plugged
859 for i in range(QUADSIZE):
860 if game.quad[0][i]!='#' and game.quad[0][i]!='T':
862 if game.quad[QUADSIZE-1][i]!='#' and game.quad[QUADSIZE-1][i]!='T':
864 if game.quad[i][0]!='#' and game.quad[i][0]!='T':
866 if game.quad[i][QUADSIZE-1]!='#' and game.quad[i][QUADSIZE-1]!='T':
868 # All plugged up -- Tholian splits
869 game.quad[game.tholian.location.i][game.tholian.location.j]='#'
871 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
872 game.tholian.move(None)
875 # Code from battle.c begins here
877 def doshield(shraise):
878 "Change shield status."
886 if scanner.sees("transfer"):
890 prout(_("Shields damaged and down."))
892 if scanner.sees("up"):
894 elif scanner.sees("down"):
897 proutn(_("Do you wish to change shield energy? "))
900 elif damaged(DSHIELD):
901 prout(_("Shields damaged and down."))
904 proutn(_("Shields are up. Do you want them down? "))
911 proutn(_("Shields are down. Do you want them up? "))
917 if action == "SHUP": # raise shields
919 prout(_("Shields already up."))
923 if game.condition != "docked":
925 prout(_("Shields raised."))
928 prout(_("Shields raising uses up last of energy."))
933 elif action == "SHDN":
935 prout(_("Shields already down."))
939 prout(_("Shields lowered."))
942 elif action == "NRG":
943 while scanner.next() != "IHREAL":
945 proutn(_("Energy to transfer to shields- "))
950 if nrg > game.energy:
951 prout(_("Insufficient ship energy."))
954 if game.shield+nrg >= game.inshld:
955 prout(_("Shield energy maximized."))
956 if game.shield+nrg > game.inshld:
957 prout(_("Excess energy requested returned to ship energy"))
958 game.energy -= game.inshld-game.shield
959 game.shield = game.inshld
961 if nrg < 0.0 and game.energy-nrg > game.inenrg:
962 # Prevent shield drain loophole
964 prout(_("Engineering to bridge--"))
965 prout(_(" Scott here. Power circuit problem, Captain."))
966 prout(_(" I can't drain the shields."))
969 if game.shield+nrg < 0:
970 prout(_("All shield energy transferred to ship."))
971 game.energy += game.shield
974 proutn(_("Scotty- \""))
976 prout(_("Transferring energy to shields.\""))
978 prout(_("Draining energy from shields.\""))
984 "Choose a device to damage, at random."
986 105, # DSRSENS: short range scanners 10.5%
987 105, # DLRSENS: long range scanners 10.5%
988 120, # DPHASER: phasers 12.0%
989 120, # DPHOTON: photon torpedoes 12.0%
990 25, # DLIFSUP: life support 2.5%
991 65, # DWARPEN: warp drive 6.5%
992 70, # DIMPULS: impulse engines 6.5%
993 145, # DSHIELD: deflector shields 14.5%
994 30, # DRADIO: subspace radio 3.0%
995 45, # DSHUTTL: shuttle 4.5%
996 15, # DCOMPTR: computer 1.5%
997 20, # NAVCOMP: navigation system 2.0%
998 75, # DTRANSP: transporter 7.5%
999 20, # DSHCTRL: high-speed shield controller 2.0%
1000 10, # DDRAY: death ray 1.0%
1001 30, # DDSP: deep-space probes 3.0%
1003 assert(sum(weights) == 1000)
1004 idx = randrange(1000)
1006 for (i, w) in enumerate(weights):
1010 return None; # we should never get here
1012 def collision(rammed, enemy):
1013 "Collision handling fot rammong events."
1014 prouts(_("***RED ALERT! RED ALERT!"))
1016 prout(_("***COLLISION IMMINENT."))
1020 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1022 proutn(_(" rammed by "))
1025 proutn(crmena(False, enemy.type, "sector", enemy.location))
1027 proutn(_(" (original position)"))
1029 deadkl(enemy.location, enemy.type, game.sector)
1030 proutn("***" + crmshp() + " heavily damaged.")
1031 icas = randrange(10, 30)
1032 prout(_("***Sickbay reports %d casualties") % icas)
1034 game.state.crew -= icas
1035 # In the pre-SST2K version, all devices got equiprobably damaged,
1036 # which was silly. Instead, pick up to half the devices at
1037 # random according to our weighting table,
1038 ncrits = randrange(NDEVICES/2)
1042 if game.damage[dev] < 0:
1044 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1045 # Damage for at least time of travel!
1046 game.damage[dev] += game.optime + extradm
1048 prout(_("***Shields are down."))
1049 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1056 def torpedo(origin, bearing, dispersion, number, nburst):
1057 "Let a photon torpedo fly"
1058 if not damaged(DSRSENS) or game.condition=="docked":
1059 setwnd(srscan_window)
1061 setwnd(message_window)
1062 ac = bearing + 0.25*dispersion # dispersion is a random variable
1063 bullseye = (15.0 - bearing)*0.5235988
1064 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1065 bumpto = coord(0, 0)
1066 # Loop to move a single torpedo
1067 setwnd(message_window)
1068 for step in range(1, QUADSIZE*2):
1069 if not track.next(): break
1071 if not w.valid_sector():
1073 iquad=game.quad[w.i][w.j]
1074 tracktorpedo(origin, w, step, number, nburst, iquad)
1078 if not damaged(DSRSENS) or game.condition == "docked":
1079 skip(1); # start new line after text track
1080 if iquad in ('E', 'F'): # Hit our ship
1082 prout(_("Torpedo hits %s.") % crmshp())
1083 hit = 700.0 + randreal(100) - \
1084 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1085 newcnd(); # we're blown out of dock
1086 if game.landed or game.condition=="docked":
1087 return hit # Cheat if on a planet
1088 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1089 # is 143 degrees, which is almost exactly 4.8 clockface units
1090 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1092 bumpto = displacement.sector()
1093 if not bumpto.valid_sector():
1095 if game.quad[bumpto.i][bumpto.j]==' ':
1098 if game.quad[bumpto.i][bumpto.j]!='.':
1099 # can't move into object
1101 game.sector = bumpto
1103 game.quad[w.i][w.j]='.'
1104 game.quad[bumpto.i][bumpto.j]=iquad
1105 prout(_(" displaced by blast to Sector %s ") % bumpto)
1106 for enemy in game.enemies:
1107 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1108 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1110 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1112 if iquad in ('C', 'S') and withprob(0.05):
1113 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1114 prout(_(" torpedo neutralized."))
1116 for enemy in game.enemies:
1117 if w == enemy.location:
1119 kp = math.fabs(enemy.power)
1120 h1 = 700.0 + randrange(100) - \
1121 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1129 if enemy.power == 0:
1132 proutn(crmena(True, iquad, "sector", w))
1133 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1135 bumpto = displacement.sector()
1136 if not bumpto.valid_sector():
1137 prout(_(" damaged but not destroyed."))
1139 if game.quad[bumpto.i][bumpto.j] == ' ':
1140 prout(_(" buffeted into black hole."))
1141 deadkl(w, iquad, bumpto)
1142 if game.quad[bumpto.i][bumpto.j] != '.':
1143 prout(_(" damaged but not destroyed."))
1145 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1146 enemy.location = bumpto
1147 game.quad[w.i][w.j]='.'
1148 game.quad[bumpto.i][bumpto.j]=iquad
1149 for enemy in game.enemies:
1150 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1151 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1153 elif iquad == 'B': # Hit a base
1155 prout(_("***STARBASE DESTROYED.."))
1156 game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
1157 game.quad[w.i][w.j]='.'
1158 game.base.invalidate()
1159 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1
1160 game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1
1161 game.state.basekl += 1
1164 elif iquad == 'P': # Hit a planet
1165 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1166 game.state.nplankl += 1
1167 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1168 game.iplnet.pclass = "destroyed"
1170 game.plnet.invalidate()
1171 game.quad[w.i][w.j] = '.'
1173 # captain perishes on planet
1176 elif iquad == '@': # Hit an inhabited world -- very bad!
1177 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1178 game.state.nworldkl += 1
1179 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1180 game.iplnet.pclass = "destroyed"
1182 game.plnet.invalidate()
1183 game.quad[w.i][w.j] = '.'
1185 # captain perishes on planet
1187 prout(_("The torpedo destroyed an inhabited planet."))
1189 elif iquad == '*': # Hit a star
1193 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1195 elif iquad == '?': # Hit a thingy
1196 if not (game.options & OPTION_THINGY) or withprob(0.3):
1198 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1200 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1202 proutn(_("Mr. Spock-"))
1203 prouts(_(" \"Fascinating!\""))
1207 # Stas Sergeev added the possibility that
1208 # you can shove the Thingy and piss it off.
1209 # It then becomes an enemy and may fire at you.
1212 elif iquad == ' ': # Black hole
1214 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1216 elif iquad == '#': # hit the web
1218 prout(_("***Torpedo absorbed by Tholian web."))
1220 elif iquad == 'T': # Hit a Tholian
1221 h1 = 700.0 + randrange(100) - \
1222 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle))
1225 game.quad[w.i][w.j] = '.'
1230 proutn(crmena(True, 'T', "sector", w))
1232 prout(_(" survives photon blast."))
1234 prout(_(" disappears."))
1235 game.tholian.move(None)
1236 game.quad[w.i][w.j] = '#'
1241 proutn("Don't know how to handle torpedo collision with ")
1242 proutn(crmena(True, iquad, "sector", w))
1247 prout(_("Torpedo missed."))
1251 "Critical-hit resolution."
1252 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1254 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1255 proutn(_("***CRITICAL HIT--"))
1256 # Select devices and cause damage
1262 # Cheat to prevent shuttle damage unless on ship
1263 if not (game.damage[j]<0.0 or (j==DSHUTTL and game.iscraft != "onship")):
1266 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1267 game.damage[j] += extradm
1269 for (i, j) in enumerate(cdam):
1271 if skipcount % 3 == 2 and i < len(cdam)-1:
1276 prout(_(" damaged."))
1277 if damaged(DSHIELD) and game.shldup:
1278 prout(_("***Shields knocked down."))
1281 def attack(torps_ok):
1282 # bad guy attacks us
1283 # torps_ok == False forces use of phasers in an attack
1284 # game could be over at this point, check
1287 attempt = False; ihurt = False;
1288 hitmax=0.0; hittot=0.0; chgfac=1.0
1291 prout("=== ATTACK!")
1292 # Tholian gets to move before attacking
1295 # if you have just entered the RNZ, you'll get a warning
1296 if game.neutz: # The one chance not to be attacked
1299 # commanders get a chance to tac-move towards you
1300 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:
1302 # if no enemies remain after movement, we're done
1303 if len(game.enemies)==0 or (len(game.enemies)==1 and thing == game.quadrant and not thing.angry):
1305 # set up partial hits if attack happens during shield status change
1306 pfac = 1.0/game.inshld
1308 chgfac = 0.25 + randreal(0.5)
1310 # message verbosity control
1311 if game.skill <= SKILL_FAIR:
1313 for enemy in game.enemies:
1315 continue; # too weak to attack
1316 # compute hit strength and diminish shield power
1318 # Increase chance of photon torpedos if docked or enemy energy is low
1319 if game.condition == "docked":
1321 if enemy.power < 500:
1323 if enemy.type=='T' or (enemy.type=='?' and not thing.angry):
1325 # different enemies have different probabilities of throwing a torp
1326 usephasers = not torps_ok or \
1327 (enemy.type == 'K' and r > 0.0005) or \
1328 (enemy.type=='C' and r > 0.015) or \
1329 (enemy.type=='R' and r > 0.3) or \
1330 (enemy.type=='S' and r > 0.07) or \
1331 (enemy.type=='?' and r > 0.05)
1332 if usephasers: # Enemy uses phasers
1333 if game.condition == "docked":
1334 continue; # Don't waste the effort!
1335 attempt = True; # Attempt to attack
1336 dustfac = randreal(0.8, 0.85)
1337 hit = enemy.power*math.pow(dustfac,enemy.kavgd)
1339 else: # Enemy uses photon torpedo
1340 # We should be able to make the bearing() method work here
1341 pcourse = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1343 proutn(_("***TORPEDO INCOMING"))
1344 if not damaged(DSRSENS):
1345 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1348 dispersion = (randreal()+randreal())*0.5 - 0.5
1349 dispersion += 0.002*enemy.power*dispersion
1350 hit = torpedo(enemy.location, pcourse, dispersion, number=1, nburst=1)
1351 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1352 finish(FWON); # Klingons did themselves in!
1353 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1354 return # Supernova or finished
1357 # incoming phaser or torpedo, shields may dissipate it
1358 if game.shldup or game.shldchg or game.condition=="docked":
1359 # shields will take hits
1360 propor = pfac * game.shield
1361 if game.condition =="docked":
1365 hitsh = propor*chgfac*hit+1.0
1367 if absorb > game.shield:
1368 absorb = game.shield
1369 game.shield -= absorb
1371 # taking a hit blasts us out of a starbase dock
1372 if game.condition == "docked":
1374 # but the shields may take care of it
1375 if propor > 0.1 and hit < 0.005*game.energy:
1377 # hit from this opponent got through shields, so take damage
1379 proutn(_("%d unit hit") % int(hit))
1380 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1381 proutn(_(" on the ") + crmshp())
1382 if not damaged(DSRSENS) and usephasers:
1383 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1385 # Decide if hit is critical
1391 if game.energy <= 0:
1392 # Returning home upon your shield, not with it...
1395 if not attempt and game.condition == "docked":
1396 prout(_("***Enemies decide against attacking your ship."))
1397 percent = 100.0*pfac*game.shield+0.5
1399 # Shields fully protect ship
1400 proutn(_("Enemy attack reduces shield strength to "))
1402 # Emit message if starship suffered hit(s)
1404 proutn(_("Energy left %2d shields ") % int(game.energy))
1407 elif not damaged(DSHIELD):
1410 proutn(_("damaged, "))
1411 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1412 # Check if anyone was hurt
1413 if hitmax >= 200 or hittot >= 500:
1414 icas = randrange(int(hittot * 0.015))
1417 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1418 prout(_(" in that last attack.\""))
1420 game.state.crew -= icas
1421 # After attack, reset average distance to enemies
1422 for enemy in game.enemies:
1423 enemy.kavgd = enemy.kdist
1424 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1427 def deadkl(w, type, mv):
1428 "Kill a Klingon, Tholian, Romulan, or Thingy."
1429 # Added mv to allow enemy to "move" before dying
1430 proutn(crmena(True, type, "sector", mv))
1431 # Decide what kind of enemy it is and update appropriately
1433 # Chalk up a Romulan
1434 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1436 game.state.nromrem -= 1
1445 # Killed some type of Klingon
1446 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1449 game.state.kcmdr.remove(game.quadrant)
1451 if game.state.kcmdr:
1452 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1453 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1456 game.state.remkl -= 1
1458 game.state.nscrem -= 1
1459 game.state.kscmdr.invalidate()
1464 # For each kind of enemy, finish message to player
1465 prout(_(" destroyed."))
1466 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1469 # Remove enemy ship from arrays describing local conditions
1470 for e in game.enemies:
1477 "Return None if target is invalid, otherwise return a course angle."
1478 if not w.valid_sector():
1482 # FIXME: C code this was translated from is wacky -- why the sign reversal?
1483 delta.j = (w.j - game.sector.j);
1484 delta.i = (game.sector.i - w.i);
1485 if delta == coord(0, 0):
1487 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1488 prout(_(" I recommend an immediate review of"))
1489 prout(_(" the Captain's psychological profile.\""))
1492 return delta.bearing()
1495 "Launch photon torpedo salvo."
1498 if damaged(DPHOTON):
1499 prout(_("Photon tubes damaged."))
1503 prout(_("No torpedoes left."))
1506 # First, get torpedo count
1509 if scanner.token == "IHALPHA":
1512 elif scanner.token == "IHEOL" or not scanner.waiting():
1513 prout(_("%d torpedoes left.") % game.torps)
1515 proutn(_("Number of torpedoes to fire- "))
1516 continue # Go back around to get a number
1517 else: # key == "IHREAL"
1519 if n <= 0: # abort command
1524 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1527 scanner.chew() # User requested more torps than available
1528 continue # Go back around
1529 break # All is good, go to next stage
1533 key = scanner.next()
1534 if i==0 and key == "IHEOL":
1535 break; # no coordinate waiting, we will try prompting
1536 if i==1 and key == "IHEOL":
1537 # direct all torpedoes at one target
1539 target.append(target[0])
1540 tcourse.append(tcourse[0])
1543 scanner.push(scanner.token)
1544 target.append(scanner.getcoord())
1545 if target[-1] == None:
1547 tcourse.append(targetcheck(target[-1]))
1548 if tcourse[-1] == None:
1551 if len(target) == 0:
1552 # prompt for each one
1554 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1556 target.append(scanner.getcoord())
1557 if target[-1] == None:
1559 tcourse.append(targetcheck(target[-1]))
1560 if tcourse[-1] == None:
1563 # Loop for moving <n> torpedoes
1565 if game.condition != "docked":
1567 dispersion = (randreal()+randreal())*0.5 -0.5
1568 if math.fabs(dispersion) >= 0.47:
1570 dispersion *= randreal(1.2, 2.2)
1572 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1574 prouts(_("***TORPEDO MISFIRES."))
1577 prout(_(" Remainder of burst aborted."))
1579 prout(_("***Photon tubes damaged by misfire."))
1580 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1582 if game.shldup or game.condition == "docked":
1583 dispersion *= 1.0 + 0.0001*game.shield
1584 torpedo(game.sector, tcourse[i], dispersion, number=i, nburst=n)
1585 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1587 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0:
1591 "Check for phasers overheating."
1593 checkburn = (rpow-1500.0)*0.00038
1594 if withprob(checkburn):
1595 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1596 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1598 def checkshctrl(rpow):
1599 "Check shield control."
1602 prout(_("Shields lowered."))
1604 # Something bad has happened
1605 prouts(_("***RED ALERT! RED ALERT!"))
1607 hit = rpow*game.shield/game.inshld
1608 game.energy -= rpow+hit*0.8
1609 game.shield -= hit*0.2
1610 if game.energy <= 0.0:
1611 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1616 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1618 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1619 icas = randrange(int(hit*0.012))
1624 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1625 prout(_(" %d casualties so far.\"") % icas)
1627 game.state.crew -= icas
1629 prout(_("Phaser energy dispersed by shields."))
1630 prout(_("Enemy unaffected."))
1635 "Register a phaser hit on Klingons and Romulans."
1639 for (k, wham) in enumerate(hits):
1642 dustfac = randreal(0.9, 1.0)
1643 hit = wham*math.pow(dustfac,game.enemies[kk].kdist)
1644 kpini = game.enemies[kk].power
1645 kp = math.fabs(kpini)
1646 if PHASEFAC*hit < kp:
1648 if game.enemies[kk].power < 0:
1649 game.enemies[kk].power -= -kp
1651 game.enemies[kk].power -= kp
1652 kpow = game.enemies[kk].power
1653 w = game.enemies[kk].location
1655 if not damaged(DSRSENS):
1657 proutn(_("%d unit hit on ") % int(hit))
1659 proutn(_("Very small hit on "))
1660 ienm = game.quad[w.i][w.j]
1663 proutn(crmena(False, ienm, "sector", w))
1667 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1671 kk -= 1 # don't do the increment
1673 else: # decide whether or not to emasculate klingon
1674 if kpow>0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1675 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1676 prout(_(" has just lost its firepower.\""))
1677 game.enemies[kk].power = -kpow
1682 "Fire phasers at bad guys."
1684 kz = 0; k = 1; irec=0 # Cheating inhibitor
1685 ifast = False; no = False; itarg = True; msgflag = True; rpow=0
1689 # SR sensors and Computer are needed for automode
1690 if damaged(DSRSENS) or damaged(DCOMPTR):
1692 if game.condition == "docked":
1693 prout(_("Phasers can't be fired through base shields."))
1696 if damaged(DPHASER):
1697 prout(_("Phaser control damaged."))
1701 if damaged(DSHCTRL):
1702 prout(_("High speed shield control damaged."))
1705 if game.energy <= 200.0:
1706 prout(_("Insufficient energy to activate high-speed shield control."))
1709 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1711 # Original code so convoluted, I re-did it all
1712 # (That was Tom Almy talking about the C code, I think -- ESR)
1713 while automode=="NOTSET":
1715 if key == "IHALPHA":
1716 if scanner.sees("manual"):
1717 if len(game.enemies)==0:
1718 prout(_("There is no enemy present to select."))
1721 automode="AUTOMATIC"
1724 key = scanner.next()
1725 elif scanner.sees("automatic"):
1726 if (not itarg) and len(game.enemies) != 0:
1727 automode = "FORCEMAN"
1729 if len(game.enemies)==0:
1730 prout(_("Energy will be expended into space."))
1731 automode = "AUTOMATIC"
1732 key = scanner.next()
1733 elif scanner.sees("no"):
1738 elif key == "IHREAL":
1739 if len(game.enemies)==0:
1740 prout(_("Energy will be expended into space."))
1741 automode = "AUTOMATIC"
1743 automode = "FORCEMAN"
1745 automode = "AUTOMATIC"
1748 if len(game.enemies)==0:
1749 prout(_("Energy will be expended into space."))
1750 automode = "AUTOMATIC"
1752 automode = "FORCEMAN"
1754 proutn(_("Manual or automatic? "))
1759 if automode == "AUTOMATIC":
1760 if key == "IHALPHA" and scanner.sees("no"):
1762 key = scanner.next()
1763 if key != "IHREAL" and len(game.enemies) != 0:
1764 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1769 for i in range(len(game.enemies)):
1770 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1772 proutn(_("%d units required. ") % irec)
1774 proutn(_("Units to fire= "))
1775 key = scanner.next()
1780 proutn(_("Energy available= %.2f") % avail)
1783 if not rpow > avail:
1790 if key == "IHALPHA" and scanner.sees("no"):
1793 game.energy -= 200; # Go and do it!
1794 if checkshctrl(rpow):
1799 if len(game.enemies):
1802 for i in range(len(game.enemies)):
1806 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))
1807 over = randreal(1.01, 1.06) * hits[i]
1809 powrem -= hits[i] + over
1810 if powrem <= 0 and temp < hits[i]:
1819 if extra > 0 and not game.alldone:
1821 proutn(_("*** Tholian web absorbs "))
1822 if len(game.enemies)>0:
1823 proutn(_("excess "))
1824 prout(_("phaser energy."))
1826 prout(_("%d expended on empty space.") % int(extra))
1827 elif automode == "FORCEMAN":
1830 if damaged(DCOMPTR):
1831 prout(_("Battle computer damaged, manual fire only."))
1834 prouts(_("---WORKING---"))
1836 prout(_("Short-range-sensors-damaged"))
1837 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1838 prout(_("Manual-fire-must-be-used"))
1840 elif automode == "MANUAL":
1842 for k in range(len(game.enemies)):
1843 aim = game.enemies[k].location
1844 ienm = game.quad[aim.i][aim.j]
1846 proutn(_("Energy available= %.2f") % (avail-0.006))
1850 if damaged(DSRSENS) and \
1851 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1852 prout(cramen(ienm) + _(" can't be located without short range scan."))
1855 hits[k] = 0; # prevent overflow -- thanks to Alexei Voitenko
1860 if itarg and k > kz:
1861 irec=(abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9,game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1864 if not damaged(DCOMPTR):
1869 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1870 key = scanner.next()
1871 if key == "IHALPHA" and scanner.sees("no"):
1873 key = scanner.next()
1875 if key == "IHALPHA":
1879 if k==1: # Let me say I'm baffled by this
1882 if scanner.real < 0:
1886 hits[k] = scanner.real
1887 rpow += scanner.real
1888 # If total requested is too much, inform and start over
1890 prout(_("Available energy exceeded -- try again."))
1893 key = scanner.next(); # scan for next value
1896 # zero energy -- abort
1899 if key == "IHALPHA" and scanner.sees("no"):
1904 game.energy -= 200.0
1905 if checkshctrl(rpow):
1909 # Say shield raised or malfunction, if necessary
1916 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1917 prouts(_(" CLICK CLICK POP . . ."))
1918 prout(_(" No response, sir!"))
1921 prout(_("Shields raised."))
1926 # Code from events,c begins here.
1928 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1929 # event of each type active at any given time. Mostly these means we can
1930 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1931 # BSD Trek, from which we swiped the idea, can have up to 5.
1933 def unschedule(evtype):
1934 "Remove an event from the schedule."
1935 game.future[evtype].date = FOREVER
1936 return game.future[evtype]
1938 def is_scheduled(evtype):
1939 "Is an event of specified type scheduled."
1940 return game.future[evtype].date != FOREVER
1942 def scheduled(evtype):
1943 "When will this event happen?"
1944 return game.future[evtype].date
1946 def schedule(evtype, offset):
1947 "Schedule an event of specified type."
1948 game.future[evtype].date = game.state.date + offset
1949 return game.future[evtype]
1951 def postpone(evtype, offset):
1952 "Postpone a scheduled event."
1953 game.future[evtype].date += offset
1956 "Rest period is interrupted by event."
1959 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
1961 game.resting = False
1967 "Run through the event queue looking for things to do."
1969 fintim = game.state.date + game.optime; yank=0
1970 ictbeam = False; istract = False
1971 w = coord(); hold = coord()
1972 ev = event(); ev2 = event()
1974 def tractorbeam(yank):
1975 "Tractor-beaming cases merge here."
1977 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
1979 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
1980 # If Kirk & Co. screwing around on planet, handle
1981 atover(True) # atover(true) is Grab
1984 if game.icraft: # Caught in Galileo?
1987 # Check to see if shuttle is aboard
1988 if game.iscraft == "offship":
1991 prout(_("Galileo, left on the planet surface, is captured"))
1992 prout(_("by aliens and made into a flying McDonald's."))
1993 game.damage[DSHUTTL] = -10
1994 game.iscraft = "removed"
1996 prout(_("Galileo, left on the planet surface, is well hidden."))
1998 game.quadrant = game.state.kscmdr
2000 game.quadrant = game.state.kcmdr[i]
2001 game.sector = randplace(QUADSIZE)
2002 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
2003 % (game.quadrant, game.sector))
2005 prout(_("(Remainder of rest/repair period cancelled.)"))
2006 game.resting = False
2008 if not damaged(DSHIELD) and game.shield > 0:
2009 doshield(shraise=True) # raise shields
2010 game.shldchg = False
2012 prout(_("(Shields not currently useable.)"))
2014 # Adjust finish time to time of tractor beaming
2015 fintim = game.state.date+game.optime
2016 attack(torps_ok=False)
2017 if not game.state.kcmdr:
2020 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2023 "Code merges here for any commander destroying a starbase."
2024 # Not perfect, but will have to do
2025 # Handle case where base is in same quadrant as starship
2026 if game.battle == game.quadrant:
2027 game.state.chart[game.battle.i][game.battle.j].starbase = False
2028 game.quad[game.base.i][game.base.j] = '.'
2029 game.base.invalidate()
2032 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2033 elif game.state.baseq and communicating():
2034 # Get word via subspace radio
2037 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2038 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2040 prout(_("the Klingon Super-Commander"))
2042 prout(_("a Klingon Commander"))
2043 game.state.chart[game.battle.i][game.battle.j].starbase = False
2044 # Remove Starbase from galaxy
2045 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2046 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2048 # reinstate a commander's base attack
2052 game.battle.invalidate()
2054 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2055 for i in range(1, NEVENTS):
2056 if i == FSNOVA: proutn("=== Supernova ")
2057 elif i == FTBEAM: proutn("=== T Beam ")
2058 elif i == FSNAP: proutn("=== Snapshot ")
2059 elif i == FBATTAK: proutn("=== Base Attack ")
2060 elif i == FCDBAS: proutn("=== Base Destroy ")
2061 elif i == FSCMOVE: proutn("=== SC Move ")
2062 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2063 elif i == FDSPROB: proutn("=== Probe Move ")
2064 elif i == FDISTR: proutn("=== Distress Call ")
2065 elif i == FENSLV: proutn("=== Enslavement ")
2066 elif i == FREPRO: proutn("=== Klingon Build ")
2068 prout("%.2f" % (scheduled(i)))
2071 radio_was_broken = damaged(DRADIO)
2074 # Select earliest extraneous event, evcode==0 if no events
2079 for l in range(1, NEVENTS):
2080 if game.future[l].date < datemin:
2083 prout("== Event %d fires" % evcode)
2084 datemin = game.future[l].date
2085 xtime = datemin-game.state.date
2086 game.state.date = datemin
2087 # Decrement Federation resources and recompute remaining time
2088 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2090 if game.state.remtime <=0:
2093 # Any crew left alive?
2094 if game.state.crew <=0:
2097 # Is life support adequate?
2098 if damaged(DLIFSUP) and game.condition != "docked":
2099 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2102 game.lsupres -= xtime
2103 if game.damage[DLIFSUP] <= xtime:
2104 game.lsupres = game.inlsr
2107 if game.condition == "docked":
2109 # Don't fix Deathray here
2110 for l in range(NDEVICES):
2111 if game.damage[l] > 0.0 and l != DDRAY:
2112 if game.damage[l]-repair > 0.0:
2113 game.damage[l] -= repair
2115 game.damage[l] = 0.0
2116 # If radio repaired, update star chart and attack reports
2117 if radio_was_broken and not damaged(DRADIO):
2118 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2119 prout(_(" surveillance reports are coming in."))
2121 if not game.iseenit:
2125 prout(_(" The star chart is now up to date.\""))
2127 # Cause extraneous event EVCODE to occur
2128 game.optime -= xtime
2129 if evcode == FSNOVA: # Supernova
2132 schedule(FSNOVA, expran(0.5*game.intime))
2133 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2135 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2136 if game.state.nscrem == 0 or \
2137 ictbeam or istract or \
2138 game.condition=="docked" or game.isatb==1 or game.iscate:
2140 if game.ientesc or \
2141 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2142 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2143 (damaged(DSHIELD) and \
2144 (game.energy < 2500 or damaged(DPHASER)) and \
2145 (game.torps < 5 or damaged(DPHOTON))):
2147 istract = ictbeam = True
2148 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2151 elif evcode == FTBEAM: # Tractor beam
2152 if not game.state.kcmdr:
2155 i = randrange(len(game.state.kcmdr))
2156 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2157 if istract or game.condition == "docked" or yank == 0:
2158 # Drats! Have to reschedule
2160 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2164 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2165 game.snapsht = copy.deepcopy(game.state)
2166 game.state.snap = True
2167 schedule(FSNAP, expran(0.5 * game.intime))
2168 elif evcode == FBATTAK: # Commander attacks starbase
2169 if not game.state.kcmdr or not game.state.baseq:
2175 for ibq in game.state.baseq:
2176 for cmdr in game.state.kcmdr:
2177 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2180 # no match found -- try later
2181 schedule(FBATTAK, expran(0.3*game.intime))
2186 # commander + starbase combination found -- launch attack
2188 schedule(FCDBAS, randreal(1.0, 4.0))
2189 if game.isatb: # extra time if SC already attacking
2190 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2191 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2192 game.iseenit = False
2193 if not communicating():
2194 continue # No warning :-(
2198 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2199 prout(_(" reports that it is under attack and that it can"))
2200 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2203 elif evcode == FSCDBAS: # Supercommander destroys base
2206 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2207 continue # WAS RETURN!
2209 game.battle = game.state.kscmdr
2211 elif evcode == FCDBAS: # Commander succeeds in destroying base
2214 if not game.state.baseq() \
2215 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2216 game.battle.invalidate()
2218 # find the lucky pair
2219 for cmdr in game.state.kcmdr:
2220 if cmdr == game.battle:
2223 # No action to take after all
2226 elif evcode == FSCMOVE: # Supercommander moves
2227 schedule(FSCMOVE, 0.2777)
2228 if not game.ientesc and not istract and game.isatb != 1 and \
2229 (not game.iscate or not game.justin):
2231 elif evcode == FDSPROB: # Move deep space probe
2232 schedule(FDSPROB, 0.01)
2233 if not game.probe.next():
2234 if not game.probe.quadrant().valid_quadrant() or \
2235 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2236 # Left galaxy or ran into supernova
2240 proutn(_("Lt. Uhura- \"The deep space probe "))
2241 if not game.probe.quadrant().valid_quadrant():
2242 prout(_("has left the galaxy.\""))
2244 prout(_("is no longer transmitting.\""))
2250 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2251 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2253 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2254 chp.klingons = pdest.klingons
2255 chp.starbase = pdest.starbase
2256 chp.stars = pdest.stars
2257 pdest.charted = True
2258 game.probe.moves -= 1 # One less to travel
2259 if game.probe.arrived() and game.isarmed and pdest.stars:
2260 supernova(game.probe) # fire in the hole!
2262 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2264 elif evcode == FDISTR: # inhabited system issues distress call
2266 # try a whole bunch of times to find something suitable
2267 for i in range(100):
2268 # need a quadrant which is not the current one,
2269 # which has some stars which are inhabited and
2270 # not already under attack, which is not
2271 # supernova'ed, and which has some Klingons in it
2272 w = randplace(GALSIZE)
2273 q = game.state.galaxy[w.i][w.j]
2274 if not (game.quadrant == w or q.planet == None or \
2275 not q.planet.inhabited or \
2276 q.supernova or q.status!="secure" or q.klingons<=0):
2279 # can't seem to find one; ignore this call
2281 prout("=== Couldn't find location for distress event.")
2283 # got one!! Schedule its enslavement
2284 ev = schedule(FENSLV, expran(game.intime))
2286 q.status = "distressed"
2287 # tell the captain about it if we can
2289 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2291 prout(_("by a Klingon invasion fleet."))
2294 elif evcode == FENSLV: # starsystem is enslaved
2295 ev = unschedule(FENSLV)
2296 # see if current distress call still active
2297 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2301 q.status = "enslaved"
2303 # play stork and schedule the first baby
2304 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2305 ev2.quadrant = ev.quadrant
2307 # report the disaster if we can
2309 prout(_("Uhura- We've lost contact with starsystem %s") % \
2311 prout(_("in Quadrant %s.\n") % ev.quadrant)
2312 elif evcode == FREPRO: # Klingon reproduces
2313 # If we ever switch to a real event queue, we'll need to
2314 # explicitly retrieve and restore the x and y.
2315 ev = schedule(FREPRO, expran(1.0 * game.intime))
2316 # see if current distress call still active
2317 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2321 if game.state.remkl >=MAXKLGAME:
2322 continue # full right now
2323 # reproduce one Klingon
2326 if game.klhere >= MAXKLQUAD:
2328 # this quadrant not ok, pick an adjacent one
2329 for m.i in range(w.i - 1, w.i + 2):
2330 for m.j in range(w.j - 1, w.j + 2):
2331 if not m.valid_quadrant():
2333 q = game.state.galaxy[m.i][m.j]
2334 # check for this quad ok (not full & no snova)
2335 if q.klingons >= MAXKLQUAD or q.supernova:
2339 continue # search for eligible quadrant failed
2343 game.state.remkl += 1
2345 if game.quadrant == w:
2347 game.enemies.append(newkling())
2348 # recompute time left
2351 if game.quadrant == w:
2352 prout(_("Spock- sensors indicate the Klingons have"))
2353 prout(_("launched a warship from %s.") % q.planet)
2355 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2356 if q.planet != None:
2357 proutn(_("near %s ") % q.planet)
2358 prout(_("in Quadrant %s.") % w)
2364 key = scanner.next()
2367 proutn(_("How long? "))
2372 origTime = delay = scanner.real
2375 if delay >= game.state.remtime or len(game.enemies) != 0:
2376 proutn(_("Are you sure? "))
2379 # Alternate resting periods (events) with attacks
2383 game.resting = False
2384 if not game.resting:
2385 prout(_("%d stardates left.") % int(game.state.remtime))
2387 temp = game.optime = delay
2388 if len(game.enemies):
2389 rtime = randreal(1.0, 2.0)
2393 if game.optime < delay:
2394 attack(torps_ok=False)
2402 # Repair Deathray if long rest at starbase
2403 if origTime-delay >= 9.99 and game.condition == "docked":
2404 game.damage[DDRAY] = 0.0
2405 # leave if quadrant supernovas
2406 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2408 game.resting = False
2413 ncourse = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2414 newc = coord(); neighbor = coord(); bump = coord(0, 0)
2416 # Wow! We've supernova'ed
2417 supernova(game.quadrant)
2419 # handle initial nova
2420 game.quad[nov.i][nov.j] = '.'
2421 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2422 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2423 game.state.starkl += 1
2424 # Set up queue to recursively trigger adjacent stars
2430 for offset.i in range(-1, 1+1):
2431 for offset.j in range(-1, 1+1):
2432 if offset.j==0 and offset.i==0:
2434 neighbor = start + offset
2435 if not neighbor.valid_sector():
2437 iquad = game.quad[neighbor.i][neighbor.j]
2438 # Empty space ends reaction
2439 if iquad in ('.', '?', ' ', 'T', '#'):
2441 elif iquad == '*': # Affect another star
2443 # This star supernovas
2444 supernova(game.quadrant)
2447 hits.append(neighbor)
2448 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2449 game.state.starkl += 1
2450 proutn(crmena(True, '*', "sector", neighbor))
2452 game.quad[neighbor.i][neighbor.j] = '.'
2454 elif iquad in ('P', '@'): # Destroy planet
2455 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2457 game.state.nplankl += 1
2459 game.state.worldkl += 1
2460 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2461 game.iplnet.pclass = "destroyed"
2463 game.plnet.invalidate()
2467 game.quad[neighbor.i][neighbor.j] = '.'
2468 elif iquad == 'B': # Destroy base
2469 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2470 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2471 game.base.invalidate()
2472 game.state.basekl += 1
2474 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2475 game.quad[neighbor.i][neighbor.j] = '.'
2476 elif iquad in ('E', 'F'): # Buffet ship
2477 prout(_("***Starship buffeted by nova."))
2479 if game.shield >= 2000.0:
2480 game.shield -= 2000.0
2482 diff = 2000.0 - game.shield
2486 prout(_("***Shields knocked out."))
2487 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2489 game.energy -= 2000.0
2490 if game.energy <= 0:
2493 # add in course nova contributes to kicking starship
2494 bump += (game.sector-hits[mm]).sgn()
2495 elif iquad == 'K': # kill klingon
2496 deadkl(neighbor, iquad, neighbor)
2497 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2498 for ll in range(len(game.enemies)):
2499 if game.enemies[ll].location == neighbor:
2501 game.enemies[ll].power -= 800.0 # If firepower is lost, die
2502 if game.enemies[ll].power <= 0.0:
2503 deadkl(neighbor, iquad, neighbor)
2505 newc = neighbor + neighbor - hits[mm]
2506 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2507 if not newc.valid_sector():
2508 # can't leave quadrant
2511 iquad1 = game.quad[newc.i][newc.j]
2513 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2515 deadkl(neighbor, iquad, newc)
2518 # can't move into something else
2521 proutn(_(", buffeted to Sector %s") % newc)
2522 game.quad[neighbor.i][neighbor.j] = '.'
2523 game.quad[newc.i][newc.j] = iquad
2524 game.enemies[ll].move(newc)
2525 # Starship affected by nova -- kick it away.
2527 direc = ncourse[3*(bump.i+1)+bump.j+2]
2532 scourse = course(bearing=direc, distance=dist)
2533 game.optime = scourse.time(warp=4)
2535 prout(_("Force of nova displaces starship."))
2536 imove(scourse, noattack=True)
2537 game.optime = scourse.time(warp=4)
2541 "Star goes supernova."
2546 # Scheduled supernova -- select star at random.
2549 for nq.i in range(GALSIZE):
2550 for nq.j in range(GALSIZE):
2551 stars += game.state.galaxy[nq.i][nq.j].stars
2553 return # nothing to supernova exists
2554 num = randrange(stars) + 1
2555 for nq.i in range(GALSIZE):
2556 for nq.j in range(GALSIZE):
2557 num -= game.state.galaxy[nq.i][nq.j].stars
2563 proutn("=== Super nova here?")
2566 if not nq == game.quadrant or game.justin:
2567 # it isn't here, or we just entered (treat as enroute)
2570 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2571 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2574 # we are in the quadrant!
2575 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2576 for ns.i in range(QUADSIZE):
2577 for ns.j in range(QUADSIZE):
2578 if game.quad[ns.i][ns.j]=='*':
2585 prouts(_("***RED ALERT! RED ALERT!"))
2587 prout(_("***Incipient supernova detected at Sector %s") % ns)
2588 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2589 proutn(_("Emergency override attempts t"))
2590 prouts("***************")
2594 # destroy any Klingons in supernovaed quadrant
2595 kldead = game.state.galaxy[nq.i][nq.j].klingons
2596 game.state.galaxy[nq.i][nq.j].klingons = 0
2597 if nq == game.state.kscmdr:
2598 # did in the Supercommander!
2599 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2603 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2604 comkills = len(game.state.kcmdr) - len(survivors)
2605 game.state.kcmdr = survivors
2607 if not game.state.kcmdr:
2609 game.state.remkl -= kldead
2610 # destroy Romulans and planets in supernovaed quadrant
2611 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2612 game.state.galaxy[nq.i][nq.j].romulans = 0
2613 game.state.nromrem -= nrmdead
2615 for loop in range(game.inplan):
2616 if game.state.planets[loop].quadrant == nq:
2617 game.state.planets[loop].pclass = "destroyed"
2619 # Destroy any base in supernovaed quadrant
2620 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2621 # If starship caused supernova, tally up destruction
2623 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2624 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2625 game.state.nplankl += npdead
2626 # mark supernova in galaxy and in star chart
2627 if game.quadrant == nq or communicating():
2628 game.state.galaxy[nq.i][nq.j].supernova = True
2629 # If supernova destroys last Klingons give special message
2630 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2633 prout(_("Lucky you!"))
2634 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2637 # if some Klingons remain, continue or die in supernova
2642 # Code from finish.c ends here.
2645 "Self-destruct maneuver. Finish with a BANG!"
2647 if damaged(DCOMPTR):
2648 prout(_("Computer damaged; cannot execute destruct sequence."))
2650 prouts(_("---WORKING---")); skip(1)
2651 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2652 prouts(" 10"); skip(1)
2653 prouts(" 9"); skip(1)
2654 prouts(" 8"); skip(1)
2655 prouts(" 7"); skip(1)
2656 prouts(" 6"); skip(1)
2658 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2660 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2662 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2666 if game.passwd != scanner.token:
2667 prouts(_("PASSWORD-REJECTED;"))
2669 prouts(_("CONTINUITY-EFFECTED"))
2672 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2673 prouts(" 5"); skip(1)
2674 prouts(" 4"); skip(1)
2675 prouts(" 3"); skip(1)
2676 prouts(" 2"); skip(1)
2677 prouts(" 1"); skip(1)
2679 prouts(_("GOODBYE-CRUEL-WORLD"))
2687 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2691 if len(game.enemies) != 0:
2692 whammo = 25.0 * game.energy
2694 while l <= len(game.enemies):
2695 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2696 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2701 "Compute our rate of kils over time."
2702 elapsed = game.state.date - game.indate
2703 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2706 starting = (game.inkling + game.incom + game.inscom)
2707 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2708 return (starting - remaining)/elapsed
2712 badpt = 5.0*game.state.starkl + \
2714 10.0*game.state.nplankl + \
2715 300*game.state.nworldkl + \
2717 100.0*game.state.basekl +\
2719 if game.ship == 'F':
2721 elif game.ship == None:
2726 # end the game, with appropriate notfications
2730 prout(_("It is stardate %.1f.") % game.state.date)
2732 if ifin == FWON: # Game has been won
2733 if game.state.nromrem != 0:
2734 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2737 prout(_("You have smashed the Klingon invasion fleet and saved"))
2738 prout(_("the Federation."))
2743 badpt = 0.0 # Close enough!
2744 # killsPerDate >= RateMax
2745 if game.state.date-game.indate < 5.0 or \
2746 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2748 prout(_("In fact, you have done so well that Starfleet Command"))
2749 if game.skill == SKILL_NOVICE:
2750 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2751 elif game.skill == SKILL_FAIR:
2752 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2753 elif game.skill == SKILL_GOOD:
2754 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2755 elif game.skill == SKILL_EXPERT:
2756 prout(_("promotes you to Commodore Emeritus."))
2758 prout(_("Now that you think you're really good, try playing"))
2759 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2760 elif game.skill == SKILL_EMERITUS:
2762 proutn(_("Computer- "))
2763 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2765 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2767 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2769 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2771 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2773 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2775 prout(_("Now you can retire and write your own Star Trek game!"))
2777 elif game.skill >= SKILL_EXPERT:
2778 if game.thawed and not game.idebug:
2779 prout(_("You cannot get a citation, so..."))
2781 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2785 # Only grant long life if alive (original didn't!)
2787 prout(_("LIVE LONG AND PROSPER."))
2792 elif ifin == FDEPLETE: # Federation Resources Depleted
2793 prout(_("Your time has run out and the Federation has been"))
2794 prout(_("conquered. Your starship is now Klingon property,"))
2795 prout(_("and you are put on trial as a war criminal. On the"))
2796 proutn(_("basis of your record, you are "))
2797 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2798 prout(_("acquitted."))
2800 prout(_("LIVE LONG AND PROSPER."))
2802 prout(_("found guilty and"))
2803 prout(_("sentenced to death by slow torture."))
2807 elif ifin == FLIFESUP:
2808 prout(_("Your life support reserves have run out, and"))
2809 prout(_("you die of thirst, starvation, and asphyxiation."))
2810 prout(_("Your starship is a derelict in space."))
2812 prout(_("Your energy supply is exhausted."))
2814 prout(_("Your starship is a derelict in space."))
2815 elif ifin == FBATTLE:
2816 prout(_("The %s has been destroyed in battle.") % crmshp())
2818 prout(_("Dulce et decorum est pro patria mori."))
2820 prout(_("You have made three attempts to cross the negative energy"))
2821 prout(_("barrier which surrounds the galaxy."))
2823 prout(_("Your navigation is abominable."))
2826 prout(_("Your starship has been destroyed by a nova."))
2827 prout(_("That was a great shot."))
2829 elif ifin == FSNOVAED:
2830 prout(_("The %s has been fried by a supernova.") % crmshp())
2831 prout(_("...Not even cinders remain..."))
2832 elif ifin == FABANDN:
2833 prout(_("You have been captured by the Klingons. If you still"))
2834 prout(_("had a starbase to be returned to, you would have been"))
2835 prout(_("repatriated and given another chance. Since you have"))
2836 prout(_("no starbases, you will be mercilessly tortured to death."))
2837 elif ifin == FDILITHIUM:
2838 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2839 elif ifin == FMATERIALIZE:
2840 prout(_("Starbase was unable to re-materialize your starship."))
2841 prout(_("Sic transit gloria mundi"))
2842 elif ifin == FPHASER:
2843 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2845 prout(_("You and your landing party have been"))
2846 prout(_("converted to energy, disipating through space."))
2847 elif ifin == FMINING:
2848 prout(_("You are left with your landing party on"))
2849 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2851 prout(_("They are very fond of \"Captain Kirk\" soup."))
2853 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2854 elif ifin == FDPLANET:
2855 prout(_("You and your mining party perish."))
2857 prout(_("That was a great shot."))
2860 prout(_("The Galileo is instantly annihilated by the supernova."))
2861 prout(_("You and your mining party are atomized."))
2863 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2864 prout(_("joins the Romulans, wreaking terror on the Federation."))
2865 elif ifin == FPNOVA:
2866 prout(_("You and your mining party are atomized."))
2868 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2869 prout(_("joins the Romulans, wreaking terror on the Federation."))
2870 elif ifin == FSTRACTOR:
2871 prout(_("The shuttle craft Galileo is also caught,"))
2872 prout(_("and breaks up under the strain."))
2874 prout(_("Your debris is scattered for millions of miles."))
2875 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2877 prout(_("The mutants attack and kill Spock."))
2878 prout(_("Your ship is captured by Klingons, and"))
2879 prout(_("your crew is put on display in a Klingon zoo."))
2880 elif ifin == FTRIBBLE:
2881 prout(_("Tribbles consume all remaining water,"))
2882 prout(_("food, and oxygen on your ship."))
2884 prout(_("You die of thirst, starvation, and asphyxiation."))
2885 prout(_("Your starship is a derelict in space."))
2887 prout(_("Your ship is drawn to the center of the black hole."))
2888 prout(_("You are crushed into extremely dense matter."))
2890 prout(_("Your last crew member has died."))
2891 if game.ship == 'F':
2893 elif game.ship == 'E':
2896 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2897 goodies = game.state.remres/game.inresor
2898 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2899 if goodies/baddies >= randreal(1.0, 1.5):
2900 prout(_("As a result of your actions, a treaty with the Klingon"))
2901 prout(_("Empire has been signed. The terms of the treaty are"))
2902 if goodies/baddies >= randreal(3.0):
2903 prout(_("favorable to the Federation."))
2905 prout(_("Congratulations!"))
2907 prout(_("highly unfavorable to the Federation."))
2909 prout(_("The Federation will be destroyed."))
2911 prout(_("Since you took the last Klingon with you, you are a"))
2912 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2913 prout(_("statue in your memory. Rest in peace, and try not"))
2914 prout(_("to think about pigeons."))
2919 "Compute player's score."
2920 timused = game.state.date - game.indate
2922 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2924 perdate = killrate()
2925 ithperd = 500*perdate + 0.5
2928 iwon = 100*game.skill
2929 if game.ship == 'E':
2931 elif game.ship == 'F':
2935 iscore = 10*(game.inkling - game.state.remkl) \
2936 + 50*(game.incom - len(game.state.kcmdr)) \
2938 + 20*(game.inrom - game.state.nromrem) \
2939 + 200*(game.inscom - game.state.nscrem) \
2940 - game.state.nromrem \
2945 prout(_("Your score --"))
2946 if game.inrom - game.state.nromrem:
2947 prout(_("%6d Romulans destroyed %5d") %
2948 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
2949 if game.state.nromrem and game.gamewon:
2950 prout(_("%6d Romulans captured %5d") %
2951 (game.state.nromrem, game.state.nromrem))
2952 if game.inkling - game.state.remkl:
2953 prout(_("%6d ordinary Klingons destroyed %5d") %
2954 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
2955 if game.incom - len(game.state.kcmdr):
2956 prout(_("%6d Klingon commanders destroyed %5d") %
2957 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
2958 if game.inscom - game.state.nscrem:
2959 prout(_("%6d Super-Commander destroyed %5d") %
2960 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
2962 prout(_("%6.2f Klingons per stardate %5d") %
2964 if game.state.starkl:
2965 prout(_("%6d stars destroyed by your action %5d") %
2966 (game.state.starkl, -5*game.state.starkl))
2967 if game.state.nplankl:
2968 prout(_("%6d planets destroyed by your action %5d") %
2969 (game.state.nplankl, -10*game.state.nplankl))
2970 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
2971 prout(_("%6d inhabited planets destroyed by your action %5d") %
2972 (game.state.nworldkl, -300*game.state.nworldkl))
2973 if game.state.basekl:
2974 prout(_("%6d bases destroyed by your action %5d") %
2975 (game.state.basekl, -100*game.state.basekl))
2977 prout(_("%6d calls for help from starbase %5d") %
2978 (game.nhelp, -45*game.nhelp))
2980 prout(_("%6d casualties incurred %5d") %
2981 (game.casual, -game.casual))
2983 prout(_("%6d crew abandoned in space %5d") %
2984 (game.abandoned, -3*game.abandoned))
2986 prout(_("%6d ship(s) lost or destroyed %5d") %
2987 (klship, -100*klship))
2989 prout(_("Penalty for getting yourself killed -200"))
2991 proutn(_("Bonus for winning "))
2992 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
2993 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
2994 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
2995 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
2996 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
2997 prout(" %5d" % iwon)
2999 prout(_("TOTAL SCORE %5d") % iscore)
3002 "Emit winner's commemmorative plaque."
3005 proutn(_("File or device name for your plaque: "))
3008 fp = open(winner, "w")
3011 prout(_("Invalid name."))
3013 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3015 # The 38 below must be 64 for 132-column paper
3016 nskip = 38 - len(winner)/2
3017 fp.write("\n\n\n\n")
3018 # --------DRAW ENTERPRISE PICTURE.
3019 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3020 fp.write(" EEE E : : : E\n" )
3021 fp.write(" EE EEE E : : NCC-1701 : E\n")
3022 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3023 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3024 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3025 fp.write(" EEEEEEE EEEEE E E E E\n")
3026 fp.write(" EEE E E E E\n")
3027 fp.write(" E E E E\n")
3028 fp.write(" EEEEEEEEEEEEE E E\n")
3029 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3030 fp.write(" :E : EEEE E\n")
3031 fp.write(" .-E -:----- E\n")
3032 fp.write(" :E : E\n")
3033 fp.write(" EE : EEEEEEEE\n")
3034 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3036 fp.write(_(" U. S. S. ENTERPRISE\n"))
3037 fp.write("\n\n\n\n")
3038 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3040 fp.write(_(" Starfleet Command bestows to you\n"))
3042 fp.write("%*s%s\n\n" % (nskip, "", winner))
3043 fp.write(_(" the rank of\n\n"))
3044 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3046 if game.skill == SKILL_EXPERT:
3047 fp.write(_(" Expert level\n\n"))
3048 elif game.skill == SKILL_EMERITUS:
3049 fp.write(_("Emeritus level\n\n"))
3051 fp.write(_(" Cheat level\n\n"))
3052 timestring = time.ctime()
3053 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3054 (timestring+4, timestring+20, timestring+11))
3055 fp.write(_(" Your score: %d\n\n") % iscore)
3056 fp.write(_(" Klingons per stardate: %.2f\n") % perdate)
3059 # Code from io.c begins here
3061 rows = linecount = 0 # for paging
3064 fullscreen_window = None
3065 srscan_window = None
3066 report_window = None
3067 status_window = None
3068 lrscan_window = None
3069 message_window = None
3070 prompt_window = None
3075 "for some recent versions of python2, the following enables UTF8"
3076 "for the older ones we probably need to set C locale, and the python3"
3077 "has no problems at all"
3078 if sys.version_info[0] < 3:
3080 locale.setlocale(locale.LC_ALL, "")
3081 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3082 gettext.textdomain("sst")
3083 if not (game.options & OPTION_CURSES):
3084 ln_env = os.getenv("LINES")
3090 stdscr = curses.initscr()
3094 if game.options & OPTION_COLOR:
3095 curses.start_color();
3096 curses.use_default_colors()
3097 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1);
3098 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1);
3099 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1);
3100 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1);
3101 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1);
3102 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1);
3103 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1);
3104 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1);
3105 global fullscreen_window, srscan_window, report_window, status_window
3106 global lrscan_window, message_window, prompt_window
3107 (rows, columns) = stdscr.getmaxyx()
3108 fullscreen_window = stdscr
3109 srscan_window = curses.newwin(12, 25, 0, 0)
3110 report_window = curses.newwin(11, 0, 1, 25)
3111 status_window = curses.newwin(10, 0, 1, 39)
3112 lrscan_window = curses.newwin(5, 0, 0, 64)
3113 message_window = curses.newwin(0, 0, 12, 0)
3114 prompt_window = curses.newwin(1, 0, rows-2, 0)
3115 message_window.scrollok(True)
3116 setwnd(fullscreen_window)
3120 if game.options & OPTION_CURSES:
3121 stdscr.keypad(False)
3127 "Wait for user action -- OK to do nothing if on a TTY"
3128 if game.options & OPTION_CURSES:
3133 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3137 if game.skill > SKILL_FAIR:
3138 prompt = _("[CONTINUE?]")
3140 prompt = _("[PRESS ENTER TO CONTINUE]")
3142 if game.options & OPTION_CURSES:
3144 setwnd(prompt_window)
3145 prompt_window.clear()
3146 prompt_window.addstr(prompt)
3147 prompt_window.getstr()
3148 prompt_window.clear()
3149 prompt_window.refresh()
3150 setwnd(message_window)
3153 sys.stdout.write('\n')
3156 sys.stdout.write('\n' * rows)
3160 "Skip i lines. Pause game if this would cause a scrolling event."
3161 for dummy in range(i):
3162 if game.options & OPTION_CURSES:
3163 (y, x) = curwnd.getyx()
3164 (my, mx) = curwnd.getmaxyx()
3165 if curwnd == message_window and y >= my - 2:
3171 except curses.error:
3176 if rows and linecount >= rows:
3179 sys.stdout.write('\n')
3182 "Utter a line with no following line feed."
3183 if game.options & OPTION_CURSES:
3187 sys.stdout.write(line)
3197 if not replayfp or replayfp.closed: # Don't slow down replays
3200 if game.options & OPTION_CURSES:
3204 if not replayfp or replayfp.closed:
3208 "Get a line of input."
3209 if game.options & OPTION_CURSES:
3210 line = curwnd.getstr() + "\n"
3213 if replayfp and not replayfp.closed:
3215 line = replayfp.readline()
3218 prout("*** Replay finished")
3221 elif line[0] != "#":
3224 line = raw_input() + "\n"
3230 "Change windows -- OK for this to be a no-op in tty mode."
3232 if game.options & OPTION_CURSES:
3234 curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window)
3237 "Clear to end of line -- can be a no-op in tty mode"
3238 if game.options & OPTION_CURSES:
3243 "Clear screen -- can be a no-op in tty mode."
3245 if game.options & OPTION_CURSES:
3251 def textcolor(color=DEFAULT):
3252 if game.options & OPTION_COLOR:
3253 if color == DEFAULT:
3255 elif color == BLACK:
3256 curwnd.attron(curses.color_pair(curses.COLOR_BLACK));
3258 curwnd.attron(curses.color_pair(curses.COLOR_BLUE));
3259 elif color == GREEN:
3260 curwnd.attron(curses.color_pair(curses.COLOR_GREEN));
3262 curwnd.attron(curses.color_pair(curses.COLOR_CYAN));
3264 curwnd.attron(curses.color_pair(curses.COLOR_RED));
3265 elif color == MAGENTA:
3266 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA));
3267 elif color == BROWN:
3268 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW));
3269 elif color == LIGHTGRAY:
3270 curwnd.attron(curses.color_pair(curses.COLOR_WHITE));
3271 elif color == DARKGRAY:
3272 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD);
3273 elif color == LIGHTBLUE:
3274 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD);
3275 elif color == LIGHTGREEN:
3276 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD);
3277 elif color == LIGHTCYAN:
3278 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD);
3279 elif color == LIGHTRED:
3280 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD);
3281 elif color == LIGHTMAGENTA:
3282 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD);
3283 elif color == YELLOW:
3284 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD);
3285 elif color == WHITE:
3286 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD);
3289 if game.options & OPTION_COLOR:
3290 curwnd.attron(curses.A_REVERSE)
3293 # Things past this point have policy implications.
3297 "Hook to be called after moving to redraw maps."
3298 if game.options & OPTION_CURSES:
3301 setwnd(srscan_window)
3305 setwnd(status_window)
3306 status_window.clear()
3307 status_window.move(0, 0)
3308 setwnd(report_window)
3309 report_window.clear()
3310 report_window.move(0, 0)
3312 setwnd(lrscan_window)
3313 lrscan_window.clear()
3314 lrscan_window.move(0, 0)
3315 lrscan(silent=False)
3317 def put_srscan_sym(w, sym):
3318 "Emit symbol for short-range scan."
3319 srscan_window.move(w.i+1, w.j*2+2)
3320 srscan_window.addch(sym)
3321 srscan_window.refresh()
3324 "Enemy fall down, go boom."
3325 if game.options & OPTION_CURSES:
3327 setwnd(srscan_window)
3328 srscan_window.attron(curses.A_REVERSE)
3329 put_srscan_sym(w, game.quad[w.i][w.j])
3333 srscan_window.attroff(curses.A_REVERSE)
3334 put_srscan_sym(w, game.quad[w.i][w.j])
3335 curses.delay_output(500)
3336 setwnd(message_window)
3339 "Sound and visual effects for teleportation."
3340 if game.options & OPTION_CURSES:
3342 setwnd(message_window)
3344 prouts(" . . . . . ")
3345 if game.options & OPTION_CURSES:
3346 #curses.delay_output(1000)
3350 def tracktorpedo(origin, w, step, i, n, iquad):
3351 "Torpedo-track animation."
3352 if not game.options & OPTION_CURSES:
3356 proutn(_("Track for torpedo number %d- ") % (i+1))
3359 proutn(_("Torpedo track- "))
3360 elif step==4 or step==9:
3364 if not damaged(DSRSENS) or game.condition=="docked":
3365 if i != 0 and step == 1:
3368 if (iquad=='.') or (iquad==' '):
3369 put_srscan_sym(w, '+')
3373 put_srscan_sym(w, iquad)
3375 curwnd.attron(curses.A_REVERSE)
3376 put_srscan_sym(w, iquad)
3380 curwnd.attroff(curses.A_REVERSE)
3381 put_srscan_sym(w, iquad)
3386 "Display the current galaxy chart."
3387 if game.options & OPTION_CURSES:
3388 setwnd(message_window)
3389 message_window.clear()
3391 if game.options & OPTION_TTY:
3396 def prstat(txt, data):
3398 if game.options & OPTION_CURSES:
3400 setwnd(status_window)
3402 proutn(" " * (NSYM - len(txt)))
3405 if game.options & OPTION_CURSES:
3406 setwnd(report_window)
3408 # Code from moving.c begins here
3410 def imove(icourse=None, noattack=False):
3411 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3414 def newquadrant(noattack):
3415 # Leaving quadrant -- allow final enemy attack
3416 # Don't do it if being pushed by Nova
3417 if len(game.enemies) != 0 and not noattack:
3419 for enemy in game.enemies:
3420 finald = (w - enemy.location).distance()
3421 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3422 # Stas Sergeev added the condition
3423 # that attacks only happen if Klingons
3424 # are present and your skill is good.
3425 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3426 attack(torps_ok=False)
3429 # check for edge of galaxy
3433 if icourse.final.i < 0:
3434 icourse.final.i = -icourse.final.i
3436 if icourse.final.j < 0:
3437 icourse.final.j = -icourse.final.j
3439 if icourse.final.i >= GALSIZE*QUADSIZE:
3440 icourse.final.i = (GALSIZE*QUADSIZE*2) - icourse.final.i
3442 if icourse.final.j >= GALSIZE*QUADSIZE:
3443 icourse.final.j = (GALSIZE*QUADSIZE*2) - icourse.final.j
3451 if game.nkinks == 3:
3452 # Three strikes -- you're out!
3456 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3457 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3458 prout(_("YOU WILL BE DESTROYED."))
3459 # Compute final position in new quadrant
3460 if trbeam: # Don't bother if we are to be beamed
3462 game.quadrant = icourse.final.quadrant()
3463 game.sector = icourse.final.sector()
3465 prout(_("Entering Quadrant %s.") % game.quadrant)
3466 game.quad[game.sector.i][game.sector.j] = game.ship
3468 if game.skill>SKILL_NOVICE:
3469 attack(torps_ok=False)
3471 def check_collision(h):
3472 iquad = game.quad[h.i][h.j]
3474 # object encountered in flight path
3475 stopegy = 50.0*icourse.distance/game.optime
3476 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3477 for enemy in game.enemies:
3478 if enemy.location == game.sector:
3480 collision(rammed=False, enemy=enemy)
3484 prouts(_("***RED ALERT! RED ALERT!"))
3486 proutn("***" + crmshp())
3487 proutn(_(" pulled into black hole at Sector %s") % h)
3488 # Getting pulled into a black hole was certain
3489 # death in Almy's original. Stas Sergeev added a
3490 # possibility that you'll get timewarped instead.
3492 for m in range(NDEVICES):
3493 if game.damage[m]>0:
3495 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3496 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3506 prout(_(" encounters Tholian web at %s;") % h)
3508 prout(_(" blocked by object at %s;") % h)
3509 proutn(_("Emergency stop required "))
3510 prout(_("%2d units of energy.") % int(stopegy))
3511 game.energy -= stopegy
3512 if game.energy <= 0:
3519 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3520 game.inorbit = False
3521 # If tractor beam is to occur, don't move full distance
3522 if game.state.date+game.optime >= scheduled(FTBEAM):
3524 game.condition = "red"
3525 icourse.distance = icourse.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3526 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3528 game.quad[game.sector.i][game.sector.j] = '.'
3529 for m in range(icourse.moves):
3531 w = icourse.sector()
3532 if icourse.origin.quadrant() != icourse.location.quadrant():
3533 newquadrant(noattack)
3535 elif check_collision(icourse, w):
3536 print "Collision detected"
3540 # We're in destination quadrant -- compute new average enemy distances
3541 game.quad[game.sector.i][game.sector.j] = game.ship
3543 for enemy in game.enemies:
3544 finald = (w-enemy.location).distance()
3545 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3546 enemy.kdist = finald
3547 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
3548 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3549 attack(torps_ok=False)
3550 for enemy in game.enemies:
3551 enemy.kavgd = enemy.kdist
3554 setwnd(message_window)
3558 "Dock our ship at a starbase."
3560 if game.condition == "docked" and verbose:
3561 prout(_("Already docked."))
3564 prout(_("You must first leave standard orbit."))
3566 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3567 prout(crmshp() + _(" not adjacent to base."))
3569 game.condition = "docked"
3573 if game.energy < game.inenrg:
3574 game.energy = game.inenrg
3575 game.shield = game.inshld
3576 game.torps = game.intorps
3577 game.lsupres = game.inlsr
3578 game.state.crew = FULLCREW
3579 if not damaged(DRADIO) and \
3580 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3581 # get attack report from base
3582 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3586 def cartesian(loc1=None, loc2=None):
3588 return game.quadrant * QUADSIZE + game.sector
3590 return game.quadrant * QUADSIZE + loc1
3592 return loc1 * QUADSIZE + loc2
3594 def getcourse(isprobe):
3595 "Get a course and distance from the user."
3597 dquad = copy.copy(game.quadrant)
3598 navmode = "unspecified"
3602 if game.landed and not isprobe:
3603 prout(_("Dummy! You can't leave standard orbit until you"))
3604 proutn(_("are back aboard the ship."))
3607 while navmode == "unspecified":
3608 if damaged(DNAVSYS):
3610 prout(_("Computer damaged; manual navigation only"))
3612 prout(_("Computer damaged; manual movement only"))
3617 key = scanner.next()
3619 proutn(_("Manual or automatic- "))
3622 elif key == "IHALPHA":
3623 if scanner.sees("manual"):
3625 key = scanner.next()
3627 elif scanner.sees("automatic"):
3628 navmode = "automatic"
3629 key = scanner.next()
3637 prout(_("(Manual navigation assumed.)"))
3639 prout(_("(Manual movement assumed.)"))
3643 if navmode == "automatic":
3644 while key == "IHEOL":
3646 proutn(_("Target quadrant or quadrant§or- "))
3648 proutn(_("Destination sector or quadrant§or- "))
3651 key = scanner.next()
3655 xi = int(round(scanner.real))-1
3656 key = scanner.next()
3660 xj = int(round(scanner.real))-1
3661 key = scanner.next()
3663 # both quadrant and sector specified
3664 xk = int(round(scanner.real))-1
3665 key = scanner.next()
3669 xl = int(round(scanner.real))-1
3675 # only one pair of numbers was specified
3677 # only quadrant specified -- go to center of dest quad
3680 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3682 # only sector specified
3686 if not dquad.valid_quadrant() or not dsect.valid_sector():
3693 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3695 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3696 # the actual deltas get computed here
3697 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3698 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3700 while key == "IHEOL":
3701 proutn(_("X and Y displacements- "))
3704 key = scanner.next()
3709 delta.j = scanner.real
3710 key = scanner.next()
3714 delta.i = scanner.real
3715 # Check for zero movement
3716 if delta.i == 0 and delta.j == 0:
3719 if itemp == "verbose" and not isprobe:
3721 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3723 return course(bearing=delta.bearing(), distance=delta.distance())
3726 def __init__(self, bearing, distance, origin=None):
3727 self.distance = distance
3728 self.bearing = bearing
3730 self.origin = cartesian(game.quadrant, game.sector)
3732 self.origin = origin
3733 # The bearing() code we inherited from FORTRAN is actually computing
3734 # clockface directions!
3735 if self.bearing < 0.0:
3736 self.bearing += 12.0
3737 self.angle = ((15.0 - self.bearing) * 0.5235988)
3739 self.origin = cartesian(game.quadrant, game.sector)
3741 self.origin = cartesian(game.quadrant, origin)
3742 self.increment = coord(-math.sin(self.angle), math.cos(self.angle))
3743 bigger = max(abs(self.increment.i), abs(self.increment.j))
3744 self.increment /= bigger
3745 self.moves = int(round(10*self.distance*bigger))
3747 self.final = (self.location + self.moves*self.increment).roundtogrid()
3749 self.location = self.origin
3752 return self.location.roundtogrid() == self.final
3754 "Next step on course."
3756 self.nextlocation = self.location + self.increment
3757 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3758 self.location = self.nextlocation
3761 return self.location.quadrant()
3763 return self.location.sector()
3764 def power(self, warp):
3765 return self.distance*(warp**3)*(game.shldup+1)
3766 def time(self, warp):
3767 return 10.0*self.distance/warp**2
3770 "Move under impulse power."
3772 if damaged(DIMPULS):
3775 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3777 if game.energy > 30.0:
3779 course = getcourse(isprobe=False)
3782 power = 20.0 + 100.0*course.distance
3785 if power >= game.energy:
3786 # Insufficient power for trip
3788 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3789 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3790 if game.energy > 30:
3791 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3792 int(0.01 * (game.energy-20.0)-0.05))
3793 prout(_(" quadrants.\""))
3795 prout(_("quadrant. They are, therefore, useless.\""))
3798 # Make sure enough time is left for the trip
3799 game.optime = course.dist/0.095
3800 if game.optime >= game.state.remtime:
3801 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3802 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3803 proutn(_("we dare spend the time?\" "))
3806 # Activate impulse engines and pay the cost
3807 imove(course, noattack=False)
3811 power = 20.0 + 100.0*course.dist
3812 game.energy -= power
3813 game.optime = course.dist/0.095
3814 if game.energy <= 0:
3818 def warp(wcourse, involuntary):
3819 "ove under warp drive."
3820 blooey = False; twarp = False
3821 if not involuntary: # Not WARPX entry
3823 if game.damage[DWARPEN] > 10.0:
3826 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3828 if damaged(DWARPEN) and game.warpfac > 4.0:
3831 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3832 prout(_(" is repaired, I can only give you warp 4.\""))
3834 # Read in course and distance
3837 wcourse = getcourse(isprobe=False)
3840 # Make sure starship has enough energy for the trip
3841 # Note: this formula is slightly different from the C version,
3842 # and lets you skate a bit closer to the edge.
3843 if wcourse.power(game.warpfac) >= game.energy:
3844 # Insufficient power for trip
3847 prout(_("Engineering to bridge--"))
3848 if not game.shldup or 0.5*wcourse.power(game.warpfac) > game.energy:
3849 iwarp = (game.energy/(wcourse.dist+0.05)) ** 0.333333333
3851 prout(_("We can't do it, Captain. We don't have enough energy."))
3853 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3856 prout(_("if you'll lower the shields."))
3860 prout(_("We haven't the energy to go that far with the shields up."))
3862 # Make sure enough time is left for the trip
3863 game.optime = wcourse.time(game.warpfac)
3864 if game.optime >= 0.8*game.state.remtime:
3866 prout(_("First Officer Spock- \"Captain, I compute that such"))
3867 proutn(_(" a trip would require approximately %2.0f") %
3868 (100.0*game.optime/game.state.remtime))
3869 prout(_(" percent of our"))
3870 proutn(_(" remaining time. Are you sure this is wise?\" "))
3876 if game.warpfac > 6.0:
3877 # Decide if engine damage will occur
3878 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3879 prob = wcourse.distance*(6.0-game.warpfac)**2/66.666666666
3880 if prob > randreal():
3882 wcourse.distance = randreal(wcourse.distance)
3883 # Decide if time warp will occur
3884 if 0.5*wcourse.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3886 if game.idebug and game.warpfac==10 and not twarp:
3888 proutn("=== Force time warp? ")
3892 # If time warp or engine damage, check path
3893 # If it is obstructed, don't do warp or damage
3894 for m_unused in range(wcourse.moves):
3896 w = wcourse.sector()
3897 if not w.valid_sector():
3899 if game.quad[w.i][w.j] != '.':
3903 # Activate Warp Engines and pay the cost
3904 imove(course, noattack=False)
3907 game.energy -= wcourse.power(game.warpfac)
3908 if game.energy <= 0:
3910 game.optime = wcourse.time(game.warpfac)
3914 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
3916 prout(_("Engineering to bridge--"))
3917 prout(_(" Scott here. The warp engines are damaged."))
3918 prout(_(" We'll have to reduce speed to warp 4."))
3923 "Change the warp factor."
3929 proutn(_("Warp factor- "))
3933 if game.damage[DWARPEN] > 10.0:
3934 prout(_("Warp engines inoperative."))
3936 if damaged(DWARPEN) and scanner.real > 4.0:
3937 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
3938 prout(_(" but right now we can only go warp 4.\""))
3940 if scanner.real > 10.0:
3941 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
3943 if scanner.real < 1.0:
3944 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
3946 oldfac = game.warpfac
3947 game.warpfac = scanner.real
3948 if game.warpfac <= oldfac or game.warpfac <= 6.0:
3949 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
3952 if game.warpfac < 8.00:
3953 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
3955 if game.warpfac == 10.0:
3956 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
3958 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
3962 "Cope with being tossed out of quadrant by supernova or yanked by beam."
3964 # is captain on planet?
3966 if damaged(DTRANSP):
3969 prout(_("Scotty rushes to the transporter controls."))
3971 prout(_("But with the shields up it's hopeless."))
3973 prouts(_("His desperate attempt to rescue you . . ."))
3978 prout(_("SUCCEEDS!"))
3981 proutn(_("The crystals mined were "))
3989 # Check to see if captain in shuttle craft
3994 # Inform captain of attempt to reach safety
3998 prouts(_("***RED ALERT! RED ALERT!"))
4000 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
4001 prouts(_(" a supernova."))
4003 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
4004 prout(_("safely out of quadrant."))
4005 if not damaged(DRADIO):
4006 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
4007 # Try to use warp engines
4008 if damaged(DWARPEN):
4010 prout(_("Warp engines damaged."))
4013 game.warpfac = randreal(6.0, 8.0)
4014 prout(_("Warp factor set to %d") % int(game.warpfac))
4015 power = 0.75*game.energy
4016 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4017 dist = max(dist, randreal(math.sqrt(2)))
4018 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4019 game.optime = bugout.time(game.warpfac)
4021 game.inorbit = False
4022 warp(bugout, involuntary=True)
4024 # This is bad news, we didn't leave quadrant.
4028 prout(_("Insufficient energy to leave quadrant."))
4031 # Repeat if another snova
4032 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4034 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4035 finish(FWON) # Snova killed remaining enemy.
4038 "Let's do the time warp again."
4039 prout(_("***TIME WARP ENTERED."))
4040 if game.state.snap and withprob(0.5):
4042 prout(_("You are traveling backwards in time %d stardates.") %
4043 int(game.state.date-game.snapsht.date))
4044 game.state = game.snapsht
4045 game.state.snap = False
4046 if len(game.state.kcmdr):
4047 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4048 schedule(FBATTAK, expran(0.3*game.intime))
4049 schedule(FSNOVA, expran(0.5*game.intime))
4050 # next snapshot will be sooner
4051 schedule(FSNAP, expran(0.25*game.state.remtime))
4053 if game.state.nscrem:
4054 schedule(FSCMOVE, 0.2777)
4058 game.battle.invalidate()
4059 # Make sure Galileo is consistant -- Snapshot may have been taken
4060 # when on planet, which would give us two Galileos!
4062 for l in range(game.inplan):
4063 if game.state.planets[l].known == "shuttle_down":
4065 if game.iscraft == "onship" and game.ship=='E':
4066 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4067 game.iscraft = "offship"
4068 # Likewise, if in the original time the Galileo was abandoned, but
4069 # was on ship earlier, it would have vanished -- let's restore it.
4070 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4071 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4072 game.iscraft = "onship"
4073 # There used to be code to do the actual reconstrction here,
4074 # but the starchart is now part of the snapshotted galaxy state.
4075 prout(_("Spock has reconstructed a correct star chart from memory"))
4077 # Go forward in time
4078 game.optime = expran(0.5*game.intime)
4079 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4080 # cheat to make sure no tractor beams occur during time warp
4081 postpone(FTBEAM, game.optime)
4082 game.damage[DRADIO] += game.optime
4084 events() # Stas Sergeev added this -- do pending events
4087 "Launch deep-space probe."
4088 # New code to launch a deep space probe
4089 if game.nprobes == 0:
4092 if game.ship == 'E':
4093 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4095 prout(_("Ye Faerie Queene has no deep space probes."))
4100 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4102 if is_scheduled(FDSPROB):
4105 if damaged(DRADIO) and game.condition != "docked":
4106 prout(_("Spock- \"Records show the previous probe has not yet"))
4107 prout(_(" reached its destination.\""))
4109 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4111 key = scanner.next()
4113 if game.nprobes == 1:
4114 prout(_("1 probe left."))
4116 prout(_("%d probes left") % game.nprobes)
4117 proutn(_("Are you sure you want to fire a probe? "))
4120 game.isarmed = False
4121 if key == "IHALPHA" and scanner.token == "armed":
4123 key = scanner.next()
4124 elif key == "IHEOL":
4125 proutn(_("Arm NOVAMAX warhead? "))
4127 elif key == "IHREAL": # first element of course
4128 scanner.push(scanner.token)
4130 game.probe = getcourse(isprobe=True)
4134 schedule(FDSPROB, 0.01) # Time to move one sector
4135 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4140 "Yell for help from nearest starbase."
4141 # There's more than one way to move in this game!
4143 # Test for conditions which prevent calling for help
4144 if game.condition == "docked":
4145 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4148 prout(_("Subspace radio damaged."))
4150 if not game.state.baseq:
4151 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4154 prout(_("You must be aboard the %s.") % crmshp())
4156 # OK -- call for help from nearest starbase
4159 # There's one in this quadrant
4160 ddist = (game.base - game.sector).distance()
4163 for ibq in game.state.baseq:
4164 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4167 # Since starbase not in quadrant, set up new quadrant
4170 # dematerialize starship
4171 game.quad[game.sector.i][game.sector.j]='.'
4172 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4173 % (game.quadrant, crmshp()))
4174 game.sector.invalidate()
4175 for m in range(1, 5+1):
4176 w = game.base.scatter()
4177 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4178 # found one -- finish up
4181 if not game.sector.is_valid():
4182 prout(_("You have been lost in space..."))
4183 finish(FMATERIALIZE)
4185 # Give starbase three chances to rematerialize starship
4186 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4187 for m in range(1, 3+1):
4188 if m == 1: proutn(_("1st"))
4189 elif m == 2: proutn(_("2nd"))
4190 elif m == 3: proutn(_("3rd"))
4191 proutn(_(" attempt to re-materialize ") + crmshp())
4192 game.quad[ix][iy]=('-','o','O')[m-1]
4195 if randreal() > probf:
4199 curses.delay_output(500)
4201 game.quad[ix][iy]='?'
4204 setwnd(message_window)
4205 finish(FMATERIALIZE)
4207 game.quad[ix][iy]=game.ship
4209 prout(_("succeeds."))
4213 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4218 if game.condition=="docked":
4220 prout(_("You cannot abandon Ye Faerie Queene."))
4223 # Must take shuttle craft to exit
4224 if game.damage[DSHUTTL]==-1:
4225 prout(_("Ye Faerie Queene has no shuttle craft."))
4227 if game.damage[DSHUTTL]<0:
4228 prout(_("Shuttle craft now serving Big Macs."))
4230 if game.damage[DSHUTTL]>0:
4231 prout(_("Shuttle craft damaged."))
4234 prout(_("You must be aboard the ship."))
4236 if game.iscraft != "onship":
4237 prout(_("Shuttle craft not currently available."))
4239 # Emit abandon ship messages
4241 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4243 prouts(_("***ALL HANDS ABANDON SHIP!"))
4245 prout(_("Captain and crew escape in shuttle craft."))
4246 if not game.state.baseq:
4247 # Oops! no place to go...
4250 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4252 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4253 prout(_("Remainder of ship's complement beam down"))
4254 prout(_("to nearest habitable planet."))
4255 elif q.planet != None and not damaged(DTRANSP):
4256 prout(_("Remainder of ship's complement beam down to %s.") %
4259 prout(_("Entire crew of %d left to die in outer space.") %
4261 game.casual += game.state.crew
4262 game.abandoned += game.state.crew
4263 # If at least one base left, give 'em the Faerie Queene
4265 game.icrystl = False # crystals are lost
4266 game.nprobes = 0 # No probes
4267 prout(_("You are captured by Klingons and released to"))
4268 prout(_("the Federation in a prisoner-of-war exchange."))
4269 nb = randrange(len(game.state.baseq))
4270 # Set up quadrant and position FQ adjacient to base
4271 if not game.quadrant == game.state.baseq[nb]:
4272 game.quadrant = game.state.baseq[nb]
4273 game.sector.i = game.sector.j = 5
4276 # position next to base by trial and error
4277 game.quad[game.sector.i][game.sector.j] = '.'
4278 for l in range(QUADSIZE):
4279 game.sector = game.base.scatter()
4280 if game.sector.valid_sector() and \
4281 game.quad[game.sector.i][game.sector.j] == '.':
4284 break # found a spot
4285 game.sector.i=QUADSIZE/2
4286 game.sector.j=QUADSIZE/2
4288 # Get new commission
4289 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4290 game.state.crew = FULLCREW
4291 prout(_("Starfleet puts you in command of another ship,"))
4292 prout(_("the Faerie Queene, which is antiquated but,"))
4293 prout(_("still useable."))
4295 prout(_("The dilithium crystals have been moved."))
4297 game.iscraft = "offship" # Galileo disappears
4299 game.condition="docked"
4300 for l in range(NDEVICES):
4301 game.damage[l] = 0.0
4302 game.damage[DSHUTTL] = -1
4303 game.energy = game.inenrg = 3000.0
4304 game.shield = game.inshld = 1250.0
4305 game.torps = game.intorps = 6
4306 game.lsupres=game.inlsr=3.0
4311 # Code from planets.c begins here.
4314 "Abort a lengthy operation if an event interrupts it."
4317 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4322 "Report on (uninhabited) planets in the galaxy."
4326 prout(_("Spock- \"Planet report follows, Captain.\""))
4328 for i in range(game.inplan):
4329 if game.state.planets[i].pclass == "destroyed":
4331 if (game.state.planets[i].known != "unknown" \
4332 and not game.state.planets[i].inhabited) \
4335 if game.idebug and game.state.planets[i].known=="unknown":
4336 proutn("(Unknown) ")
4337 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4338 proutn(_(" class "))
4339 proutn(game.state.planets[i].pclass)
4341 if game.state.planets[i].crystals != "present":
4343 prout(_("dilithium crystals present."))
4344 if game.state.planets[i].known=="shuttle_down":
4345 prout(_(" Shuttle Craft Galileo on surface."))
4347 prout(_("No information available."))
4350 "Enter standard orbit."
4354 prout(_("Already in standard orbit."))
4356 if damaged(DWARPEN) and damaged(DIMPULS):
4357 prout(_("Both warp and impulse engines damaged."))
4359 if not game.plnet.is_valid():
4360 prout("There is no planet in this sector.")
4362 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4363 prout(crmshp() + _(" not adjacent to planet."))
4366 game.optime = randreal(0.02, 0.05)
4367 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4371 game.height = randreal(1400, 8600)
4372 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4377 "Examine planets in this quadrant."
4378 if damaged(DSRSENS):
4379 if game.options & OPTION_TTY:
4380 prout(_("Short range sensors damaged."))
4382 if game.iplnet == None:
4383 if game.options & OPTION_TTY:
4384 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4386 if game.iplnet.known == "unknown":
4387 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4389 prout(_(" Planet at Sector %s is of class %s.") %
4390 (game.plnet, game.iplnet.pclass))
4391 if game.iplnet.known=="shuttle_down":
4392 prout(_(" Sensors show Galileo still on surface."))
4393 proutn(_(" Readings indicate"))
4394 if game.iplnet.crystals != "present":
4396 prout(_(" dilithium crystals present.\""))
4397 if game.iplnet.known == "unknown":
4398 game.iplnet.known = "known"
4399 elif game.iplnet.inhabited:
4400 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4401 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4404 "Use the transporter."
4408 if damaged(DTRANSP):
4409 prout(_("Transporter damaged."))
4410 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4412 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4416 if not game.inorbit:
4417 prout(crmshp() + _(" not in standard orbit."))
4420 prout(_("Impossible to transport through shields."))
4422 if game.iplnet.known=="unknown":
4423 prout(_("Spock- \"Captain, we have no information on this planet"))
4424 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4425 prout(_(" you may not go down.\""))
4427 if not game.landed and game.iplnet.crystals=="absent":
4428 prout(_("Spock- \"Captain, I fail to see the logic in"))
4429 prout(_(" exploring a planet with no dilithium crystals."))
4430 proutn(_(" Are you sure this is wise?\" "))
4434 if not (game.options & OPTION_PLAIN):
4435 nrgneed = 50 * game.skill + game.height / 100.0
4436 if nrgneed > game.energy:
4437 prout(_("Engineering to bridge--"))
4438 prout(_(" Captain, we don't have enough energy for transportation."))
4440 if not game.landed and nrgneed * 2 > game.energy:
4441 prout(_("Engineering to bridge--"))
4442 prout(_(" Captain, we have enough energy only to transport you down to"))
4443 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4444 if game.iplnet.known == "shuttle_down":
4445 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4446 proutn(_(" Are you sure this is wise?\" "))
4451 # Coming from planet
4452 if game.iplnet.known=="shuttle_down":
4453 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4457 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4458 prout(_("Landing party assembled, ready to beam up."))
4460 prout(_("Kirk whips out communicator..."))
4461 prouts(_("BEEP BEEP BEEP"))
4463 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4466 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4468 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4470 prout(_("Kirk- \"Energize.\""))
4473 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4476 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4478 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4481 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4482 game.landed = not game.landed
4483 game.energy -= nrgneed
4485 prout(_("Transport complete."))
4486 if game.landed and game.iplnet.known=="shuttle_down":
4487 prout(_("The shuttle craft Galileo is here!"))
4488 if not game.landed and game.imine:
4495 "Strip-mine a world for dilithium."
4499 prout(_("Mining party not on planet."))
4501 if game.iplnet.crystals == "mined":
4502 prout(_("This planet has already been strip-mined for dilithium."))
4504 elif game.iplnet.crystals == "absent":
4505 prout(_("No dilithium crystals on this planet."))
4508 prout(_("You've already mined enough crystals for this trip."))
4510 if game.icrystl and game.cryprob == 0.05:
4511 prout(_("With all those fresh crystals aboard the ") + crmshp())
4512 prout(_("there's no reason to mine more at this time."))
4514 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4517 prout(_("Mining operation complete."))
4518 game.iplnet.crystals = "mined"
4519 game.imine = game.ididit = True
4522 "Use dilithium crystals."
4526 if not game.icrystl:
4527 prout(_("No dilithium crystals available."))
4529 if game.energy >= 1000:
4530 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4531 prout(_(" except when Condition Yellow exists."))
4533 prout(_("Spock- \"Captain, I must warn you that loading"))
4534 prout(_(" raw dilithium crystals into the ship's power"))
4535 prout(_(" system may risk a severe explosion."))
4536 proutn(_(" Are you sure this is wise?\" "))
4541 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4542 prout(_(" Mr. Spock and I will try it.\""))
4544 prout(_("Spock- \"Crystals in place, Sir."))
4545 prout(_(" Ready to activate circuit.\""))
4547 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4549 if withprob(game.cryprob):
4550 prouts(_(" \"Activating now! - - No good! It's***"))
4552 prouts(_("***RED ALERT! RED A*L********************************"))
4555 prouts(_("****************** KA-BOOM!!!! *******************"))
4559 game.energy += randreal(5000.0, 5500.0)
4560 prouts(_(" \"Activating now! - - "))
4561 prout(_("The instruments"))
4562 prout(_(" are going crazy, but I think it's"))
4563 prout(_(" going to work!! Congratulations, Sir!\""))
4568 "Use shuttlecraft for planetary jaunt."
4571 if damaged(DSHUTTL):
4572 if game.damage[DSHUTTL] == -1.0:
4573 if game.inorbit and game.iplnet.known == "shuttle_down":
4574 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4576 prout(_("Ye Faerie Queene had no shuttle craft."))
4577 elif game.damage[DSHUTTL] > 0:
4578 prout(_("The Galileo is damaged."))
4579 else: # game.damage[DSHUTTL] < 0
4580 prout(_("Shuttle craft is now serving Big Macs."))
4582 if not game.inorbit:
4583 prout(crmshp() + _(" not in standard orbit."))
4585 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4586 prout(_("Shuttle craft not currently available."))
4588 if not game.landed and game.iplnet.known=="shuttle_down":
4589 prout(_("You will have to beam down to retrieve the shuttle craft."))
4591 if game.shldup or game.condition == "docked":
4592 prout(_("Shuttle craft cannot pass through shields."))
4594 if game.iplnet.known=="unknown":
4595 prout(_("Spock- \"Captain, we have no information on this planet"))
4596 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4597 prout(_(" you may not fly down.\""))
4599 game.optime = 3.0e-5*game.height
4600 if game.optime >= 0.8*game.state.remtime:
4601 prout(_("First Officer Spock- \"Captain, I compute that such"))
4602 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4603 int(100*game.optime/game.state.remtime))
4604 prout(_("remaining time."))
4605 proutn(_("Are you sure this is wise?\" "))
4611 if game.iscraft == "onship":
4613 if not damaged(DTRANSP):
4614 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4618 proutn(_("Shuttle crew"))
4620 proutn(_("Rescue party"))
4621 prout(_(" boards Galileo and swoops toward planet surface."))
4622 game.iscraft = "offship"
4626 game.iplnet.known="shuttle_down"
4627 prout(_("Trip complete."))
4630 # Ready to go back to ship
4631 prout(_("You and your mining party board the"))
4632 prout(_("shuttle craft for the trip back to the Enterprise."))
4634 prouts(_("The short hop begins . . ."))
4636 game.iplnet.known="known"
4642 game.iscraft = "onship"
4648 prout(_("Trip complete."))
4651 # Kirk on ship and so is Galileo
4652 prout(_("Mining party assembles in the hangar deck,"))
4653 prout(_("ready to board the shuttle craft \"Galileo\"."))
4655 prouts(_("The hangar doors open; the trip begins."))
4658 game.iscraft = "offship"
4661 game.iplnet.known = "shuttle_down"
4664 prout(_("Trip complete."))
4668 "Use the big zapper."
4672 if game.ship != 'E':
4673 prout(_("Ye Faerie Queene has no death ray."))
4675 if len(game.enemies)==0:
4676 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4679 prout(_("Death Ray is damaged."))
4681 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4682 prout(_(" is highly unpredictible. Considering the alternatives,"))
4683 proutn(_(" are you sure this is wise?\" "))
4686 prout(_("Spock- \"Acknowledged.\""))
4689 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4691 prout(_("Crew scrambles in emergency preparation."))
4692 prout(_("Spock and Scotty ready the death ray and"))
4693 prout(_("prepare to channel all ship's power to the device."))
4695 prout(_("Spock- \"Preparations complete, sir.\""))
4696 prout(_("Kirk- \"Engage!\""))
4698 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4701 if game.options & OPTION_PLAIN:
4705 prouts(_("Sulu- \"Captain! It's working!\""))
4707 while len(game.enemies) > 0:
4708 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4709 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4710 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4712 if (game.options & OPTION_PLAIN) == 0:
4713 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4715 prout(_(" is still operational.\""))
4717 prout(_(" has been rendered nonfunctional.\""))
4718 game.damage[DDRAY] = 39.95
4720 r = randreal() # Pick failure method
4722 prouts(_("Sulu- \"Captain! It's working!\""))
4724 prouts(_("***RED ALERT! RED ALERT!"))
4726 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4728 prouts(_("***RED ALERT! RED A*L********************************"))
4731 prouts(_("****************** KA-BOOM!!!! *******************"))
4736 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4738 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4740 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4741 prout(_(" have apparently been transformed into strange mutations."))
4742 prout(_(" Vulcans do not seem to be affected."))
4744 prout(_("Kirk- \"Raauch! Raauch!\""))
4748 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4750 proutn(_("Spock- \"I believe the word is"))
4751 prouts(_(" *ASTONISHING*"))
4752 prout(_(" Mr. Sulu."))
4753 for i in range(QUADSIZE):
4754 for j in range(QUADSIZE):
4755 if game.quad[i][j] == '.':
4756 game.quad[i][j] = '?'
4757 prout(_(" Captain, our quadrant is now infested with"))
4758 prouts(_(" - - - - - - *THINGS*."))
4760 prout(_(" I have no logical explanation.\""))
4762 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4764 prout(_("Scotty- \"There are so many tribbles down here"))
4765 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4769 # Code from reports.c begins here
4771 def attackreport(curt):
4772 "eport status of bases under attack."
4774 if is_scheduled(FCDBAS):
4775 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4776 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4777 elif game.isatb == 1:
4778 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4779 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4781 prout(_("No Starbase is currently under attack."))
4783 if is_scheduled(FCDBAS):
4784 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4786 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4790 # report on general game status
4792 s1 = "" and game.thawed and _("thawed ")
4793 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4794 s3 = (None, _("novice"), _("fair"),
4795 _("good"), _("expert"), _("emeritus"))[game.skill]
4796 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4797 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4798 prout(_("No plaque is allowed."))
4800 prout(_("This is tournament game %d.") % game.tourn)
4801 prout(_("Your secret password is \"%s\"") % game.passwd)
4802 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4803 (game.inkling + game.incom + game.inscom)))
4804 if game.incom - len(game.state.kcmdr):
4805 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4806 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4807 prout(_(", but no Commanders."))
4810 if game.skill > SKILL_FAIR:
4811 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4812 if len(game.state.baseq) != game.inbase:
4814 if game.inbase-len(game.state.baseq)==1:
4815 proutn(_("has been 1 base"))
4817 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4818 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4820 prout(_("There are %d bases.") % game.inbase)
4821 if communicating() or game.iseenit:
4822 # Don't report this if not seen and
4823 # either the radio is dead or not at base!
4827 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4829 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4830 if game.ship == 'E':
4831 proutn(_("You have "))
4833 proutn("%d" % (game.nprobes))
4836 proutn(_(" deep space probe"))
4840 if communicating() and is_scheduled(FDSPROB):
4842 proutn(_("An armed deep space probe is in "))
4844 proutn(_("A deep space probe is in "))
4845 prout("Quadrant %s." % game.probec)
4847 if game.cryprob <= .05:
4848 prout(_("Dilithium crystals aboard ship... not yet used."))
4852 while game.cryprob > ai:
4855 prout(_("Dilithium crystals have been used %d time%s.") % \
4856 (i, (_("s"), "")[i==1]))
4860 "Long-range sensor scan."
4861 if damaged(DLRSENS):
4862 # Now allow base's sensors if docked
4863 if game.condition != "docked":
4865 prout(_("LONG-RANGE SENSORS DAMAGED."))
4868 prout(_("Starbase's long-range scan"))
4870 prout(_("Long-range scan"))
4871 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4874 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4875 if not coord(x, y).valid_quadrant():
4879 if not damaged(DRADIO):
4880 game.state.galaxy[x][y].charted = True
4881 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4882 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4883 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4884 if not silent and game.state.galaxy[x][y].supernova:
4887 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4895 for i in range(NDEVICES):
4898 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4899 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4901 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4902 game.damage[i]+0.05,
4903 DOCKFAC*game.damage[i]+0.005))
4905 prout(_("All devices functional."))
4908 "Update the chart in the Enterprise's computer from galaxy data."
4909 game.lastchart = game.state.date
4910 for i in range(GALSIZE):
4911 for j in range(GALSIZE):
4912 if game.state.galaxy[i][j].charted:
4913 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
4914 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
4915 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
4918 "Display the star chart."
4920 if (game.options & OPTION_AUTOSCAN):
4922 if not damaged(DRADIO):
4924 if game.lastchart < game.state.date and game.condition == "docked":
4925 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
4927 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
4928 if game.state.date > game.lastchart:
4929 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
4930 prout(" 1 2 3 4 5 6 7 8")
4931 for i in range(GALSIZE):
4932 proutn("%d |" % (i+1))
4933 for j in range(GALSIZE):
4934 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4938 if game.state.galaxy[i][j].supernova:
4940 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
4942 elif game.state.galaxy[i][j].charted:
4943 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
4947 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4955 def sectscan(goodScan, i, j):
4956 "Light up an individual dot in a sector."
4957 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
4958 textcolor({"green":GREEN,
4962 "dead":BROWN}[game.condition])
4963 if game.quad[i][j] != game.ship:
4965 proutn("%c " % game.quad[i][j])
4971 "Emit status report lines"
4972 if not req or req == 1:
4973 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
4974 % (game.state.date, game.state.remtime))
4975 if not req or req == 2:
4976 if game.condition != "docked":
4978 prstat(_("Condition"), _("%s, %i DAMAGES") % \
4979 (game.condition.upper(), sum(map(lambda x: x > 0, game.damage))))
4980 if not req or req == 3:
4981 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
4982 if not req or req == 4:
4983 if damaged(DLIFSUP):
4984 if game.condition == "docked":
4985 s = _("DAMAGED, Base provides")
4987 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
4990 prstat(_("Life Support"), s)
4991 if not req or req == 5:
4992 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
4993 if not req or req == 6:
4995 if game.icrystl and (game.options & OPTION_SHOWME):
4996 extra = _(" (have crystals)")
4997 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
4998 if not req or req == 7:
4999 prstat(_("Torpedoes"), "%d" % (game.torps))
5000 if not req or req == 8:
5001 if damaged(DSHIELD):
5007 data = _(" %d%% %.1f units") \
5008 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5009 prstat(_("Shields"), s+data)
5010 if not req or req == 9:
5011 prstat(_("Klingons Left"), "%d" \
5012 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5013 if not req or req == 10:
5014 if game.options & OPTION_WORLDS:
5015 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5016 if plnet and plnet.inhabited:
5017 prstat(_("Major system"), plnet.name)
5019 prout(_("Sector is uninhabited"))
5020 elif not req or req == 11:
5021 attackreport(not req)
5024 "Request specified status data, a historical relic from slow TTYs."
5025 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5026 while scanner.next() == "IHEOL":
5027 proutn(_("Information desired? "))
5029 if scanner.token in requests:
5030 status(requests.index(scanner.token))
5032 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5033 prout((" date, condition, position, lsupport, warpfactor,"))
5034 prout((" energy, torpedoes, shields, klingons, system, time."))
5039 if damaged(DSRSENS):
5040 # Allow base's sensors if docked
5041 if game.condition != "docked":
5042 prout(_(" S.R. SENSORS DAMAGED!"))
5045 prout(_(" [Using Base's sensors]"))
5047 prout(_(" Short-range scan"))
5048 if goodScan and not damaged(DRADIO):
5049 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5050 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5051 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5052 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5053 prout(" 1 2 3 4 5 6 7 8 9 10")
5054 if game.condition != "docked":
5056 for i in range(QUADSIZE):
5057 proutn("%2d " % (i+1))
5058 for j in range(QUADSIZE):
5059 sectscan(goodScan, i, j)
5063 "Use computer to get estimated time of arrival for a warp jump."
5064 w1 = coord(); w2 = coord()
5066 if damaged(DCOMPTR):
5067 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5070 if scanner.next() != "IHREAL":
5073 proutn(_("Destination quadrant and/or sector? "))
5074 if scanner.next()!="IHREAL":
5077 w1.j = int(scanner.real-0.5)
5078 if scanner.next() != "IHREAL":
5081 w1.i = int(scanner.real-0.5)
5082 if scanner.next() == "IHREAL":
5083 w2.j = int(scanner.real-0.5)
5084 if scanner.next() != "IHREAL":
5087 w2.i = int(scanner.real-0.5)
5089 if game.quadrant.j>w1.i:
5093 if game.quadrant.i>w1.j:
5097 if not w1.valid_quadrant() or not w2.valid_sector():
5100 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5101 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5104 prout(_("Answer \"no\" if you don't know the value:"))
5107 proutn(_("Time or arrival date? "))
5108 if scanner.next()=="IHREAL":
5109 ttime = scanner.real
5110 if ttime > game.state.date:
5111 ttime -= game.state.date # Actually a star date
5112 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5113 if ttime <= 1e-10 or twarp > 10:
5114 prout(_("We'll never make it, sir."))
5121 proutn(_("Warp factor? "))
5122 if scanner.next()== "IHREAL":
5124 twarp = scanner.real
5125 if twarp<1.0 or twarp > 10.0:
5129 prout(_("Captain, certainly you can give me one of these."))
5132 ttime = (10.0*dist)/twarp**2
5133 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5134 if tpower >= game.energy:
5135 prout(_("Insufficient energy, sir."))
5136 if not game.shldup or tpower > game.energy*2.0:
5139 proutn(_("New warp factor to try? "))
5140 if scanner.next() == "IHREAL":
5142 twarp = scanner.real
5143 if twarp<1.0 or twarp > 10.0:
5151 prout(_("But if you lower your shields,"))
5152 proutn(_("remaining"))
5155 proutn(_("Remaining"))
5156 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5158 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5160 prout(_("Any warp speed is adequate."))
5162 prout(_("Minimum warp needed is %.2f,") % (twarp))
5163 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5164 if game.state.remtime < ttime:
5165 prout(_("Unfortunately, the Federation will be destroyed by then."))
5167 prout(_("You'll be taking risks at that speed, Captain"))
5168 if (game.isatb==1 and game.state.kscmdr == w1 and \
5169 scheduled(FSCDBAS)< ttime+game.state.date) or \
5170 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5171 prout(_("The starbase there will be destroyed by then."))
5172 proutn(_("New warp factor to try? "))
5173 if scanner.next() == "IHREAL":
5175 twarp = scanner.real
5176 if twarp<1.0 or twarp > 10.0:
5184 # Code from setup.c begins here
5187 "Issue a historically correct banner."
5189 prout(_("-SUPER- STAR TREK"))
5191 # From the FORTRAN original
5192 # prout(_("Latest update-21 Sept 78"))
5198 scanner.push("emsave.trk")
5199 key = scanner.next()
5201 proutn(_("File name: "))
5202 key = scanner.next()
5203 if key != "IHALPHA":
5207 if '.' not in scanner.token:
5208 scanner.token += ".trk"
5210 fp = open(scanner.token, "wb")
5212 prout(_("Can't freeze game as file %s") % scanner.token)
5214 cPickle.dump(game, fp)
5218 "Retrieve saved game."
5219 game.passwd[0] = '\0'
5220 key = scanner.next()
5222 proutn(_("File name: "))
5223 key = scanner.next()
5224 if key != "IHALPHA":
5228 if '.' not in scanner.token:
5229 scanner.token += ".trk"
5231 fp = open(scanner.token, "rb")
5233 prout(_("Can't thaw game in %s") % scanner.token)
5235 game = cPickle.load(fp)
5239 # I used <http://www.memory-alpha.org> to find planets
5240 # with references in ST:TOS. Earth and the Alpha Centauri
5241 # Colony have been omitted.
5243 # Some planets marked Class G and P here will be displayed as class M
5244 # because of the way planets are generated. This is a known bug.
5247 _("Andoria (Fesoan)"), # several episodes
5248 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5249 _("Vulcan (T'Khasi)"), # many episodes
5250 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5251 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5252 _("Ardana"), # TOS: "The Cloud Minders"
5253 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5254 _("Gideon"), # TOS: "The Mark of Gideon"
5255 _("Aldebaran III"), # TOS: "The Deadly Years"
5256 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5257 _("Altair IV"), # TOS: "Amok Time
5258 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5259 _("Benecia"), # TOS: "The Conscience of the King"
5260 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5261 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5262 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5263 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5264 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5265 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5266 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5267 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5268 _("Ingraham B"), # TOS: "Operation: Annihilate"
5269 _("Janus IV"), # TOS: "The Devil in the Dark"
5270 _("Makus III"), # TOS: "The Galileo Seven"
5271 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5272 _("Omega IV"), # TOS: "The Omega Glory"
5273 _("Regulus V"), # TOS: "Amok Time
5274 _("Deneva"), # TOS: "Operation -- Annihilate!"
5275 # Worlds from BSD Trek
5276 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5277 _("Beta III"), # TOS: "The Return of the Archons"
5278 _("Triacus"), # TOS: "And the Children Shall Lead",
5279 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5281 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5282 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5283 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5284 # _("Izar"), # TOS: "Whom Gods Destroy"
5285 # _("Tiburon"), # TOS: "The Way to Eden"
5286 # _("Merak II"), # TOS: "The Cloud Minders"
5287 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5288 # _("Iotia"), # TOS: "A Piece of the Action"
5292 _("S. R. Sensors"), \
5293 _("L. R. Sensors"), \
5295 _("Photon Tubes"), \
5296 _("Life Support"), \
5297 _("Warp Engines"), \
5298 _("Impulse Engines"), \
5300 _("Subspace Radio"), \
5301 _("Shuttle Craft"), \
5303 _("Navigation System"), \
5305 _("Shield Control"), \
5311 "Prepare to play, set up cosmos."
5313 # Decide how many of everything
5315 return # frozen game
5316 # Prepare the Enterprise
5317 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5319 game.state.crew = FULLCREW
5320 game.energy = game.inenrg = 5000.0
5321 game.shield = game.inshld = 2500.0
5324 game.quadrant = randplace(GALSIZE)
5325 game.sector = randplace(QUADSIZE)
5326 game.torps = game.intorps = 10
5327 game.nprobes = randrange(2, 5)
5329 for i in range(NDEVICES):
5330 game.damage[i] = 0.0
5331 # Set up assorted game parameters
5332 game.battle = coord()
5333 game.state.date = game.indate = 100.0 * randreal(20, 51)
5334 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5335 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5336 game.isatb = game.state.nplankl = 0
5337 game.state.starkl = game.state.basekl = 0
5338 game.iscraft = "onship"
5341 # Starchart is functional but we've never seen it
5342 game.lastchart = FOREVER
5343 # Put stars in the galaxy
5345 for i in range(GALSIZE):
5346 for j in range(GALSIZE):
5347 k = randrange(1, QUADSIZE**2/10+1)
5349 game.state.galaxy[i][j].stars = k
5350 # Locate star bases in galaxy
5351 for i in range(game.inbase):
5354 w = randplace(GALSIZE)
5355 if not game.state.galaxy[w.i][w.j].starbase:
5358 # C version: for (j = i-1; j > 0; j--)
5359 # so it did them in the opposite order.
5360 for j in range(1, i):
5361 # Improved placement algorithm to spread out bases
5362 distq = (w - game.state.baseq[j]).distance()
5363 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5366 prout("=== Abandoning base #%d at %s" % (i, w))
5368 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5370 prout("=== Saving base #%d, close to #%d" % (i, j))
5373 game.state.baseq.append(w)
5374 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5375 # Position ordinary Klingon Battle Cruisers
5377 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5378 if klumper > MAXKLQUAD:
5382 klump = (1.0 - r*r)*klumper
5387 w = randplace(GALSIZE)
5388 if not game.state.galaxy[w.i][w.j].supernova and \
5389 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5391 game.state.galaxy[w.i][w.j].klingons += int(klump)
5394 # Position Klingon Commander Ships
5395 for i in range(game.incom):
5397 w = randplace(GALSIZE)
5398 if not welcoming(w) or w in game.state.kcmdr:
5400 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5402 game.state.galaxy[w.i][w.j].klingons += 1
5403 game.state.kcmdr.append(w)
5404 # Locate planets in galaxy
5405 for i in range(game.inplan):
5407 w = randplace(GALSIZE)
5408 if game.state.galaxy[w.i][w.j].planet == None:
5412 new.crystals = "absent"
5413 if (game.options & OPTION_WORLDS) and i < NINHAB:
5414 new.pclass = "M" # All inhabited planets are class M
5415 new.crystals = "absent"
5417 new.name = systnames[i]
5418 new.inhabited = True
5420 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5422 new.crystals = "present"
5423 new.known = "unknown"
5424 new.inhabited = False
5425 game.state.galaxy[w.i][w.j].planet = new
5426 game.state.planets.append(new)
5428 for i in range(game.state.nromrem):
5429 w = randplace(GALSIZE)
5430 game.state.galaxy[w.i][w.j].romulans += 1
5431 # Place the Super-Commander if needed
5432 if game.state.nscrem > 0:
5434 w = randplace(GALSIZE)
5437 game.state.kscmdr = w
5438 game.state.galaxy[w.i][w.j].klingons += 1
5439 # Initialize times for extraneous events
5440 schedule(FSNOVA, expran(0.5 * game.intime))
5441 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5442 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5443 schedule(FBATTAK, expran(0.3*game.intime))
5445 if game.state.nscrem:
5446 schedule(FSCMOVE, 0.2777)
5451 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5452 schedule(FDISTR, expran(1.0 + game.intime))
5457 # Place thing (in tournament game, we don't want one!)
5458 # New in SST2K: never place the Thing near a starbase.
5459 # This makes sense and avoids a special case in the old code.
5461 if game.tourn is None:
5463 thing = randplace(GALSIZE)
5464 if thing not in game.state.baseq:
5467 game.state.snap = False
5468 if game.skill == SKILL_NOVICE:
5469 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5470 prout(_("a deadly Klingon invasion force. As captain of the United"))
5471 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5472 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5473 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5474 prout(_("your mission. As you proceed you may be given more time."))
5476 prout(_("You will have %d supporting starbases.") % (game.inbase))
5477 proutn(_("Starbase locations- "))
5479 prout(_("Stardate %d.") % int(game.state.date))
5481 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5482 prout(_("An unknown number of Romulans."))
5483 if game.state.nscrem:
5484 prout(_("And one (GULP) Super-Commander."))
5485 prout(_("%d stardates.") % int(game.intime))
5486 proutn(_("%d starbases in ") % game.inbase)
5487 for i in range(game.inbase):
5488 proutn(`game.state.baseq[i]`)
5491 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5492 proutn(_(" Sector %s") % game.sector)
5494 prout(_("Good Luck!"))
5495 if game.state.nscrem:
5496 prout(_(" YOU'LL NEED IT."))
5499 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5501 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5502 attack(torps_ok=False)
5505 "Choose your game type."
5507 game.tourn = game.length = 0
5509 game.skill = SKILL_NONE
5510 if not scanner.inqueue: # Can start with command line options
5511 proutn(_("Would you like a regular, tournament, or saved game? "))
5513 if scanner.sees("tournament"):
5514 while scanner.next() == "IHEOL":
5515 proutn(_("Type in tournament number-"))
5516 if scanner.real == 0:
5518 continue # We don't want a blank entry
5519 game.tourn = int(round(scanner.real))
5520 random.seed(scanner.real)
5522 logfp.write("# random.seed(%d)\n" % scanner.real)
5524 if scanner.sees("saved") or scanner.sees("frozen"):
5528 if game.passwd == None:
5530 if not game.alldone:
5531 game.thawed = True # No plaque if not finished
5535 if scanner.sees("regular"):
5537 proutn(_("What is \"%s\"?") % scanner.token)
5539 while game.length==0 or game.skill==SKILL_NONE:
5540 if scanner.next() == "IHALPHA":
5541 if scanner.sees("short"):
5543 elif scanner.sees("medium"):
5545 elif scanner.sees("long"):
5547 elif scanner.sees("novice"):
5548 game.skill = SKILL_NOVICE
5549 elif scanner.sees("fair"):
5550 game.skill = SKILL_FAIR
5551 elif scanner.sees("good"):
5552 game.skill = SKILL_GOOD
5553 elif scanner.sees("expert"):
5554 game.skill = SKILL_EXPERT
5555 elif scanner.sees("emeritus"):
5556 game.skill = SKILL_EMERITUS
5558 proutn(_("What is \""))
5559 proutn(scanner.token)
5564 proutn(_("Would you like a Short, Medium, or Long game? "))
5565 elif game.skill == SKILL_NONE:
5566 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5567 # Choose game options -- added by ESR for SST2K
5568 if scanner.next() != "IHALPHA":
5570 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5572 if scanner.sees("plain"):
5573 # Approximates the UT FORTRAN version.
5574 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5575 game.options |= OPTION_PLAIN
5576 elif scanner.sees("almy"):
5577 # Approximates Tom Almy's version.
5578 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5579 game.options |= OPTION_ALMY
5580 elif scanner.sees("fancy") or scanner.sees("\n"):
5582 elif len(scanner.token):
5583 proutn(_("What is \"%s\"?") % scanner.token)
5584 game.options &=~ OPTION_COLOR
5586 if game.passwd == "debug":
5588 prout("=== Debug mode enabled.")
5589 # Use parameters to generate initial values of things
5590 game.damfac = 0.5 * game.skill
5591 game.inbase = randrange(BASEMIN, BASEMAX+1)
5593 if game.options & OPTION_PLANETS:
5594 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5595 if game.options & OPTION_WORLDS:
5596 game.inplan += int(NINHAB)
5597 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5598 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5599 game.state.remtime = 7.0 * game.length
5600 game.intime = game.state.remtime
5601 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5602 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5603 game.state.remres = (game.inkling+4*game.incom)*game.intime
5604 game.inresor = game.state.remres
5605 if game.inkling > 50:
5606 game.state.inbase += 1
5609 def dropin(iquad=None):
5610 "Drop a feature on a random dot in the current quadrant."
5612 w = randplace(QUADSIZE)
5613 if game.quad[w.i][w.j] == '.':
5615 if iquad is not None:
5616 game.quad[w.i][w.j] = iquad
5620 "Update our alert status."
5621 game.condition = "green"
5622 if game.energy < 1000.0:
5623 game.condition = "yellow"
5624 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5625 game.condition = "red"
5627 game.condition="dead"
5630 "Drop new Klingon into current quadrant."
5631 return enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5634 "Set up a new state of quadrant, for when we enter or re-enter it."
5637 game.neutz = game.inorbit = game.landed = False
5638 game.ientesc = game.iseenit = False
5639 # Create a blank quadrant
5640 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5642 # Attempt to escape Super-commander, so tbeam back!
5645 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5646 # cope with supernova
5649 game.klhere = q.klingons
5650 game.irhere = q.romulans
5652 game.quad[game.sector.i][game.sector.j] = game.ship
5655 # Position ordinary Klingons
5656 for i in range(game.klhere):
5658 # If we need a commander, promote a Klingon
5659 for cmdr in game.state.kcmdr:
5660 if cmdr == game.quadrant:
5661 e = game.enemies[game.klhere-1]
5662 game.quad[e.location.i][e.location.j] = 'C'
5663 e.power = randreal(950,1350) + 50.0*game.skill
5665 # If we need a super-commander, promote a Klingon
5666 if game.quadrant == game.state.kscmdr:
5668 game.quad[e.location.i][e.location.j] = 'S'
5669 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5670 game.iscate = (game.state.remkl > 1)
5671 # Put in Romulans if needed
5672 for i in range(q.romulans):
5673 enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5674 # If quadrant needs a starbase, put it in
5676 game.base = dropin('B')
5677 # If quadrant needs a planet, put it in
5679 game.iplnet = q.planet
5680 if not q.planet.inhabited:
5681 game.plnet = dropin('P')
5683 game.plnet = dropin('@')
5684 # Check for condition
5687 if game.irhere > 0 and game.klhere == 0:
5689 if not damaged(DRADIO):
5691 prout(_("LT. Uhura- \"Captain, an urgent message."))
5692 prout(_(" I'll put it on audio.\" CLICK"))
5694 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5695 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5696 # Put in THING if needed
5697 if thing == game.quadrant:
5698 enemy(type='?', loc=dropin(),
5699 power=randreal(6000,6500.0)+250.0*game.skill)
5700 if not damaged(DSRSENS):
5702 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5703 prout(_(" Please examine your short-range scan.\""))
5704 # Decide if quadrant needs a Tholian; lighten up if skill is low
5705 if game.options & OPTION_THOLIAN:
5706 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5707 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5708 (game.skill > SKILL_GOOD and withprob(0.08)):
5711 w.i = withprob(0.5) * (QUADSIZE-1)
5712 w.j = withprob(0.5) * (QUADSIZE-1)
5713 if game.quad[w.i][w.j] == '.':
5715 game.tholian = enemy(type='T', loc=w,
5716 power=randrange(100, 500) + 25.0*game.skill)
5717 # Reserve unoccupied corners
5718 if game.quad[0][0]=='.':
5719 game.quad[0][0] = 'X'
5720 if game.quad[0][QUADSIZE-1]=='.':
5721 game.quad[0][QUADSIZE-1] = 'X'
5722 if game.quad[QUADSIZE-1][0]=='.':
5723 game.quad[QUADSIZE-1][0] = 'X'
5724 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5725 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5726 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
5727 # And finally the stars
5728 for i in range(q.stars):
5730 # Put in a few black holes
5731 for i in range(1, 3+1):
5734 # Take out X's in corners if Tholian present
5736 if game.quad[0][0]=='X':
5737 game.quad[0][0] = '.'
5738 if game.quad[0][QUADSIZE-1]=='X':
5739 game.quad[0][QUADSIZE-1] = '.'
5740 if game.quad[QUADSIZE-1][0]=='X':
5741 game.quad[QUADSIZE-1][0] = '.'
5742 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5743 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5746 "Set the self-destruct password."
5747 if game.options & OPTION_PLAIN:
5750 proutn(_("Please type in a secret password- "))
5752 game.passwd = scanner.token
5753 if game.passwd != None:
5757 game.passwd += chr(ord('a')+randrange(26))
5758 game.passwd += chr(ord('a')+randrange(26))
5759 game.passwd += chr(ord('a')+randrange(26))
5761 # Code from sst.c begins here
5764 "SRSCAN": OPTION_TTY,
5765 "STATUS": OPTION_TTY,
5766 "REQUEST": OPTION_TTY,
5767 "LRSCAN": OPTION_TTY,
5780 "SENSORS": OPTION_PLANETS,
5781 "ORBIT": OPTION_PLANETS,
5782 "TRANSPORT": OPTION_PLANETS,
5783 "MINE": OPTION_PLANETS,
5784 "CRYSTALS": OPTION_PLANETS,
5785 "SHUTTLE": OPTION_PLANETS,
5786 "PLANETS": OPTION_PLANETS,
5791 "PROBE": OPTION_PROBE,
5793 "FREEZE": 0, # Synonym for SAVE
5799 "SOS": 0, # Synonym for MAYDAY
5800 "CALL": 0, # Synonym for MAYDAY
5806 "Generate a list of legal commands."
5807 prout(_("LEGAL COMMANDS ARE:"))
5809 for key in commands:
5810 if not commands[key] or (commands[key] & game.options):
5811 proutn("%-12s " % key)
5813 if emitted % 5 == 4:
5818 "Browse on-line help."
5819 key = scanner.next()
5822 setwnd(prompt_window)
5823 proutn(_("Help on what command? "))
5824 key = scanner.next()
5825 setwnd(message_window)
5828 if scanner.token.upper() in commands or scanner.token == "ABBREV":
5835 cmd = scanner.token.upper()
5836 for directory in docpath:
5838 fp = open(os.path.join(directory, "sst.doc"), "r")
5843 prout(_("Spock- \"Captain, that information is missing from the"))
5844 prout(_(" computer. You need to find sst.doc and put it somewhere"))
5845 proutn(_(" in these directories: %s") % ":".join(docpath))
5847 # This used to continue: "You need to find SST.DOC and put
5848 # it in the current directory."
5851 linebuf = fp.readline()
5853 prout(_("Spock- \"Captain, there is no information on that command.\""))
5856 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5857 linebuf = linebuf[3:].strip()
5858 if cmd.upper() == linebuf:
5861 prout(_("Spock- \"Captain, I've found the following information:\""))
5864 linebuf = fp.readline()
5865 if "******" in linebuf:
5871 "Command-interpretation loop."
5873 setwnd(message_window)
5874 while True: # command loop
5876 while True: # get a command
5878 game.optime = game.justin = False
5880 setwnd(prompt_window)
5883 if scanner.next() == "IHEOL":
5884 if game.options & OPTION_CURSES:
5887 elif scanner.token == "":
5891 setwnd(message_window)
5893 candidates = filter(lambda x: x.startswith(scanner.token.upper()),
5895 if len(candidates) == 1:
5898 elif candidates and not (game.options & OPTION_PLAIN):
5899 prout("Commands with prefix '%s': %s" % (scanner.token, " ".join(candidates)))
5903 if cmd == "SRSCAN": # srscan
5905 elif cmd == "STATUS": # status
5907 elif cmd == "REQUEST": # status request
5909 elif cmd == "LRSCAN": # long range scan
5910 lrscan(silent=False)
5911 elif cmd == "PHASERS": # phasers
5915 elif cmd in ("TORPEDO", "PHOTONS"): # photon torpedos
5919 elif cmd == "MOVE": # move under warp
5920 warp(wcourse=None, involuntary=False)
5921 elif cmd == "SHIELDS": # shields
5922 doshield(shraise=False)
5925 game.shldchg = False
5926 elif cmd == "DOCK": # dock at starbase
5929 attack(torps_ok=False)
5930 elif cmd == "DAMAGES": # damage reports
5932 elif cmd == "CHART": # chart
5934 elif cmd == "IMPULSE": # impulse
5936 elif cmd == "REST": # rest
5940 elif cmd == "WARP": # warp
5942 elif cmd == "SCORE": # score
5944 elif cmd == "SENSORS": # sensors
5946 elif cmd == "ORBIT": # orbit
5950 elif cmd == "TRANSPORT": # transport "beam"
5952 elif cmd == "MINE": # mine
5956 elif cmd == "CRYSTALS": # crystals
5960 elif cmd == "SHUTTLE": # shuttle
5964 elif cmd == "PLANETS": # Planet list
5966 elif cmd == "REPORT": # Game Report
5968 elif cmd == "COMPUTER": # use COMPUTER!
5970 elif cmd == "COMMANDS":
5972 elif cmd == "EMEXIT": # Emergency exit
5973 clrscr() # Hide screen
5974 freeze(True) # forced save
5975 raise SystemExit,1 # And quick exit
5976 elif cmd == "PROBE":
5977 probe() # Launch probe
5980 elif cmd == "ABANDON": # Abandon Ship
5982 elif cmd == "DESTRUCT": # Self Destruct
5984 elif cmd == "SAVE": # Save Game
5987 if game.skill > SKILL_GOOD:
5988 prout(_("WARNING--Saved games produce no plaques!"))
5989 elif cmd == "DEATHRAY": # Try a desparation measure
5993 elif cmd == "DEBUGCMD": # What do we want for debug???
5995 elif cmd == "MAYDAY": # Call for help
6000 game.alldone = True # quit the game
6005 break # Game has ended
6006 if game.optime != 0.0:
6009 break # Events did us in
6010 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6013 if hitme and not game.justin:
6014 attack(torps_ok=True)
6017 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6028 "Emit the name of an enemy or feature."
6029 if type == 'R': s = _("Romulan")
6030 elif type == 'K': s = _("Klingon")
6031 elif type == 'C': s = _("Commander")
6032 elif type == 'S': s = _("Super-commander")
6033 elif type == '*': s = _("Star")
6034 elif type == 'P': s = _("Planet")
6035 elif type == 'B': s = _("Starbase")
6036 elif type == ' ': s = _("Black hole")
6037 elif type == 'T': s = _("Tholian")
6038 elif type == '#': s = _("Tholian web")
6039 elif type == '?': s = _("Stranger")
6040 elif type == '@': s = _("Inhabited World")
6041 else: s = "Unknown??"
6044 def crmena(stars, enemy, loctype, w):
6045 "Emit the name of an enemy and his location."
6049 buf += cramen(enemy) + _(" at ")
6050 if loctype == "quadrant":
6051 buf += _("Quadrant ")
6052 elif loctype == "sector":
6057 "Emit our ship name."
6058 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6061 "Emit a line of stars"
6062 prouts("******************************************************")
6066 return -avrage*math.log(1e-7 + randreal())
6068 def randplace(size):
6069 "Choose a random location."
6071 w.i = randrange(size)
6072 w.j = randrange(size)
6082 # Get a token from the user
6085 # Fill the token quue if nothing here
6086 while not self.inqueue:
6088 if curwnd==prompt_window:
6090 setwnd(message_window)
6097 self.inqueue = line.lstrip().split() + ["\n"]
6098 # From here on in it's all looking at the queue
6099 self.token = self.inqueue.pop(0)
6100 if self.token == "\n":
6104 self.real = float(self.token)
6105 self.type = "IHREAL"
6110 self.token = self.token.lower()
6111 self.type = "IHALPHA"
6114 def append(self, tok):
6115 self.inqueue.append(tok)
6116 def push(self, tok):
6117 self.inqueue.insert(0, tok)
6121 # Demand input for next scan
6123 self.real = self.token = None
6125 # compares s to item and returns true if it matches to the length of s
6126 return s.startswith(self.token)
6128 # Round token value to nearest integer
6129 return int(round(scanner.real))
6133 if scanner.type != "IHREAL":
6136 s.i = scanner.int()-1
6138 if scanner.type != "IHREAL":
6141 s.j = scanner.int()-1
6144 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6147 "Yes-or-no confirmation."
6151 if scanner.token == 'y':
6153 if scanner.token == 'n':
6156 proutn(_("Please answer with \"y\" or \"n\": "))
6159 "Complain about unparseable input."
6162 prout(_("Beg your pardon, Captain?"))
6165 "Access to the internals for debugging."
6166 proutn("Reset levels? ")
6168 if game.energy < game.inenrg:
6169 game.energy = game.inenrg
6170 game.shield = game.inshld
6171 game.torps = game.intorps
6172 game.lsupres = game.inlsr
6173 proutn("Reset damage? ")
6175 for i in range(NDEVICES):
6176 if game.damage[i] > 0.0:
6177 game.damage[i] = 0.0
6178 proutn("Toggle debug flag? ")
6180 game.idebug = not game.idebug
6182 prout("Debug output ON")
6184 prout("Debug output OFF")
6185 proutn("Cause selective damage? ")
6187 for i in range(NDEVICES):
6188 proutn("Kill %s?" % device[i])
6190 key = scanner.next()
6191 if key == "IHALPHA" and scanner.sees("y"):
6192 game.damage[i] = 10.0
6193 proutn("Examine/change events? ")
6198 FSNOVA: "Supernova ",
6201 FBATTAK: "Base Attack ",
6202 FCDBAS: "Base Destroy ",
6203 FSCMOVE: "SC Move ",
6204 FSCDBAS: "SC Base Destroy ",
6205 FDSPROB: "Probe Move ",
6206 FDISTR: "Distress Call ",
6207 FENSLV: "Enslavement ",
6208 FREPRO: "Klingon Build ",
6210 for i in range(1, NEVENTS):
6213 proutn("%.2f" % (scheduled(i)-game.state.date))
6214 if i == FENSLV or i == FREPRO:
6216 proutn(" in %s" % ev.quadrant)
6221 key = scanner.next()
6225 elif key == "IHREAL":
6226 ev = schedule(i, scanner.real)
6227 if i == FENSLV or i == FREPRO:
6229 proutn("In quadrant- ")
6230 key = scanner.next()
6231 # "IHEOL" says to leave coordinates as they are
6234 prout("Event %d canceled, no x coordinate." % (i))
6237 w.i = int(round(scanner.real))
6238 key = scanner.next()
6240 prout("Event %d canceled, no y coordinate." % (i))
6243 w.j = int(round(scanner.real))
6246 proutn("Induce supernova here? ")
6248 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6251 if __name__ == '__main__':
6252 import getopt, socket
6254 global line, thing, game
6259 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6260 if os.getenv("TERM"):
6261 game.options |= OPTION_CURSES
6263 game.options |= OPTION_TTY
6264 seed = int(time.time())
6265 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:txV")
6266 for (switch, val) in options:
6269 replayfp = open(val, "r")
6271 sys.stderr.write("sst: can't open replay file %s\n" % val)
6274 line = replayfp.readline().strip()
6275 (leader, key, seed) = line.split()
6277 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6278 line = replayfp.readline().strip()
6279 arguments += line.split()[2:]
6281 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6283 game.options |= OPTION_TTY
6284 game.options &=~ OPTION_CURSES
6285 elif switch == '-s':
6287 elif switch == '-t':
6288 game.options |= OPTION_TTY
6289 game.options &=~ OPTION_CURSES
6290 elif switch == '-x':
6292 elif switch == '-V':
6293 print "SST2K", version
6296 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6298 # where to save the input in case of bugs
6299 if "TMPDIR" in os.environ:
6300 tmpdir = os.environ['TMPDIR']
6304 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6306 sys.stderr.write("sst: warning, can't open logfile\n")
6309 logfp.write("# seed %s\n" % seed)
6310 logfp.write("# options %s\n" % " ".join(arguments))
6311 logfp.write("# recorded by %s@%s on %s\n" % \
6312 (getpass.getuser(),socket.gethostname(),time.ctime()))
6314 scanner = sstscanner()
6315 map(scanner.append, arguments)
6318 while True: # Play a game
6319 setwnd(fullscreen_window)
6325 game.alldone = False
6331 if game.tourn and game.alldone:
6332 proutn(_("Do you want your score recorded?"))
6338 proutn(_("Do you want to play again? "))
6342 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6346 except KeyboardInterrupt: