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 ion how to modify (and how not to modify!) this code.
14 import os, sys, math, curses, time, readline, cPickle, random, copy, gettext, getpass
16 SSTDOC = "/usr/share/doc/sst/sst.doc"
19 def _(str): return gettext.gettext(str)
21 GALSIZE = 8 # Galaxy size in quadrants
22 NINHAB = (GALSIZE * GALSIZE / 2) # Number of inhabited worlds
23 MAXUNINHAB = 10 # Maximum uninhabited worlds
24 QUADSIZE = 10 # Quadrant size in sectors
25 BASEMIN = 2 # Minimum starbases
26 BASEMAX = (GALSIZE * GALSIZE / 12) # Maximum starbases
27 MAXKLGAME = 127 # Maximum Klingons per game
28 MAXKLQUAD = 9 # Maximum Klingons per quadrant
29 FULLCREW = 428 # Crew size. BSD Trek was 387, that's wrong
30 FOREVER = 1e30 # Time for the indefinite future
31 MAXBURST = 3 # Max # of torps you can launch in one turn
32 MINCMDR = 10 # Minimum number of Klingon commanders
33 DOCKFAC = 0.25 # Repair faster when docked
34 PHASEFAC = 2.0 # Unclear what this is, it was in the C version
58 def __init__(self, x=None, y=None):
61 def valid_quadrant(self):
62 return self.i>=0 and self.i<GALSIZE and self.j>=0 and self.j<GALSIZE
63 def valid_sector(self):
64 return self.i>=0 and self.i<QUADSIZE and self.j>=0 and self.j<QUADSIZE
66 self.i = self.j = None
68 return self.i != None and self.j != None
69 def __eq__(self, other):
70 return other != None and self.i == other.i and self.j == other.j
71 def __ne__(self, other):
72 return other == None or self.i != other.i or self.j != other.j
73 def __add__(self, other):
74 return coord(self.i+other.i, self.j+other.j)
75 def __sub__(self, other):
76 return coord(self.i-other.i, self.j-other.j)
77 def __mul__(self, other):
78 return coord(self.i*other, self.j*other)
79 def __rmul__(self, other):
80 return coord(self.i*other, self.j*other)
81 def __div__(self, other):
82 return coord(self.i/other, self.j/other)
83 def __mod__(self, other):
84 return coord(self.i % other, self.j % other)
85 def __rdiv__(self, other):
86 return coord(self.i/other, self.j/other)
87 def roundtogrid(self):
88 return coord(int(round(self.i)), int(round(self.j)))
89 def distance(self, other=None):
90 if not other: other = coord(0, 0)
91 return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
93 return 1.90985*math.atan2(self.j, self.i)
99 s.i = self.i / abs(self.i)
103 s.j = self.j / abs(self.j)
106 #print "Location %s -> %s" % (self, (self / QUADSIZE).roundtogrid())
107 return self.roundtogrid() / QUADSIZE
109 return self.roundtogrid() % QUADSIZE
112 s.i = self.i + randrange(-1, 2)
113 s.j = self.j + randrange(-1, 2)
116 if self.i == None or self.j == None:
118 return "%s - %s" % (self.i+1, self.j+1)
123 self.name = None # string-valued if inhabited
124 self.quadrant = coord() # quadrant located
125 self.pclass = None # could be ""M", "N", "O", or "destroyed"
126 self.crystals = "absent"# could be "mined", "present", "absent"
127 self.known = "unknown" # could be "unknown", "known", "shuttle_down"
128 self.inhabited = False # is it inhabites?
136 self.starbase = False
139 self.supernova = False
141 self.status = "secure" # Could be "secure", "distressed", "enslaved"
149 def fill2d(size, fillfun):
150 "Fill an empty list in 2D."
152 for i in range(size):
154 for j in range(size):
155 lst[i].append(fillfun(i, j))
160 self.snap = False # snapshot taken
161 self.crew = 0 # crew complement
162 self.remkl = 0 # remaining klingons
163 self.nscrem = 0 # remaining super commanders
164 self.starkl = 0 # destroyed stars
165 self.basekl = 0 # destroyed bases
166 self.nromrem = 0 # Romulans remaining
167 self.nplankl = 0 # destroyed uninhabited planets
168 self.nworldkl = 0 # destroyed inhabited planets
169 self.planets = [] # Planet information
170 self.date = 0.0 # stardate
171 self.remres = 0 # remaining resources
172 self.remtime = 0 # remaining time
173 self.baseq = [] # Base quadrant coordinates
174 self.kcmdr = [] # Commander quadrant coordinates
175 self.kscmdr = coord() # Supercommander quadrant coordinates
177 self.galaxy = fill2d(GALSIZE, lambda i, j: quadrant())
179 self.chart = fill2d(GALSIZE, lambda i, j: page())
183 self.date = None # A real number
184 self.quadrant = None # A coord structure
187 OPTION_ALL = 0xffffffff
188 OPTION_TTY = 0x00000001 # old interface
189 OPTION_CURSES = 0x00000002 # new interface
190 OPTION_IOMODES = 0x00000003 # cover both interfaces
191 OPTION_PLANETS = 0x00000004 # planets and mining
192 OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version)
193 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005)
194 OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980)
195 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
196 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy)
197 OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy)
198 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005)
199 OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005)
200 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006)
201 OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006)
202 OPTION_PLAIN = 0x01000000 # user chose plain game
203 OPTION_ALMY = 0x02000000 # user chose Almy variant
204 OPTION_COLOR = 0x04000000 # enable color display (experimental, ESR, 2010)
223 NDEVICES= 16 # Number of devices
232 def damaged(dev): return (game.damage[dev] != 0.0)
233 def communicating(): return not damaged(DRADIO) or game.condition=="docked"
235 # Define future events
236 FSPY = 0 # Spy event happens always (no future[] entry)
237 # can cause SC to tractor beam Enterprise
238 FSNOVA = 1 # Supernova
239 FTBEAM = 2 # Commander tractor beams Enterprise
240 FSNAP = 3 # Snapshot for time warp
241 FBATTAK = 4 # Commander attacks base
242 FCDBAS = 5 # Commander destroys base
243 FSCMOVE = 6 # Supercommander moves (might attack base)
244 FSCDBAS = 7 # Supercommander destroys base
245 FDSPROB = 8 # Move deep space probe
246 FDISTR = 9 # Emit distress call from an inhabited world
247 FENSLV = 10 # Inhabited word is enslaved */
248 FREPRO = 11 # Klingons build a ship in an enslaved system
251 # Abstract out the event handling -- underlying data structures will change
252 # when we implement stateful events
253 def findevent(evtype): return game.future[evtype]
256 def __init__(self, type=None, loc=None, power=None):
258 self.location = coord()
261 self.power = power # enemy energy level
262 game.enemies.append(self)
264 motion = (loc != self.location)
265 if self.location.i is not None and self.location.j is not None:
268 game.quad[self.location.i][self.location.j] = '#'
270 game.quad[self.location.i][self.location.j] = '.'
272 self.location = copy.copy(loc)
273 game.quad[self.location.i][self.location.j] = self.type
274 self.kdist = self.kavgd = (game.sector - loc).distance()
276 self.location = coord()
277 self.kdist = self.kavgd = None
278 game.enemies.remove(self)
281 return "<%s,%s.%f>" % (self.type, self.location, self.power) # For debugging
285 self.options = None # Game options
286 self.state = snapshot() # A snapshot structure
287 self.snapsht = snapshot() # Last snapshot taken for time-travel purposes
288 self.quad = None # contents of our quadrant
289 self.damage = [0.0] * NDEVICES # damage encountered
290 self.future = [] # future events
291 for i in range(NEVENTS):
292 self.future.append(event())
293 self.passwd = None; # Self Destruct password
295 self.quadrant = None # where we are in the large
296 self.sector = None # where we are in the small
297 self.tholian = None # Tholian enemy object
298 self.base = None # position of base in current quadrant
299 self.battle = None # base coordinates being attacked
300 self.plnet = None # location of planet in quadrant
301 self.gamewon = False # Finished!
302 self.ididit = False # action taken -- allows enemy to attack
303 self.alive = False # we are alive (not killed)
304 self.justin = False # just entered quadrant
305 self.shldup = False # shields are up
306 self.shldchg = False # shield is changing (affects efficiency)
307 self.iscate = False # super commander is here
308 self.ientesc = False # attempted escape from supercommander
309 self.resting = False # rest time
310 self.icraft = False # Kirk in Galileo
311 self.landed = False # party on planet (true), on ship (false)
312 self.alldone = False # game is now finished
313 self.neutz = False # Romulan Neutral Zone
314 self.isarmed = False # probe is armed
315 self.inorbit = False # orbiting a planet
316 self.imine = False # mining
317 self.icrystl = False # dilithium crystals aboard
318 self.iseenit = False # seen base attack report
319 self.thawed = False # thawed game
320 self.condition = None # "green", "yellow", "red", "docked", "dead"
321 self.iscraft = None # "onship", "offship", "removed"
322 self.skill = None # Player skill level
323 self.inkling = 0 # initial number of klingons
324 self.inbase = 0 # initial number of bases
325 self.incom = 0 # initial number of commanders
326 self.inscom = 0 # initial number of commanders
327 self.inrom = 0 # initial number of commanders
328 self.instar = 0 # initial stars
329 self.intorps = 0 # initial/max torpedoes
330 self.torps = 0 # number of torpedoes
331 self.ship = 0 # ship type -- 'E' is Enterprise
332 self.abandoned = 0 # count of crew abandoned in space
333 self.length = 0 # length of game
334 self.klhere = 0 # klingons here
335 self.casual = 0 # causalties
336 self.nhelp = 0 # calls for help
337 self.nkinks = 0 # count of energy-barrier crossings
338 self.iplnet = None # planet # in quadrant
339 self.inplan = 0 # initial planets
340 self.irhere = 0 # Romulans in quadrant
341 self.isatb = 0 # =2 if super commander is attacking base
342 self.tourn = None # tournament number
343 self.nprobes = 0 # number of probes available
344 self.inresor = 0.0 # initial resources
345 self.intime = 0.0 # initial time
346 self.inenrg = 0.0 # initial/max energy
347 self.inshld = 0.0 # initial/max shield
348 self.inlsr = 0.0 # initial life support resources
349 self.indate = 0.0 # initial date
350 self.energy = 0.0 # energy level
351 self.shield = 0.0 # shield level
352 self.warpfac = 0.0 # warp speed
353 self.lsupres = 0.0 # life support reserves
354 self.optime = 0.0 # time taken by current operation
355 self.damfac = 0.0 # damage factor
356 self.lastchart = 0.0 # time star chart was last updated
357 self.cryprob = 0.0 # probability that crystal will work
358 self.probe = None # object holding probe course info
359 self.height = 0.0 # height of orbit around planet
361 # Stas thinks this should be (C expression):
362 # game.state.remkl + len(game.state.kcmdr) > 0 ?
363 # game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr)) : 99
364 # He says the existing expression is prone to divide-by-zero errors
365 # after killing the last klingon when score is shown -- perhaps also
366 # if the only remaining klingon is SCOM.
367 game.state.remtime = game.state.remres/(game.state.remkl + 4*len(game.state.kcmdr))
393 return random.random() < p
395 def randrange(*args):
396 return random.randrange(*args)
401 v *= args[0] # from [0, args[0])
403 v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
406 # Code from ai.c begins here
409 "Would this quadrant welcome another Klingon?"
410 return iq.valid_quadrant() and \
411 not game.state.galaxy[iq.i][iq.j].supernova and \
412 game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
414 def tryexit(enemy, look, irun):
415 "A bad guy attempts to bug out."
417 iq.i = game.quadrant.i+(look.i+(QUADSIZE-1))/QUADSIZE - 1
418 iq.j = game.quadrant.j+(look.j+(QUADSIZE-1))/QUADSIZE - 1
419 if not welcoming(iq):
421 if enemy.type == 'R':
422 return False; # Romulans cannot escape!
424 # avoid intruding on another commander's territory
425 if enemy.type == 'C':
426 if iq in game.state.kcmdr:
428 # refuse to leave if currently attacking starbase
429 if game.battle == game.quadrant:
431 # don't leave if over 1000 units of energy
432 if enemy.power > 1000.0:
434 # emit escape message and move out of quadrant.
435 # we know this if either short or long range sensors are working
436 if not damaged(DSRSENS) or not damaged(DLRSENS) or \
437 game.condition == "docked":
438 prout(crmena(True, enemy.type, "sector", enemy.location) + \
439 (_(" escapes to Quadrant %s (and regains strength).") % q))
440 # handle local matters related to escape
443 if game.condition != "docked":
445 # Handle global matters related to escape
446 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
447 game.state.galaxy[iq.i][iq.j].klingons += 1
452 schedule(FSCMOVE, 0.2777)
456 for cmdr in game.state.kcmdr:
457 if cmdr == game.quadrant:
458 game.state.kcmdr[n] = iq
460 return True; # success
462 # The bad-guy movement algorithm:
464 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
465 # If both are operating full strength, force is 1000. If both are damaged,
466 # force is -1000. Having shields down subtracts an additional 1000.
468 # 2. Enemy has forces equal to the energy of the attacker plus
469 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
470 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
472 # Attacker Initial energy levels (nominal):
473 # Klingon Romulan Commander Super-Commander
474 # Novice 400 700 1200
476 # Good 450 800 1300 1750
477 # Expert 475 850 1350 1875
478 # Emeritus 500 900 1400 2000
479 # VARIANCE 75 200 200 200
481 # Enemy vessels only move prior to their attack. In Novice - Good games
482 # only commanders move. In Expert games, all enemy vessels move if there
483 # is a commander present. In Emeritus games all enemy vessels move.
485 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
486 # forces are 1000 greater than Enterprise.
488 # Agressive action on average cuts the distance between the ship and
489 # the enemy to 1/4 the original.
491 # 4. At lower energy advantage, movement units are proportional to the
492 # advantage with a 650 advantage being to hold ground, 800 to move forward
493 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
495 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
496 # retreat, especially at high skill levels.
498 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
500 def movebaddy(enemy):
501 "Tactical movement for the bad guys."
502 next = coord(); look = coord()
504 # This should probably be just (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
505 if game.skill >= SKILL_EXPERT:
506 nbaddys = (((game.quadrant in game.state.kcmdr)*2 + (game.state.kscmdr==game.quadrant)*2+game.klhere*1.23+game.irhere*1.5)/2.0)
508 nbaddys = (game.quadrant in game.state.kcmdr) + (game.state.kscmdr==game.quadrant)
510 mdist = int(dist1 + 0.5); # Nearest integer distance
511 # If SC, check with spy to see if should hi-tail it
512 if enemy.type=='S' and \
513 (enemy.power <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
517 # decide whether to advance, retreat, or hold position
518 forces = enemy.power+100.0*len(game.enemies)+400*(nbaddys-1)
520 forces += 1000; # Good for enemy if shield is down!
521 if not damaged(DPHASER) or not damaged(DPHOTON):
522 if damaged(DPHASER): # phasers damaged
525 forces -= 0.2*(game.energy - 2500.0)
526 if damaged(DPHOTON): # photon torpedoes damaged
529 forces -= 50.0*game.torps
531 # phasers and photon tubes both out!
534 if forces <= 1000.0 and game.condition != "docked": # Typical situation
535 motion = ((forces + randreal(200))/150.0) - 5.0
537 if forces > 1000.0: # Very strong -- move in for kill
538 motion = (1.0 - randreal())**2 * dist1 + 1.0
539 if game.condition=="docked" and (game.options & OPTION_BASE): # protected by base -- back off !
540 motion -= game.skill*(2.0-randreal()**2)
542 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
543 # don't move if no motion
546 # Limit motion according to skill
547 if abs(motion) > game.skill:
552 # calculate preferred number of steps
553 nsteps = abs(int(motion))
554 if motion > 0 and nsteps > mdist:
555 nsteps = mdist; # don't overshoot
556 if nsteps > QUADSIZE:
557 nsteps = QUADSIZE; # This shouldn't be necessary
559 nsteps = 1; # This shouldn't be necessary
561 proutn("NSTEPS = %d:" % nsteps)
562 # Compute preferred values of delta X and Y
563 m = game.sector - enemy.location
564 if 2.0 * abs(m.i) < abs(m.j):
566 if 2.0 * abs(m.j) < abs(game.sector.i-enemy.location.i):
568 m = (motion * m).sgn()
569 next = enemy.location
571 for ll in range(nsteps):
573 proutn(" %d" % (ll+1))
574 # Check if preferred position available
585 attempts = 0; # Settle mysterious hang problem
586 while attempts < 20 and not success:
588 if look.i < 0 or look.i >= QUADSIZE:
589 if motion < 0 and tryexit(enemy, look, irun):
591 if krawli == m.i or m.j == 0:
593 look.i = next.i + krawli
595 elif look.j < 0 or look.j >= QUADSIZE:
596 if motion < 0 and tryexit(enemy, look, irun):
598 if krawlj == m.j or m.i == 0:
600 look.j = next.j + krawlj
602 elif (game.options & OPTION_RAMMING) and game.quad[look.i][look.j] != '.':
603 # See if enemy should ram ship
604 if game.quad[look.i][look.j] == game.ship and \
605 (enemy.type == 'C' or enemy.type == 'S'):
606 collision(rammed=True, enemy=enemy)
608 if krawli != m.i and m.j != 0:
609 look.i = next.i + krawli
611 elif krawlj != m.j and m.i != 0:
612 look.j = next.j + krawlj
615 break; # we have failed
627 if not damaged(DSRSENS) or game.condition == "docked":
628 proutn(_("*** %s from Sector %s") % (cramen(enemy.type), enemy.location))
629 if enemy.kdist < dist1:
630 proutn(_(" advances to "))
632 proutn(_(" retreats to "))
633 prout("Sector %s." % next)
636 "Sequence Klingon tactical movement."
639 # Figure out which Klingon is the commander (or Supercommander)
641 if game.quadrant in game.state.kcmdr:
642 for enemy in game.enemies:
643 if enemy.type == 'C':
645 if game.state.kscmdr==game.quadrant:
646 for enemy in game.enemies:
647 if enemy.type == 'S':
650 # If skill level is high, move other Klingons and Romulans too!
651 # Move these last so they can base their actions on what the
653 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
654 for enemy in game.enemies:
655 if enemy.type in ('K', 'R'):
657 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
659 def movescom(iq, avoid):
660 "Commander movement helper."
661 # Avoid quadrants with bases if we want to avoid Enterprise
662 if not welcoming(iq) or (avoid and iq in game.state.baseq):
664 if game.justin and not game.iscate:
667 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons -= 1
668 game.state.kscmdr = iq
669 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].klingons += 1
670 if game.state.kscmdr==game.quadrant:
671 # SC has scooted, remove him from current quadrant
676 for enemy in game.enemies:
677 if enemy.type == 'S':
681 if game.condition != "docked":
683 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
684 # check for a helpful planet
685 for i in range(game.inplan):
686 if game.state.planets[i].quadrant == game.state.kscmdr and \
687 game.state.planets[i].crystals == "present":
689 game.state.planets[i].pclass = "destroyed"
690 game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].planet = None
693 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
694 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
695 prout(_(" by the Super-commander.\""))
697 return True; # looks good!
699 def supercommander():
700 "Move the Super Commander."
701 iq = coord(); sc = coord(); ibq = coord(); idelta = coord()
704 prout("== SUPERCOMMANDER")
705 # Decide on being active or passive
706 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 \
707 (game.state.date-game.indate) < 3.0)
708 if not game.iscate and avoid:
709 # compute move away from Enterprise
710 idelta = game.state.kscmdr-game.quadrant
711 if idelta.distance() > 2.0:
713 idelta.i = game.state.kscmdr.j-game.quadrant.j
714 idelta.j = game.quadrant.i-game.state.kscmdr.i
716 # compute distances to starbases
717 if not game.state.baseq:
721 sc = game.state.kscmdr
722 for base in game.state.baseq:
723 basetbl.append((i, (base - sc).distance()))
724 if game.state.baseq > 1:
725 basetbl.sort(lambda x, y: cmp(x[1]. y[1]))
726 # look for nearest base without a commander, no Enterprise, and
727 # without too many Klingons, and not already under attack.
728 ifindit = iwhichb = 0
729 for (i2, base) in enumerate(game.state.baseq):
730 i = basetbl[i2][0]; # bug in original had it not finding nearest
731 if base==game.quadrant or base==game.battle or not welcoming(base):
733 # if there is a commander, and no other base is appropriate,
734 # we will take the one with the commander
735 for cmdr in game.state.kcmdr:
736 if base == cmdr and ifindit != 2:
740 else: # no commander -- use this one
745 return # Nothing suitable -- wait until next time
746 ibq = game.state.baseq[iwhichb]
747 # decide how to move toward base
748 idelta = ibq - game.state.kscmdr
749 # Maximum movement is 1 quadrant in either or both axes
750 idelta = idelta.sgn()
751 # try moving in both x and y directions
752 # there was what looked like a bug in the Almy C code here,
753 # but it might be this translation is just wrong.
754 iq = game.state.kscmdr + idelta
755 if not movescom(iq, avoid):
756 # failed -- try some other maneuvers
757 if idelta.i==0 or idelta.j==0:
760 iq.j = game.state.kscmdr.j + 1
761 if not movescom(iq, avoid):
762 iq.j = game.state.kscmdr.j - 1
765 iq.i = game.state.kscmdr.i + 1
766 if not movescom(iq, avoid):
767 iq.i = game.state.kscmdr.i - 1
770 # try moving just in x or y
771 iq.j = game.state.kscmdr.j
772 if not movescom(iq, avoid):
773 iq.j = game.state.kscmdr.j + idelta.j
774 iq.i = game.state.kscmdr.i
777 if len(game.state.baseq) == 0:
780 for ibq in game.state.baseq:
781 if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
784 return # no, don't attack base!
787 schedule(FSCDBAS, randreal(1.0, 3.0))
788 if is_scheduled(FCDBAS):
789 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
790 if not communicating():
794 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
796 prout(_(" reports that it is under attack from the Klingon Super-commander."))
797 proutn(_(" It can survive until stardate %d.\"") \
798 % int(scheduled(FSCDBAS)))
801 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
805 game.optime = 0.0; # actually finished
807 # Check for intelligence report
810 (not communicating()) or \
811 not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].charted):
814 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
815 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
820 if not game.tholian or game.justin:
823 if game.tholian.location.i == 0 and game.tholian.location.j == 0:
824 id.i = 0; id.j = QUADSIZE-1
825 elif game.tholian.location.i == 0 and game.tholian.location.j == QUADSIZE-1:
826 id.i = QUADSIZE-1; id.j = QUADSIZE-1
827 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == QUADSIZE-1:
828 id.i = QUADSIZE-1; id.j = 0
829 elif game.tholian.location.i == QUADSIZE-1 and game.tholian.location.j == 0:
832 # something is wrong!
833 game.tholian.move(None)
834 prout("***Internal error: Tholian in a bad spot.")
836 # do nothing if we are blocked
837 if game.quad[id.i][id.j] not in ('.', '#'):
839 here = copy.copy(game.tholian.location)
840 delta = (id - game.tholian.location).sgn()
842 while here.i != id.i:
844 if game.quad[here.i][here.j]=='.':
845 game.tholian.move(here)
847 while here.j != id.j:
849 if game.quad[here.i][here.j]=='.':
850 game.tholian.move(here)
851 # check to see if all holes plugged
852 for i in range(QUADSIZE):
853 if game.quad[0][i]!='#' and game.quad[0][i]!='T':
855 if game.quad[QUADSIZE-1][i]!='#' and game.quad[QUADSIZE-1][i]!='T':
857 if game.quad[i][0]!='#' and game.quad[i][0]!='T':
859 if game.quad[i][QUADSIZE-1]!='#' and game.quad[i][QUADSIZE-1]!='T':
861 # All plugged up -- Tholian splits
862 game.quad[game.tholian.location.i][game.tholian.location.j]='#'
864 prout(crmena(True, 'T', "sector", game.tholian) + _(" completes web."))
865 game.tholian.move(None)
868 # Code from battle.c begins here
870 def doshield(shraise):
871 "Change shield status."
879 if scanner.sees("transfer"):
883 prout(_("Shields damaged and down."))
885 if scanner.sees("up"):
887 elif scanner.sees("down"):
890 proutn(_("Do you wish to change shield energy? "))
893 elif damaged(DSHIELD):
894 prout(_("Shields damaged and down."))
897 proutn(_("Shields are up. Do you want them down? "))
904 proutn(_("Shields are down. Do you want them up? "))
910 if action == "SHUP": # raise shields
912 prout(_("Shields already up."))
916 if game.condition != "docked":
918 prout(_("Shields raised."))
921 prout(_("Shields raising uses up last of energy."))
926 elif action == "SHDN":
928 prout(_("Shields already down."))
932 prout(_("Shields lowered."))
935 elif action == "NRG":
936 while scanner.next() != "IHREAL":
938 proutn(_("Energy to transfer to shields- "))
943 if nrg > game.energy:
944 prout(_("Insufficient ship energy."))
947 if game.shield+nrg >= game.inshld:
948 prout(_("Shield energy maximized."))
949 if game.shield+nrg > game.inshld:
950 prout(_("Excess energy requested returned to ship energy"))
951 game.energy -= game.inshld-game.shield
952 game.shield = game.inshld
954 if nrg < 0.0 and game.energy-nrg > game.inenrg:
955 # Prevent shield drain loophole
957 prout(_("Engineering to bridge--"))
958 prout(_(" Scott here. Power circuit problem, Captain."))
959 prout(_(" I can't drain the shields."))
962 if game.shield+nrg < 0:
963 prout(_("All shield energy transferred to ship."))
964 game.energy += game.shield
967 proutn(_("Scotty- \""))
969 prout(_("Transferring energy to shields.\""))
971 prout(_("Draining energy from shields.\""))
977 "Choose a device to damage, at random."
979 105, # DSRSENS: short range scanners 10.5%
980 105, # DLRSENS: long range scanners 10.5%
981 120, # DPHASER: phasers 12.0%
982 120, # DPHOTON: photon torpedoes 12.0%
983 25, # DLIFSUP: life support 2.5%
984 65, # DWARPEN: warp drive 6.5%
985 70, # DIMPULS: impulse engines 6.5%
986 145, # DSHIELD: deflector shields 14.5%
987 30, # DRADIO: subspace radio 3.0%
988 45, # DSHUTTL: shuttle 4.5%
989 15, # DCOMPTR: computer 1.5%
990 20, # NAVCOMP: navigation system 2.0%
991 75, # DTRANSP: transporter 7.5%
992 20, # DSHCTRL: high-speed shield controller 2.0%
993 10, # DDRAY: death ray 1.0%
994 30, # DDSP: deep-space probes 3.0%
996 assert(sum(weights) == 1000)
997 idx = randrange(1000)
999 for (i, w) in enumerate(weights):
1003 return None; # we should never get here
1005 def collision(rammed, enemy):
1006 "Collision handling fot rammong events."
1007 prouts(_("***RED ALERT! RED ALERT!"))
1009 prout(_("***COLLISION IMMINENT."))
1013 hardness = {'R':1.5, 'C':2.0, 'S':2.5, 'T':0.5, '?':4.0}.get(enemy.type, 1.0)
1015 proutn(_(" rammed by "))
1018 proutn(crmena(False, enemy.type, "sector", enemy.location))
1020 proutn(_(" (original position)"))
1022 deadkl(enemy.location, enemy.type, game.sector)
1023 proutn("***" + crmship() + " heavily damaged.")
1024 icas = randrange(10, 30)
1025 prout(_("***Sickbay reports %d casualties"), icas)
1027 game.state.crew -= icas
1028 # In the pre-SST2K version, all devices got equiprobably damaged,
1029 # which was silly. Instead, pick up to half the devices at
1030 # random according to our weighting table,
1031 ncrits = randrange(NDEVICES/2)
1032 for m in range(ncrits):
1034 if game.damage[dev] < 0:
1036 extradm = (10.0*hardness*randreal()+1.0)*game.damfac
1037 # Damage for at least time of travel!
1038 game.damage[dev] += game.optime + extradm
1040 prout(_("***Shields are down."))
1041 if game.state.remkl + len(game.state.kcmdr) + game.state.nscrem:
1048 def torpedo(origin, bearing, dispersion, number, nburst):
1049 "Let a photon torpedo fly"
1050 if not damaged(DSRSENS) or game.condition=="docked":
1051 setwnd(srscan_window)
1053 setwnd(message_window)
1054 ac = bearing + 0.25*dispersion # dispersion is a random variable
1055 bullseye = (15.0 - bearing)*0.5235988
1056 track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
1057 bumpto = coord(0, 0)
1058 # Loop to move a single torpedo
1059 setwnd(message_window)
1060 for step in range(1, QUADSIZE*2):
1061 if not track.next(): break
1063 if not w.valid_sector():
1065 iquad=game.quad[w.i][w.j]
1066 tracktorpedo(origin, w, step, number, nburst, iquad)
1070 if not damaged(DSRSENS) or game.condition == "docked":
1071 skip(1); # start new line after text track
1072 if iquad in ('E', 'F'): # Hit our ship
1074 prout(_("Torpedo hits %s.") % crmshp())
1075 hit = 700.0 + randreal(100) - \
1076 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1077 newcnd(); # we're blown out of dock
1078 if game.landed or game.condition=="docked":
1079 return hit # Cheat if on a planet
1080 # In the C/FORTRAN version, dispersion was 2.5 radians, which
1081 # is 143 degrees, which is almost exactly 4.8 clockface units
1082 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1084 bumpto = displacement.sector()
1085 if not bumpto.valid_sector():
1087 if game.quad[bumpto.i][bumpto.j]==' ':
1090 if game.quad[bumpto.i][bumpto.j]!='.':
1091 # can't move into object
1093 game.sector = bumpto
1095 game.quad[w.i][w.j]='.'
1096 game.quad[bumpto.i][bumpto.j]=iquad
1097 prout(_(" displaced by blast to Sector %s ") % bumpto)
1098 for enemy in game.enemies:
1099 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1100 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1102 elif iquad in ('C', 'S', 'R', 'K'): # Hit a regular enemy
1104 if iquad in ('C', 'S') and withprob(0.05):
1105 prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
1106 prout(_(" torpedo neutralized."))
1108 for enemy in game.enemies:
1109 if w == enemy.location:
1111 kp = math.fabs(enemy.power)
1112 h1 = 700.0 + randrange(100) - \
1113 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
1121 if enemy.power == 0:
1124 proutn(crmena(True, iquad, "sector", w))
1125 displacement = course(track.bearing+randreal(-2.4,2.4), distance=2**0.5)
1127 bumpto = displacement.sector()
1128 if not bumpto.valid_sector():
1129 prout(_(" damaged but not destroyed."))
1131 if game.quad[bumpto.i][bumpto.j] == ' ':
1132 prout(_(" buffeted into black hole."))
1133 deadkl(w, iquad, bumpto)
1134 if game.quad[bumpto.i][bumpto.j] != '.':
1135 prout(_(" damaged but not destroyed."))
1137 prout(_(" damaged-- displaced by blast to Sector %s ")%bumpto)
1138 enemy.location = bumpto
1139 game.quad[w.i][w.j]='.'
1140 game.quad[bumpto.i][bumpto.j]=iquad
1141 for enemy in game.enemies:
1142 enemy.kdist = enemy.kavgd = (game.sector-enemy.location).distance()
1143 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1145 elif iquad == 'B': # Hit a base
1147 prout(_("***STARBASE DESTROYED.."))
1148 game.state.baseq = filter(lambda x: x != game.quadrant, game.state.baseq)
1149 game.quad[w.i][w.j]='.'
1150 game.base.invalidate()
1151 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase -= 1
1152 game.state.chart[game.quadrant.i][game.quadrant.j].starbase -= 1
1153 game.state.basekl += 1
1156 elif iquad == 'P': # Hit a planet
1157 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1158 game.state.nplankl += 1
1159 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1160 game.iplnet.pclass = "destroyed"
1162 game.plnet.invalidate()
1163 game.quad[w.i][w.j] = '.'
1165 # captain perishes on planet
1168 elif iquad == '@': # Hit an inhabited world -- very bad!
1169 prout(crmena(True, iquad, "sector", w) + _(" destroyed."))
1170 game.state.nworldkl += 1
1171 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
1172 game.iplnet.pclass = "destroyed"
1174 game.plnet.invalidate()
1175 game.quad[w.i][w.j] = '.'
1177 # captain perishes on planet
1179 prout(_("The torpedo destroyed an inhabited planet."))
1181 elif iquad == '*': # Hit a star
1185 prout(crmena(True, '*', "sector", w) + _(" unaffected by photon blast."))
1187 elif iquad == '?': # Hit a thingy
1188 if not (game.options & OPTION_THINGY) or withprob(0.3):
1190 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1192 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1194 proutn(_("Mr. Spock-"))
1195 prouts(_(" \"Fascinating!\""))
1199 # Stas Sergeev added the possibility that
1200 # you can shove the Thingy and piss it off.
1201 # It then becomes an enemy and may fire at you.
1205 elif iquad == ' ': # Black hole
1207 prout(crmena(True, ' ', "sector", w) + _(" swallows torpedo."))
1209 elif iquad == '#': # hit the web
1211 prout(_("***Torpedo absorbed by Tholian web."))
1213 elif iquad == 'T': # Hit a Tholian
1214 h1 = 700.0 + randrange(100) - \
1215 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle))
1218 game.quad[w.i][w.j] = '.'
1223 proutn(crmena(True, 'T', "sector", w))
1225 prout(_(" survives photon blast."))
1227 prout(_(" disappears."))
1228 game.tholian.move(None)
1229 game.quad[w.i][w.j] = '#'
1234 proutn("Don't know how to handle torpedo collision with ")
1235 proutn(crmena(True, iquad, "sector", w))
1240 prout(_("Torpedo missed."))
1244 "Critical-hit resolution."
1245 if hit < (275.0-25.0*game.skill)*randreal(1.0, 1.5):
1247 ncrit = int(1.0 + hit/(500.0+randreal(100)))
1248 proutn(_("***CRITICAL HIT--"))
1249 # Select devices and cause damage
1251 for loop1 in range(ncrit):
1254 # Cheat to prevent shuttle damage unless on ship
1255 if not (game.damage[j]<0.0 or (j==DSHUTTL and game.iscraft != "onship")):
1258 extradm = (hit*game.damfac)/(ncrit*randreal(75, 100))
1259 game.damage[j] += extradm
1261 for (i, j) in enumerate(cdam):
1263 if skipcount % 3 == 2 and i < len(cdam)-1:
1268 prout(_(" damaged."))
1269 if damaged(DSHIELD) and game.shldup:
1270 prout(_("***Shields knocked down."))
1273 def attack(torps_ok):
1274 # bad guy attacks us
1275 # torps_ok == False forces use of phasers in an attack
1276 # game could be over at this point, check
1279 attempt = False; ihurt = False;
1280 hitmax=0.0; hittot=0.0; chgfac=1.0
1283 prout("=== ATTACK!")
1284 # Tholian gets to move before attacking
1287 # if you have just entered the RNZ, you'll get a warning
1288 if game.neutz: # The one chance not to be attacked
1291 # commanders get a chance to tac-move towards you
1292 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:
1294 # if no enemies remain after movement, we're done
1295 if len(game.enemies)==0 or (len(game.enemies)==1 and thing == game.quadrant and not thing.angry):
1297 # set up partial hits if attack happens during shield status change
1298 pfac = 1.0/game.inshld
1300 chgfac = 0.25 + randreal(0.5)
1302 # message verbosity control
1303 if game.skill <= SKILL_FAIR:
1305 for enemy in game.enemies:
1307 continue; # too weak to attack
1308 # compute hit strength and diminish shield power
1310 # Increase chance of photon torpedos if docked or enemy energy is low
1311 if game.condition == "docked":
1313 if enemy.power < 500:
1315 if enemy.type=='T' or (enemy.type=='?' and not thing.angry):
1317 # different enemies have different probabilities of throwing a torp
1318 usephasers = not torps_ok or \
1319 (enemy.type == 'K' and r > 0.0005) or \
1320 (enemy.type=='C' and r > 0.015) or \
1321 (enemy.type=='R' and r > 0.3) or \
1322 (enemy.type=='S' and r > 0.07) or \
1323 (enemy.type=='?' and r > 0.05)
1324 if usephasers: # Enemy uses phasers
1325 if game.condition == "docked":
1326 continue; # Don't waste the effort!
1327 attempt = True; # Attempt to attack
1328 dustfac = randreal(0.8, 0.85)
1329 hit = enemy.power*math.pow(dustfac,enemy.kavgd)
1331 else: # Enemy uses photon torpedo
1332 # We should be able to make the bearing() method work here
1333 course = 1.90985*math.atan2(game.sector.j-enemy.location.j, enemy.location.i-game.sector.i)
1335 proutn(_("***TORPEDO INCOMING"))
1336 if not damaged(DSRSENS):
1337 proutn(_(" From ") + crmena(False, enemy.type, where, enemy.location))
1340 dispersion = (randreal()+randreal())*0.5 - 0.5
1341 dispersion += 0.002*enemy.power*dispersion
1342 hit = torpedo(enemy.location, course, dispersion, number=1, nburst=1)
1343 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1344 finish(FWON); # Klingons did themselves in!
1345 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.alldone:
1346 return # Supernova or finished
1349 # incoming phaser or torpedo, shields may dissipate it
1350 if game.shldup or game.shldchg or game.condition=="docked":
1351 # shields will take hits
1352 propor = pfac * game.shield
1353 if game.condition =="docked":
1357 hitsh = propor*chgfac*hit+1.0
1359 if absorb > game.shield:
1360 absorb = game.shield
1361 game.shield -= absorb
1363 # taking a hit blasts us out of a starbase dock
1364 if game.condition == "docked":
1366 # but the shields may take care of it
1367 if propor > 0.1 and hit < 0.005*game.energy:
1369 # hit from this opponent got through shields, so take damage
1371 proutn(_("%d unit hit") % int(hit))
1372 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1373 proutn(_(" on the ") + crmshp())
1374 if not damaged(DSRSENS) and usephasers:
1375 prout(_(" from ") + crmena(False, enemy.type, where, enemy.location))
1377 # Decide if hit is critical
1383 if game.energy <= 0:
1384 # Returning home upon your shield, not with it...
1387 if not attempt and game.condition == "docked":
1388 prout(_("***Enemies decide against attacking your ship."))
1389 percent = 100.0*pfac*game.shield+0.5
1391 # Shields fully protect ship
1392 proutn(_("Enemy attack reduces shield strength to "))
1394 # Emit message if starship suffered hit(s)
1396 proutn(_("Energy left %2d shields ") % int(game.energy))
1399 elif not damaged(DSHIELD):
1402 proutn(_("damaged, "))
1403 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1404 # Check if anyone was hurt
1405 if hitmax >= 200 or hittot >= 500:
1406 icas = randrange(int(hittot * 0.015))
1409 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1410 prout(_(" in that last attack.\""))
1412 game.state.crew -= icas
1413 # After attack, reset average distance to enemies
1414 for enemy in game.enemies:
1415 enemy.kavgd = enemy.kdist
1416 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
1419 def deadkl(w, type, mv):
1420 "Kill a Klingon, Tholian, Romulan, or Thingy."
1421 # Added mv to allow enemy to "move" before dying
1422 proutn(crmena(True, type, "sector", mv))
1423 # Decide what kind of enemy it is and update appropriately
1425 # Chalk up a Romulan
1426 game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans -= 1
1428 game.state.nromrem -= 1
1437 # Killed some type of Klingon
1438 game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons -= 1
1441 game.state.kcmdr.remove(game.quadrant)
1443 if game.state.kcmdr:
1444 schedule(FTBEAM, expran(1.0*game.incom/len(game.state.kcmdr)))
1445 if is_scheduled(FCDBAS) and game.battle == game.quadrant:
1448 game.state.remkl -= 1
1450 game.state.nscrem -= 1
1451 game.state.kscmdr.invalidate()
1456 # For each kind of enemy, finish message to player
1457 prout(_(" destroyed."))
1458 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1461 # Remove enemy ship from arrays describing local conditions
1462 for e in game.enemies:
1469 "Return None if target is invalid, otherwise return a course angle."
1470 if not w.valid_sector():
1474 # FIXME: C code this was translated from is wacky -- why the sign reversal?
1475 delta.j = (w.j - game.sector.j);
1476 delta.i = (game.sector.i - w.i);
1477 if delta == coord(0, 0):
1479 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1480 prout(_(" I recommend an immediate review of"))
1481 prout(_(" the Captain's psychological profile.\""))
1484 return delta.bearing()
1487 "Launch photon torpedo."
1490 if damaged(DPHOTON):
1491 prout(_("Photon tubes damaged."))
1495 prout(_("No torpedoes left."))
1498 # First, get torpedo count
1501 if scanner.token == "IHALPHA":
1504 elif scanner.token == "IHEOL" or not scanner.waiting():
1505 prout(_("%d torpedoes left.") % game.torps)
1507 proutn(_("Number of torpedoes to fire- "))
1508 continue # Go back around to get a number
1509 else: # key == "IHREAL"
1511 if n <= 0: # abort command
1516 prout(_("Maximum of %d torpedoes per burst.") % MAXBURST)
1519 scanner.chew() # User requested more torps than available
1520 continue # Go back around
1521 break # All is good, go to next stage
1525 key = scanner.next()
1526 if i==0 and key == "IHEOL":
1527 break; # no coordinate waiting, we will try prompting
1528 if i==1 and key == "IHEOL":
1529 # direct all torpedoes at one target
1531 target.append(target[0])
1532 course.append(course[0])
1535 scanner.push(scanner.token)
1536 target.append(scanner.getcoord())
1537 if target[-1] == None:
1539 course.append(targetcheck(target[-1]))
1540 if course[-1] == None:
1543 if len(target) == 0:
1544 # prompt for each one
1546 proutn(_("Target sector for torpedo number %d- ") % (i+1))
1548 target.append(scanner.getcoord())
1549 if target[-1] == None:
1551 course.append(targetcheck(target[-1]))
1552 if course[-1] == None:
1555 # Loop for moving <n> torpedoes
1557 if game.condition != "docked":
1559 dispersion = (randreal()+randreal())*0.5 -0.5
1560 if math.fabs(dispersion) >= 0.47:
1562 dispersion *= randreal(1.2, 2.2)
1564 prouts(_("***TORPEDO NUMBER %d MISFIRES") % (i+1))
1566 prouts(_("***TORPEDO MISFIRES."))
1569 prout(_(" Remainder of burst aborted."))
1571 prout(_("***Photon tubes damaged by misfire."))
1572 game.damage[DPHOTON] = game.damfac * randreal(1.0, 3.0)
1574 if game.shldup or game.condition == "docked":
1575 dispersion *= 1.0 + 0.0001*game.shield
1576 torpedo(game.sector, course[i], dispersion, number=i, nburst=n)
1577 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
1579 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1583 "Check for phasers overheating."
1585 checkburn = (rpow-1500.0)*0.00038
1586 if withprob(checkburn):
1587 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1588 game.damage[DPHASER] = game.damfac* randreal(1.0, 2.0) * (1.0+checkburn)
1590 def checkshctrl(rpow):
1591 "Check shield control."
1594 prout(_("Shields lowered."))
1596 # Something bad has happened
1597 prouts(_("***RED ALERT! RED ALERT!"))
1599 hit = rpow*game.shield/game.inshld
1600 game.energy -= rpow+hit*0.8
1601 game.shield -= hit*0.2
1602 if game.energy <= 0.0:
1603 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1608 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1610 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1611 icas = randrange(int(hit*0.012))
1616 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1617 prout(_(" %d casualties so far.\"") % icas)
1619 game.state.crew -= icas
1621 prout(_("Phaser energy dispersed by shields."))
1622 prout(_("Enemy unaffected."))
1627 "Register a phaser hit on Klingons and Romulans."
1628 nenhr2 = len(game.enemies); kk=0
1631 for (k, wham) in enumerate(hits):
1634 dustfac = randreal(0.9, 1.0)
1635 hit = wham*math.pow(dustfac,game.enemies[kk].kdist)
1636 kpini = game.enemies[kk].power
1637 kp = math.fabs(kpini)
1638 if PHASEFAC*hit < kp:
1640 if game.enemies[kk].power < 0:
1641 game.enemies[kk].power -= -kp
1643 game.enemies[kk].power -= kp
1644 kpow = game.enemies[kk].power
1645 w = game.enemies[kk].location
1647 if not damaged(DSRSENS):
1649 proutn(_("%d unit hit on ") % int(hit))
1651 proutn(_("Very small hit on "))
1652 ienm = game.quad[w.i][w.j]
1655 proutn(crmena(False, ienm, "sector", w))
1659 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
1663 kk -= 1 # don't do the increment
1665 else: # decide whether or not to emasculate klingon
1666 if kpow>0 and withprob(0.9) and kpow <= randreal(0.4, 0.8)*kpini:
1667 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s")%w)
1668 prout(_(" has just lost its firepower.\""))
1669 game.enemies[kk].power = -kpow
1674 "Fire phasers at bad guys."
1676 kz = 0; k = 1; irec=0 # Cheating inhibitor
1677 ifast = False; no = False; itarg = True; msgflag = True; rpow=0
1681 # SR sensors and Computer are needed for automode
1682 if damaged(DSRSENS) or damaged(DCOMPTR):
1684 if game.condition == "docked":
1685 prout(_("Phasers can't be fired through base shields."))
1688 if damaged(DPHASER):
1689 prout(_("Phaser control damaged."))
1693 if damaged(DSHCTRL):
1694 prout(_("High speed shield control damaged."))
1697 if game.energy <= 200.0:
1698 prout(_("Insufficient energy to activate high-speed shield control."))
1701 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1703 # Original code so convoluted, I re-did it all
1704 # (That was Tom Almy talking about the C code, I think -- ESR)
1705 while automode=="NOTSET":
1707 if key == "IHALPHA":
1708 if scanner.sees("manual"):
1709 if len(game.enemies)==0:
1710 prout(_("There is no enemy present to select."))
1713 automode="AUTOMATIC"
1716 key = scanner.next()
1717 elif scanner.sees("automatic"):
1718 if (not itarg) and len(game.enemies) != 0:
1719 automode = "FORCEMAN"
1721 if len(game.enemies)==0:
1722 prout(_("Energy will be expended into space."))
1723 automode = "AUTOMATIC"
1724 key = scanner.next()
1725 elif scanner.sees("no"):
1730 elif key == "IHREAL":
1731 if len(game.enemies)==0:
1732 prout(_("Energy will be expended into space."))
1733 automode = "AUTOMATIC"
1735 automode = "FORCEMAN"
1737 automode = "AUTOMATIC"
1740 if len(game.enemies)==0:
1741 prout(_("Energy will be expended into space."))
1742 automode = "AUTOMATIC"
1744 automode = "FORCEMAN"
1746 proutn(_("Manual or automatic? "))
1751 if automode == "AUTOMATIC":
1752 if key == "IHALPHA" and scanner.sees("no"):
1754 key = scanner.next()
1755 if key != "IHREAL" and len(game.enemies) != 0:
1756 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1761 for i in range(len(game.enemies)):
1762 irec += math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))*randreal(1.01, 1.06) + 1.0
1764 proutn(_("%d units required. ") % irec)
1766 proutn(_("Units to fire= "))
1767 key = scanner.next()
1772 proutn(_("Energy available= %.2f") % avail)
1775 if not rpow > avail:
1782 if key == "IHALPHA" and scanner.sees("no"):
1785 game.energy -= 200; # Go and do it!
1786 if checkshctrl(rpow):
1791 if len(game.enemies):
1794 for i in range(len(game.enemies)):
1798 hits[i] = math.fabs(game.enemies[i].power)/(PHASEFAC*math.pow(0.90,game.enemies[i].kdist))
1799 over = randreal(1.01, 1.06) * hits[i]
1801 powrem -= hits[i] + over
1802 if powrem <= 0 and temp < hits[i]:
1811 if extra > 0 and not game.alldone:
1813 proutn(_("*** Tholian web absorbs "))
1814 if len(game.enemies)>0:
1815 proutn(_("excess "))
1816 prout(_("phaser energy."))
1818 prout(_("%d expended on empty space.") % int(extra))
1819 elif automode == "FORCEMAN":
1822 if damaged(DCOMPTR):
1823 prout(_("Battle computer damaged, manual fire only."))
1826 prouts(_("---WORKING---"))
1828 prout(_("Short-range-sensors-damaged"))
1829 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1830 prout(_("Manual-fire-must-be-used"))
1832 elif automode == "MANUAL":
1834 for k in range(len(game.enemies)):
1835 aim = game.enemies[k].location
1836 ienm = game.quad[aim.i][aim.j]
1838 proutn(_("Energy available= %.2f") % (avail-0.006))
1842 if damaged(DSRSENS) and \
1843 not game.sector.distance(aim)<2**0.5 and ienm in ('C', 'S'):
1844 prout(cramen(ienm) + _(" can't be located without short range scan."))
1847 hits[k] = 0; # prevent overflow -- thanks to Alexei Voitenko
1852 if itarg and k > kz:
1853 irec=(abs(game.enemies[k].power)/(PHASEFAC*math.pow(0.9,game.enemies[k].kdist))) * randreal(1.01, 1.06) + 1.0
1856 if not damaged(DCOMPTR):
1861 proutn(_("units to fire at %s- ") % crmena(False, ienm, "sector", aim))
1862 key = scanner.next()
1863 if key == "IHALPHA" and scanner.sees("no"):
1865 key = scanner.next()
1867 if key == "IHALPHA":
1871 if k==1: # Let me say I'm baffled by this
1874 if scanner.real < 0:
1878 hits[k] = scanner.real
1879 rpow += scanner.real
1880 # If total requested is too much, inform and start over
1882 prout(_("Available energy exceeded -- try again."))
1885 key = scanner.next(); # scan for next value
1888 # zero energy -- abort
1891 if key == "IHALPHA" and scanner.sees("no"):
1896 game.energy -= 200.0
1897 if checkshctrl(rpow):
1901 # Say shield raised or malfunction, if necessary
1908 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
1909 prouts(_(" CLICK CLICK POP . . ."))
1910 prout(_(" No response, sir!"))
1913 prout(_("Shields raised."))
1918 # Code from events,c begins here.
1920 # This isn't a real event queue a la BSD Trek yet -- you can only have one
1921 # event of each type active at any given time. Mostly these means we can
1922 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
1923 # BSD Trek, from which we swiped the idea, can have up to 5.
1925 def unschedule(evtype):
1926 "Remove an event from the schedule."
1927 game.future[evtype].date = FOREVER
1928 return game.future[evtype]
1930 def is_scheduled(evtype):
1931 "Is an event of specified type scheduled."
1932 return game.future[evtype].date != FOREVER
1934 def scheduled(evtype):
1935 "When will this event happen?"
1936 return game.future[evtype].date
1938 def schedule(evtype, offset):
1939 "Schedule an event of specified type."
1940 game.future[evtype].date = game.state.date + offset
1941 return game.future[evtype]
1943 def postpone(evtype, offset):
1944 "Postpone a scheduled event."
1945 game.future[evtype].date += offset
1948 "Rest period is interrupted by event."
1951 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
1953 game.resting = False
1959 "Run through the event queue looking for things to do."
1961 fintim = game.state.date + game.optime; yank=0
1962 ictbeam = False; istract = False
1963 w = coord(); hold = coord()
1964 ev = event(); ev2 = event()
1966 def tractorbeam(yank):
1967 "Tractor-beaming cases merge here."
1969 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
1971 prout("***" + crmshp() + _(" caught in long range tractor beam--"))
1972 # If Kirk & Co. screwing around on planet, handle
1973 atover(True) # atover(true) is Grab
1976 if game.icraft: # Caught in Galileo?
1979 # Check to see if shuttle is aboard
1980 if game.iscraft == "offship":
1983 prout(_("Galileo, left on the planet surface, is captured"))
1984 prout(_("by aliens and made into a flying McDonald's."))
1985 game.damage[DSHUTTL] = -10
1986 game.iscraft = "removed"
1988 prout(_("Galileo, left on the planet surface, is well hidden."))
1990 game.quadrant = game.state.kscmdr
1992 game.quadrant = game.state.kcmdr[i]
1993 game.sector = randplace(QUADSIZE)
1994 prout(crmshp() + _(" is pulled to Quadrant %s, Sector %s") \
1995 % (game.quadrant, game.sector))
1997 prout(_("(Remainder of rest/repair period cancelled.)"))
1998 game.resting = False
2000 if not damaged(DSHIELD) and game.shield > 0:
2001 doshield(shraise=True) # raise shields
2002 game.shldchg = False
2004 prout(_("(Shields not currently useable.)"))
2006 # Adjust finish time to time of tractor beaming
2007 fintim = game.state.date+game.optime
2008 attack(torps_ok=False)
2009 if not game.state.kcmdr:
2012 schedule(FTBEAM, game.optime+expran(1.5*game.intime/len(game.state.kcmdr)))
2015 "Code merges here for any commander destroying a starbase."
2016 # Not perfect, but will have to do
2017 # Handle case where base is in same quadrant as starship
2018 if game.battle == game.quadrant:
2019 game.state.chart[game.battle.i][game.battle.j].starbase = False
2020 game.quad[game.base.i][game.base.j] = '.'
2021 game.base.invalidate()
2024 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2025 elif game.state.baseq and communicating():
2026 # Get word via subspace radio
2029 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2030 proutn(_(" the starbase in Quadrant %s has been destroyed by") % game.battle)
2032 prout(_("the Klingon Super-Commander"))
2034 prout(_("a Klingon Commander"))
2035 game.state.chart[game.battle.i][game.battle.j].starbase = False
2036 # Remove Starbase from galaxy
2037 game.state.galaxy[game.battle.i][game.battle.j].starbase = False
2038 game.state.baseq = filter(lambda x: x != game.battle, game.state.baseq)
2040 # reinstate a commander's base attack
2044 game.battle.invalidate()
2046 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2047 for i in range(1, NEVENTS):
2048 if i == FSNOVA: proutn("=== Supernova ")
2049 elif i == FTBEAM: proutn("=== T Beam ")
2050 elif i == FSNAP: proutn("=== Snapshot ")
2051 elif i == FBATTAK: proutn("=== Base Attack ")
2052 elif i == FCDBAS: proutn("=== Base Destroy ")
2053 elif i == FSCMOVE: proutn("=== SC Move ")
2054 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2055 elif i == FDSPROB: proutn("=== Probe Move ")
2056 elif i == FDISTR: proutn("=== Distress Call ")
2057 elif i == FENSLV: proutn("=== Enslavement ")
2058 elif i == FREPRO: proutn("=== Klingon Build ")
2060 prout("%.2f" % (scheduled(i)))
2063 radio_was_broken = damaged(DRADIO)
2066 # Select earliest extraneous event, evcode==0 if no events
2071 for l in range(1, NEVENTS):
2072 if game.future[l].date < datemin:
2075 prout("== Event %d fires" % evcode)
2076 datemin = game.future[l].date
2077 xtime = datemin-game.state.date
2078 game.state.date = datemin
2079 # Decrement Federation resources and recompute remaining time
2080 game.state.remres -= (game.state.remkl+4*len(game.state.kcmdr))*xtime
2082 if game.state.remtime <=0:
2085 # Any crew left alive?
2086 if game.state.crew <=0:
2089 # Is life support adequate?
2090 if damaged(DLIFSUP) and game.condition != "docked":
2091 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2094 game.lsupres -= xtime
2095 if game.damage[DLIFSUP] <= xtime:
2096 game.lsupres = game.inlsr
2099 if game.condition == "docked":
2101 # Don't fix Deathray here
2102 for l in range(NDEVICES):
2103 if game.damage[l] > 0.0 and l != DDRAY:
2104 if game.damage[l]-repair > 0.0:
2105 game.damage[l] -= repair
2107 game.damage[l] = 0.0
2108 # If radio repaired, update star chart and attack reports
2109 if radio_was_broken and not damaged(DRADIO):
2110 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2111 prout(_(" surveillance reports are coming in."))
2113 if not game.iseenit:
2117 prout(_(" The star chart is now up to date.\""))
2119 # Cause extraneous event EVCODE to occur
2120 game.optime -= xtime
2121 if evcode == FSNOVA: # Supernova
2124 schedule(FSNOVA, expran(0.5*game.intime))
2125 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2127 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2128 if game.state.nscrem == 0 or \
2129 ictbeam or istract or \
2130 game.condition=="docked" or game.isatb==1 or game.iscate:
2132 if game.ientesc or \
2133 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2134 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2135 (damaged(DSHIELD) and \
2136 (game.energy < 2500 or damaged(DPHASER)) and \
2137 (game.torps < 5 or damaged(DPHOTON))):
2139 istract = ictbeam = True
2140 tractorbeam((game.state.kscmdr-game.quadrant).distance())
2143 elif evcode == FTBEAM: # Tractor beam
2144 if not game.state.kcmdr:
2147 i = randrange(len(game.state.kcmdr))
2148 yank = (game.state.kcmdr[i]-game.quadrant).distance()
2149 if istract or game.condition == "docked" or yank == 0:
2150 # Drats! Have to reschedule
2152 game.optime + expran(1.5*game.intime/len(game.state.kcmdr)))
2156 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2157 game.snapsht = copy.deepcopy(game.state)
2158 game.state.snap = True
2159 schedule(FSNAP, expran(0.5 * game.intime))
2160 elif evcode == FBATTAK: # Commander attacks starbase
2161 if not game.state.kcmdr or not game.state.baseq:
2167 for ibq in game.state.baseq:
2168 for cmdr in game.state.kcmdr:
2169 if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr:
2172 # no match found -- try later
2173 schedule(FBATTAK, expran(0.3*game.intime))
2178 # commander + starbase combination found -- launch attack
2180 schedule(FCDBAS, randreal(1.0, 4.0))
2181 if game.isatb: # extra time if SC already attacking
2182 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2183 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2184 game.iseenit = False
2185 if not communicating():
2186 continue # No warning :-(
2190 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2191 prout(_(" reports that it is under attack and that it can"))
2192 prout(_(" hold out only until stardate %d.\"") % (int(scheduled(FCDBAS))))
2195 elif evcode == FSCDBAS: # Supercommander destroys base
2198 if not game.state.galaxy[game.state.kscmdr.i][game.state.kscmdr.j].starbase:
2199 continue # WAS RETURN!
2201 game.battle = game.state.kscmdr
2203 elif evcode == FCDBAS: # Commander succeeds in destroying base
2206 if not game.state.baseq() \
2207 or not game.state.galaxy[game.battle.i][game.battle.j].starbase:
2208 game.battle.invalidate()
2210 # find the lucky pair
2211 for cmdr in game.state.kcmdr:
2212 if cmdr == game.battle:
2215 # No action to take after all
2218 elif evcode == FSCMOVE: # Supercommander moves
2219 schedule(FSCMOVE, 0.2777)
2220 if not game.ientesc and not istract and game.isatb != 1 and \
2221 (not game.iscate or not game.justin):
2223 elif evcode == FDSPROB: # Move deep space probe
2224 schedule(FDSPROB, 0.01)
2225 if not game.probe.next():
2226 if not game.probe.quadrant().valid_quadrant() or \
2227 game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
2228 # Left galaxy or ran into supernova
2232 proutn(_("Lt. Uhura- \"The deep space probe "))
2233 if not game.probe.quadrant().valid_quadrant():
2234 prout(_("has left the galaxy.\""))
2236 prout(_("is no longer transmitting.\""))
2242 prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
2243 pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
2245 chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
2246 chp.klingons = pdest.klingons
2247 chp.starbase = pdest.starbase
2248 chp.stars = pdest.stars
2249 pdest.charted = True
2250 game.probe.moves -= 1 # One less to travel
2251 if game.probe.arrived() and game.isarmed and pdest.stars:
2252 supernova(game.probe) # fire in the hole!
2254 if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
2256 elif evcode == FDISTR: # inhabited system issues distress call
2258 # try a whole bunch of times to find something suitable
2259 for i in range(100):
2260 # need a quadrant which is not the current one,
2261 # which has some stars which are inhabited and
2262 # not already under attack, which is not
2263 # supernova'ed, and which has some Klingons in it
2264 w = randplace(GALSIZE)
2265 q = game.state.galaxy[w.i][w.j]
2266 if not (game.quadrant == w or q.planet == None or \
2267 not q.planet.inhabited or \
2268 q.supernova or q.status!="secure" or q.klingons<=0):
2271 # can't seem to find one; ignore this call
2273 prout("=== Couldn't find location for distress event.")
2275 # got one!! Schedule its enslavement
2276 ev = schedule(FENSLV, expran(game.intime))
2278 q.status = "distressed"
2279 # tell the captain about it if we can
2281 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2283 prout(_("by a Klingon invasion fleet."))
2286 elif evcode == FENSLV: # starsystem is enslaved
2287 ev = unschedule(FENSLV)
2288 # see if current distress call still active
2289 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2293 q.status = "enslaved"
2295 # play stork and schedule the first baby
2296 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2297 ev2.quadrant = ev.quadrant
2299 # report the disaster if we can
2301 prout(_("Uhura- We've lost contact with starsystem %s") % \
2303 prout(_("in Quadrant %s.\n") % ev.quadrant)
2304 elif evcode == FREPRO: # Klingon reproduces
2305 # If we ever switch to a real event queue, we'll need to
2306 # explicitly retrieve and restore the x and y.
2307 ev = schedule(FREPRO, expran(1.0 * game.intime))
2308 # see if current distress call still active
2309 q = game.state.galaxy[ev.quadrant.i][ev.quadrant.j]
2313 if game.state.remkl >=MAXKLGAME:
2314 continue # full right now
2315 # reproduce one Klingon
2318 if game.klhere >= MAXKLQUAD:
2320 # this quadrant not ok, pick an adjacent one
2321 for m.i in range(w.i - 1, w.i + 2):
2322 for m.j in range(w.j - 1, w.j + 2):
2323 if not m.valid_quadrant():
2325 q = game.state.galaxy[m.i][m.j]
2326 # check for this quad ok (not full & no snova)
2327 if q.klingons >= MAXKLQUAD or q.supernova:
2331 continue # search for eligible quadrant failed
2335 game.state.remkl += 1
2337 if game.quadrant == w:
2339 game.enemies.append(newkling())
2340 # recompute time left
2343 if game.quadrant == w:
2344 prout(_("Spock- sensors indicate the Klingons have"))
2345 prout(_("launched a warship from %s.") % q.planet)
2347 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2348 if q.planet != None:
2349 proutn(_("near %s ") % q.planet)
2350 prout(_("in Quadrant %s.") % w)
2356 key = scanner.next()
2359 proutn(_("How long? "))
2364 origTime = delay = scanner.real
2367 if delay >= game.state.remtime or len(game.enemies) != 0:
2368 proutn(_("Are you sure? "))
2371 # Alternate resting periods (events) with attacks
2375 game.resting = False
2376 if not game.resting:
2377 prout(_("%d stardates left.") % int(game.state.remtime))
2379 temp = game.optime = delay
2380 if len(game.enemies):
2381 rtime = randreal(1.0, 2.0)
2385 if game.optime < delay:
2386 attack(torps_ok=False)
2394 # Repair Deathray if long rest at starbase
2395 if origTime-delay >= 9.99 and game.condition == "docked":
2396 game.damage[DDRAY] = 0.0
2397 # leave if quadrant supernovas
2398 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
2400 game.resting = False
2405 course = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2406 newc = coord(); neighbor = coord(); bump = coord(0, 0)
2408 # Wow! We've supernova'ed
2409 supernova(game.quadrant)
2411 # handle initial nova
2412 game.quad[nov.i][nov.j] = '.'
2413 prout(crmena(False, '*', "sector", nov) + _(" novas."))
2414 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2415 game.state.starkl += 1
2416 # Set up queue to recursively trigger adjacent stars
2422 for offset.i in range(-1, 1+1):
2423 for offset.j in range(-1, 1+1):
2424 if offset.j==0 and offset.i==0:
2426 neighbor = start + offset
2427 if not neighbor.valid_sector():
2429 iquad = game.quad[neighbor.i][neighbor.j]
2430 # Empty space ends reaction
2431 if iquad in ('.', '?', ' ', 'T', '#'):
2433 elif iquad == '*': # Affect another star
2435 # This star supernovas
2436 supernova(game.quadrant)
2439 hits.append(neighbor)
2440 game.state.galaxy[game.quadrant.i][game.quadrant.j].stars -= 1
2441 game.state.starkl += 1
2442 proutn(crmena(True, '*', "sector", neighbor))
2444 game.quad[neighbor.i][neighbor.j] = '.'
2446 elif iquad in ('P', '@'): # Destroy planet
2447 game.state.galaxy[game.quadrant.i][game.quadrant.j].planet = None
2449 game.state.nplankl += 1
2451 game.state.worldkl += 1
2452 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2453 game.iplnet.pclass = "destroyed"
2455 game.plnet.invalidate()
2459 game.quad[neighbor.i][neighbor.j] = '.'
2460 elif iquad == 'B': # Destroy base
2461 game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase = False
2462 game.state.baseq = filter(lambda x: x!= game.quadrant, game.state.baseq)
2463 game.base.invalidate()
2464 game.state.basekl += 1
2466 prout(crmena(True, 'B', "sector", neighbor) + _(" destroyed."))
2467 game.quad[neighbor.i][neighbor.j] = '.'
2468 elif iquad in ('E', 'F'): # Buffet ship
2469 prout(_("***Starship buffeted by nova."))
2471 if game.shield >= 2000.0:
2472 game.shield -= 2000.0
2474 diff = 2000.0 - game.shield
2478 prout(_("***Shields knocked out."))
2479 game.damage[DSHIELD] += 0.005*game.damfac*randreal()*diff
2481 game.energy -= 2000.0
2482 if game.energy <= 0:
2485 # add in course nova contributes to kicking starship
2486 bump += (game.sector-hits[mm]).sgn()
2487 elif iquad == 'K': # kill klingon
2488 deadkl(neighbor, iquad, neighbor)
2489 elif iquad in ('C','S','R'): # Damage/destroy big enemies
2490 for ll in range(len(game.enemies)):
2491 if game.enemies[ll].location == neighbor:
2493 game.enemies[ll].power -= 800.0 # If firepower is lost, die
2494 if game.enemies[ll].power <= 0.0:
2495 deadkl(neighbor, iquad, neighbor)
2497 newc = neighbor + neighbor - hits[mm]
2498 proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
2499 if not newc.valid_sector():
2500 # can't leave quadrant
2503 iquad1 = game.quad[newc.i][newc.j]
2505 proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc))
2507 deadkl(neighbor, iquad, newc)
2510 # can't move into something else
2513 proutn(_(", buffeted to Sector %s") % newc)
2514 game.quad[neighbor.i][neighbor.j] = '.'
2515 game.quad[newc.i][newc.j] = iquad
2516 game.enemies[ll].move(newc)
2517 # Starship affected by nova -- kick it away.
2519 direc = course[3*(bump.i+1)+bump.j+2]
2524 course = course(bearing=direc, distance=dist)
2525 game.optime = course.time(warp=4)
2527 prout(_("Force of nova displaces starship."))
2528 imove(course, noattack=True)
2529 game.optime = course.time(warp=4)
2533 "Star goes supernova."
2538 # Scheduled supernova -- select star at random.
2541 for nq.i in range(GALSIZE):
2542 for nq.j in range(GALSIZE):
2543 stars += game.state.galaxy[nq.i][nq.j].stars
2545 return # nothing to supernova exists
2546 num = randrange(stars) + 1
2547 for nq.i in range(GALSIZE):
2548 for nq.j in range(GALSIZE):
2549 num -= game.state.galaxy[nq.i][nq.j].stars
2555 proutn("=== Super nova here?")
2558 if not nq == game.quadrant or game.justin:
2559 # it isn't here, or we just entered (treat as enroute)
2562 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2563 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2566 # we are in the quadrant!
2567 num = randrange(game.state.galaxy[nq.i][nq.j].stars) + 1
2568 for ns.i in range(QUADSIZE):
2569 for ns.j in range(QUADSIZE):
2570 if game.quad[ns.i][ns.j]=='*':
2577 prouts(_("***RED ALERT! RED ALERT!"))
2579 prout(_("***Incipient supernova detected at Sector %s") % ns)
2580 if (ns.i-game.sector.i)**2 + (ns.j-game.sector.j)**2 <= 2.1:
2581 proutn(_("Emergency override attempts t"))
2582 prouts("***************")
2586 # destroy any Klingons in supernovaed quadrant
2587 kldead = game.state.galaxy[nq.i][nq.j].klingons
2588 game.state.galaxy[nq.i][nq.j].klingons = 0
2589 if nq == game.state.kscmdr:
2590 # did in the Supercommander!
2591 game.state.nscrem = game.state.kscmdr.i = game.state.kscmdr.j = game.isatb = 0
2595 survivors = filter(lambda w: w != nq, game.state.kcmdr)
2596 comkills = len(game.state.kcmdr) - len(survivors)
2597 game.state.kcmdr = survivors
2599 if not game.state.kcmdr:
2601 game.state.remkl -= kldead
2602 # destroy Romulans and planets in supernovaed quadrant
2603 nrmdead = game.state.galaxy[nq.i][nq.j].romulans
2604 game.state.galaxy[nq.i][nq.j].romulans = 0
2605 game.state.nromrem -= nrmdead
2607 for loop in range(game.inplan):
2608 if game.state.planets[loop].quadrant == nq:
2609 game.state.planets[loop].pclass = "destroyed"
2611 # Destroy any base in supernovaed quadrant
2612 game.state.baseq = filter(lambda x: x != nq, game.state.baseq)
2613 # If starship caused supernova, tally up destruction
2615 game.state.starkl += game.state.galaxy[nq.i][nq.j].stars
2616 game.state.basekl += game.state.galaxy[nq.i][nq.j].starbase
2617 game.state.nplankl += npdead
2618 # mark supernova in galaxy and in star chart
2619 if game.quadrant == nq or communicating():
2620 game.state.galaxy[nq.i][nq.j].supernova = True
2621 # If supernova destroys last Klingons give special message
2622 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0 and not nq == game.quadrant:
2625 prout(_("Lucky you!"))
2626 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2629 # if some Klingons remain, continue or die in supernova
2634 # Code from finish.c ends here.
2637 "Self-destruct maneuver. Finish with a BANG!"
2639 if damaged(DCOMPTR):
2640 prout(_("Computer damaged; cannot execute destruct sequence."))
2642 prouts(_("---WORKING---")); skip(1)
2643 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2644 prouts(" 10"); skip(1)
2645 prouts(" 9"); skip(1)
2646 prouts(" 8"); skip(1)
2647 prouts(" 7"); skip(1)
2648 prouts(" 6"); skip(1)
2650 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2652 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2654 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2658 if game.passwd != scanner.token:
2659 prouts(_("PASSWORD-REJECTED;"))
2661 prouts(_("CONTINUITY-EFFECTED"))
2664 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2665 prouts(" 5"); skip(1)
2666 prouts(" 4"); skip(1)
2667 prouts(" 3"); skip(1)
2668 prouts(" 2"); skip(1)
2669 prouts(" 1"); skip(1)
2671 prouts(_("GOODBYE-CRUEL-WORLD"))
2679 prouts(_("********* Entropy of %s maximized *********") % crmshp())
2683 if len(game.enemies) != 0:
2684 whammo = 25.0 * game.energy
2686 while l <= len(game.enemies):
2687 if game.enemies[l].power*game.enemies[l].kdist <= whammo:
2688 deadkl(game.enemies[l].location, game.quad[game.enemies[l].location.i][game.enemies[l].location.j], game.enemies[l].location)
2693 "Compute our rate of kils over time."
2694 elapsed = game.state.date - game.indate
2695 if elapsed == 0: # Avoid divide-by-zero error if calculated on turn 0
2698 starting = (game.inkling + game.incom + game.inscom)
2699 remaining = (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)
2700 return (starting - remaining)/elapsed
2704 badpt = 5.0*game.state.starkl + \
2706 10.0*game.state.nplankl + \
2707 300*game.state.nworldkl + \
2709 100.0*game.state.basekl +\
2711 if game.ship == 'F':
2713 elif game.ship == None:
2718 # end the game, with appropriate notfications
2722 prout(_("It is stardate %.1f.") % game.state.date)
2724 if ifin == FWON: # Game has been won
2725 if game.state.nromrem != 0:
2726 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2729 prout(_("You have smashed the Klingon invasion fleet and saved"))
2730 prout(_("the Federation."))
2735 badpt = 0.0 # Close enough!
2736 # killsPerDate >= RateMax
2737 if game.state.date-game.indate < 5.0 or \
2738 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2740 prout(_("In fact, you have done so well that Starfleet Command"))
2741 if game.skill == SKILL_NOVICE:
2742 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2743 elif game.skill == SKILL_FAIR:
2744 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2745 elif game.skill == SKILL_GOOD:
2746 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2747 elif game.skill == SKILL_EXPERT:
2748 prout(_("promotes you to Commodore Emeritus."))
2750 prout(_("Now that you think you're really good, try playing"))
2751 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2752 elif game.skill == SKILL_EMERITUS:
2754 proutn(_("Computer- "))
2755 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2757 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2759 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2761 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2763 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
2765 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
2767 prout(_("Now you can retire and write your own Star Trek game!"))
2769 elif game.skill >= SKILL_EXPERT:
2770 if game.thawed and not idebug:
2771 prout(_("You cannot get a citation, so..."))
2773 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
2777 # Only grant long life if alive (original didn't!)
2779 prout(_("LIVE LONG AND PROSPER."))
2784 elif ifin == FDEPLETE: # Federation Resources Depleted
2785 prout(_("Your time has run out and the Federation has been"))
2786 prout(_("conquered. Your starship is now Klingon property,"))
2787 prout(_("and you are put on trial as a war criminal. On the"))
2788 proutn(_("basis of your record, you are "))
2789 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
2790 prout(_("acquitted."))
2792 prout(_("LIVE LONG AND PROSPER."))
2794 prout(_("found guilty and"))
2795 prout(_("sentenced to death by slow torture."))
2799 elif ifin == FLIFESUP:
2800 prout(_("Your life support reserves have run out, and"))
2801 prout(_("you die of thirst, starvation, and asphyxiation."))
2802 prout(_("Your starship is a derelict in space."))
2804 prout(_("Your energy supply is exhausted."))
2806 prout(_("Your starship is a derelict in space."))
2807 elif ifin == FBATTLE:
2808 prout(_("The %s has been destroyed in battle.") % crmshp())
2810 prout(_("Dulce et decorum est pro patria mori."))
2812 prout(_("You have made three attempts to cross the negative energy"))
2813 prout(_("barrier which surrounds the galaxy."))
2815 prout(_("Your navigation is abominable."))
2818 prout(_("Your starship has been destroyed by a nova."))
2819 prout(_("That was a great shot."))
2821 elif ifin == FSNOVAED:
2822 prout(_("The %s has been fried by a supernova.") % crmshp())
2823 prout(_("...Not even cinders remain..."))
2824 elif ifin == FABANDN:
2825 prout(_("You have been captured by the Klingons. If you still"))
2826 prout(_("had a starbase to be returned to, you would have been"))
2827 prout(_("repatriated and given another chance. Since you have"))
2828 prout(_("no starbases, you will be mercilessly tortured to death."))
2829 elif ifin == FDILITHIUM:
2830 prout(_("Your starship is now an expanding cloud of subatomic particles"))
2831 elif ifin == FMATERIALIZE:
2832 prout(_("Starbase was unable to re-materialize your starship."))
2833 prout(_("Sic transit gloria mundi"))
2834 elif ifin == FPHASER:
2835 prout(_("The %s has been cremated by its own phasers.") % crmshp())
2837 prout(_("You and your landing party have been"))
2838 prout(_("converted to energy, disipating through space."))
2839 elif ifin == FMINING:
2840 prout(_("You are left with your landing party on"))
2841 prout(_("a wild jungle planet inhabited by primitive cannibals."))
2843 prout(_("They are very fond of \"Captain Kirk\" soup."))
2845 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2846 elif ifin == FDPLANET:
2847 prout(_("You and your mining party perish."))
2849 prout(_("That was a great shot."))
2852 prout(_("The Galileo is instantly annihilated by the supernova."))
2853 prout(_("You and your mining party are atomized."))
2855 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2856 prout(_("joins the Romulans, wreaking terror on the Federation."))
2857 elif ifin == FPNOVA:
2858 prout(_("You and your mining party are atomized."))
2860 prout(_("Mr. Spock takes command of the %s and") % crmshp())
2861 prout(_("joins the Romulans, wreaking terror on the Federation."))
2862 elif ifin == FSTRACTOR:
2863 prout(_("The shuttle craft Galileo is also caught,"))
2864 prout(_("and breaks up under the strain."))
2866 prout(_("Your debris is scattered for millions of miles."))
2867 prout(_("Without your leadership, the %s is destroyed.") % crmshp())
2869 prout(_("The mutants attack and kill Spock."))
2870 prout(_("Your ship is captured by Klingons, and"))
2871 prout(_("your crew is put on display in a Klingon zoo."))
2872 elif ifin == FTRIBBLE:
2873 prout(_("Tribbles consume all remaining water,"))
2874 prout(_("food, and oxygen on your ship."))
2876 prout(_("You die of thirst, starvation, and asphyxiation."))
2877 prout(_("Your starship is a derelict in space."))
2879 prout(_("Your ship is drawn to the center of the black hole."))
2880 prout(_("You are crushed into extremely dense matter."))
2882 prout(_("Your last crew member has died."))
2883 if game.ship == 'F':
2885 elif game.ship == 'E':
2888 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0:
2889 goodies = game.state.remres/game.inresor
2890 baddies = (game.state.remkl + 2.0*len(game.state.kcmdr))/(game.inkling+2.0*game.incom)
2891 if goodies/baddies >= randreal(1.0, 1.5):
2892 prout(_("As a result of your actions, a treaty with the Klingon"))
2893 prout(_("Empire has been signed. The terms of the treaty are"))
2894 if goodies/baddies >= randreal(3.0):
2895 prout(_("favorable to the Federation."))
2897 prout(_("Congratulations!"))
2899 prout(_("highly unfavorable to the Federation."))
2901 prout(_("The Federation will be destroyed."))
2903 prout(_("Since you took the last Klingon with you, you are a"))
2904 prout(_("martyr and a hero. Someday maybe they'll erect a"))
2905 prout(_("statue in your memory. Rest in peace, and try not"))
2906 prout(_("to think about pigeons."))
2911 "Compute player's score."
2912 timused = game.state.date - game.indate
2914 if (timused == 0 or (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) != 0) and timused < 5.0:
2916 perdate = killrate()
2917 ithperd = 500*perdate + 0.5
2920 iwon = 100*game.skill
2921 if game.ship == 'E':
2923 elif game.ship == 'F':
2927 iscore = 10*(game.inkling - game.state.remkl) \
2928 + 50*(game.incom - len(game.state.kcmdr)) \
2930 + 20*(game.inrom - game.state.nromrem) \
2931 + 200*(game.inscom - game.state.nscrem) \
2932 - game.state.nromrem \
2937 prout(_("Your score --"))
2938 if game.inrom - game.state.nromrem:
2939 prout(_("%6d Romulans destroyed %5d") %
2940 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
2941 if game.state.nromrem and game.gamewon:
2942 prout(_("%6d Romulans captured %5d") %
2943 (game.state.nromrem, game.state.nromrem))
2944 if game.inkling - game.state.remkl:
2945 prout(_("%6d ordinary Klingons destroyed %5d") %
2946 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
2947 if game.incom - len(game.state.kcmdr):
2948 prout(_("%6d Klingon commanders destroyed %5d") %
2949 (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr))))
2950 if game.inscom - game.state.nscrem:
2951 prout(_("%6d Super-Commander destroyed %5d") %
2952 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
2954 prout(_("%6.2f Klingons per stardate %5d") %
2956 if game.state.starkl:
2957 prout(_("%6d stars destroyed by your action %5d") %
2958 (game.state.starkl, -5*game.state.starkl))
2959 if game.state.nplankl:
2960 prout(_("%6d planets destroyed by your action %5d") %
2961 (game.state.nplankl, -10*game.state.nplankl))
2962 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
2963 prout(_("%6d inhabited planets destroyed by your action %5d") %
2964 (game.state.nworldkl, -300*game.state.nworldkl))
2965 if game.state.basekl:
2966 prout(_("%6d bases destroyed by your action %5d") %
2967 (game.state.basekl, -100*game.state.basekl))
2969 prout(_("%6d calls for help from starbase %5d") %
2970 (game.nhelp, -45*game.nhelp))
2972 prout(_("%6d casualties incurred %5d") %
2973 (game.casual, -game.casual))
2975 prout(_("%6d crew abandoned in space %5d") %
2976 (game.abandoned, -3*game.abandoned))
2978 prout(_("%6d ship(s) lost or destroyed %5d") %
2979 (klship, -100*klship))
2981 prout(_("Penalty for getting yourself killed -200"))
2983 proutn(_("Bonus for winning "))
2984 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
2985 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
2986 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
2987 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
2988 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
2989 prout(" %5d" % iwon)
2991 prout(_("TOTAL SCORE %5d") % iscore)
2994 "Emit winner's commemmorative plaque."
2997 proutn(_("File or device name for your plaque: "))
3000 fp = open(winner, "w")
3003 prout(_("Invalid name."))
3005 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3007 # The 38 below must be 64 for 132-column paper
3008 nskip = 38 - len(winner)/2
3009 fp.write("\n\n\n\n")
3010 # --------DRAW ENTERPRISE PICTURE.
3011 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3012 fp.write(" EEE E : : : E\n" )
3013 fp.write(" EE EEE E : : NCC-1701 : E\n")
3014 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3015 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3016 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3017 fp.write(" EEEEEEE EEEEE E E E E\n")
3018 fp.write(" EEE E E E E\n")
3019 fp.write(" E E E E\n")
3020 fp.write(" EEEEEEEEEEEEE E E\n")
3021 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3022 fp.write(" :E : EEEE E\n")
3023 fp.write(" .-E -:----- E\n")
3024 fp.write(" :E : E\n")
3025 fp.write(" EE : EEEEEEEE\n")
3026 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3028 fp.write(_(" U. S. S. ENTERPRISE\n"))
3029 fp.write("\n\n\n\n")
3030 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3032 fp.write(_(" Starfleet Command bestows to you\n"))
3034 fp.write("%*s%s\n\n" % (nskip, "", winner))
3035 fp.write(_(" the rank of\n\n"))
3036 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3038 if game.skill == SKILL_EXPERT:
3039 fp.write(_(" Expert level\n\n"))
3040 elif game.skill == SKILL_EMERITUS:
3041 fp.write(_("Emeritus level\n\n"))
3043 fp.write(_(" Cheat level\n\n"))
3044 timestring = time.ctime()
3045 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3046 (timestring+4, timestring+20, timestring+11))
3047 fp.write(_(" Your score: %d\n\n") % iscore)
3048 fp.write(_(" Klingons per stardate: %.2f\n") % perdate)
3051 # Code from io.c begins here
3053 rows = linecount = 0 # for paging
3056 fullscreen_window = None
3057 srscan_window = None
3058 report_window = None
3059 status_window = None
3060 lrscan_window = None
3061 message_window = None
3062 prompt_window = None
3067 gettext.bindtextdomain("sst", "/usr/local/share/locale")
3068 gettext.textdomain("sst")
3069 if not (game.options & OPTION_CURSES):
3070 ln_env = os.getenv("LINES")
3076 stdscr = curses.initscr()
3080 if game.options & OPTION_COLOR:
3081 curses.start_color();
3082 curses.use_default_colors()
3083 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, -1);
3084 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, -1);
3085 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, -1);
3086 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, -1);
3087 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, -1);
3088 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, -1);
3089 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, -1);
3090 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, -1);
3091 global fullscreen_window, srscan_window, report_window, status_window
3092 global lrscan_window, message_window, prompt_window
3093 (rows, columns) = stdscr.getmaxyx()
3094 fullscreen_window = stdscr
3095 srscan_window = curses.newwin(12, 25, 0, 0)
3096 report_window = curses.newwin(11, 0, 1, 25)
3097 status_window = curses.newwin(10, 0, 1, 39)
3098 lrscan_window = curses.newwin(5, 0, 0, 64)
3099 message_window = curses.newwin(0, 0, 12, 0)
3100 prompt_window = curses.newwin(1, 0, rows-2, 0)
3101 message_window.scrollok(True)
3102 setwnd(fullscreen_window)
3106 if game.options & OPTION_CURSES:
3107 stdscr.keypad(False)
3113 "Wait for user action -- OK to do nothing if on a TTY"
3114 if game.options & OPTION_CURSES:
3119 prouts(_("[ANNOUNCEMENT ARRIVING...]"))
3123 if game.skill > SKILL_FAIR:
3124 prompt = _("[CONTINUE?]")
3126 prompt = _("[PRESS ENTER TO CONTINUE]")
3128 if game.options & OPTION_CURSES:
3130 setwnd(prompt_window)
3131 prompt_window.clear()
3132 prompt_window.addstr(prompt)
3133 prompt_window.getstr()
3134 prompt_window.clear()
3135 prompt_window.refresh()
3136 setwnd(message_window)
3139 sys.stdout.write('\n')
3142 for j in range(rows):
3143 sys.stdout.write('\n')
3147 "Skip i lines. Pause game if this would cause a scrolling event."
3148 for dummy in range(i):
3149 if game.options & OPTION_CURSES:
3150 (y, x) = curwnd.getyx()
3151 (my, mx) = curwnd.getmaxyx()
3152 if curwnd == message_window and y >= my - 3:
3158 except curses.error:
3163 if rows and linecount >= rows:
3166 sys.stdout.write('\n')
3169 "Utter a line with no following line feed."
3170 if game.options & OPTION_CURSES:
3174 sys.stdout.write(line)
3184 if not replayfp or replayfp.closed: # Don't slow down replays
3187 if game.options & OPTION_CURSES:
3191 if not replayfp or replayfp.closed:
3195 "Get a line of input."
3196 if game.options & OPTION_CURSES:
3197 line = curwnd.getstr() + "\n"
3200 if replayfp and not replayfp.closed:
3202 line = replayfp.readline()
3205 prout("*** Replay finished")
3208 elif line[0] != "#":
3211 line = raw_input() + "\n"
3217 "Change windows -- OK for this to be a no-op in tty mode."
3219 if game.options & OPTION_CURSES:
3221 curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window)
3224 "Clear to end of line -- can be a no-op in tty mode"
3225 if game.options & OPTION_CURSES:
3230 "Clear screen -- can be a no-op in tty mode."
3232 if game.options & OPTION_CURSES:
3238 def textcolor(color=DEFAULT):
3239 if game.options & OPTION_COLOR:
3240 if color == DEFAULT:
3242 elif color == BLACK:
3243 curwnd.attron(curses.color_pair(curses.COLOR_BLACK));
3245 curwnd.attron(curses.color_pair(curses.COLOR_BLUE));
3246 elif color == GREEN:
3247 curwnd.attron(curses.color_pair(curses.COLOR_GREEN));
3249 curwnd.attron(curses.color_pair(curses.COLOR_CYAN));
3251 curwnd.attron(curses.color_pair(curses.COLOR_RED));
3252 elif color == MAGENTA:
3253 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA));
3254 elif color == BROWN:
3255 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW));
3256 elif color == LIGHTGRAY:
3257 curwnd.attron(curses.color_pair(curses.COLOR_WHITE));
3258 elif color == DARKGRAY:
3259 curwnd.attron(curses.color_pair(curses.COLOR_BLACK) | curses.A_BOLD);
3260 elif color == LIGHTBLUE:
3261 curwnd.attron(curses.color_pair(curses.COLOR_BLUE) | curses.A_BOLD);
3262 elif color == LIGHTGREEN:
3263 curwnd.attron(curses.color_pair(curses.COLOR_GREEN) | curses.A_BOLD);
3264 elif color == LIGHTCYAN:
3265 curwnd.attron(curses.color_pair(curses.COLOR_CYAN) | curses.A_BOLD);
3266 elif color == LIGHTRED:
3267 curwnd.attron(curses.color_pair(curses.COLOR_RED) | curses.A_BOLD);
3268 elif color == LIGHTMAGENTA:
3269 curwnd.attron(curses.color_pair(curses.COLOR_MAGENTA) | curses.A_BOLD);
3270 elif color == YELLOW:
3271 curwnd.attron(curses.color_pair(curses.COLOR_YELLOW) | curses.A_BOLD);
3272 elif color == WHITE:
3273 curwnd.attron(curses.color_pair(curses.COLOR_WHITE) | curses.A_BOLD);
3276 if game.options & OPTION_COLOR:
3277 curwnd.attron(curses.A_REVERSE)
3280 # Things past this point have policy implications.
3284 "Hook to be called after moving to redraw maps."
3285 if game.options & OPTION_CURSES:
3288 setwnd(srscan_window)
3292 setwnd(status_window)
3293 status_window.clear()
3294 status_window.move(0, 0)
3295 setwnd(report_window)
3296 report_window.clear()
3297 report_window.move(0, 0)
3299 setwnd(lrscan_window)
3300 lrscan_window.clear()
3301 lrscan_window.move(0, 0)
3302 lrscan(silent=False)
3304 def put_srscan_sym(w, sym):
3305 "Emit symbol for short-range scan."
3306 srscan_window.move(w.i+1, w.j*2+2)
3307 srscan_window.addch(sym)
3308 srscan_window.refresh()
3311 "Enemy fall down, go boom."
3312 if game.options & OPTION_CURSES:
3314 setwnd(srscan_window)
3315 srscan_window.attron(curses.A_REVERSE)
3316 put_srscan_sym(w, game.quad[w.i][w.j])
3320 srscan_window.attroff(curses.A_REVERSE)
3321 put_srscan_sym(w, game.quad[w.i][w.j])
3322 curses.delay_output(500)
3323 setwnd(message_window)
3326 "Sound and visual effects for teleportation."
3327 if game.options & OPTION_CURSES:
3329 setwnd(message_window)
3331 prouts(" . . . . . ")
3332 if game.options & OPTION_CURSES:
3333 #curses.delay_output(1000)
3337 def tracktorpedo(origin, w, step, i, n, iquad):
3338 "Torpedo-track animation."
3339 if not game.options & OPTION_CURSES:
3343 proutn(_("Track for torpedo number %d- ") % (i+1))
3346 proutn(_("Torpedo track- "))
3347 elif step==4 or step==9:
3351 if not damaged(DSRSENS) or game.condition=="docked":
3352 if i != 0 and step == 1:
3355 if (iquad=='.') or (iquad==' '):
3356 put_srscan_sym(w, '+')
3360 put_srscan_sym(w, iquad)
3362 curwnd.attron(curses.A_REVERSE)
3363 put_srscan_sym(w, iquad)
3367 curwnd.attroff(curses.A_REVERSE)
3368 put_srscan_sym(w, iquad)
3373 "Display the current galaxy chart."
3374 if game.options & OPTION_CURSES:
3375 setwnd(message_window)
3376 message_window.clear()
3378 if game.options & OPTION_TTY:
3383 def prstat(txt, data):
3385 if game.options & OPTION_CURSES:
3387 setwnd(status_window)
3389 proutn(" " * (NSYM - len(txt)))
3392 if game.options & OPTION_CURSES:
3393 setwnd(report_window)
3395 # Code from moving.c begins here
3397 def imove(course=None, noattack=False):
3398 "Movement execution for warp, impulse, supernova, and tractor-beam events."
3401 def newquadrant(noattack):
3402 # Leaving quadrant -- allow final enemy attack
3403 # Don't do it if being pushed by Nova
3404 if len(game.enemies) != 0 and not noattack:
3406 for enemy in game.enemies:
3407 finald = (w - enemy.location).distance()
3408 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3409 # Stas Sergeev added the condition
3410 # that attacks only happen if Klingons
3411 # are present and your skill is good.
3412 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3413 attack(torps_ok=False)
3416 # check for edge of galaxy
3420 if course.final.i < 0:
3421 course.final.i = -course.final.i
3423 if course.final.j < 0:
3424 course.final.j = -course.final.j
3426 if course.final.i >= GALSIZE*QUADSIZE:
3427 course.final.i = (GALSIZE*QUADSIZE*2) - course.final.i
3429 if course.final.j >= GALSIZE*QUADSIZE:
3430 course.final.j = (GALSIZE*QUADSIZE*2) - course.final.j
3438 if game.nkinks == 3:
3439 # Three strikes -- you're out!
3443 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3444 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3445 prout(_("YOU WILL BE DESTROYED."))
3446 # Compute final position in new quadrant
3447 if trbeam: # Don't bother if we are to be beamed
3449 game.quadrant = course.final.quadrant()
3450 game.sector = course.final.sector()
3452 prout(_("Entering Quadrant %s.") % game.quadrant)
3453 game.quad[game.sector.i][game.sector.j] = game.ship
3455 if game.skill>SKILL_NOVICE:
3456 attack(torps_ok=False)
3458 def check_collision(h):
3459 iquad = game.quad[h.i][h.j]
3461 # object encountered in flight path
3462 stopegy = 50.0*course.distance/game.optime
3463 if iquad in ('T', 'K', 'C', 'S', 'R', '?'):
3464 for enemy in game.enemies:
3465 if enemy.location == game.sector:
3467 collision(rammed=False, enemy=enemy)
3471 prouts(_("***RED ALERT! RED ALERT!"))
3473 proutn("***" + crmshp())
3474 proutn(_(" pulled into black hole at Sector %s") % h)
3475 # Getting pulled into a black hole was certain
3476 # death in Almy's original. Stas Sergeev added a
3477 # possibility that you'll get timewarped instead.
3479 for m in range(NDEVICES):
3480 if game.damage[m]>0:
3482 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3483 if (game.options & OPTION_BLKHOLE) and withprob(1-probf):
3493 prout(_(" encounters Tholian web at %s;") % h)
3495 prout(_(" blocked by object at %s;") % h)
3496 proutn(_("Emergency stop required "))
3497 prout(_("%2d units of energy.") % int(stopegy))
3498 game.energy -= stopegy
3499 if game.energy <= 0:
3506 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3507 game.inorbit = False
3508 # If tractor beam is to occur, don't move full distance
3509 if game.state.date+game.optime >= scheduled(FTBEAM):
3511 game.condition = "red"
3512 course.distance = course.distance*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3513 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3515 game.quad[game.sector.i][game.sector.j] = '.'
3516 for m in range(course.moves):
3519 if course.origin.quadrant() != course.location.quadrant():
3520 newquadrant(noattack)
3522 elif check_collision(w):
3523 print "Collision detected"
3527 # We're in destination quadrant -- compute new average enemy distances
3528 game.quad[game.sector.i][game.sector.j] = game.ship
3530 for enemy in game.enemies:
3531 finald = (w-enemy.location).distance()
3532 enemy.kavgd = 0.5 * (finald + enemy.kdist)
3533 enemy.kdist = finald
3534 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
3535 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
3536 attack(torps_ok=False)
3537 for enemy in game.enemies:
3538 enemy.kavgd = enemy.kdist
3541 setwnd(message_window)
3545 "Dock our ship at a starbase."
3547 if game.condition == "docked" and verbose:
3548 prout(_("Already docked."))
3551 prout(_("You must first leave standard orbit."))
3553 if not game.base.is_valid() or abs(game.sector.i-game.base.i) > 1 or abs(game.sector.j-game.base.j) > 1:
3554 prout(crmshp() + _(" not adjacent to base."))
3556 game.condition = "docked"
3560 if game.energy < game.inenrg:
3561 game.energy = game.inenrg
3562 game.shield = game.inshld
3563 game.torps = game.intorps
3564 game.lsupres = game.inlsr
3565 game.state.crew = FULLCREW
3566 if not damaged(DRADIO) and \
3567 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3568 # get attack report from base
3569 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3573 def cartesian(loc1=None, loc2=None):
3575 return game.quadrant * QUADSIZE + game.sector
3577 return game.quadrant * QUADSIZE + loc1
3579 return loc1 * QUADSIZE + loc2
3581 def getcourse(isprobe):
3582 "Get a course and distance from the user."
3584 dquad = copy.copy(game.quadrant)
3585 navmode = "unspecified"
3589 if game.landed and not isprobe:
3590 prout(_("Dummy! You can't leave standard orbit until you"))
3591 proutn(_("are back aboard the ship."))
3594 while navmode == "unspecified":
3595 if damaged(DNAVSYS):
3597 prout(_("Computer damaged; manual navigation only"))
3599 prout(_("Computer damaged; manual movement only"))
3604 key = scanner.next()
3606 proutn(_("Manual or automatic- "))
3609 elif key == "IHALPHA":
3610 if scanner.sees("manual"):
3612 key = scanner.next()
3614 elif scanner.sees("automatic"):
3615 navmode = "automatic"
3616 key = scanner.next()
3624 prout(_("(Manual navigation assumed.)"))
3626 prout(_("(Manual movement assumed.)"))
3630 if navmode == "automatic":
3631 while key == "IHEOL":
3633 proutn(_("Target quadrant or quadrant§or- "))
3635 proutn(_("Destination sector or quadrant§or- "))
3638 key = scanner.next()
3642 xi = int(round(scanner.real))-1
3643 key = scanner.next()
3647 xj = int(round(scanner.real))-1
3648 key = scanner.next()
3650 # both quadrant and sector specified
3651 xk = int(round(scanner.real))-1
3652 key = scanner.next()
3656 xl = int(round(scanner.real))-1
3662 # only one pair of numbers was specified
3664 # only quadrant specified -- go to center of dest quad
3667 dsect.j = dsect.i = 4 # preserves 1-origin behavior
3669 # only sector specified
3673 if not dquad.valid_quadrant() or not dsect.valid_sector():
3680 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % dsect)
3682 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3683 # the actual deltas get computed here
3684 delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
3685 delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
3687 while key == "IHEOL":
3688 proutn(_("X and Y displacements- "))
3691 key = scanner.next()
3696 delta.j = scanner.real
3697 key = scanner.next()
3701 delta.i = scanner.real
3702 # Check for zero movement
3703 if delta.i == 0 and delta.j == 0:
3706 if itemp == "verbose" and not isprobe:
3708 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
3710 return course(bearing=delta.bearing(), distance=delta.distance())
3713 def __init__(self, bearing, distance, origin=None):
3714 self.distance = distance
3715 self.bearing = bearing
3717 self.origin = cartesian(game.quadrant, game.sector)
3719 self.origin = origin
3720 # The bearing() code we inherited from FORTRAN is actually computing
3721 # clockface directions!
3722 if self.bearing < 0.0:
3723 self.bearing += 12.0
3724 self.angle = ((15.0 - self.bearing) * 0.5235988)
3726 self.origin = cartesian(game.quadrant, game.sector)
3728 self.origin = cartesian(game.quadrant, origin)
3729 self.increment = coord(-math.sin(self.angle), math.cos(self.angle))
3730 bigger = max(abs(self.increment.i), abs(self.increment.j))
3731 self.increment /= bigger
3732 self.moves = int(round(10*self.distance*bigger))
3734 self.final = (self.location + self.moves*self.increment).roundtogrid()
3736 self.location = self.origin
3739 return self.location.roundtogrid() == self.final
3741 "Next step on course."
3743 self.nextlocation = self.location + self.increment
3744 samequad = (self.location.quadrant() == self.nextlocation.quadrant())
3745 self.location = self.nextlocation
3748 return self.location.quadrant()
3750 return self.location.sector()
3751 def power(self, warp):
3752 return self.distance*(warp**3)*(game.shldup+1)
3753 def time(self, warp):
3754 return 10.0*self.distance/warp**2
3757 "Move under impulse power."
3759 if damaged(DIMPULS):
3762 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
3764 if game.energy > 30.0:
3766 course = getcourse(isprobe=False)
3769 power = 20.0 + 100.0*course.distance
3772 if power >= game.energy:
3773 # Insufficient power for trip
3775 prout(_("First Officer Spock- \"Captain, the impulse engines"))
3776 prout(_("require 20.0 units to engage, plus 100.0 units per"))
3777 if game.energy > 30:
3778 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
3779 int(0.01 * (game.energy-20.0)-0.05))
3780 prout(_(" quadrants.\""))
3782 prout(_("quadrant. They are, therefore, useless.\""))
3785 # Make sure enough time is left for the trip
3786 game.optime = course.dist/0.095
3787 if game.optime >= game.state.remtime:
3788 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
3789 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
3790 proutn(_("we dare spend the time?\" "))
3793 # Activate impulse engines and pay the cost
3794 imove(course, noattack=False)
3798 power = 20.0 + 100.0*course.dist
3799 game.energy -= power
3800 game.optime = course.dist/0.095
3801 if game.energy <= 0:
3805 def warp(course, involuntary):
3806 "ove under warp drive."
3807 blooey = False; twarp = False
3808 if not involuntary: # Not WARPX entry
3810 if game.damage[DWARPEN] > 10.0:
3813 prout(_("Engineer Scott- \"The warp engines are damaged, Sir.\""))
3815 if damaged(DWARPEN) and game.warpfac > 4.0:
3818 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
3819 prout(_(" is repaired, I can only give you warp 4.\""))
3821 # Read in course and distance
3824 course = getcourse(isprobe=False)
3827 # Make sure starship has enough energy for the trip
3828 # Note: this formula is slightly different from the C version,
3829 # and lets you skate a bit closer to the edge.
3830 if course.power(game.warpfac) >= game.energy:
3831 # Insufficient power for trip
3834 prout(_("Engineering to bridge--"))
3835 if not game.shldup or 0.5*power > game.energy:
3836 iwarp = (game.energy/(course.dist+0.05)) ** 0.333333333
3838 prout(_("We can't do it, Captain. We don't have enough energy."))
3840 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
3843 prout(_("if you'll lower the shields."))
3847 prout(_("We haven't the energy to go that far with the shields up."))
3849 # Make sure enough time is left for the trip
3850 game.optime = course.time(game.warpfac)
3851 if game.optime >= 0.8*game.state.remtime:
3853 prout(_("First Officer Spock- \"Captain, I compute that such"))
3854 proutn(_(" a trip would require approximately %2.0f") %
3855 (100.0*game.optime/game.state.remtime))
3856 prout(_(" percent of our"))
3857 proutn(_(" remaining time. Are you sure this is wise?\" "))
3863 if game.warpfac > 6.0:
3864 # Decide if engine damage will occur
3865 # ESR: Seems wrong. Probability of damage goes *down* with distance?
3866 prob = course.distance*(6.0-game.warpfac)**2/66.666666666
3867 if prob > randreal():
3869 course.distance = randreal(course.distance)
3870 # Decide if time warp will occur
3871 if 0.5*course.distance*math.pow(7.0,game.warpfac-10.0) > randreal():
3873 if idebug and game.warpfac==10 and not twarp:
3875 proutn("=== Force time warp? ")
3879 # If time warp or engine damage, check path
3880 # If it is obstructed, don't do warp or damage
3881 for m in range(course.moves):
3884 if not w.valid_sector():
3886 if game.quad[w.i][w.j] != '.':
3890 # Activate Warp Engines and pay the cost
3891 imove(course, noattack=False)
3894 game.energy -= course.power(game.warpfac)
3895 if game.energy <= 0:
3897 game.optime = course.time(game.warpfac)
3901 game.damage[DWARPEN] = game.damfac * randreal(1.0, 4.0)
3903 prout(_("Engineering to bridge--"))
3904 prout(_(" Scott here. The warp engines are damaged."))
3905 prout(_(" We'll have to reduce speed to warp 4."))
3910 "Change the warp factor."
3916 proutn(_("Warp factor- "))
3921 if game.damage[DWARPEN] > 10.0:
3922 prout(_("Warp engines inoperative."))
3924 if damaged(DWARPEN) and scanner.real > 4.0:
3925 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
3926 prout(_(" but right now we can only go warp 4.\""))
3928 if scanner.real > 10.0:
3929 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
3931 if scanner.real < 1.0:
3932 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
3934 oldfac = game.warpfac
3935 game.warpfac = scanner.real
3936 if game.warpfac <= oldfac or game.warpfac <= 6.0:
3937 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
3940 if game.warpfac < 8.00:
3941 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
3943 if game.warpfac == 10.0:
3944 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
3946 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
3950 "Cope with being tossed out of quadrant by supernova or yanked by beam."
3952 # is captain on planet?
3954 if damaged(DTRANSP):
3957 prout(_("Scotty rushes to the transporter controls."))
3959 prout(_("But with the shields up it's hopeless."))
3961 prouts(_("His desperate attempt to rescue you . . ."))
3966 prout(_("SUCCEEDS!"))
3969 proutn(_("The crystals mined were "))
3977 # Check to see if captain in shuttle craft
3982 # Inform captain of attempt to reach safety
3986 prouts(_("***RED ALERT! RED ALERT!"))
3988 proutn(_("The %s has stopped in a quadrant containing") % crmshp())
3989 prouts(_(" a supernova."))
3991 prout(_("***Emergency automatic override attempts to hurl ")+crmshp())
3992 prout(_("safely out of quadrant."))
3993 if not damaged(DRADIO):
3994 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
3995 # Try to use warp engines
3996 if damaged(DWARPEN):
3998 prout(_("Warp engines damaged."))
4001 game.warpfac = randreal(6.0, 8.0)
4002 prout(_("Warp factor set to %d") % int(game.warpfac))
4003 power = 0.75*game.energy
4004 dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4005 dist = max(dist, randreal(math.sqrt(2)))
4006 bugout = course(bearing=randreal(12), distance=dist) # How dumb!
4007 game.optime = bugout.time(game.warpfac)
4009 game.inorbit = False
4010 warp(bugout, involuntary=True)
4012 # This is bad news, we didn't leave quadrant.
4016 prout(_("Insufficient energy to leave quadrant."))
4019 # Repeat if another snova
4020 if not game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
4022 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)==0:
4023 finish(FWON) # Snova killed remaining enemy.
4026 "Let's do the time warp again."
4027 prout(_("***TIME WARP ENTERED."))
4028 if game.state.snap and withprob(0.5):
4030 prout(_("You are traveling backwards in time %d stardates.") %
4031 int(game.state.date-game.snapsht.date))
4032 game.state = game.snapsht
4033 game.state.snap = False
4034 if len(game.state.kcmdr):
4035 schedule(FTBEAM, expran(game.intime/len(game.state.kcmdr)))
4036 schedule(FBATTAK, expran(0.3*game.intime))
4037 schedule(FSNOVA, expran(0.5*game.intime))
4038 # next snapshot will be sooner
4039 schedule(FSNAP, expran(0.25*game.state.remtime))
4041 if game.state.nscrem:
4042 schedule(FSCMOVE, 0.2777)
4046 game.battle.invalidate()
4047 # Make sure Galileo is consistant -- Snapshot may have been taken
4048 # when on planet, which would give us two Galileos!
4050 for l in range(game.inplan):
4051 if game.state.planets[l].known == "shuttle_down":
4053 if game.iscraft == "onship" and game.ship=='E':
4054 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4055 game.iscraft = "offship"
4056 # Likewise, if in the original time the Galileo was abandoned, but
4057 # was on ship earlier, it would have vanished -- let's restore it.
4058 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4059 prout(_("Chekov- \"Security reports the Galileo has reappeared in the dock!\""))
4060 game.iscraft = "onship"
4061 # There used to be code to do the actual reconstrction here,
4062 # but the starchart is now part of the snapshotted galaxy state.
4063 prout(_("Spock has reconstructed a correct star chart from memory"))
4065 # Go forward in time
4066 game.optime = expran(0.5*game.intime)
4067 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4068 # cheat to make sure no tractor beams occur during time warp
4069 postpone(FTBEAM, game.optime)
4070 game.damage[DRADIO] += game.optime
4072 events() # Stas Sergeev added this -- do pending events
4075 "Launch deep-space probe."
4076 # New code to launch a deep space probe
4077 if game.nprobes == 0:
4080 if game.ship == 'E':
4081 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4083 prout(_("Ye Faerie Queene has no deep space probes."))
4088 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4090 if is_scheduled(FDSPROB):
4093 if damaged(DRADIO) and game.condition != "docked":
4094 prout(_("Spock- \"Records show the previous probe has not yet"))
4095 prout(_(" reached its destination.\""))
4097 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4099 key = scanner.next()
4101 if game.nprobes == 1:
4102 prout(_("1 probe left."))
4104 prout(_("%d probes left") % game.nprobes)
4105 proutn(_("Are you sure you want to fire a probe? "))
4108 game.isarmed = False
4109 if key == "IHALPHA" and scanner.token == "armed":
4111 key = scanner.next()
4112 elif key == "IHEOL":
4113 proutn(_("Arm NOVAMAX warhead? "))
4115 elif key == "IHREAL": # first element of course
4116 scanner.push(scanner.token)
4118 game.probe = getcourse(isprobe=True)
4122 schedule(FDSPROB, 0.01) # Time to move one sector
4123 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4128 "Yell for help from nearest starbase."
4129 # There's more than one way to move in this game!
4131 # Test for conditions which prevent calling for help
4132 if game.condition == "docked":
4133 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4136 prout(_("Subspace radio damaged."))
4138 if not game.state.baseq:
4139 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4142 prout(_("You must be aboard the %s.") % crmshp())
4144 # OK -- call for help from nearest starbase
4147 # There's one in this quadrant
4148 ddist = (game.base - game.sector).distance()
4151 for ibq in game.state.baseq:
4152 xdist = QUADSIZE * (ibq - game.quadrant).distance()
4155 # Since starbase not in quadrant, set up new quadrant
4158 # dematerialize starship
4159 game.quad[game.sector.i][game.sector.j]='.'
4160 proutn(_("Starbase in Quadrant %s responds--%s dematerializes") \
4161 % (game.quadrant, crmshp()))
4162 game.sector.invalidate()
4163 for m in range(1, 5+1):
4164 w = game.base.scatter()
4165 if w.valid_sector() and game.quad[w.i][w.j]=='.':
4166 # found one -- finish up
4169 if not game.sector.is_valid():
4170 prout(_("You have been lost in space..."))
4171 finish(FMATERIALIZE)
4173 # Give starbase three chances to rematerialize starship
4174 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4175 for m in range(1, 3+1):
4176 if m == 1: proutn(_("1st"))
4177 elif m == 2: proutn(_("2nd"))
4178 elif m == 3: proutn(_("3rd"))
4179 proutn(_(" attempt to re-materialize ") + crmshp())
4180 game.quad[ix][iy]=('-','o','O')[m-1]
4183 if randreal() > probf:
4187 curses.delay_output(500)
4189 game.quad[ix][iy]='?'
4192 setwnd(message_window)
4193 finish(FMATERIALIZE)
4195 game.quad[ix][iy]=game.ship
4197 prout(_("succeeds."))
4201 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4206 if game.condition=="docked":
4208 prout(_("You cannot abandon Ye Faerie Queene."))
4211 # Must take shuttle craft to exit
4212 if game.damage[DSHUTTL]==-1:
4213 prout(_("Ye Faerie Queene has no shuttle craft."))
4215 if game.damage[DSHUTTL]<0:
4216 prout(_("Shuttle craft now serving Big Macs."))
4218 if game.damage[DSHUTTL]>0:
4219 prout(_("Shuttle craft damaged."))
4222 prout(_("You must be aboard the ship."))
4224 if game.iscraft != "onship":
4225 prout(_("Shuttle craft not currently available."))
4227 # Emit abandon ship messages
4229 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4231 prouts(_("***ALL HANDS ABANDON SHIP!"))
4233 prout(_("Captain and crew escape in shuttle craft."))
4234 if not game.state.baseq:
4235 # Oops! no place to go...
4238 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
4240 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4241 prout(_("Remainder of ship's complement beam down"))
4242 prout(_("to nearest habitable planet."))
4243 elif q.planet != None and not damaged(DTRANSP):
4244 prout(_("Remainder of ship's complement beam down to %s.") %
4247 prout(_("Entire crew of %d left to die in outer space.") %
4249 game.casual += game.state.crew
4250 game.abandoned += game.state.crew
4251 # If at least one base left, give 'em the Faerie Queene
4253 game.icrystl = False # crystals are lost
4254 game.nprobes = 0 # No probes
4255 prout(_("You are captured by Klingons and released to"))
4256 prout(_("the Federation in a prisoner-of-war exchange."))
4257 nb = randrange(len(game.state.baseq))
4258 # Set up quadrant and position FQ adjacient to base
4259 if not game.quadrant == game.state.baseq[nb]:
4260 game.quadrant = game.state.baseq[nb]
4261 game.sector.i = game.sector.j = 5
4264 # position next to base by trial and error
4265 game.quad[game.sector.i][game.sector.j] = '.'
4266 for l in range(QUADSIZE):
4267 game.sector = game.base.scatter()
4268 if game.sector.valid_sector() and \
4269 game.quad[game.sector.i][game.sector.j] == '.':
4272 break # found a spot
4273 game.sector.i=QUADSIZE/2
4274 game.sector.j=QUADSIZE/2
4276 # Get new commission
4277 game.quad[game.sector.i][game.sector.j] = game.ship = 'F'
4278 game.state.crew = FULLCREW
4279 prout(_("Starfleet puts you in command of another ship,"))
4280 prout(_("the Faerie Queene, which is antiquated but,"))
4281 prout(_("still useable."))
4283 prout(_("The dilithium crystals have been moved."))
4285 game.iscraft = "offship" # Galileo disappears
4287 game.condition="docked"
4288 for l in range(NDEVICES):
4289 game.damage[l] = 0.0
4290 game.damage[DSHUTTL] = -1
4291 game.energy = game.inenrg = 3000.0
4292 game.shield = game.inshld = 1250.0
4293 game.torps = game.intorps = 6
4294 game.lsupres=game.inlsr=3.0
4299 # Code from planets.c begins here.
4302 "Abort a lengthy operation if an event interrupts it."
4305 if game.alldone or game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova or game.justin:
4310 "Report on (uninhabited) planets in the galaxy."
4314 prout(_("Spock- \"Planet report follows, Captain.\""))
4316 for i in range(game.inplan):
4317 if game.state.planets[i].pclass == "destroyed":
4319 if (game.state.planets[i].known != "unknown" \
4320 and not game.state.planets[i].inhabited) \
4323 if idebug and game.state.planets[i].known=="unknown":
4324 proutn("(Unknown) ")
4325 proutn(_("Quadrant %s") % game.state.planets[i].quadrant)
4326 proutn(_(" class "))
4327 proutn(game.state.planets[i].pclass)
4329 if game.state.planets[i].crystals != present:
4331 prout(_("dilithium crystals present."))
4332 if game.state.planets[i].known=="shuttle_down":
4333 prout(_(" Shuttle Craft Galileo on surface."))
4335 prout(_("No information available."))
4338 "Enter standard orbit."
4342 prout(_("Already in standard orbit."))
4344 if damaged(DWARPEN) and damaged(DIMPULS):
4345 prout(_("Both warp and impulse engines damaged."))
4347 if not game.plnet.is_valid():
4348 prout("There is no planet in this sector.")
4350 if abs(game.sector.i-game.plnet.i)>1 or abs(game.sector.j-game.plnet.j)>1:
4351 prout(crmshp() + _(" not adjacent to planet."))
4354 game.optime = randreal(0.02, 0.05)
4355 prout(_("Helmsman Sulu- \"Entering standard orbit, Sir.\""))
4359 game.height = randreal(1400, 8600)
4360 prout(_("Sulu- \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4365 "Examine planets in this quadrant."
4366 if damaged(DSRSENS):
4367 if game.options & OPTION_TTY:
4368 prout(_("Short range sensors damaged."))
4370 if game.iplnet == None:
4371 if game.options & OPTION_TTY:
4372 prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4374 if game.iplnet.known == "unknown":
4375 prout(_("Spock- \"Sensor scan for Quadrant %s-") % game.quadrant)
4377 prout(_(" Planet at Sector %s is of class %s.") %
4378 (game.plnet, game.iplnet.pclass))
4379 if game.iplnet.known=="shuttle_down":
4380 prout(_(" Sensors show Galileo still on surface."))
4381 proutn(_(" Readings indicate"))
4382 if game.iplnet.crystals != "present":
4384 prout(_(" dilithium crystals present.\""))
4385 if game.iplnet.known == "unknown":
4386 game.iplnet.known = "known"
4387 elif game.iplnet.inhabited:
4388 prout(_("Spock- \"The inhabited planet %s ") % game.iplnet.name)
4389 prout(_(" is located at Sector %s, Captain.\"") % game.plnet)
4392 "Use the transporter."
4396 if damaged(DTRANSP):
4397 prout(_("Transporter damaged."))
4398 if not damaged(DSHUTTL) and (game.iplnet.known=="shuttle_down" or game.iscraft == "onship"):
4400 proutn(_("Spock- \"May I suggest the shuttle craft, Sir?\" "))
4404 if not game.inorbit:
4405 prout(crmshp() + _(" not in standard orbit."))
4408 prout(_("Impossible to transport through shields."))
4410 if game.iplnet.known=="unknown":
4411 prout(_("Spock- \"Captain, we have no information on this planet"))
4412 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4413 prout(_(" you may not go down.\""))
4415 if not game.landed and game.iplnet.crystals=="absent":
4416 prout(_("Spock- \"Captain, I fail to see the logic in"))
4417 prout(_(" exploring a planet with no dilithium crystals."))
4418 proutn(_(" Are you sure this is wise?\" "))
4422 if not (game.options & OPTION_PLAIN):
4423 nrgneed = 50 * game.skill + game.height / 100.0
4424 if nrgneed > game.energy:
4425 prout(_("Engineering to bridge--"))
4426 prout(_(" Captain, we don't have enough energy for transportation."))
4428 if not game.landed and nrgneed * 2 > game.energy:
4429 prout(_("Engineering to bridge--"))
4430 prout(_(" Captain, we have enough energy only to transport you down to"))
4431 prout(_(" the planet, but there wouldn't be an energy for the trip back."))
4432 if game.iplnet.known == "shuttle_down":
4433 prout(_(" Although the Galileo shuttle craft may still be on a surface."))
4434 proutn(_(" Are you sure this is wise?\" "))
4439 # Coming from planet
4440 if game.iplnet.known=="shuttle_down":
4441 proutn(_("Spock- \"Wouldn't you rather take the Galileo?\" "))
4445 prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4446 prout(_("Landing party assembled, ready to beam up."))
4448 prout(_("Kirk whips out communicator..."))
4449 prouts(_("BEEP BEEP BEEP"))
4451 prout(_("\"Kirk to enterprise- Lock on coordinates...energize.\""))
4454 prout(_("Scotty- \"Transporter room ready, Sir.\""))
4456 prout(_("Kirk and landing party prepare to beam down to planet surface."))
4458 prout(_("Kirk- \"Energize.\""))
4461 prouts("WWHOOOIIIIIRRRRREEEE.E.E. . . . . . .")
4464 prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4466 prout(_("Scotty- \"Oh my God! I've lost them.\""))
4469 prouts(". . . . . . .E.E.EEEERRRRRIIIIIOOOHWW")
4470 game.landed = not game.landed
4471 game.energy -= nrgneed
4473 prout(_("Transport complete."))
4474 if game.landed and game.iplnet.known=="shuttle_down":
4475 prout(_("The shuttle craft Galileo is here!"))
4476 if not game.landed and game.imine:
4483 "Strip-mine a world for dilithium."
4487 prout(_("Mining party not on planet."))
4489 if game.iplnet.crystals == "mined":
4490 prout(_("This planet has already been strip-mined for dilithium."))
4492 elif game.iplnet.crystals == "absent":
4493 prout(_("No dilithium crystals on this planet."))
4496 prout(_("You've already mined enough crystals for this trip."))
4498 if game.icrystl and game.cryprob == 0.05:
4499 prout(_("With all those fresh crystals aboard the ") + crmshp())
4500 prout(_("there's no reason to mine more at this time."))
4502 game.optime = randreal(0.1, 0.3)*(ord(game.iplnet.pclass)-ord("L"))
4505 prout(_("Mining operation complete."))
4506 game.iplnet.crystals = "mined"
4507 game.imine = game.ididit = True
4510 "Use dilithium crystals."
4514 if not game.icrystl:
4515 prout(_("No dilithium crystals available."))
4517 if game.energy >= 1000:
4518 prout(_("Spock- \"Captain, Starfleet Regulations prohibit such an operation"))
4519 prout(_(" except when Condition Yellow exists."))
4521 prout(_("Spock- \"Captain, I must warn you that loading"))
4522 prout(_(" raw dilithium crystals into the ship's power"))
4523 prout(_(" system may risk a severe explosion."))
4524 proutn(_(" Are you sure this is wise?\" "))
4529 prout(_("Engineering Officer Scott- \"(GULP) Aye Sir."))
4530 prout(_(" Mr. Spock and I will try it.\""))
4532 prout(_("Spock- \"Crystals in place, Sir."))
4533 prout(_(" Ready to activate circuit.\""))
4535 prouts(_("Scotty- \"Keep your fingers crossed, Sir!\""))
4537 if withprob(game.cryprob):
4538 prouts(_(" \"Activating now! - - No good! It's***"))
4540 prouts(_("***RED ALERT! RED A*L********************************"))
4543 prouts(_("****************** KA-BOOM!!!! *******************"))
4547 game.energy += randreal(5000.0, 5500.0)
4548 prouts(_(" \"Activating now! - - "))
4549 prout(_("The instruments"))
4550 prout(_(" are going crazy, but I think it's"))
4551 prout(_(" going to work!! Congratulations, Sir!\""))
4556 "Use shuttlecraft for planetary jaunt."
4559 if damaged(DSHUTTL):
4560 if game.damage[DSHUTTL] == -1.0:
4561 if game.inorbit and game.iplnet.known == "shuttle_down":
4562 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4564 prout(_("Ye Faerie Queene had no shuttle craft."))
4565 elif game.damage[DSHUTTL] > 0:
4566 prout(_("The Galileo is damaged."))
4567 else: # game.damage[DSHUTTL] < 0
4568 prout(_("Shuttle craft is now serving Big Macs."))
4570 if not game.inorbit:
4571 prout(crmshp() + _(" not in standard orbit."))
4573 if (game.iplnet.known != "shuttle_down") and game.iscraft != "onship":
4574 prout(_("Shuttle craft not currently available."))
4576 if not game.landed and game.iplnet.known=="shuttle_down":
4577 prout(_("You will have to beam down to retrieve the shuttle craft."))
4579 if game.shldup or game.condition == "docked":
4580 prout(_("Shuttle craft cannot pass through shields."))
4582 if game.iplnet.known=="unknown":
4583 prout(_("Spock- \"Captain, we have no information on this planet"))
4584 prout(_(" and Starfleet Regulations clearly state that in this situation"))
4585 prout(_(" you may not fly down.\""))
4587 game.optime = 3.0e-5*game.height
4588 if game.optime >= 0.8*game.state.remtime:
4589 prout(_("First Officer Spock- \"Captain, I compute that such"))
4590 proutn(_(" a maneuver would require approximately %2d%% of our") % \
4591 int(100*game.optime/game.state.remtime))
4592 prout(_("remaining time."))
4593 proutn(_("Are you sure this is wise?\" "))
4599 if game.iscraft == "onship":
4601 if not damaged(DTRANSP):
4602 proutn(_("Spock- \"Would you rather use the transporter?\" "))
4606 proutn(_("Shuttle crew"))
4608 proutn(_("Rescue party"))
4609 prout(_(" boards Galileo and swoops toward planet surface."))
4610 game.iscraft = "offship"
4614 game.iplnet.known="shuttle_down"
4615 prout(_("Trip complete."))
4618 # Ready to go back to ship
4619 prout(_("You and your mining party board the"))
4620 prout(_("shuttle craft for the trip back to the Enterprise."))
4622 prouts(_("The short hop begins . . ."))
4624 game.iplnet.known="known"
4630 game.iscraft = "onship"
4636 prout(_("Trip complete."))
4639 # Kirk on ship and so is Galileo
4640 prout(_("Mining party assembles in the hangar deck,"))
4641 prout(_("ready to board the shuttle craft \"Galileo\"."))
4643 prouts(_("The hangar doors open; the trip begins."))
4646 game.iscraft = "offship"
4649 game.iplnet.known = "shuttle_down"
4652 prout(_("Trip complete."))
4656 "Use the big zapper."
4660 if game.ship != 'E':
4661 prout(_("Ye Faerie Queene has no death ray."))
4663 if len(game.enemies)==0:
4664 prout(_("Sulu- \"But Sir, there are no enemies in this quadrant.\""))
4667 prout(_("Death Ray is damaged."))
4669 prout(_("Spock- \"Captain, the 'Experimental Death Ray'"))
4670 prout(_(" is highly unpredictible. Considering the alternatives,"))
4671 proutn(_(" are you sure this is wise?\" "))
4674 prout(_("Spock- \"Acknowledged.\""))
4677 prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
4679 prout(_("Crew scrambles in emergency preparation."))
4680 prout(_("Spock and Scotty ready the death ray and"))
4681 prout(_("prepare to channel all ship's power to the device."))
4683 prout(_("Spock- \"Preparations complete, sir.\""))
4684 prout(_("Kirk- \"Engage!\""))
4686 prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
4689 if game.options & OPTION_PLAIN:
4693 prouts(_("Sulu- \"Captain! It's working!\""))
4695 while len(game.enemies) > 0:
4696 deadkl(game.enemies[1].location, game.quad[game.enemies[1].location.i][game.enemies[1].location.j],game.enemies[1].location)
4697 prout(_("Ensign Chekov- \"Congratulations, Captain!\""))
4698 if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem) == 0:
4700 if (game.options & OPTION_PLAIN) == 0:
4701 prout(_("Spock- \"Captain, I believe the `Experimental Death Ray'"))
4703 prout(_(" is still operational.\""))
4705 prout(_(" has been rendered nonfunctional.\""))
4706 game.damage[DDRAY] = 39.95
4708 r = randreal() # Pick failure method
4710 prouts(_("Sulu- \"Captain! It's working!\""))
4712 prouts(_("***RED ALERT! RED ALERT!"))
4714 prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
4716 prouts(_("***RED ALERT! RED A*L********************************"))
4719 prouts(_("****************** KA-BOOM!!!! *******************"))
4724 prouts(_("Sulu- \"Captain! Yagabandaghangrapl, brachriigringlanbla!\""))
4726 prout(_("Lt. Uhura- \"Graaeek! Graaeek!\""))
4728 prout(_("Spock- \"Fascinating! . . . All humans aboard"))
4729 prout(_(" have apparently been transformed into strange mutations."))
4730 prout(_(" Vulcans do not seem to be affected."))
4732 prout(_("Kirk- \"Raauch! Raauch!\""))
4737 prouts(_("Sulu- \"Captain! It's --WHAT?!?!\""))
4739 proutn(_("Spock- \"I believe the word is"))
4740 prouts(_(" *ASTONISHING*"))
4741 prout(_(" Mr. Sulu."))
4742 for i in range(QUADSIZE):
4743 for j in range(QUADSIZE):
4744 if game.quad[i][j] == '.':
4745 game.quad[i][j] = '?'
4746 prout(_(" Captain, our quadrant is now infested with"))
4747 prouts(_(" - - - - - - *THINGS*."))
4749 prout(_(" I have no logical explanation.\""))
4751 prouts(_("Sulu- \"Captain! The Death Ray is creating tribbles!\""))
4753 prout(_("Scotty- \"There are so many tribbles down here"))
4754 prout(_(" in Engineering, we can't move for 'em, Captain.\""))
4758 # Code from reports.c begins here
4760 def attackreport(curt):
4761 "eport status of bases under attack."
4763 if is_scheduled(FCDBAS):
4764 prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
4765 prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
4766 elif game.isatb == 1:
4767 prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
4768 prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
4770 prout(_("No Starbase is currently under attack."))
4772 if is_scheduled(FCDBAS):
4773 proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
4775 proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
4779 # report on general game status
4781 s1 = "" and game.thawed and _("thawed ")
4782 s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
4783 s3 = (None, _("novice"). _("fair"),
4784 _("good"), _("expert"), _("emeritus"))[game.skill]
4785 prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
4786 if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
4787 prout(_("No plaque is allowed."))
4789 prout(_("This is tournament game %d.") % game.tourn)
4790 prout(_("Your secret password is \"%s\"") % game.passwd)
4791 proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)),
4792 (game.inkling + game.incom + game.inscom)))
4793 if game.incom - len(game.state.kcmdr):
4794 prout(_(", including %d Commander%s.") % (game.incom - len(game.state.kcmdr), (_("s"), "")[(game.incom - len(game.state.kcmdr))==1]))
4795 elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
4796 prout(_(", but no Commanders."))
4799 if game.skill > SKILL_FAIR:
4800 prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
4801 if len(game.state.baseq) != game.inbase:
4803 if game.inbase-len(game.state.baseq)==1:
4804 proutn(_("has been 1 base"))
4806 proutn(_("have been %d bases") % (game.inbase-len(game.state.baseq)))
4807 prout(_(" destroyed, %d remaining.") % len(game.state.baseq))
4809 prout(_("There are %d bases.") % game.inbase)
4810 if communicating() or game.iseenit:
4811 # Don't report this if not seen and
4812 # either the radio is dead or not at base!
4816 prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
4818 prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1]))
4819 if game.ship == 'E':
4820 proutn(_("You have "))
4822 proutn("%d" % (game.nprobes))
4825 proutn(_(" deep space probe"))
4829 if communicating() and is_scheduled(FDSPROB):
4831 proutn(_("An armed deep space probe is in "))
4833 proutn(_("A deep space probe is in "))
4834 prout("Quadrant %s." % game.probec)
4836 if game.cryprob <= .05:
4837 prout(_("Dilithium crystals aboard ship... not yet used."))
4841 while game.cryprob > ai:
4844 prout(_("Dilithium crystals have been used %d time%s.") % \
4845 (i, (_("s"), "")[i==1]))
4849 "Long-range sensor scan."
4850 if damaged(DLRSENS):
4851 # Now allow base's sensors if docked
4852 if game.condition != "docked":
4854 prout(_("LONG-RANGE SENSORS DAMAGED."))
4857 prout(_("Starbase's long-range scan"))
4859 prout(_("Long-range scan"))
4860 for x in range(game.quadrant.i-1, game.quadrant.i+2):
4863 for y in range(game.quadrant.j-1, game.quadrant.j+2):
4864 if not coord(x, y).valid_quadrant():
4868 if not damaged(DRADIO):
4869 game.state.galaxy[x][y].charted = True
4870 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
4871 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
4872 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
4873 if not silent and game.state.galaxy[x][y].supernova:
4876 proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
4883 for i in range(NDEVICES):
4886 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
4887 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
4889 prout(" %-26s\t%8.2f\t\t%8.2f" % (device[i],
4890 game.damage[i]+0.05,
4891 DOCKFAC*game.damage[i]+0.005))
4893 prout(_("All devices functional."))
4896 "Update the chart in the Enterprise's computer from galaxy data."
4897 game.lastchart = game.state.date
4898 for i in range(GALSIZE):
4899 for j in range(GALSIZE):
4900 if game.state.galaxy[i][j].charted:
4901 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
4902 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
4903 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
4906 "Display the star chart."
4908 if (game.options & OPTION_AUTOSCAN):
4910 if not damaged(DRADIO):
4912 if game.lastchart < game.state.date and game.condition == "docked":
4913 prout(_("Spock- \"I revised the Star Chart from the starbase's records.\""))
4915 prout(_(" STAR CHART FOR THE KNOWN GALAXY"))
4916 if game.state.date > game.lastchart:
4917 prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
4918 prout(" 1 2 3 4 5 6 7 8")
4919 for i in range(GALSIZE):
4920 proutn("%d |" % (i+1))
4921 for j in range(GALSIZE):
4922 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4926 if game.state.galaxy[i][j].supernova:
4928 elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
4930 elif game.state.galaxy[i][j].charted:
4931 show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
4935 if (game.options & OPTION_SHOWME) and i == game.quadrant.i and j == game.quadrant.j:
4943 def sectscan(goodScan, i, j):
4944 "Light up an individual dot in a sector."
4945 if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
4946 textcolor({"green":GREEN,
4950 "dead":BROWN}[game.condition])
4951 if game.quad[i][j] != game.ship:
4953 proutn("%c " % game.quad[i][j])
4959 "Emit status report lines"
4960 if not req or req == 1:
4961 prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
4962 % (game.state.date, game.state.remtime))
4963 if not req or req == 2:
4964 if game.condition != "docked":
4966 prstat(_("Condition"), _("%s, %i DAMAGES") % \
4967 (game.condition.upper(), sum(map(lambda x: x > 0, game.damage))))
4968 if not req or req == 3:
4969 prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
4970 if not req or req == 4:
4971 if damaged(DLIFSUP):
4972 if game.condition == "docked":
4973 s = _("DAMAGED, Base provides")
4975 s = _("DAMAGED, reserves=%4.2f") % game.lsupres
4978 prstat(_("Life Support"), s)
4979 if not req or req == 5:
4980 prstat(_("Warp Factor"), "%.1f" % game.warpfac)
4981 if not req or req == 6:
4983 if game.icrystl and (game.options & OPTION_SHOWME):
4984 extra = _(" (have crystals)")
4985 prstat(_("Energy"), "%.2f%s" % (game.energy, extra))
4986 if not req or req == 7:
4987 prstat(_("Torpedoes"), "%d" % (game.torps))
4988 if not req or req == 8:
4989 if damaged(DSHIELD):
4995 data = _(" %d%% %.1f units") \
4996 % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
4997 prstat(_("Shields"), s+data)
4998 if not req or req == 9:
4999 prstat(_("Klingons Left"), "%d" \
5000 % (game.state.remkl+len(game.state.kcmdr)+game.state.nscrem))
5001 if not req or req == 10:
5002 if game.options & OPTION_WORLDS:
5003 plnet = game.state.galaxy[game.quadrant.i][game.quadrant.j].planet
5004 if plnet and plnet.inhabited:
5005 prstat(_("Major system"), plnet.name)
5007 prout(_("Sector is uninhabited"))
5008 elif not req or req == 11:
5009 attackreport(not req)
5012 "Request specified status data, a historical relic from slow TTYs."
5013 requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5014 while scanner.next() == "IHEOL":
5015 proutn(_("Information desired? "))
5017 if scanner.token in requests:
5018 status(requests.index(scanner.token))
5020 prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5021 prout((" date, condition, position, lsupport, warpfactor,"))
5022 prout((" energy, torpedoes, shields, klingons, system, time."))
5027 if damaged(DSRSENS):
5028 # Allow base's sensors if docked
5029 if game.condition != "docked":
5030 prout(_(" S.R. SENSORS DAMAGED!"))
5033 prout(_(" [Using Base's sensors]"))
5035 prout(_(" Short-range scan"))
5036 if goodScan and not damaged(DRADIO):
5037 game.state.chart[game.quadrant.i][game.quadrant.j].klingons = game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons
5038 game.state.chart[game.quadrant.i][game.quadrant.j].starbase = game.state.galaxy[game.quadrant.i][game.quadrant.j].starbase
5039 game.state.chart[game.quadrant.i][game.quadrant.j].stars = game.state.galaxy[game.quadrant.i][game.quadrant.j].stars
5040 game.state.galaxy[game.quadrant.i][game.quadrant.j].charted = True
5041 prout(" 1 2 3 4 5 6 7 8 9 10")
5042 if game.condition != "docked":
5044 for i in range(QUADSIZE):
5045 proutn("%2d " % (i+1))
5046 for j in range(QUADSIZE):
5047 sectscan(goodScan, i, j)
5051 "Use computer to get estimated time of arrival for a warp jump."
5052 w1 = coord(); w2 = coord()
5054 if damaged(DCOMPTR):
5055 prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5058 if scanner.next() != "IHREAL":
5061 proutn(_("Destination quadrant and/or sector? "))
5062 if scanner.next()!="IHREAL":
5065 w1.j = int(scanner.real-0.5)
5066 if scanner.next() != "IHREAL":
5069 w1.i = int(scanner.real-0.5)
5070 if scanner.next() == "IHREAL":
5071 w2.j = int(scanner.real-0.5)
5072 if scanner.next() != "IHREAL":
5075 w2.i = int(scanner.real-0.5)
5077 if game.quadrant.j>w1.i:
5081 if game.quadrant.i>w1.j:
5085 if not w1.valid_quadrant() or not w2.valid_sector():
5088 dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+
5089 (w1.i-game.quadrant.i+(w2.i-game.sector.i)/(QUADSIZE*1.0))**2)
5092 prout(_("Answer \"no\" if you don't know the value:"))
5095 proutn(_("Time or arrival date? "))
5096 if scanner.next()=="IHREAL":
5097 ttime = scanner.real
5098 if ttime > game.state.date:
5099 ttime -= game.state.date # Actually a star date
5100 twarp=(math.floor(math.sqrt((10.0*dist)/ttime)*10.0)+1.0)/10.0
5101 if ttime <= 1e-10 or twarp > 10:
5102 prout(_("We'll never make it, sir."))
5109 proutn(_("Warp factor? "))
5110 if scanner.next()== "IHREAL":
5112 twarp = scanner.real
5113 if twarp<1.0 or twarp > 10.0:
5117 prout(_("Captain, certainly you can give me one of these."))
5120 ttime = (10.0*dist)/twarp**2
5121 tpower = dist*twarp*twarp*twarp*(game.shldup+1)
5122 if tpower >= game.energy:
5123 prout(_("Insufficient energy, sir."))
5124 if not game.shldup or tpower > game.energy*2.0:
5127 proutn(_("New warp factor to try? "))
5128 if scanner.next() == "IHREAL":
5130 twarp = scanner.real
5131 if twarp<1.0 or twarp > 10.0:
5139 prout(_("But if you lower your shields,"))
5140 proutn(_("remaining"))
5143 proutn(_("Remaining"))
5144 prout(_(" energy will be %.2f.") % (game.energy-tpower))
5146 prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5148 prout(_("Any warp speed is adequate."))
5150 prout(_("Minimum warp needed is %.2f,") % (twarp))
5151 prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5152 if game.state.remtime < ttime:
5153 prout(_("Unfortunately, the Federation will be destroyed by then."))
5155 prout(_("You'll be taking risks at that speed, Captain"))
5156 if (game.isatb==1 and game.state.kscmdr == w1 and \
5157 scheduled(FSCDBAS)< ttime+game.state.date) or \
5158 (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5159 prout(_("The starbase there will be destroyed by then."))
5160 proutn(_("New warp factor to try? "))
5161 if scanner.next() == "IHREAL":
5163 twarp = scanner.real
5164 if twarp<1.0 or twarp > 10.0:
5172 # Code from setup.c begins here
5175 "Issue a historically correct banner."
5177 prout(_("-SUPER- STAR TREK"))
5179 # From the FORTRAN original
5180 # prout(_("Latest update-21 Sept 78"))
5186 scanner.push("emsave.trk")
5187 key = scanner.next()
5189 proutn(_("File name: "))
5190 key = scanner.next()
5191 if key != "IHALPHA":
5195 if '.' not in scanner.token:
5196 scanner.token += ".trk"
5198 fp = open(scanner.token, "wb")
5200 prout(_("Can't freeze game as file %s") % scanner.token)
5202 cPickle.dump(game, fp)
5206 "Retrieve saved game."
5207 game.passwd[0] = '\0'
5208 key = scanner.next()
5210 proutn(_("File name: "))
5211 key = scanner.next()
5212 if key != "IHALPHA":
5216 if '.' not in scanner.token:
5217 scanner.token += ".trk"
5219 fp = open(scanner.token, "rb")
5221 prout(_("Can't thaw game in %s") % scanner.token)
5223 game = cPickle.load(fp)
5227 # I used <http://www.memory-alpha.org> to find planets
5228 # with references in ST:TOS. Eath and the Alpha Centauri
5229 # Colony have been omitted.
5231 # Some planets marked Class G and P here will be displayed as class M
5232 # because of the way planets are generated. This is a known bug.
5235 _("Andoria (Fesoan)"), # several episodes
5236 _("Tellar Prime (Miracht)"), # TOS: "Journey to Babel"
5237 _("Vulcan (T'Khasi)"), # many episodes
5238 _("Medusa"), # TOS: "Is There in Truth No Beauty?"
5239 _("Argelius II (Nelphia)"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5240 _("Ardana"), # TOS: "The Cloud Minders"
5241 _("Catulla (Cendo-Prae)"), # TOS: "The Way to Eden"
5242 _("Gideon"), # TOS: "The Mark of Gideon"
5243 _("Aldebaran III"), # TOS: "The Deadly Years"
5244 _("Alpha Majoris I"), # TOS: "Wolf in the Fold"
5245 _("Altair IV"), # TOS: "Amok Time
5246 _("Ariannus"), # TOS: "Let That Be Your Last Battlefield"
5247 _("Benecia"), # TOS: "The Conscience of the King"
5248 _("Beta Niobe I (Sarpeidon)"), # TOS: "All Our Yesterdays"
5249 _("Alpha Carinae II"), # TOS: "The Ultimate Computer"
5250 _("Capella IV (Kohath)"), # TOS: "Friday's Child" (Class G)
5251 _("Daran V"), # TOS: "For the World is Hollow and I Have Touched the Sky"
5252 _("Deneb II"), # TOS: "Wolf in the Fold" ("IV" in BSD)
5253 _("Eminiar VII"), # TOS: "A Taste of Armageddon"
5254 _("Gamma Canaris IV"), # TOS: "Metamorphosis"
5255 _("Gamma Tranguli VI (Vaalel)"), # TOS: "The Apple"
5256 _("Ingraham B"), # TOS: "Operation: Annihilate"
5257 _("Janus IV"), # TOS: "The Devil in the Dark"
5258 _("Makus III"), # TOS: "The Galileo Seven"
5259 _("Marcos XII"), # TOS: "And the Children Shall Lead",
5260 _("Omega IV"), # TOS: "The Omega Glory"
5261 _("Regulus V"), # TOS: "Amok Time
5262 _("Deneva"), # TOS: "Operation -- Annihilate!"
5263 # Worlds from BSD Trek
5264 _("Rigel II"), # TOS: "Shore Leave" ("III" in BSD)
5265 _("Beta III"), # TOS: "The Return of the Archons"
5266 _("Triacus"), # TOS: "And the Children Shall Lead",
5267 _("Exo III"), # TOS: "What Are Little Girls Made Of?" (Class P)
5269 # _("Hansen's Planet"), # TOS: "The Galileo Seven"
5270 # _("Taurus IV"), # TOS: "The Galileo Seven" (class G)
5271 # _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?"
5272 # _("Izar"), # TOS: "Whom Gods Destroy"
5273 # _("Tiburon"), # TOS: "The Way to Eden"
5274 # _("Merak II"), # TOS: "The Cloud Minders"
5275 # _("Coridan (Desotriana)"), # TOS: "Journey to Babel"
5276 # _("Iotia"), # TOS: "A Piece of the Action"
5280 _("S. R. Sensors"), \
5281 _("L. R. Sensors"), \
5283 _("Photon Tubes"), \
5284 _("Life Support"), \
5285 _("Warp Engines"), \
5286 _("Impulse Engines"), \
5288 _("Subspace Radio"), \
5289 _("Shuttle Craft"), \
5291 _("Navigation System"), \
5293 _("Shield Control"), \
5299 "Prepare to play, set up cosmos."
5301 # Decide how many of everything
5303 return # frozen game
5304 # Prepare the Enterprise
5305 game.alldone = game.gamewon = game.shldchg = game.shldup = False
5307 game.state.crew = FULLCREW
5308 game.energy = game.inenrg = 5000.0
5309 game.shield = game.inshld = 2500.0
5312 game.quadrant = randplace(GALSIZE)
5313 game.sector = randplace(QUADSIZE)
5314 game.torps = game.intorps = 10
5315 game.nprobes = randrange(2, 5)
5317 for i in range(NDEVICES):
5318 game.damage[i] = 0.0
5319 # Set up assorted game parameters
5320 game.battle = coord()
5321 game.state.date = game.indate = 100.0 * randreal(20, 51)
5322 game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5323 game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5324 game.isatb = game.state.nplankl = 0
5325 game.state.starkl = game.state.basekl = 0
5326 game.iscraft = "onship"
5329 # Starchart is functional but we've never seen it
5330 game.lastchart = FOREVER
5331 # Put stars in the galaxy
5333 for i in range(GALSIZE):
5334 for j in range(GALSIZE):
5335 k = randrange(1, QUADSIZE**2/10+1)
5337 game.state.galaxy[i][j].stars = k
5338 # Locate star bases in galaxy
5339 for i in range(game.inbase):
5342 w = randplace(GALSIZE)
5343 if not game.state.galaxy[w.i][w.j].starbase:
5346 # C version: for (j = i-1; j > 0; j--)
5347 # so it did them in the opposite order.
5348 for j in range(1, i):
5349 # Improved placement algorithm to spread out bases
5350 distq = (w - game.state.baseq[j]).distance()
5351 if distq < 6.0*(BASEMAX+1-game.inbase) and withprob(0.75):
5354 prout("=== Abandoning base #%d at %s" % (i, w))
5356 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5358 prout("=== Saving base #%d, close to #%d" % (i, j))
5361 game.state.baseq.append(w)
5362 game.state.galaxy[w.i][w.j].starbase = game.state.chart[w.i][w.j].starbase = True
5363 # Position ordinary Klingon Battle Cruisers
5365 klumper = 0.25*game.skill*(9.0-game.length)+1.0
5366 if klumper > MAXKLQUAD:
5370 klump = (1.0 - r*r)*klumper
5375 w = randplace(GALSIZE)
5376 if not game.state.galaxy[w.i][w.j].supernova and \
5377 game.state.galaxy[w.i][w.j].klingons + klump <= MAXKLQUAD:
5379 game.state.galaxy[w.i][w.j].klingons += int(klump)
5382 # Position Klingon Commander Ships
5383 for i in range(game.incom):
5385 w = randplace(GALSIZE)
5386 if not welcoming(w) or w in game.state.kcmdr:
5388 if (game.state.galaxy[w.i][w.j].klingons or withprob(0.25)):
5390 game.state.galaxy[w.i][w.j].klingons += 1
5391 game.state.kcmdr.append(w)
5392 # Locate planets in galaxy
5393 for i in range(game.inplan):
5395 w = randplace(GALSIZE)
5396 if game.state.galaxy[w.i][w.j].planet == None:
5400 new.crystals = "absent"
5401 if (game.options & OPTION_WORLDS) and i < NINHAB:
5402 new.pclass = "M" # All inhabited planets are class M
5403 new.crystals = "absent"
5405 new.name = systnames[i]
5406 new.inhabited = True
5408 new.pclass = ("M", "N", "O")[randrange(0, 3)]
5410 new.crystals = "present"
5411 new.known = "unknown"
5412 new.inhabited = False
5413 game.state.galaxy[w.i][w.j].planet = new
5414 game.state.planets.append(new)
5416 for i in range(game.state.nromrem):
5417 w = randplace(GALSIZE)
5418 game.state.galaxy[w.i][w.j].romulans += 1
5419 # Place the Super-Commander if needed
5420 if game.state.nscrem > 0:
5422 w = randplace(GALSIZE)
5425 game.state.kscmdr = w
5426 game.state.galaxy[w.i][w.j].klingons += 1
5427 # Initialize times for extraneous events
5428 schedule(FSNOVA, expran(0.5 * game.intime))
5429 schedule(FTBEAM, expran(1.5 * (game.intime / len(game.state.kcmdr))))
5430 schedule(FSNAP, randreal(1.0, 2.0)) # Force an early snapshot
5431 schedule(FBATTAK, expran(0.3*game.intime))
5433 if game.state.nscrem:
5434 schedule(FSCMOVE, 0.2777)
5439 if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5440 schedule(FDISTR, expran(1.0 + game.intime))
5445 # Place thing (in tournament game, we don't want one!)
5446 # New in SST2K: never place the Thing near a starbase.
5447 # This makes sense and avoids a special case in the old code.
5449 if game.tourn is None:
5451 thing = randplace(GALSIZE)
5452 if thing not in game.state.baseq:
5455 game.state.snap = False
5456 if game.skill == SKILL_NOVICE:
5457 prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5458 prout(_("a deadly Klingon invasion force. As captain of the United"))
5459 prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5460 prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5461 prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5462 prout(_("your mission. As you proceed you may be given more time."))
5464 prout(_("You will have %d supporting starbases.") % (game.inbase))
5465 proutn(_("Starbase locations- "))
5467 prout(_("Stardate %d.") % int(game.state.date))
5469 prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5470 prout(_("An unknown number of Romulans."))
5471 if game.state.nscrem:
5472 prout(_("And one (GULP) Super-Commander."))
5473 prout(_("%d stardates.") % int(game.intime))
5474 proutn(_("%d starbases in ") % game.inbase)
5475 for i in range(game.inbase):
5476 proutn(`game.state.baseq[i]`)
5479 proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5480 proutn(_(" Sector %s") % game.sector)
5482 prout(_("Good Luck!"))
5483 if game.state.nscrem:
5484 prout(_(" YOU'LL NEED IT."))
5487 if len(game.enemies) - (thing == game.quadrant) - (game.tholian != None):
5489 if game.neutz: # bad luck to start in a Romulan Neutral Zone
5490 attack(torps_ok=False)
5493 "Choose your game type."
5495 game.tourn = game.length = 0
5497 game.skill = SKILL_NONE
5498 if not scanner.inqueue: # Can start with command line options
5499 proutn(_("Would you like a regular, tournament, or saved game? "))
5501 if scanner.sees("tournament"):
5502 while scanner.next() == "IHEOL":
5503 proutn(_("Type in tournament number-"))
5504 if scanner.real == 0:
5506 continue # We don't want a blank entry
5507 game.tourn = int(round(scanner.real))
5508 random.seed(scanner.real)
5510 logfp.write("# random.seed(%d)\n" % scanner.real)
5512 if scanner.sees("saved") or scanner.sees("frozen"):
5516 if game.passwd == None:
5518 if not game.alldone:
5519 game.thawed = True # No plaque if not finished
5523 if scanner.sees("regular"):
5525 proutn(_("What is \"%s\"?") % scanner.token)
5527 while game.length==0 or game.skill==SKILL_NONE:
5528 if scanner.next() == "IHALPHA":
5529 if scanner.sees("short"):
5531 elif scanner.sees("medium"):
5533 elif scanner.sees("long"):
5535 elif scanner.sees("novice"):
5536 game.skill = SKILL_NOVICE
5537 elif scanner.sees("fair"):
5538 game.skill = SKILL_FAIR
5539 elif scanner.sees("good"):
5540 game.skill = SKILL_GOOD
5541 elif scanner.sees("expert"):
5542 game.skill = SKILL_EXPERT
5543 elif scanner.sees("emeritus"):
5544 game.skill = SKILL_EMERITUS
5546 proutn(_("What is \""))
5547 proutn(scanner.token)
5552 proutn(_("Would you like a Short, Medium, or Long game? "))
5553 elif game.skill == SKILL_NONE:
5554 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5555 # Choose game options -- added by ESR for SST2K
5556 if scanner.next() != "IHALPHA":
5558 proutn(_("Choose your game style (plain, almy, fancy or just press enter): "))
5560 if scanner.sees("plain"):
5561 # Approximates the UT FORTRAN version.
5562 game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5563 game.options |= OPTION_PLAIN
5564 elif scanner.sees("almy"):
5565 # Approximates Tom Almy's version.
5566 game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
5567 game.options |= OPTION_ALMY
5568 elif scanner.sees("fancy") or scanner.sees("\n"):
5570 elif len(scanner.token):
5571 proutn(_("What is \"%s\"?") % scanner.token)
5572 game.options &=~ OPTION_COLOR
5574 if game.passwd == "debug":
5576 prout("=== Debug mode enabled.")
5577 # Use parameters to generate initial values of things
5578 game.damfac = 0.5 * game.skill
5579 game.inbase = randrange(BASEMIN, BASEMAX+1)
5581 if game.options & OPTION_PLANETS:
5582 game.inplan += randrange(MAXUNINHAB/2, MAXUNINHAB+1)
5583 if game.options & OPTION_WORLDS:
5584 game.inplan += int(NINHAB)
5585 game.state.nromrem = game.inrom = randrange(2 *game.skill)
5586 game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
5587 game.state.remtime = 7.0 * game.length
5588 game.intime = game.state.remtime
5589 game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*randreal())*game.skill*0.1+.15)
5590 game.incom = min(MINCMDR, int(game.skill + 0.0625*game.inkling*randreal()))
5591 game.state.remres = (game.inkling+4*game.incom)*game.intime
5592 game.inresor = game.state.remres
5593 if game.inkling > 50:
5594 game.state.inbase += 1
5597 def dropin(iquad=None):
5598 "Drop a feature on a random dot in the current quadrant."
5600 w = randplace(QUADSIZE)
5601 if game.quad[w.i][w.j] == '.':
5603 if iquad is not None:
5604 game.quad[w.i][w.j] = iquad
5608 "Update our alert status."
5609 game.condition = "green"
5610 if game.energy < 1000.0:
5611 game.condition = "yellow"
5612 if game.state.galaxy[game.quadrant.i][game.quadrant.j].klingons or game.state.galaxy[game.quadrant.i][game.quadrant.j].romulans:
5613 game.condition = "red"
5615 game.condition="dead"
5618 "Drop new Klingon into current quadrant."
5619 return enemy('K', loc=dropin(), power=randreal(300,450)+25.0*game.skill)
5622 "Set up a new state of quadrant, for when we enter or re-enter it."
5625 game.neutz = game.inorbit = game.landed = False
5626 game.ientesc = game.iseenit = False
5627 # Create a blank quadrant
5628 game.quad = fill2d(QUADSIZE, lambda i, j: '.')
5630 # Attempt to escape Super-commander, so tbeam back!
5633 q = game.state.galaxy[game.quadrant.i][game.quadrant.j]
5634 # cope with supernova
5637 game.klhere = q.klingons
5638 game.irhere = q.romulans
5640 game.quad[game.sector.i][game.sector.j] = game.ship
5643 # Position ordinary Klingons
5644 for i in range(game.klhere):
5646 # If we need a commander, promote a Klingon
5647 for cmdr in game.state.kcmdr:
5648 if cmdr == game.quadrant:
5649 e = game.enemies[game.klhere-1]
5650 game.quad[e.location.i][e.location.j] = 'C'
5651 e.power = randreal(950,1350) + 50.0*game.skill
5653 # If we need a super-commander, promote a Klingon
5654 if game.quadrant == game.state.kscmdr:
5656 game.quad[e.location.i][e.location.j] = 'S'
5657 e.power = randreal(1175.0, 1575.0) + 125.0*game.skill
5658 game.iscate = (game.state.remkl > 1)
5659 # Put in Romulans if needed
5660 for i in range(q.romulans):
5661 enemy('R', loc=dropin(), power=randreal(400.0,850.0)+50.0*game.skill)
5662 # If quadrant needs a starbase, put it in
5664 game.base = dropin('B')
5665 # If quadrant needs a planet, put it in
5667 game.iplnet = q.planet
5668 if not q.planet.inhabited:
5669 game.plnet = dropin('P')
5671 game.plnet = dropin('@')
5672 # Check for condition
5675 if game.irhere > 0 and game.klhere == 0:
5677 if not damaged(DRADIO):
5679 prout(_("LT. Uhura- \"Captain, an urgent message."))
5680 prout(_(" I'll put it on audio.\" CLICK"))
5682 prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
5683 prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
5684 # Put in THING if needed
5685 if thing == game.quadrant:
5686 enemy(type='?', loc=dropin(),
5687 power=randreal(6000,6500.0)+250.0*game.skill)
5688 if not damaged(DSRSENS):
5690 prout(_("Mr. Spock- \"Captain, this is most unusual."))
5691 prout(_(" Please examine your short-range scan.\""))
5692 # Decide if quadrant needs a Tholian; lighten up if skill is low
5693 if game.options & OPTION_THOLIAN:
5694 if (game.skill < SKILL_GOOD and withprob(0.02)) or \
5695 (game.skill == SKILL_GOOD and withprob(0.05)) or \
5696 (game.skill > SKILL_GOOD and withprob(0.08)):
5699 w.i = withprob(0.5) * (QUADSIZE-1)
5700 w.j = withprob(0.5) * (QUADSIZE-1)
5701 if game.quad[w.i][w.j] == '.':
5703 game.tholian = enemy(type='T', loc=w,
5704 power=randrange(100, 500) + 25.0*game.skill)
5705 # Reserve unoccupied corners
5706 if game.quad[0][0]=='.':
5707 game.quad[0][0] = 'X'
5708 if game.quad[0][QUADSIZE-1]=='.':
5709 game.quad[0][QUADSIZE-1] = 'X'
5710 if game.quad[QUADSIZE-1][0]=='.':
5711 game.quad[QUADSIZE-1][0] = 'X'
5712 if game.quad[QUADSIZE-1][QUADSIZE-1]=='.':
5713 game.quad[QUADSIZE-1][QUADSIZE-1] = 'X'
5714 game.enemies.sort(lambda x, y: cmp(x.kdist, y.kdist))
5715 # And finally the stars
5716 for i in range(q.stars):
5718 # Put in a few black holes
5719 for i in range(1, 3+1):
5722 # Take out X's in corners if Tholian present
5724 if game.quad[0][0]=='X':
5725 game.quad[0][0] = '.'
5726 if game.quad[0][QUADSIZE-1]=='X':
5727 game.quad[0][QUADSIZE-1] = '.'
5728 if game.quad[QUADSIZE-1][0]=='X':
5729 game.quad[QUADSIZE-1][0] = '.'
5730 if game.quad[QUADSIZE-1][QUADSIZE-1]=='X':
5731 game.quad[QUADSIZE-1][QUADSIZE-1] = '.'
5734 "Set the self-destruct password."
5735 if game.options & OPTION_PLAIN:
5738 proutn(_("Please type in a secret password- "))
5740 game.passwd = scanner.token
5741 if game.passwd != None:
5746 game.passwd += chr(ord('a')+randrange(26))
5748 # Code from sst.c begins here
5751 "SRSCAN": OPTION_TTY,
5752 "STATUS": OPTION_TTY,
5753 "REQUEST": OPTION_TTY,
5754 "LRSCAN": OPTION_TTY,
5767 "SENSORS": OPTION_PLANETS,
5768 "ORBIT": OPTION_PLANETS,
5769 "TRANSPORT": OPTION_PLANETS,
5770 "MINE": OPTION_PLANETS,
5771 "CRYSTALS": OPTION_PLANETS,
5772 "SHUTTLE": OPTION_PLANETS,
5773 "PLANETS": OPTION_PLANETS,
5778 "PROBE": OPTION_PROBE,
5780 "FREEZE": 0, # Synonym for SAVE
5786 "SOS": 0, # Synonym for MAYDAY
5787 "CALL": 0, # Synonym for MAYDAY
5793 "Generate a list of legal commands."
5794 prout(_("LEGAL COMMANDS ARE:"))
5796 for key in commands:
5797 if not commands[key] or (commands[key] & game.options):
5798 proutn("%-12s " % key)
5800 if emitted % 5 == 4:
5805 "Browse on-line help."
5806 key = scanner.next()
5809 setwnd(prompt_window)
5810 proutn(_("Help on what command? "))
5811 key = scanner.next()
5812 setwnd(message_window)
5815 if scanner.token in commands or scanner.token == "ABBREV":
5822 cmd = scanner.token.upper()
5824 fp = open(SSTDOC, "r")
5827 fp = open(DOC_NAME, "r")
5829 prout(_("Spock- \"Captain, that information is missing from the"))
5830 proutn(_(" computer. You need to find "))
5832 prout(_(" and put it in the"))
5833 proutn(_(" current directory or to "))
5836 # This used to continue: "You need to find SST.DOC and put
5837 # it in the current directory."
5840 linebuf = fp.readline()
5842 prout(_("Spock- \"Captain, there is no information on that command.\""))
5845 if linebuf[0] == '%' and linebuf[1] == '%' and linebuf[2] == ' ':
5846 linebuf = linebuf[3:].strip()
5850 prout(_("Spock- \"Captain, I've found the following information:\""))
5852 while linebuf in fp:
5853 if "******" in linebuf:
5859 "Command-interpretation loop."
5861 setwnd(message_window)
5862 while True: # command loop
5864 while True: # get a command
5866 game.optime = game.justin = False
5868 setwnd(prompt_window)
5871 if scanner.next() == "IHEOL":
5872 if game.options & OPTION_CURSES:
5875 elif scanner.token == "":
5879 setwnd(message_window)
5881 candidates = filter(lambda x: x.startswith(scanner.token.upper()),
5883 if len(candidates) == 1:
5886 elif candidates and not (game.options & OPTION_PLAIN):
5887 prout("Commands with prefix '%s': %s" % (scanner.token, " ".join(candidates)))
5891 if cmd == "SRSCAN": # srscan
5893 elif cmd == "STATUS": # status
5895 elif cmd == "REQUEST": # status request
5897 elif cmd == "LRSCAN": # long range scan
5898 lrscan(silent=False)
5899 elif cmd == "PHASERS": # phasers
5903 elif cmd == "TORPEDO": # photon torpedos
5907 elif cmd == "MOVE": # move under warp
5908 warp(course=None, involuntary=False)
5909 elif cmd == "SHIELDS": # shields
5910 doshield(shraise=False)
5913 game.shldchg = False
5914 elif cmd == "DOCK": # dock at starbase
5917 attack(torps_ok=False)
5918 elif cmd == "DAMAGES": # damage reports
5920 elif cmd == "CHART": # chart
5922 elif cmd == "IMPULSE": # impulse
5924 elif cmd == "REST": # rest
5928 elif cmd == "WARP": # warp
5930 elif cmd == "SCORE": # score
5932 elif cmd == "SENSORS": # sensors
5934 elif cmd == "ORBIT": # orbit
5938 elif cmd == "TRANSPORT": # transport "beam"
5940 elif cmd == "MINE": # mine
5944 elif cmd == "CRYSTALS": # crystals
5948 elif cmd == "SHUTTLE": # shuttle
5952 elif cmd == "PLANETS": # Planet list
5954 elif cmd == "REPORT": # Game Report
5956 elif cmd == "COMPUTER": # use COMPUTER!
5958 elif cmd == "COMMANDS":
5960 elif cmd == "EMEXIT": # Emergency exit
5961 clrscr() # Hide screen
5962 freeze(True) # forced save
5963 raise SysExit,1 # And quick exit
5964 elif cmd == "PROBE":
5965 probe() # Launch probe
5968 elif cmd == "ABANDON": # Abandon Ship
5970 elif cmd == "DESTRUCT": # Self Destruct
5972 elif cmd == "SAVE": # Save Game
5975 if game.skill > SKILL_GOOD:
5976 prout(_("WARNING--Saved games produce no plaques!"))
5977 elif cmd == "DEATHRAY": # Try a desparation measure
5981 elif cmd == "DEBUGCMD": # What do we want for debug???
5983 elif cmd == "MAYDAY": # Call for help
5988 game.alldone = True # quit the game
5993 break # Game has ended
5994 if game.optime != 0.0:
5997 break # Events did us in
5998 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6001 if hitme and not game.justin:
6002 attack(torps_ok=True)
6005 if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
6016 "Emit the name of an enemy or feature."
6017 if type == 'R': s = _("Romulan")
6018 elif type == 'K': s = _("Klingon")
6019 elif type == 'C': s = _("Commander")
6020 elif type == 'S': s = _("Super-commander")
6021 elif type == '*': s = _("Star")
6022 elif type == 'P': s = _("Planet")
6023 elif type == 'B': s = _("Starbase")
6024 elif type == ' ': s = _("Black hole")
6025 elif type == 'T': s = _("Tholian")
6026 elif type == '#': s = _("Tholian web")
6027 elif type == '?': s = _("Stranger")
6028 elif type == '@': s = _("Inhabited World")
6029 else: s = "Unknown??"
6032 def crmena(stars, enemy, loctype, w):
6033 "Emit the name of an enemy and his location."
6037 buf += cramen(enemy) + _(" at ")
6038 if loctype == "quadrant":
6039 buf += _("Quadrant ")
6040 elif loctype == "sector":
6045 "Emit our ship name."
6046 return{'E':_("Enterprise"),'F':_("Faerie Queene")}.get(game.ship,"Ship???")
6049 "Emit a line of stars"
6050 prouts("******************************************************")
6054 return -avrage*math.log(1e-7 + randreal())
6056 def randplace(size):
6057 "Choose a random location."
6059 w.i = randrange(size)
6060 w.j = randrange(size)
6070 # Get a token from the user
6073 # Fill the token quue if nothing here
6074 while not self.inqueue:
6076 if curwnd==prompt_window:
6078 setwnd(message_window)
6085 self.inqueue = line.lstrip().split() + ["\n"]
6086 # From here on in it's all looking at the queue
6087 self.token = self.inqueue.pop(0)
6088 if self.token == "\n":
6092 self.real = float(self.token)
6093 self.type = "IHREAL"
6098 self.token = self.token.lower()
6099 self.type = "IHALPHA"
6102 def append(self, tok):
6103 self.inqueue.append(tok)
6104 def push(self, tok):
6105 self.inqueue.insert(0, tok)
6109 # Demand input for next scan
6111 self.real = self.token = None
6113 # compares s to item and returns true if it matches to the length of s
6114 return s.startswith(self.token)
6116 # Round token value to nearest integer
6117 return int(round(scanner.real))
6121 if scanner.type != "IHREAL":
6124 s.i = scanner.int()-1
6126 if scanner.type != "IHREAL":
6129 s.j = scanner.int()-1
6132 return "<sstcanner: token=%s, type=%s, queue=%s>" % (scanner.token, scanner.type, scanner.inqueue)
6135 "Yes-or-no confirmation."
6139 if scanner.token == 'y':
6141 if scanner.token == 'n':
6144 proutn(_("Please answer with \"y\" or \"n\": "))
6147 "Complain about unparseable input."
6150 prout(_("Beg your pardon, Captain?"))
6153 "Access to the internals for debugging."
6154 proutn("Reset levels? ")
6156 if game.energy < game.inenrg:
6157 game.energy = game.inenrg
6158 game.shield = game.inshld
6159 game.torps = game.intorps
6160 game.lsupres = game.inlsr
6161 proutn("Reset damage? ")
6163 for i in range(NDEVICES):
6164 if game.damage[i] > 0.0:
6165 game.damage[i] = 0.0
6166 proutn("Toggle debug flag? ")
6170 prout("Debug output ON")
6172 prout("Debug output OFF")
6173 proutn("Cause selective damage? ")
6175 for i in range(NDEVICES):
6176 proutn("Kill %s?" % device[i])
6178 key = scanner.next()
6179 if key == "IHALPHA" and scanner.sees("y"):
6180 game.damage[i] = 10.0
6181 proutn("Examine/change events? ")
6186 FSNOVA: "Supernova ",
6189 FBATTAK: "Base Attack ",
6190 FCDBAS: "Base Destroy ",
6191 FSCMOVE: "SC Move ",
6192 FSCDBAS: "SC Base Destroy ",
6193 FDSPROB: "Probe Move ",
6194 FDISTR: "Distress Call ",
6195 FENSLV: "Enslavement ",
6196 FREPRO: "Klingon Build ",
6198 for i in range(1, NEVENTS):
6201 proutn("%.2f" % (scheduled(i)-game.state.date))
6202 if i == FENSLV or i == FREPRO:
6204 proutn(" in %s" % ev.quadrant)
6209 key = scanner.next()
6213 elif key == "IHREAL":
6214 ev = schedule(i, scanner.real)
6215 if i == FENSLV or i == FREPRO:
6217 proutn("In quadrant- ")
6218 key = scanner.next()
6219 # "IHEOL" says to leave coordinates as they are
6222 prout("Event %d canceled, no x coordinate." % (i))
6225 w.i = int(round(scanner.real))
6226 key = scanner.next()
6228 prout("Event %d canceled, no y coordinate." % (i))
6231 w.j = int(round(scanner.real))
6234 proutn("Induce supernova here? ")
6236 game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova = True
6239 if __name__ == '__main__':
6240 import getopt, socket
6242 global line, thing, game, idebug
6248 game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
6249 if os.getenv("TERM"):
6250 game.options |= OPTION_CURSES
6252 game.options |= OPTION_TTY
6253 seed = int(time.time())
6254 (options, arguments) = getopt.getopt(sys.argv[1:], "r:s:tx")
6255 for (switch, val) in options:
6258 replayfp = open(val, "r")
6260 sys.stderr.write("sst: can't open replay file %s\n" % val)
6263 line = replayfp.readline().strip()
6264 (leader, key, seed) = line.split()
6266 sys.stderr.write("sst2k: seed set to %s\n" % seed)
6267 line = replayfp.readline().strip()
6268 arguments += line.split()[2:]
6270 sys.stderr.write("sst: replay file %s is ill-formed\n"% val)
6272 game.options |= OPTION_TTY
6273 game.options &=~ OPTION_CURSES
6274 elif switch == '-s':
6276 elif switch == '-t':
6277 game.options |= OPTION_TTY
6278 game.options &=~ OPTION_CURSES
6279 elif switch == '-x':
6282 sys.stderr.write("usage: sst [-t] [-x] [startcommand...].\n")
6284 # where to save the input in case of bugs
6285 if "TMPDIR" in os.environ:
6286 tmpdir = os.environ['TMPDIR']
6290 logfp = open(os.path.join(tmpdir, "sst-input.log"), "w")
6292 sys.stderr.write("sst: warning, can't open logfile\n")
6295 logfp.write("# seed %s\n" % seed)
6296 logfp.write("# options %s\n" % " ".join(arguments))
6297 logfp.write("# recorded by %s@%s on %s\n" % \
6298 (getpass.getuser(),socket.gethostname(),time.ctime()))
6300 scanner = sstscanner()
6301 map(scanner.append, arguments)
6304 while True: # Play a game
6305 setwnd(fullscreen_window)
6311 game.alldone = False
6317 if game.tourn and game.alldone:
6318 proutn(_("Do you want your score recorded?"))
6324 proutn(_("Do you want to play again? "))
6328 prout(_("May the Great Bird of the Galaxy roost upon your home planet."))
6332 except KeyboardInterrupt: