setup.py code added to Python translation.
[super-star-trek.git] / src / sst.py
1 """
2 sst.py =-- Super Star Trek in Python
3
4 This code is a Python translation of a C translation of a FORTRAN original.
5 The FORTRANness still shows in many ways, notably the use of 1-origin index
6 an a lot of parallel arrays where a more modern language would use structures
7 or objects.
8 """
9 import os, sys, math, curses, time, atexit, readline, cPickle, random
10
11 SSTDOC = "/usr/share/doc/sst/sst.doc"
12
13 # Stub to be replaced
14 def _(str): return str
15
16 PHASEFAC        = 2.0
17 GALSIZE         = 8
18 NINHAB          = (GALSIZE * GALSIZE / 2)
19 MAXUNINHAB      = 10
20 PLNETMAX        = (NINHAB + MAXUNINHAB)
21 QUADSIZE        = 10
22 BASEMAX         = (GALSIZE * GALSIZE / 12)
23 MAXKLGAME       = 127
24 MAXKLQUAD       = 9
25 FULLCREW        = 428   # BSD Trek was 387, that's wrong 
26 FOREVER         = 1e30
27
28 # These functions hide the difference between 0-origin and 1-origin addressing.
29 def VALID_QUADRANT(x, y):       return ((x)>=1 and (x)<=GALSIZE and (y)>=1 and (y)<=GALSIZE)
30 def VALID_SECTOR(x, y): return ((x)>=1 and (x)<=QUADSIZE and (y)>=1 and (y)<=QUADSIZE)
31
32 def square(i):          return ((i)*(i))
33 def distance(c1, c2):   return math.sqrt(square(c1.x - c2.x) + square(c1.y - c2.y))
34 def invalidate(w):      w.x = w.y = 0
35 def is_valid(w):        return (w.x != 0 and w.y != 0)
36
37 # How to represent features
38 IHR = 'R',
39 IHK = 'K',
40 IHC = 'C',
41 IHS = 'S',
42 IHSTAR = '*',
43 IHP = 'P',
44 IHW = '@',
45 IHB = 'B',
46 IHBLANK = ' ',
47 IHDOT = '.',
48 IHQUEST = '?',
49 IHE = 'E',
50 IHF = 'F',
51 IHT = 'T',
52 IHWEB = '#',
53 IHMATER0 = '-',
54 IHMATER1 = 'o',
55 IHMATER2 = '0'
56
57 class coord:
58     def __init(self, x=None, y=None):
59         self.x = x
60         self.y = y
61     def invalidate(self):
62         self.x = self.y = None
63     def is_valid(self):
64         return self.x != None and self.y != None
65     def __eq__(self, other):
66         return self.x == other.y and self.x == other.y
67     def __add__(self, other):
68         return coord(self.x+self.x, self.y+self.y)
69     def __sub__(self, other):
70         return coord(self.x-self.x, self.y-self.y)
71     def distance(self, other):
72         return math.sqrt((self.x - other.x)**2 + (self.y - other.y)**2)
73     def sgn(self):
74         return coord(self.x / abs(x), self.y / abs(y));
75     def __hash__(self):
76         return hash((x, y))
77     def __str__(self):
78         return "%d - %d" % (self.x, self.y)
79
80 class planet:
81     def __init(self):
82         self.name = None        # string-valued if inhabited
83         self.w = coord()        # quadrant located
84         self.pclass = None      # could be ""M", "N", "O", or "destroyed"
85         self.crystals = None    # could be "mined", "present", "absent"
86         self.known = None       # could be "unknown", "known", "shuttle_down"
87         self.inhabited          # is it inhabites?
88     def __str__(self):
89         return self.name
90
91 NOPLANET = None
92 class quadrant:
93     def __init(self):
94         self.stars = None
95         self.planet = None
96         self.starbase = None
97         self.klingons = None
98         self.romulans = None
99         self.supernova = None
100         self.charted = None
101         self.status = None      # Could be "secure", "distressed", "enslaved"
102
103 class page:
104     def __init(self):
105         self.stars = None
106         self.starbase = None
107         self.klingons = None
108
109 class snapshot:
110     def __init(self):
111         self.snap = False       # snapshot taken
112         self.crew = None        # crew complement
113         self.remkl = None       # remaining klingons
114         self.remcom = None      # remaining commanders
115         self.nscrem = None      # remaining super commanders
116         self.rembase = None     # remaining bases
117         self.starkl = None      # destroyed stars
118         self.basekl = None      # destroyed bases
119         self.nromrem = None     # Romulans remaining
120         self.nplankl = None     # destroyed uninhabited planets
121         self.nworldkl = None    # destroyed inhabited planets
122         self.planets = []       # Planet information
123         self.date = None        # stardate
124         self.remres = None      # remaining resources
125         self.remtime = None     # remaining time
126         self.baseq = []         # Base quadrant coordinates
127         for i in range(BASEMAX+1):
128             self.baseq.append(coord())
129         self.kcmdr = []         # Commander quadrant coordinates
130         for i in range(QUADSIZE+1):
131             self.kcmdr.append(coord())
132         self.kscmdr = coord()   # Supercommander quadrant coordinates
133         self.galaxy = []        # The Galaxy (subscript 0 not used)
134         for i in range(GALSIZE+1):
135             self.chart.append([])
136             for j in range(GALSIZE+1):
137                 self.galaxy[i].append(quadrant())
138         self.chart = []         # the starchart (subscript 0 not used)
139         for i in range(GALSIZE+1):
140             self.chart.append([])
141             for j in range(GALSIZE+1):
142                 self.chart[i].append(page())
143
144 class event:
145     def __init__(self):
146         self.date = None        # A real number
147         self.quadrant = None    # A coord structure
148
149 # game options 
150 OPTION_ALL      = 0xffffffff
151 OPTION_TTY      = 0x00000001    # old interface 
152 OPTION_CURSES   = 0x00000002    # new interface 
153 OPTION_IOMODES  = 0x00000003    # cover both interfaces 
154 OPTION_PLANETS  = 0x00000004    # planets and mining 
155 OPTION_THOLIAN  = 0x00000008    # Tholians and their webs 
156 OPTION_THINGY   = 0x00000010    # Space Thingy can shoot back 
157 OPTION_PROBE    = 0x00000020    # deep-space probes 
158 OPTION_SHOWME   = 0x00000040    # bracket Enterprise in chart 
159 OPTION_RAMMING  = 0x00000080    # enemies may ram Enterprise 
160 OPTION_MVBADDY  = 0x00000100    # more enemies can move 
161 OPTION_BLKHOLE  = 0x00000200    # black hole may timewarp you 
162 OPTION_BASE     = 0x00000400    # bases have good shields 
163 OPTION_WORLDS   = 0x00000800    # logic for inhabited worlds 
164 OPTION_PLAIN    = 0x01000000    # user chose plain game 
165 OPTION_ALMY     = 0x02000000    # user chose Almy variant 
166
167 # Define devices 
168 DSRSENS = 0
169 DLRSENS = 1
170 DPHASER = 2
171 DPHOTON = 3
172 DLIFSUP = 4
173 DWARPEN = 5
174 DIMPULS = 6
175 DSHIELD = 7
176 DRADIO  = 0
177 DSHUTTL = 9
178 DCOMPTR = 10
179 DNAVSYS = 11
180 DTRANSP = 12
181 DSHCTRL = 13
182 DDRAY   = 14
183 DDSP    = 15
184 NDEVICES= 16    # Number of devices
185
186 SKILL_NONE      = 0
187 SKILL_NOVICE    = 1
188 SKILL_FAIR      = 2
189 SKILL_GOOD      = 3
190 SKILL_EXPERT    = 4
191 SKILL_EMERITUS  = 5
192
193 def damaged(dev):       return (game.damage[dev] != 0.0)
194 def communicating():    return not damaged(DRADIO) or game.condition=="docked"
195
196 # Define future events 
197 FSPY    = 0     # Spy event happens always (no future[] entry)
198                 # can cause SC to tractor beam Enterprise
199 FSNOVA  = 1     # Supernova
200 FTBEAM  = 2     # Commander tractor beams Enterprise
201 FSNAP   = 3     # Snapshot for time warp
202 FBATTAK = 4     # Commander attacks base
203 FCDBAS  = 5     # Commander destroys base
204 FSCMOVE = 6     # Supercommander moves (might attack base)
205 FSCDBAS = 7     # Supercommander destroys base
206 FDSPROB = 8     # Move deep space probe
207 FDISTR  = 9     # Emit distress call from an inhabited world 
208 FENSLV  = 10    # Inhabited word is enslaved */
209 FREPRO  = 11    # Klingons build a ship in an enslaved system
210 NEVENTS = 12
211
212 #
213 # abstract out the event handling -- underlying data structures will change
214 # when we implement stateful events
215
216 def findevent(evtype):  return game.future[evtype]
217
218 class gamestate:
219     def __init__(self):
220         self.options = None     # Game options
221         self.state = None       # A snapshot structure
222         self.snapsht = None     # Last snapshot taken for time-travel purposes
223         self.quad = [[IHDOT * (QUADSIZE+1)] * (QUADSIZE+1)]     # contents of our quadrant
224         self.kpower = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)]       # enemy energy levels
225         self.kdist = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)]        # enemy distances
226         self.kavgd = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)]        # average distances
227         self.damage = [0.0] * NDEVICES  # damage encountered
228         self.future = [0.0] * NEVENTS   # future events
229         for i in range(NEVENTS):
230             self.future.append(event())
231         self.passwd  = None;            # Self Destruct password
232         self.ks = [[None * (QUADSIZE+1)] * (QUADSIZE+1)]        # enemy sector locations
233         self.quadrant = None    # where we are in the large
234         self.sector = None      # where we are in the small
235         self.tholian = None     # coordinates of Tholian
236         self.base = None        # position of base in current quadrant
237         self.battle = None      # base coordinates being attacked
238         self.plnet = None       # location of planet in quadrant
239         self.probec = None      # current probe quadrant
240         self.gamewon = False    # Finished!
241         self.ididit = False     # action taken -- allows enemy to attack
242         self.alive = False      # we are alive (not killed)
243         self.justin = False     # just entered quadrant
244         self.shldup = False     # shields are up
245         self.shldchg = False    # shield is changing (affects efficiency)
246         self.comhere = False    # commander here
247         self.ishere = False     # super-commander in quadrant
248         self.iscate = False     # super commander is here
249         self.ientesc = False    # attempted escape from supercommander
250         self.ithere = False     # Tholian is here 
251         self.resting = False    # rest time
252         self.icraft = False     # Kirk in Galileo
253         self.landed = False     # party on planet (true), on ship (false)
254         self.alldone = False    # game is now finished
255         self.neutz = False      # Romulan Neutral Zone
256         self.isarmed = False    # probe is armed
257         self.inorbit = False    # orbiting a planet
258         self.imine = False      # mining
259         self.icrystl = False    # dilithium crystals aboard
260         self.iseenit = False    # seen base attack report
261         self.thawed = False     # thawed game
262         self.condition = None   # "green", "yellow", "red", "docked", "dead"
263         self.iscraft = None     # "onship", "offship", "removed"
264         self.skill = None       # Player skill level
265         self.inkling = 0        # initial number of klingons
266         self.inbase = 0         # initial number of bases
267         self.incom = 0          # initial number of commanders
268         self.inscom = 0         # initial number of commanders
269         self.inrom = 0          # initial number of commanders
270         self.instar = 0         # initial stars
271         self.intorps = 0        # initial/max torpedoes
272         self.torps = 0          # number of torpedoes
273         self.ship = 0           # ship type -- 'E' is Enterprise
274         self.abandoned = 0      # count of crew abandoned in space
275         self.length = 0         # length of game
276         self.klhere = 0         # klingons here
277         self.casual = 0         # causalties
278         self.nhelp = 0          # calls for help
279         self.nkinks = 0         # count of energy-barrier crossings
280         self.iplnet = 0         # planet # in quadrant
281         self.inplan = 0         # initial planets
282         self.nenhere = 0        # number of enemies in quadrant
283         self.irhere = 0         # Romulans in quadrant
284         self.isatb = 0          # =1 if super commander is attacking base
285         self.tourn = 0          # tournament number
286         self.proben = 0         # number of moves for probe
287         self.nprobes = 0        # number of probes available
288         self.inresor = 0.0      # initial resources
289         self.intime = 0.0       # initial time
290         self.inenrg = 0.0       # initial/max energy
291         self.inshld = 0.0       # initial/max shield
292         self.inlsr = 0.0        # initial life support resources
293         self.indate = 0.0       # initial date
294         self.energy = 0.0       # energy level
295         self.shield = 0.0       # shield level
296         self.warpfac = 0.0      # warp speed
297         self.wfacsq = 0.0       # squared warp factor
298         self.lsupres = 0.0      # life support reserves
299         self.dist = 0.0         # movement distance
300         self.direc = 0.0        # movement direction
301         self.optime = 0.0       # time taken by current operation
302         self.docfac = 0.0       # repair factor when docking (constant?)
303         self.damfac = 0.0       # damage factor
304         self.lastchart = 0.0    # time star chart was last updated
305         self.cryprob = 0.0      # probability that crystal will work
306         self.probex = 0.0       # location of probe
307         self.probey = 0.0       #
308         self.probeinx = 0.0     # probe x,y increment
309         self.probeiny = 0.0     #
310         self.height = 0.0       # height of orbit around planet
311     def recompute(self):
312         # Stas thinks this should be (C expression): 
313         # game.state.remkl + game.state.remcom > 0 ?
314         #       game.state.remres/(game.state.remkl + 4*game.state.remcom) : 99
315         # He says the existing expression is prone to divide-by-zero errors
316         # after killing the last klingon when score is shown -- perhaps also
317         # if the only remaining klingon is SCOM.
318         game.state.remtime = game.state.remres/(game.state.remkl + 4*game.state.remcom)
319 # From enumerated type 'feature'
320 IHR = 'R'
321 IHK = 'K'
322 IHC = 'C'
323 IHS = 'S'
324 IHSTAR = '*'
325 IHP = 'P'
326 IHW = '@'
327 IHB = 'B'
328 IHBLANK = ' '
329 IHDOT = '.'
330 IHQUEST = '?'
331 IHE = 'E'
332 IHF = 'F'
333 IHT = 'T'
334 IHWEB = '#'
335 IHMATER0 = '-'
336 IHMATER1 = 'o'
337 IHMATER2 = '0'
338
339
340 # From enumerated type 'FINTYPE'
341 FWON = 0
342 FDEPLETE = 1
343 FLIFESUP = 2
344 FNRG = 3
345 FBATTLE = 4
346 FNEG3 = 5
347 FNOVA = 6
348 FSNOVAED = 7
349 FABANDN = 8
350 FDILITHIUM = 9
351 FMATERIALIZE = 10
352 FPHASER = 11
353 FLOST = 12
354 FMINING = 13
355 FDPLANET = 14
356 FPNOVA = 15
357 FSSC = 16
358 FSTRACTOR = 17
359 FDRAY = 18
360 FTRIBBLE = 19
361 FHOLE = 20
362 FCREW = 21
363
364 # From enumerated type 'COLORS'
365 DEFAULT = 0
366 BLACK = 1
367 BLUE = 2
368 GREEN = 3
369 CYAN = 4
370 RED = 5
371 MAGENTA = 6
372 BROWN = 7
373 LIGHTGRAY = 8
374 DARKGRAY = 9
375 LIGHTBLUE = 10
376 LIGHTGREEN = 11
377 LIGHTCYAN = 12
378 LIGHTRED = 13
379 LIGHTMAGENTA = 14
380 YELLOW = 15
381 WHITE = 16
382
383 # Code from ai.c begins here
384
385 def tryexit(look, ienm, loccom, irun):
386     # a bad guy attempts to bug out 
387     iq = coord()
388     iq.x = game.quadrant.x+(look.x+(QUADSIZE-1))/QUADSIZE - 1
389     iq.y = game.quadrant.y+(look.y+(QUADSIZE-1))/QUADSIZE - 1
390     if not VALID_QUADRANT(iq.x,iq.y) or \
391         game.state.galaxy[iq.x][iq.y].supernova or \
392         game.state.galaxy[iq.x][iq.y].klingons > MAXKLQUAD-1:
393         return False; # no can do -- neg energy, supernovae, or >MAXKLQUAD-1 Klingons 
394     if ienm == IHR:
395         return False; # Romulans cannot escape! 
396     if not irun:
397         # avoid intruding on another commander's territory 
398         if ienm == IHC:
399             for n in range(1, game.state.remcom+1):
400                 if game.state.kcmdr[n] == iq:
401                     return False
402             # refuse to leave if currently attacking starbase 
403             if game.battle == game.quadrant:
404                 return False
405         # don't leave if over 1000 units of energy 
406         if game.kpower[loccom] > 1000.0:
407             return False
408     # print escape message and move out of quadrant.
409     # we know this if either short or long range sensors are working
410     if not damaged(DSRSENS) or not damaged(DLRSENS) or \
411         game.condition == docked:
412         crmena(True, ienm, "sector", game.ks[loccom])
413         prout(_(" escapes to Quadrant %s (and regains strength).") % q)
414     # handle local matters related to escape 
415     game.quad[game.ks[loccom].x][game.ks[loccom].y] = IHDOT
416     game.ks[loccom] = game.ks[game.nenhere]
417     game.kavgd[loccom] = game.kavgd[game.nenhere]
418     game.kpower[loccom] = game.kpower[game.nenhere]
419     game.kdist[loccom] = game.kdist[game.nenhere]
420     game.klhere -= 1
421     game.nenhere -= 1
422     if game.condition != docked:
423         newcnd()
424     # Handle global matters related to escape 
425     game.state.galaxy[game.quadrant.x][game.quadrant.y].klingons -= 1
426     game.state.galaxy[iq.x][iq.y].klingons += 1
427     if ienm==IHS:
428         game.ishere = False
429         game.iscate = False
430         game.ientesc = False
431         game.isatb = 0
432         schedule(FSCMOVE, 0.2777)
433         unschedule(FSCDBAS)
434         game.state.kscmdr=iq
435     else:
436         for n in range(1, game.state.remcom+1):
437             if game.state.kcmdr[n] == game.quadrant:
438                 game.state.kcmdr[n]=iq
439                 break
440         game.comhere = False
441     return True; # success 
442
443 #
444 # The bad-guy movement algorithm:
445
446 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
447 # If both are operating full strength, force is 1000. If both are damaged,
448 # force is -1000. Having shields down subtracts an additional 1000.
449
450 # 2. Enemy has forces equal to the energy of the attacker plus
451 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
452 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
453
454 # Attacker Initial energy levels (nominal):
455 # Klingon   Romulan   Commander   Super-Commander
456 # Novice    400        700        1200        
457 # Fair      425        750        1250
458 # Good      450        800        1300        1750
459 # Expert    475        850        1350        1875
460 # Emeritus  500        900        1400        2000
461 # VARIANCE   75        200         200         200
462
463 # Enemy vessels only move prior to their attack. In Novice - Good games
464 # only commanders move. In Expert games, all enemy vessels move if there
465 # is a commander present. In Emeritus games all enemy vessels move.
466
467 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
468 # forces are 1000 greater than Enterprise.
469
470 # Agressive action on average cuts the distance between the ship and
471 # the enemy to 1/4 the original.
472
473 # 4.  At lower energy advantage, movement units are proportional to the
474 # advantage with a 650 advantage being to hold ground, 800 to move forward
475 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
476
477 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
478 # retreat, especially at high skill levels.
479
480 # 5.  Motion is limited to skill level, except for SC hi-tailing it out.
481
482
483 def movebaddy(com, loccom, ienm):
484     # tactical movement for the bad guys 
485     next = coord(); look = coord()
486     irun = False
487     # This should probably be just game.comhere + game.ishere 
488     if game.skill >= SKILL_EXPERT:
489         nbaddys = ((game.comhere*2 + game.ishere*2+game.klhere*1.23+game.irhere*1.5)/2.0)
490     else:
491         nbaddys = game.comhere + game.ishere
492
493     dist1 = game.kdist[loccom]
494     mdist = int(dist1 + 0.5); # Nearest integer distance 
495
496     # If SC, check with spy to see if should hi-tail it 
497     if ienm==IHS and \
498         (game.kpower[loccom] <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
499         irun = True
500         motion = -QUADSIZE
501     else:
502         # decide whether to advance, retreat, or hold position 
503         forces = game.kpower[loccom]+100.0*game.nenhere+400*(nbaddys-1)
504         if not game.shldup:
505             forces += 1000; # Good for enemy if shield is down! 
506         if not damaged(DPHASER) or not damaged(DPHOTON):
507             if damaged(DPHASER): # phasers damaged 
508                 forces += 300.0
509             else:
510                 forces -= 0.2*(game.energy - 2500.0)
511             if damaged(DPHOTON): # photon torpedoes damaged 
512                 forces += 300.0
513             else:
514                 forces -= 50.0*game.torps
515         else:
516             # phasers and photon tubes both out! 
517             forces += 1000.0
518         motion = 0
519         if forces <= 1000.0 and game.condition != "docked": # Typical situation 
520             motion = ((forces+200.0*Rand())/150.0) - 5.0
521         else:
522             if forces > 1000.0: # Very strong -- move in for kill 
523                 motion = (1.0-square(Rand()))*dist1 + 1.0
524             if game.condition=="docked" and (game.options & OPTION_BASE): # protected by base -- back off ! 
525                 motion -= game.skill*(2.0-square(Rand()))
526         if idebug:
527             proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
528         # don't move if no motion 
529         if motion==0:
530             return
531         # Limit motion according to skill 
532         if abs(motion) > game.skill:
533             if motion < 0:
534                 motion = -game.skill
535             else:
536                 motion = game.skill
537     # calculate preferred number of steps 
538     if motion < 0:
539         msteps = -motion
540     else:
541         msteps = motion
542     if motion > 0 and nsteps > mdist:
543         nsteps = mdist; # don't overshoot 
544     if nsteps > QUADSIZE:
545         nsteps = QUADSIZE; # This shouldn't be necessary 
546     if nsteps < 1:
547         nsteps = 1; # This shouldn't be necessary 
548     if idebug:
549         proutn("NSTEPS = %d:" % nsteps)
550     # Compute preferred values of delta X and Y 
551     mx = game.sector.x - com.x
552     my = game.sector.y - com.y
553     if 2.0 * abs(mx) < abs(my):
554         mx = 0
555     if 2.0 * abs(my) < abs(game.sector.x-com.x):
556         my = 0
557     if mx != 0:
558         if mx*motion < 0:
559             mx = -1
560         else:
561             mx = 1
562     if my != 0:
563         if my*motion < 0:
564             my = -1
565         else:
566             my = 1
567     next = com
568     # main move loop 
569     for ll in range(nsteps):
570         if idebug:
571             proutn(" %d" % (ll+1))
572         # Check if preferred position available 
573         look.x = next.x + mx
574         look.y = next.y + my
575         if mx < 0:
576             krawlx = 1
577         else:
578             krawlx = -1
579         if my < 0:
580             krawly = 1
581         else:
582             krawly = -1
583         success = False
584         attempts = 0; # Settle mysterious hang problem 
585         while attempts < 20 and not success:
586             attempts += 1
587             if look.x < 1 or look.x > QUADSIZE:
588                 if motion < 0 and tryexit(look, ienm, loccom, irun):
589                     return
590                 if krawlx == mx or my == 0:
591                     break
592                 look.x = next.x + krawlx
593                 krawlx = -krawlx
594             elif look.y < 1 or look.y > QUADSIZE:
595                 if motion < 0 and tryexit(look, ienm, loccom, irun):
596                     return
597                 if krawly == my or mx == 0:
598                     break
599                 look.y = next.y + krawly
600                 krawly = -krawly
601             elif (game.options & OPTION_RAMMING) and game.quad[look.x][look.y] != IHDOT:
602                 # See if we should ram ship 
603                 if game.quad[look.x][look.y] == game.ship and \
604                     (ienm == IHC or ienm == IHS):
605                     ram(True, ienm, com)
606                     return
607                 if krawlx != mx and my != 0:
608                     look.x = next.x + krawlx
609                     krawlx = -krawlx
610                 elif krawly != my and mx != 0:
611                     look.y = next.y + krawly
612                     krawly = -krawly
613                 else:
614                     break; # we have failed 
615             else:
616                 success = True
617         if success:
618             next = look
619             if idebug:
620                 proutn(`next`)
621         else:
622             break; # done early 
623         
624     if idebug:
625         skip(1)
626     # Put commander in place within same quadrant 
627     game.quad[com.x][com.y] = IHDOT
628     game.quad[next.x][next.y] = ienm
629     if next != com:
630         # it moved 
631         game.ks[loccom] = next
632         game.kdist[loccom] = game.kavgd[loccom] = distance(game.sector, next)
633         if not damaged(DSRSENS) or game.condition == docked:
634             proutn("***")
635             cramen(ienm)
636             proutn(_(" from Sector %s") % com)
637             if game.kdist[loccom] < dist1:
638                 proutn(_(" advances to "))
639             else:
640                 proutn(_(" retreats to "))
641             prout("Sector %s." % next)
642
643 def moveklings():
644     # Klingon tactical movement 
645     if idebug:
646         prout("== MOVCOM")
647     # Figure out which Klingon is the commander (or Supercommander)
648     # and do move
649     if game.comhere:
650         for i in range(1, game.nenhere+1):
651             w = game.ks[i]
652             if game.quad[w.x][w.y] == IHC:
653                 movebaddy(w, i, IHC)
654                 break
655     if game.ishere:
656         for i in range(1, game.nenhere+1):
657             w = game.ks[i]
658             if game.quad[w.x][w.y] == IHS:
659                 movebaddy(w, i, IHS)
660                 break
661     # If skill level is high, move other Klingons and Romulans too!
662     # Move these last so they can base their actions on what the
663     # commander(s) do.
664     if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
665         for i in range(1, game.nenhere+1):
666             w = game.ks[i]
667             if game.quad[w.x][w.y] == IHK or game.quad[w.x][w.y] == IHR:
668                 movebaddy(w, i, game.quad[w.x][w.y])
669     sortklings();
670
671 def movescom(iq, avoid):
672     # commander movement helper 
673     if iq == game.quadrant or not VALID_QUADRANT(iq.x, iq.y) or \
674         game.state.galaxy[iq.x][iq.y].supernova or \
675         game.state.galaxy[iq.x][iq.y].klingons > MAXKLQUAD-1:
676         return 1
677     if avoid:
678         # Avoid quadrants with bases if we want to avoid Enterprise 
679         for i in range(1, game.state.rembase+1):
680             if game.state.baseq[i] == iq:
681                 return True
682     if game.justin and not game.iscate:
683         return True
684     # do the move 
685     game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].klingons -= 1
686     game.state.kscmdr = iq
687     game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].klingons += 1
688     if game.ishere:
689         # SC has scooted, Remove him from current quadrant 
690         game.iscate=False
691         game.isatb=0
692         game.ishere = False
693         game.ientesc = False
694         unschedule(FSCDBAS)
695         for i in range(1, game.nenhere+1):
696             if game.quad[game.ks[i].x][game.ks[i].y] == IHS:
697                 break
698         game.quad[game.ks[i].x][game.ks[i].y] = IHDOT
699         game.ks[i] = game.ks[game.nenhere]
700         game.kdist[i] = game.kdist[game.nenhere]
701         game.kavgd[i] = game.kavgd[game.nenhere]
702         game.kpower[i] = game.kpower[game.nenhere]
703         game.klhere -= 1
704         game.nenhere -= 1
705         if game.condition!=docked:
706             newcnd()
707         sortklings()
708     # check for a helpful planet 
709     for i in range(game.inplan):
710         if game.state.planets[i].w == game.state.kscmdr and \
711             game.state.planets[i].crystals == "present":
712             # destroy the planet 
713             game.state.planets[i].pclass = "destroyed"
714             game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].planet = NOPLANET
715             if communicating():
716                 announce()
717                 prout(_("Lt. Uhura-  \"Captain, Starfleet Intelligence reports"))
718                 proutn(_("   a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
719                 prout(_("   by the Super-commander.\""))
720             break
721     return False; # looks good! 
722                         
723 def supercommander():
724     # move the Super Commander 
725     iq = coord(); sc = coord(); ibq = coord(); idelta = coord()
726     basetbl = []
727     if idebug:
728         prout("== SUPERCOMMANDER")
729     # Decide on being active or passive 
730     avoid = ((game.incom - game.state.remcom + game.inkling - game.state.remkl)/(game.state.date+0.01-game.indate) < 0.1*game.skill*(game.skill+1.0) or \
731             (game.state.date-game.indate) < 3.0)
732     if not game.iscate and avoid:
733         # compute move away from Enterprise 
734         idelta = game.state.kscmdr-game.quadrant
735         if math.sqrt(idelta.x*idelta.x+idelta.y*idelta.y) > 2.0:
736             # circulate in space 
737             idelta.x = game.state.kscmdr.y-game.quadrant.y
738             idelta.y = game.quadrant.x-game.state.kscmdr.x
739     else:
740         # compute distances to starbases 
741         if game.state.rembase <= 0:
742             # nothing left to do 
743             unschedule(FSCMOVE)
744             return
745         sc = game.state.kscmdr
746         for i in range(1, game.state.rembase+1):
747             basetbl.append((i, distance(game.state.baseq[i], sc)))
748         if game.state.rembase > 1:
749             basetbl.sort(lambda x, y: cmp(x[1]. y[1]))
750         # look for nearest base without a commander, no Enterprise, and
751         # without too many Klingons, and not already under attack. 
752         ifindit = iwhichb = 0
753         for i2 in range(1, game.state.rembase+1):
754             i = basetbl[i2][0]; # bug in original had it not finding nearest
755             ibq = game.state.baseq[i]
756             if ibq == game.quadrant or ibq == game.battle or \
757                 game.state.galaxy[ibq.x][ibq.y].supernova or \
758                 game.state.galaxy[ibq.x][ibq.y].klingons > MAXKLQUAD-1:
759                 continue
760             # if there is a commander, and no other base is appropriate,
761             #   we will take the one with the commander
762             for j in range(1, game.state.remcom+1):
763                 if ibq == game.state.kcmdr[j] and ifindit!= 2:
764                     ifindit = 2
765                     iwhichb = i
766                     break
767             if j > game.state.remcom: # no commander -- use this one 
768                 ifindit = 1
769                 iwhichb = i
770                 break
771         if ifindit==0:
772             return; # Nothing suitable -- wait until next time
773         ibq = game.state.baseq[iwhichb]
774         # decide how to move toward base 
775         idelta = ibq - game.state.kscmdr
776     # Maximum movement is 1 quadrant in either or both axes 
777     idelta = idelta.sgn()
778     # try moving in both x and y directions
779     # there was what looked like a bug in the Almy C code here,
780     # but it might be this translation is just wrong.
781     iq = game.state.kscmdr + idelta
782     if movescom(iq, avoid):
783         # failed -- try some other maneuvers 
784         if idelta.x==0 or idelta.y==0:
785             # attempt angle move 
786             if idelta.x != 0:
787                 iq.y = game.state.kscmdr.y + 1
788                 if movescom(iq, avoid):
789                     iq.y = game.state.kscmdr.y - 1
790                     movescom(iq, avoid)
791             else:
792                 iq.x = game.state.kscmdr.x + 1
793                 if movescom(iq, avoid):
794                     iq.x = game.state.kscmdr.x - 1
795                     movescom(iq, avoid)
796         else:
797             # try moving just in x or y 
798             iq.y = game.state.kscmdr.y
799             if movescom(iq, avoid):
800                 iq.y = game.state.kscmdr.y + idelta.y
801                 iq.x = game.state.kscmdr.x
802                 movescom(iq, avoid)
803     # check for a base 
804     if game.state.rembase == 0:
805         unschedule(FSCMOVE)
806     else:
807         for i in range(1, game.state.rembase+1):
808             ibq = game.state.baseq[i]
809             if ibq == game.state.kscmdr and game.state.kscmdr == game.battle:
810                 # attack the base 
811                 if avoid:
812                     return; # no, don't attack base! 
813                 game.iseenit = False
814                 game.isatb = 1
815                 schedule(FSCDBAS, 1.0 +2.0*Rand())
816                 if is_scheduled(FCDBAS):
817                     postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
818                 if not communicating():
819                     return; # no warning 
820                 game.iseenit = True
821                 announce()
822                 prout(_("Lt. Uhura-  \"Captain, the starbase in Quadrant %s") \
823                       % game.state.kscmdr)
824                 prout(_("   reports that it is under attack from the Klingon Super-commander."))
825                 proutn(_("   It can survive until stardate %d.\"") \
826                        % int(scheduled(FSCDBAS)))
827                 if not game.resting:
828                     return
829                 prout(_("Mr. Spock-  \"Captain, shall we cancel the rest period?\""))
830                 if ja() == False:
831                     return
832                 game.resting = False
833                 game.optime = 0.0; # actually finished 
834                 return
835     # Check for intelligence report 
836     if not idebug and \
837         (Rand() > 0.2 or \
838          (not communicating()) or \
839          not game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].charted):
840         return
841     announce()
842     prout(_("Lt. Uhura-  \"Captain, Starfleet Intelligence reports"))
843     proutn(_("   the Super-commander is in Quadrant %s,") % game.state.kscmdr)
844     return;
845
846 def movetholian():
847     # move the Tholian 
848     if not game.ithere or game.justin:
849         return
850
851     if game.tholian.x == 1 and game.tholian.y == 1:
852         idx = 1; idy = QUADSIZE
853     elif game.tholian.x == 1 and game.tholian.y == QUADSIZE:
854         idx = QUADSIZE; idy = QUADSIZE
855     elif game.tholian.x == QUADSIZE and game.tholian.y == QUADSIZE:
856         idx = QUADSIZE; idy = 1
857     elif game.tholian.x == QUADSIZE and game.tholian.y == 1:
858         idx = 1; idy = 1
859     else:
860         # something is wrong! 
861         game.ithere = False
862         return
863
864     # do nothing if we are blocked 
865     if game.quad[idx][idy]!= IHDOT and game.quad[idx][idy]!= IHWEB:
866         return
867     game.quad[game.tholian.x][game.tholian.y] = IHWEB
868
869     if game.tholian.x != idx:
870         # move in x axis 
871         im = math.fabs(idx - game.tholian.x)*1.0/(idx - game.tholian.x)
872         while game.tholian.x != idx:
873             game.tholian.x += im
874             if game.quad[game.tholian.x][game.tholian.y]==IHDOT:
875                 game.quad[game.tholian.x][game.tholian.y] = IHWEB
876     elif game.tholian.y != idy:
877         # move in y axis 
878         im = math.fabs(idy - game.tholian.y)*1.0/(idy - game.tholian.y)
879         while game.tholian.y != idy:
880             game.tholian.y += im
881             if game.quad[game.tholian.x][game.tholian.y]==IHDOT:
882                 game.quad[game.tholian.x][game.tholian.y] = IHWEB
883     game.quad[game.tholian.x][game.tholian.y] = IHT
884     game.ks[game.nenhere] = game.tholian
885
886     # check to see if all holes plugged 
887     for i in range(1, QUADSIZE+1):
888         if game.quad[1][i]!=IHWEB and game.quad[1][i]!=IHT:
889             return
890         if game.quad[QUADSIZE][i]!=IHWEB and game.quad[QUADSIZE][i]!=IHT:
891             return
892         if game.quad[i][1]!=IHWEB and game.quad[i][1]!=IHT:
893             return
894         if game.quad[i][QUADSIZE]!=IHWEB and game.quad[i][QUADSIZE]!=IHT:
895             return
896     # All plugged up -- Tholian splits 
897     game.quad[game.tholian.x][game.tholian.y]=IHWEB
898     dropin(IHBLANK)
899     crmena(True, IHT, "sector", game.tholian)
900     prout(_(" completes web."))
901     game.ithere = False
902     game.nenhere -= 1
903     return
904
905 # Code from battle.c begins here
906
907 def doshield(shraise):
908     # change shield status 
909     action = "NONE"
910     game.ididit = False
911     if shraise:
912         action = "SHUP"
913     else:
914         key = scan()
915         if key == IHALPHA:
916             if isit("transfer"):
917                 action = "NRG"
918             else:
919                 chew()
920                 if damaged(DSHIELD):
921                     prout(_("Shields damaged and down."))
922                     return
923                 if isit("up"):
924                     action = "SHUP"
925                 elif isit("down"):
926                     action = "SHDN"
927         if action=="NONE":
928             proutn(_("Do you wish to change shield energy? "))
929             if ja() == True:
930                 proutn(_("Energy to transfer to shields- "))
931                 action = "NRG"
932             elif damaged(DSHIELD):
933                 prout(_("Shields damaged and down."))
934                 return
935             elif game.shldup:
936                 proutn(_("Shields are up. Do you want them down? "))
937                 if ja() == True:
938                     action = "SHDN"
939                 else:
940                     chew()
941                     return
942             else:
943                 proutn(_("Shields are down. Do you want them up? "))
944                 if ja() == True:
945                     action = "SHUP"
946                 else:
947                     chew()
948                     return    
949     if action == "SHUP": # raise shields 
950         if game.shldup:
951             prout(_("Shields already up."))
952             return
953         game.shldup = True
954         game.shldchg = True
955         if game.condition != "docked":
956             game.energy -= 50.0
957         prout(_("Shields raised."))
958         if game.energy <= 0:
959             skip(1)
960             prout(_("Shields raising uses up last of energy."))
961             finish(FNRG)
962             return
963         game.ididit=True
964         return
965     elif action == "SHDN":
966         if not game.shldup:
967             prout(_("Shields already down."))
968             return
969         game.shldup=False
970         game.shldchg=True
971         prout(_("Shields lowered."))
972         game.ididit = True
973         return
974     elif action == "NRG":
975         while scan() != IHREAL:
976             chew()
977             proutn(_("Energy to transfer to shields- "))
978         chew()
979         if aaitem==0:
980             return
981         if aaitem > game.energy:
982             prout(_("Insufficient ship energy."))
983             return
984         game.ididit = True
985         if game.shield+aaitem >= game.inshld:
986             prout(_("Shield energy maximized."))
987             if game.shield+aaitem > game.inshld:
988                 prout(_("Excess energy requested returned to ship energy"))
989             game.energy -= game.inshld-game.shield
990             game.shield = game.inshld
991             return
992         if aaitem < 0.0 and game.energy-aaitem > game.inenrg:
993             # Prevent shield drain loophole 
994             skip(1)
995             prout(_("Engineering to bridge--"))
996             prout(_("  Scott here. Power circuit problem, Captain."))
997             prout(_("  I can't drain the shields."))
998             game.ididit = False
999             return
1000         if game.shield+aaitem < 0:
1001             prout(_("All shield energy transferred to ship."))
1002             game.energy += game.shield
1003             game.shield = 0.0
1004             return
1005         proutn(_("Scotty- \""))
1006         if aaitem > 0:
1007             prout(_("Transferring energy to shields.\""))
1008         else:
1009             prout(_("Draining energy from shields.\""))
1010         game.shield += aaitem
1011         game.energy -= aaitem
1012         return
1013
1014 def randdevice():
1015     # choose a device to damage, at random. 
1016     #
1017     # Quoth Eric Allman in the code of BSD-Trek:
1018     # "Under certain conditions you can get a critical hit.  This
1019     # sort of hit damages devices.  The probability that a given
1020     # device is damaged depends on the device.  Well protected
1021     # devices (such as the computer, which is in the core of the
1022     # ship and has considerable redundancy) almost never get
1023     # damaged, whereas devices which are exposed (such as the
1024     # warp engines) or which are particularly delicate (such as
1025     # the transporter) have a much higher probability of being
1026     # damaged."
1027     # 
1028     # This is one place where OPTION_PLAIN does not restore the
1029     # original behavior, which was equiprobable damage across
1030     # all devices.  If we wanted that, we'd return NDEVICES*Rand()
1031     # and have done with it.  Also, in the original game, DNAVYS
1032     # and DCOMPTR were the same device. 
1033     # 
1034     # Instead, we use a table of weights similar to the one from BSD Trek.
1035     # BSD doesn't have the shuttle, shield controller, death ray, or probes. 
1036     # We don't have a cloaking device.  The shuttle got the allocation
1037     # for the cloaking device, then we shaved a half-percent off
1038     # everything to have some weight to give DSHCTRL/DDRAY/DDSP.
1039     # 
1040     weights = (
1041         105,    # DSRSENS: short range scanners 10.5% 
1042         105,    # DLRSENS: long range scanners          10.5% 
1043         120,    # DPHASER: phasers                      12.0% 
1044         120,    # DPHOTON: photon torpedoes             12.0% 
1045         25,     # DLIFSUP: life support          2.5% 
1046         65,     # DWARPEN: warp drive                    6.5% 
1047         70,     # DIMPULS: impulse engines               6.5% 
1048         145,    # DSHIELD: deflector shields            14.5% 
1049         30,     # DRADIO:  subspace radio                3.0% 
1050         45,     # DSHUTTL: shuttle                       4.5% 
1051         15,     # DCOMPTR: computer                      1.5% 
1052         20,     # NAVCOMP: navigation system             2.0% 
1053         75,     # DTRANSP: transporter                   7.5% 
1054         20,     # DSHCTRL: high-speed shield controller 2.0% 
1055         10,     # DDRAY: death ray                       1.0% 
1056         30,     # DDSP: deep-space probes                3.0% 
1057     )
1058     idx = Rand() * 1000.0       # weights must sum to 1000 
1059     sum = 0
1060     for (i, w) in enumerate(weights):
1061         sum += w
1062         if idx < sum:
1063             return i
1064     return None;        # we should never get here
1065
1066 def ram(ibumpd, ienm, w):
1067     # make our ship ram something 
1068     prouts(_("***RED ALERT!  RED ALERT!"))
1069     skip(1)
1070     prout(_("***COLLISION IMMINENT."))
1071     skip(2)
1072     proutn("***")
1073     crmshp()
1074     hardness = {IHR:1.5, IHC:2.0, IHS:2.5, IHT:0.5, IHQUEST:4.0}.get(ienm, 1.0)
1075     if ibumpd:
1076         proutn(_(" rammed by "))
1077     else:
1078         proutn(_(" rams "))
1079     crmena(False, ienm, sector, w)
1080     if ibumpd:
1081         proutn(_(" (original position)"))
1082     skip(1)
1083     deadkl(w, ienm, game.sector)
1084     proutn("***")
1085     crmshp()
1086     prout(_(" heavily damaged."))
1087     icas = 10.0+20.0*Rand()
1088     prout(_("***Sickbay reports %d casualties"), icas)
1089     game.casual += icas
1090     game.state.crew -= icas
1091     #
1092     # In the pre-SST2K version, all devices got equiprobably damaged,
1093     # which was silly.  Instead, pick up to half the devices at
1094     # random according to our weighting table,
1095     # 
1096     ncrits = Rand() * (NDEVICES/2)
1097     for m in range(ncrits):
1098         dev = randdevice()
1099         if game.damage[dev] < 0:
1100             continue
1101         extradm = (10.0*hardness*Rand()+1.0)*game.damfac
1102         # Damage for at least time of travel! 
1103         game.damage[dev] += game.optime + extradm
1104     game.shldup = False
1105     prout(_("***Shields are down."))
1106     if game.state.remkl + game.state.remcom + game.state.nscrem:
1107         announce()
1108         damagereport()
1109     else:
1110         finish(FWON)
1111     return;
1112
1113 def torpedo(course, r, incoming, i, n):
1114     # let a photon torpedo fly 
1115     iquad = 0
1116     shoved = False
1117     ac = course + 0.25*r
1118     angle = (15.0-ac)*0.5235988
1119     bullseye = (15.0 - course)*0.5235988
1120     deltax = -math.sin(angle);
1121     deltay = math.cos(angle);
1122     x = incoming.x; y = incoming.y
1123     w = coord(); jw = coord()
1124     w.x = w.y = jw.x = jw.y = 0
1125     bigger = max(math.fabs(deltax), math.fabs(deltay))
1126     deltax /= bigger
1127     deltay /= bigger
1128     if not damaged(DSRSENS) or game.condition=="docked":
1129         setwnd(srscan_window)
1130     else: 
1131         setwnd(message_window)
1132     # Loop to move a single torpedo 
1133     for l in range(1, 15+1):
1134         x += deltax
1135         w.x = x + 0.5
1136         y += deltay
1137         w.y = y + 0.5
1138         if not VALID_SECTOR(w.x, w.y):
1139             break
1140         iquad=game.quad[w.x][w.y]
1141         tracktorpedo(w, l, i, n, iquad)
1142         if iquad==IHDOT:
1143             continue
1144         # hit something 
1145         setwnd(message_window)
1146         if damaged(DSRSENS) and not game.condition=="docked":
1147             skip(1);    # start new line after text track 
1148         if iquad in (IHE, IHF): # Hit our ship 
1149             skip(1)
1150             proutn(_("Torpedo hits "))
1151             crmshp()
1152             prout(".")
1153             hit = 700.0 + 100.0*Rand() - \
1154                 1000.0 * distance(w, incoming) * math.fabs(math.sin(bullseye-angle))
1155             newcnd(); # we're blown out of dock 
1156             # We may be displaced. 
1157             if game.landed or game.condition=="docked":
1158                 return hit # Cheat if on a planet 
1159             ang = angle + 2.5*(Rand()-0.5)
1160             temp = math.fabs(math.sin(ang))
1161             if math.fabs(math.cos(ang)) > temp:
1162                 temp = math.fabs(math.cos(ang))
1163             xx = -math.sin(ang)/temp
1164             yy = math.cos(ang)/temp
1165             jw.x=w.x+xx+0.5
1166             jw.y=w.y+yy+0.5
1167             if not VALID_SECTOR(jw.x, jw.y):
1168                 return hit
1169             if game.quad[jw.x][jw.y]==IHBLANK:
1170                 finish(FHOLE)
1171                 return hit
1172             if game.quad[jw.x][jw.y]!=IHDOT:
1173                 # can't move into object 
1174                 return hit
1175             game.sector = jw
1176             crmshp()
1177             shoved = True
1178         elif iquad in (IHC, IHS): # Hit a commander 
1179             if Rand() <= 0.05:
1180                 crmena(True, iquad, sector, w)
1181                 prout(_(" uses anti-photon device;"))
1182                 prout(_("   torpedo neutralized."))
1183                 return None
1184         elif iquad in (IHR, IHK): # Hit a regular enemy 
1185             # find the enemy 
1186             for ll in range(1, game.nenhere+1):
1187                 if w == game.ks[ll]:
1188                     break
1189             kp = math.fabs(game.kpower[ll])
1190             h1 = 700.0 + 100.0*Rand() - \
1191                 1000.0 * distance(w, incoming) * math.fabs(math.sin(bullseye-angle))
1192             h1 = math.fabs(h1)
1193             if kp < h1:
1194                 h1 = kp
1195             if game.kpower[ll] < 0:
1196                 game.kpower[ll] -= -h1
1197             else:
1198                 game.kpower[ll] -= h1
1199             if game.kpower[ll] == 0:
1200                 deadkl(w, iquad, w)
1201                 return None
1202             crmena(True, iquad, "sector", w)
1203             # If enemy damaged but not destroyed, try to displace 
1204             ang = angle + 2.5*(Rand()-0.5)
1205             temp = math.fabs(math.sin(ang))
1206             if math.fabs(math.cos(ang)) > temp:
1207                 temp = math.fabs(math.cos(ang))
1208             xx = -math.sin(ang)/temp
1209             yy = math.cos(ang)/temp
1210             jw.x=w.x+xx+0.5
1211             jw.y=w.y+yy+0.5
1212             if not VALID_SECTOR(jw.x, jw.y):
1213                 prout(_(" damaged but not destroyed."))
1214                 return
1215             if game.quad[jw.x][jw.y]==IHBLANK:
1216                 prout(_(" buffeted into black hole."))
1217                 deadkl(w, iquad, jw)
1218                 return None
1219             if game.quad[jw.x][jw.y]!=IHDOT:
1220                 # can't move into object 
1221                 prout(_(" damaged but not destroyed."))
1222                 return None
1223             proutn(_(" damaged--"))
1224             game.ks[ll] = jw
1225             shoved = True
1226             break
1227         elif iquad == IHB: # Hit a base 
1228             skip(1)
1229             prout(_("***STARBASE DESTROYED.."))
1230             for ll in range(1, game.state.rembase+1):
1231                 if game.state.baseq[ll] == game.quadrant:
1232                     game.state.baseq[ll]=game.state.baseq[game.state.rembase]
1233                     break
1234             game.quad[w.x][w.y]=IHDOT
1235             game.state.rembase -= 1
1236             game.base.x=game.base.y=0
1237             game.state.galaxy[game.quadrant.x][game.quadrant.y].starbase -= 1
1238             game.state.chart[game.quadrant.x][game.quadrant.y].starbase -= 1
1239             game.state.basekl += 1
1240             newcnd()
1241             return None
1242         elif iquad == IHP: # Hit a planet 
1243             crmena(True, iquad, sector, w)
1244             prout(_(" destroyed."))
1245             game.state.nplankl += 1
1246             game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = NOPLANET
1247             game.state.planets[game.iplnet].pclass = destroyed
1248             game.iplnet = 0
1249             invalidate(game.plnet)
1250             game.quad[w.x][w.y] = IHDOT
1251             if game.landed:
1252                 # captain perishes on planet 
1253                 finish(FDPLANET)
1254             return None
1255         elif iquad == IHW: # Hit an inhabited world -- very bad! 
1256             crmena(True, iquad, sector, w)
1257             prout(_(" destroyed."))
1258             game.state.nworldkl += 1
1259             game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = NOPLANET
1260             game.state.planets[game.iplnet].pclass = destroyed
1261             game.iplnet = 0
1262             invalidate(game.plnet)
1263             game.quad[w.x][w.y] = IHDOT
1264             if game.landed:
1265                 # captain perishes on planet 
1266                 finish(FDPLANET)
1267             prout(_("You have just destroyed an inhabited planet."))
1268             prout(_("Celebratory rallies are being held on the Klingon homeworld."))
1269             return None
1270         elif iquad == IHSTAR: # Hit a star 
1271             if Rand() > 0.10:
1272                 nova(w)
1273                 return None
1274             crmena(True, IHSTAR, sector, w)
1275             prout(_(" unaffected by photon blast."))
1276             return None
1277         elif iquad == IHQUEST: # Hit a thingy 
1278             if not (game.options & OPTION_THINGY) or Rand()>0.7:
1279                 skip(1)
1280                 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1281                 skip(1)
1282                 prouts(_("    HACK!     HACK!    HACK!        *CHOKE!*  "))
1283                 skip(1)
1284                 proutn(_("Mr. Spock-"))
1285                 prouts(_("  \"Fascinating!\""))
1286                 skip(1)
1287                 deadkl(w, iquad, w)
1288             else:
1289                 #
1290                 # Stas Sergeev added the possibility that
1291                 # you can shove the Thingy and piss it off.
1292                 # It then becomes an enemy and may fire at you.
1293                 # 
1294                 iqengry = True
1295                 shoved = True
1296             return None
1297         elif iquad == IHBLANK: # Black hole 
1298             skip(1)
1299             crmena(True, IHBLANK, sector, w)
1300             prout(_(" swallows torpedo."))
1301             return None
1302         elif iquad == IHWEB: # hit the web 
1303             skip(1)
1304             prout(_("***Torpedo absorbed by Tholian web."))
1305             return None
1306         elif iquad == IHT:  # Hit a Tholian 
1307             h1 = 700.0 + 100.0*Rand() - \
1308                 1000.0 * distance(w, incoming) * math.fabs(math.sin(bullseye-angle))
1309             h1 = math.fabs(h1)
1310             if h1 >= 600:
1311                 game.quad[w.x][w.y] = IHDOT
1312                 game.ithere = False
1313                 deadkl(w, iquad, w)
1314                 return None
1315             skip(1)
1316             crmena(True, IHT, sector, w)
1317             if Rand() > 0.05:
1318                 prout(_(" survives photon blast."))
1319                 return None
1320             prout(_(" disappears."))
1321             game.quad[w.x][w.y] = IHWEB
1322             game.ithere = False
1323             game.nenhere -= 1
1324             dropin(IHBLANK)
1325             return None
1326         else: # Problem!
1327             skip(1)
1328             proutn("Don't know how to handle torpedo collision with ")
1329             crmena(True, iquad, sector, w)
1330             skip(1)
1331             return None
1332         break
1333     if curwnd!=message_window:
1334         setwnd(message_window)
1335     if shoved:
1336         game.quad[w.x][w.y]=IHDOT
1337         game.quad[jw.x][jw.y]=iquad
1338         prout(_(" displaced by blast to Sector %s ") % jw)
1339         for ll in range(1, game.nenhere+1):
1340             game.kdist[ll] = game.kavgd[ll] = distance(game.sector,game.ks[ll])
1341         sortklings()
1342         return None
1343     skip(1)
1344     prout(_("Torpedo missed."))
1345     return None;
1346
1347 def fry(hit):
1348     # critical-hit resolution 
1349     ktr=1
1350     # a critical hit occured 
1351     if hit < (275.0-25.0*game.skill)*(1.0+0.5*Rand()):
1352         return
1353
1354     ncrit = 1.0 + hit/(500.0+100.0*Rand())
1355     proutn(_("***CRITICAL HIT--"))
1356     # Select devices and cause damage
1357     cdam = []
1358     for loop1 in range(ncrit):
1359         while True:
1360             j = randdevice()
1361             # Cheat to prevent shuttle damage unless on ship 
1362             if not (game.damage[j]<0.0 or (j==DSHUTTL and game.iscraft != "onship")):
1363                 break
1364         cdam.append(j)
1365         extradm = (hit*game.damfac)/(ncrit*(75.0+25.0*Rand()))
1366         game.damage[j] += extradm
1367         if loop1 > 0:
1368             for loop2 in range(loop1):
1369                 if j == cdam[loop2]:
1370                     break
1371             if loop2 < loop1:
1372                 continue
1373             ktr += 1
1374             if ktr==3:
1375                 skip(1)
1376             proutn(_(" and "))
1377         proutn(device[j])
1378     prout(_(" damaged."))
1379     if damaged(DSHIELD) and game.shldup:
1380         prout(_("***Shields knocked down."))
1381         game.shldup=False
1382
1383 def attack(torps_ok):
1384     # bad guy attacks us 
1385     # torps_ok == false forces use of phasers in an attack 
1386     atackd = False; attempt = False; ihurt = False;
1387     hitmax=0.0; hittot=0.0; chgfac=1.0
1388     jay = coord()
1389     where = "neither"
1390
1391     # game could be over at this point, check 
1392     if game.alldone:
1393         return
1394
1395     if idebug:
1396         prout("=== ATTACK!")
1397
1398     # Tholian gewts to move before attacking 
1399     if game.ithere:
1400         movetholian()
1401
1402     # if you have just entered the RNZ, you'll get a warning 
1403     if game.neutz: # The one chance not to be attacked 
1404         game.neutz = False
1405         return
1406
1407     # commanders get a chance to tac-move towards you 
1408     if (((game.comhere or game.ishere) and not game.justin) or game.skill == SKILL_EMERITUS) and torps_ok:
1409         moveklings()
1410
1411     # if no enemies remain after movement, we're done 
1412     if game.nenhere==0 or (game.nenhere==1 and iqhere and not iqengry):
1413         return
1414
1415     # set up partial hits if attack happens during shield status change 
1416     pfac = 1.0/game.inshld
1417     if game.shldchg:
1418         chgfac = 0.25+0.5*Rand()
1419
1420     skip(1)
1421
1422     # message verbosity control 
1423     if game.skill <= SKILL_FAIR:
1424         where = "sector"
1425
1426     for loop in range(1, game.nenhere+1):
1427         if game.kpower[loop] < 0:
1428             continue;   # too weak to attack 
1429         # compute hit strength and diminish shield power 
1430         r = Rand()
1431         # Increase chance of photon torpedos if docked or enemy energy low 
1432         if game.condition == "docked":
1433             r *= 0.25
1434         if game.kpower[loop] < 500:
1435             r *= 0.25; 
1436         jay = game.ks[loop]
1437         iquad = game.quad[jay.x][jay.y]
1438         if iquad==IHT or (iquad==IHQUEST and not iqengry):
1439             continue
1440         # different enemies have different probabilities of throwing a torp 
1441         usephasers = not torps_ok or \
1442             (iquad == IHK and r > 0.0005) or \
1443             (iquad==IHC and r > 0.015) or \
1444             (iquad==IHR and r > 0.3) or \
1445             (iquad==IHS and r > 0.07) or \
1446             (iquad==IHQUEST and r > 0.05)
1447         if usephasers:      # Enemy uses phasers 
1448             if game.condition == "docked":
1449                 continue; # Don't waste the effort! 
1450             attempt = True; # Attempt to attack 
1451             dustfac = 0.8+0.05*Rand()
1452             hit = game.kpower[loop]*math.pow(dustfac,game.kavgd[loop])
1453             game.kpower[loop] *= 0.75
1454         else: # Enemy uses photon torpedo 
1455             course = 1.90985*math.atan2(game.sector.y-jay.y, jay.x-game.sector.x)
1456             hit = 0
1457             proutn(_("***TORPEDO INCOMING"))
1458             if not damaged(DSRSENS):
1459                 proutn(_(" From "))
1460                 crmena(False, iquad, where, jay)
1461             attempt = True
1462             prout("  ")
1463             r = (Rand()+Rand())*0.5 -0.5
1464             r += 0.002*game.kpower[loop]*r
1465             hit = torpedo(course, r, jay, 1, 1)
1466             if (game.state.remkl + game.state.remcom + game.state.nscrem)==0:
1467                 finish(FWON); # Klingons did themselves in! 
1468             if game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova or game.alldone:
1469                 return; # Supernova or finished 
1470             if hit == None:
1471                 continue
1472         # incoming phaser or torpedo, shields may dissipate it 
1473         if game.shldup or game.shldchg or game.condition=="docked":
1474             # shields will take hits 
1475             propor = pfac * game.shield
1476             if game.condition =="docked":
1477                 propr *= 2.1
1478             if propor < 0.1:
1479                 propor = 0.1
1480             hitsh = propor*chgfac*hit+1.0
1481             absorb = 0.8*hitsh
1482             if absorb > game.shield:
1483                 absorb = game.shield
1484             game.shield -= absorb
1485             hit -= hitsh
1486             # taking a hit blasts us out of a starbase dock 
1487             if game.condition == "docked":
1488                 dock(False)
1489             # but the shields may take care of it 
1490             if propor > 0.1 and hit < 0.005*game.energy:
1491                 continue
1492         # hit from this opponent got through shields, so take damage 
1493         ihurt = True
1494         proutn(_("%d unit hit") % int(hit))
1495         if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1496             proutn(_(" on the "))
1497             crmshp()
1498         if not damaged(DSRSENS) and usephasers:
1499             proutn(_(" from "))
1500             crmena(False, iquad, where, jay)
1501         skip(1)
1502         # Decide if hit is critical 
1503         if hit > hitmax:
1504             hitmax = hit
1505         hittot += hit
1506         fry(hit)
1507         game.energy -= hit
1508     if game.energy <= 0:
1509         # Returning home upon your shield, not with it... 
1510         finish(FBATTLE)
1511         return
1512     if not attempt and game.condition == "docked":
1513         prout(_("***Enemies decide against attacking your ship."))
1514     if not atackd:
1515         return
1516     percent = 100.0*pfac*game.shield+0.5
1517     if not ihurt:
1518         # Shields fully protect ship 
1519         proutn(_("Enemy attack reduces shield strength to "))
1520     else:
1521         # Print message if starship suffered hit(s) 
1522         skip(1)
1523         proutn(_("Energy left %2d    shields ") % int(game.energy))
1524         if game.shldup:
1525             proutn(_("up "))
1526         elif not damaged(DSHIELD):
1527             proutn(_("down "))
1528         else:
1529             proutn(_("damaged, "))
1530     prout(_("%d%%,   torpedoes left %d") % (percent, game.torps))
1531     # Check if anyone was hurt 
1532     if hitmax >= 200 or hittot >= 500:
1533         icas= hittot*Rand()*0.015
1534         if icas >= 2:
1535             skip(1)
1536             prout(_("Mc Coy-  \"Sickbay to bridge.  We suffered %d casualties") % icas)
1537             prout(_("   in that last attack.\""))
1538             game.casual += icas
1539             game.state.crew -= icas
1540     # After attack, reset average distance to enemies 
1541     for loop in range(1, game.nenhere+1):
1542         game.kavgd[loop] = game.kdist[loop]
1543     sortklings()
1544     return;
1545                 
1546 def deadkl(w, type, mv):
1547     # kill a Klingon, Tholian, Romulan, or Thingy 
1548     # Added mv to allow enemy to "move" before dying 
1549
1550     crmena(True, type, sector, mv)
1551     # Decide what kind of enemy it is and update appropriately 
1552     if type == IHR:
1553         # chalk up a Romulan 
1554         game.state.galaxy[game.quadrant.x][game.quadrant.y].romulans -= 1
1555         game.irhere -= 1
1556         game.state.nromrem -= 1
1557     elif type == IHT:
1558         # Killed a Tholian 
1559         game.ithere = False
1560     elif type == IHQUEST:
1561         # Killed a Thingy 
1562         iqhere = iqengry = False
1563         invalidate(thing)
1564     else:
1565         # Some type of a Klingon 
1566         game.state.galaxy[game.quadrant.x][game.quadrant.y].klingons -= 1
1567         game.klhere -= 1
1568         if type == IHC:
1569             game.comhere = False
1570             for i in range(1, game.state.remcom+1):
1571                 if game.state.kcmdr[i] == game.quadrant:
1572                     break
1573             game.state.kcmdr[i] = game.state.kcmdr[game.state.remcom]
1574             game.state.kcmdr[game.state.remcom].x = 0
1575             game.state.kcmdr[game.state.remcom].y = 0
1576             game.state.remcom -= 1
1577             unschedule(FTBEAM)
1578             if game.state.remcom != 0:
1579                 schedule(FTBEAM, expran(1.0*game.incom/game.state.remcom))
1580         elif type ==  IHK:
1581             game.state.remkl -= 1
1582         elif type ==  IHS:
1583             game.state.nscrem -= 1
1584             game.ishere = False
1585             game.state.kscmdr.x = game.state.kscmdr.y = game.isatb = 0
1586             game.iscate = False
1587             unschedule(FSCMOVE)
1588             unschedule(FSCDBAS)
1589         else:
1590             prout("*** Internal error, deadkl() called on %s\n" % type)
1591
1592     # For each kind of enemy, finish message to player 
1593     prout(_(" destroyed."))
1594     game.quad[w.x][w.y] = IHDOT
1595     if (game.state.remkl + game.state.remcom + game.state.nscrem)==0:
1596         return
1597     game.recompute()
1598     # Remove enemy ship from arrays describing local conditions 
1599     if is_scheduled(FCDBAS) and game.battle == game.quadrant and type==IHC:
1600         unschedule(FCDBAS)
1601     for i in range(1, game.nenhere+1):
1602         if game.ks[i] == w:
1603             break
1604     game.nenhere -= 1
1605     if i <= game.nenhere:
1606         for j in range(i, game.nenhere+1):
1607             game.ks[j] = game.ks[j+1]
1608             game.kpower[j] = game.kpower[j+1]
1609             game.kavgd[j] = game.kdist[j] = game.kdist[j+1]
1610     game.ks[game.nenhere+1].x = 0
1611     game.ks[game.nenhere+1].x = 0
1612     game.kdist[game.nenhere+1] = 0
1613     game.kavgd[game.nenhere+1] = 0
1614     game.kpower[game.nenhere+1] = 0
1615     return;
1616
1617 def targetcheck(x, y):
1618     # Return None if target is invalid 
1619     if not VALID_SECTOR(x, y):
1620         huh()
1621         return None
1622     deltx = 0.1*(y - game.sector.y)
1623     delty = 0.1*(x - game.sector.x)
1624     if deltx==0 and delty== 0:
1625         skip(1)
1626         prout(_("Spock-  \"Bridge to sickbay.  Dr. McCoy,"))
1627         prout(_("  I recommend an immediate review of"))
1628         prout(_("  the Captain's psychological profile.\""))
1629         chew()
1630         return None
1631     return 1.90985932*math.atan2(deltx, delty)
1632
1633 def photon():
1634     # launch photon torpedo 
1635     game.ididit = False
1636     if damaged(DPHOTON):
1637         prout(_("Photon tubes damaged."))
1638         chew()
1639         return
1640     if game.torps == 0:
1641         prout(_("No torpedoes left."))
1642         chew()
1643         return
1644     key = scan()
1645     while True:
1646         if key == IHALPHA:
1647             huh()
1648             return
1649         elif key == IHEOL:
1650             prout(_("%d torpedoes left.") % game.torps)
1651             proutn(_("Number of torpedoes to fire- "))
1652             key = scan()
1653         else: # key == IHREAL  {
1654             n = aaitem + 0.5
1655             if n <= 0: # abort command 
1656                 chew()
1657                 return
1658             if n > 3:
1659                 chew()
1660                 prout(_("Maximum of 3 torpedoes per burst."))
1661                 key = IHEOL
1662                 return
1663             if n <= game.torps:
1664                 break
1665             chew()
1666             key = IHEOL
1667     for i in range(1, n+1):
1668         key = scan()
1669         if i==1 and key == IHEOL:
1670             break;      # we will try prompting 
1671         if i==2 and key == IHEOL:
1672             # direct all torpedoes at one target 
1673             while i <= n:
1674                 targ[i][1] = targ[1][1]
1675                 targ[i][2] = targ[1][2]
1676                 course[i] = course[1]
1677                 i += 1
1678             break
1679         if key != IHREAL:
1680             huh()
1681             return
1682         targ[i][1] = aaitem
1683         key = scan()
1684         if key != IHREAL:
1685             huh()
1686             return
1687         targ[i][2] = aaitem
1688         course[i] = targetcheck(targ[i][1], targ[i][2])
1689         if course[i] == None:
1690             return
1691     chew()
1692     if i == 1 and key == IHEOL:
1693         # prompt for each one 
1694         for i in range(1, n+1):
1695             proutn(_("Target sector for torpedo number %d- ") % i)
1696             key = scan()
1697             if key != IHREAL:
1698                 huh()
1699                 return
1700             targ[i][1] = aaitem
1701             key = scan()
1702             if key != IHREAL:
1703                 huh()
1704                 return
1705             targ[i][2] = aaitem
1706             chew()
1707             course[i] = targetcheck(targ[i][1], targ[i][2])
1708             if course[i] == None:
1709                 return
1710     game.ididit = True
1711     # Loop for moving <n> torpedoes 
1712     for i in range(1, n+1):
1713         if game.condition != "docked":
1714             game.torps -= 1
1715         r = (Rand()+Rand())*0.5 -0.5
1716         if math.fabs(r) >= 0.47:
1717             # misfire! 
1718             r = (Rand()+1.2) * r
1719             if n>1:
1720                 prouts(_("***TORPEDO NUMBER %d MISFIRES") % i)
1721             else:
1722                 prouts(_("***TORPEDO MISFIRES."))
1723             skip(1)
1724             if i < n:
1725                 prout(_("  Remainder of burst aborted."))
1726             if Rand() <= 0.2:
1727                 prout(_("***Photon tubes damaged by misfire."))
1728                 game.damage[DPHOTON] = game.damfac*(1.0+2.0*Rand())
1729             break
1730         if game.shldup or game.condition == "docked":
1731             r *= 1.0 + 0.0001*game.shield
1732         torpedo(course[i], r, game.sector, i, n)
1733         if game.alldone or game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
1734             return
1735     if (game.state.remkl + game.state.remcom + game.state.nscrem)==0:
1736         finish(FWON);
1737
1738 def overheat(rpow):
1739     # check for phasers overheating 
1740     if rpow > 1500:
1741         chekbrn = (rpow-1500.)*0.00038
1742         if Rand() <= chekbrn:
1743             prout(_("Weapons officer Sulu-  \"Phasers overheated, sir.\""))
1744             game.damage[DPHASER] = game.damfac*(1.0 + Rand()) * (1.0+chekbrn)
1745
1746 def checkshctrl(rpow):
1747     # check shield control 
1748         
1749     skip(1)
1750     if Rand() < 0.998:
1751         prout(_("Shields lowered."))
1752         return False
1753     # Something bad has happened 
1754     prouts(_("***RED ALERT!  RED ALERT!"))
1755     skip(2)
1756     hit = rpow*game.shield/game.inshld
1757     game.energy -= rpow+hit*0.8
1758     game.shield -= hit*0.2
1759     if game.energy <= 0.0:
1760         prouts(_("Sulu-  \"Captain! Shield malf***********************\""))
1761         skip(1)
1762         stars()
1763         finish(FPHASER)
1764         return True
1765     prouts(_("Sulu-  \"Captain! Shield malfunction! Phaser fire contained!\""))
1766     skip(2)
1767     prout(_("Lt. Uhura-  \"Sir, all decks reporting damage.\""))
1768     icas = hit*Rand()*0.012
1769     skip(1)
1770     fry(0.8*hit)
1771     if icas:
1772         skip(1)
1773         prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1774         prout(_("  %d casualties so far.\"") % icas)
1775         game.casual += icas
1776         game.state.crew -= icas
1777     skip(1)
1778     prout(_("Phaser energy dispersed by shields."))
1779     prout(_("Enemy unaffected."))
1780     overheat(rpow)
1781     return True;
1782
1783 def hittem(doublehits):
1784     # register a phaser hit on Klingons and Romulans 
1785     nenhr2=game.nenhere; kk=1
1786     w = coord()
1787     skip(1)
1788     for k in range(1, nenhr2+1):
1789         wham = hits[k]
1790         if wham==0:
1791             continue
1792         dustfac = 0.9 + 0.01*Rand()
1793         hit = wham*math.pow(dustfac,game.kdist[kk])
1794         kpini = game.kpower[kk]
1795         kp = math.fabs(kpini)
1796         if PHASEFAC*hit < kp:
1797             kp = PHASEFAC*hit
1798         if game.kpower[kk] < 0:
1799             game.kpower[kk] -= -kp
1800         else:
1801             game.kpower[kk] -= kp
1802         kpow = game.kpower[kk]
1803         w = game.ks[kk]
1804         if hit > 0.005:
1805             if not damaged(DSRSENS):
1806                 boom(w)
1807             proutn(_("%d unit hit on ") % int(hit))
1808         else:
1809             proutn(_("Very small hit on "))
1810         ienm = game.quad[w.x][w.y]
1811         if ienm==IHQUEST:
1812             iqengry = True
1813         crmena(False, ienm, "sector", w)
1814         skip(1)
1815         if kpow == 0:
1816             deadkl(w, ienm, w)
1817             if (game.state.remkl + game.state.remcom + game.state.nscrem)==0:
1818                 finish(FWON);           
1819             if game.alldone:
1820                 return
1821             kk -= 1; # don't do the increment 
1822         else: # decide whether or not to emasculate klingon 
1823             if kpow > 0 and Rand() >= 0.9 and \
1824                 kpow <= ((0.4 + 0.4*Rand())*kpini):
1825                 prout(_("***Mr. Spock-  \"Captain, the vessel at Sector %s"), w)
1826                 prout(_("   has just lost its firepower.\""))
1827                 game.kpower[kk] = -kpow
1828         kk += 1
1829     return;
1830
1831 def phasers():
1832     # fire phasers 
1833     hits = []; rpow=0
1834     kz = 0; k = 1; irec=0 # Cheating inhibitor 
1835     ifast = False; no = False; itarg = True; msgflag = True
1836     automode = "NOTSET"
1837     key=0
1838
1839     skip(1)
1840     # SR sensors and Computer are needed fopr automode 
1841     if damaged(DSRSENS) or damaged(DCOMPTR):
1842         itarg = False
1843     if game.condition == "docked":
1844         prout(_("Phasers can't be fired through base shields."))
1845         chew()
1846         return
1847     if damaged(DPHASER):
1848         prout(_("Phaser control damaged."))
1849         chew()
1850         return
1851     if game.shldup:
1852         if damaged(DSHCTRL):
1853             prout(_("High speed shield control damaged."))
1854             chew()
1855             return
1856         if game.energy <= 200.0:
1857             prout(_("Insufficient energy to activate high-speed shield control."))
1858             chew()
1859             return
1860         prout(_("Weapons Officer Sulu-  \"High-speed shield control enabled, sir.\""))
1861         ifast = True
1862                 
1863     # Original code so convoluted, I re-did it all 
1864     while automode=="NOTSET":
1865         key=scan()
1866         if key == IHALPHA:
1867             if isit("manual"):
1868                 if game.nenhere==0:
1869                     prout(_("There is no enemy present to select."))
1870                     chew()
1871                     key = IHEOL
1872                     automode="AUTOMATIC"
1873                 else:
1874                     automode = "MANUAL"
1875                     key = scan()
1876             elif isit("automatic"):
1877                 if (not itarg) and game.nenhere != 0:
1878                     automode = "FORCEMAN"
1879                 else:
1880                     if game.nenhere==0:
1881                         prout(_("Energy will be expended into space."))
1882                     automode = "AUTOMATIC"
1883                     key = scan()
1884             elif isit("no"):
1885                 no = True
1886             else:
1887                 huh()
1888                 return
1889         elif key == IHREAL:
1890             if game.nenhere==0:
1891                 prout(_("Energy will be expended into space."))
1892                 automode = "AUTOMATIC"
1893             elif not itarg:
1894                 automode = "FORCEMAN"
1895             else:
1896                 automode = "AUTOMATIC"
1897         else:
1898             # IHEOL 
1899             if game.nenhere==0:
1900                 prout(_("Energy will be expended into space."))
1901                 automode = "AUTOMATIC"
1902             elif not itarg:
1903                 automode = "FORCEMAN"
1904             else: 
1905                 proutn(_("Manual or automatic? "))                      
1906     avail = game.energy
1907     if ifast:
1908         avail -= 200.0
1909     if automode == "AUTOMATIC":
1910         if key == IHALPHA and isit("no"):
1911             no = True
1912             key = scan()
1913         if key != IHREAL and game.nenhere != 0:
1914             prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1915         irec=0
1916         while True:
1917             chew()
1918             if not kz:
1919                 for i in range(1, game.nenhere+1):
1920                     irec += math.fabs(game.kpower[i])/(PHASEFAC*math.pow(0.90,game.kdist[i]))*(1.01+0.05*Rand()) + 1.0
1921             kz=1
1922             proutn(_("%d units required. ") % irec)
1923             chew()
1924             proutn(_("Units to fire= "))
1925             key = scan()
1926             if key!=IHREAL:
1927                 return
1928             rpow = aaitem
1929             if rpow > avail:
1930                 proutn(_("Energy available= %.2f") % avail)
1931                 skip(1)
1932                 key = IHEOL
1933             if not rpow > avail:
1934                 break
1935         if rpow<=0:
1936             # chicken out 
1937             chew()
1938             return
1939         key=scan()
1940         if key == IHALPHA and isit("no"):
1941             no = True
1942         if ifast:
1943             game.energy -= 200; # Go and do it! 
1944             if checkshctrl(rpow):
1945                 return
1946         chew()
1947         game.energy -= rpow
1948         extra = rpow
1949         if game.nenhere:
1950             extra = 0.0
1951             powrem = rpow
1952             for i in range(1, game.nenhere+1):
1953                 hits[i] = 0.0
1954                 if powrem <= 0:
1955                     continue
1956                 hits[i] = math.fabs(game.kpower[i])/(PHASEFAC*math.pow(0.90,game.kdist[i]))
1957                 over = (0.01 + 0.05*Rand())*hits[i]
1958                 temp = powrem
1959                 powrem -= hits[i] + over
1960                 if powrem <= 0 and temp < hits[i]:
1961                     hits[i] = temp
1962                 if powrem <= 0:
1963                     over = 0.0
1964                 extra += over
1965             if powrem > 0.0:
1966                 extra += powrem
1967             hittem(hits)
1968             game.ididit = True
1969         if extra > 0 and not game.alldone:
1970             if game.ithere:
1971                 proutn(_("*** Tholian web absorbs "))
1972                 if game.nenhere>0:
1973                     proutn(_("excess "))
1974                 prout(_("phaser energy."))
1975             else:
1976                 prout(_("%d expended on empty space.") % int(extra))
1977     elif automode == "FORCEMAN":
1978         chew()
1979         key = IHEOL
1980         if damaged(DCOMPTR):
1981             prout(_("Battle computer damaged, manual fire only."))
1982         else:
1983             skip(1)
1984             prouts(_("---WORKING---"))
1985             skip(1)
1986             prout(_("Short-range-sensors-damaged"))
1987             prout(_("Insufficient-data-for-automatic-phaser-fire"))
1988             prout(_("Manual-fire-must-be-used"))
1989             skip(1)
1990     elif automode == "MANUAL":
1991         rpow = 0.0
1992         for k in range(1, game.nenhere+1):
1993             aim = game.ks[k]
1994             ienm = game.quad[aim.x][aim.y]
1995             if msgflag:
1996                 proutn(_("Energy available= %.2f") % (avail-0.006))
1997                 skip(1)
1998                 msgflag = False
1999                 rpow = 0.0
2000             if damaged(DSRSENS) and not (abs(game.sector.x-aim.x) < 2 and abs(game.sector.y-aim.y) < 2) and \
2001                 (ienm == IHC or ienm == IHS):
2002                 cramen(ienm)
2003                 prout(_(" can't be located without short range scan."))
2004                 chew()
2005                 key = IHEOL
2006                 hits[k] = 0; # prevent overflow -- thanks to Alexei Voitenko 
2007                 k += 1
2008                 continue
2009             if key == IHEOL:
2010                 chew()
2011                 if itarg and k > kz:
2012                     irec=(abs(game.kpower[k])/(PHASEFAC*math.pow(0.9,game.kdist[k]))) * (1.01+0.05*Rand()) + 1.0
2013                 kz = k
2014                 proutn("(")
2015                 if not damaged(DCOMPTR):
2016                     proutn("%d" % irec)
2017                 else:
2018                     proutn("??")
2019                 proutn(")  ")
2020                 proutn(_("units to fire at "))
2021                 crmena(False, ienm, sector, aim)
2022                 proutn("-  ")
2023                 key = scan()
2024             if key == IHALPHA and isit("no"):
2025                 no = True
2026                 key = scan()
2027                 continue
2028             if key == IHALPHA:
2029                 huh()
2030                 return
2031             if key == IHEOL:
2032                 if k==1: # Let me say I'm baffled by this 
2033                     msgflag = True
2034                 continue
2035             if aaitem < 0:
2036                 # abort out 
2037                 chew()
2038                 return
2039             hits[k] = aaitem
2040             rpow += aaitem
2041             # If total requested is too much, inform and start over 
2042             if rpow > avail:
2043                 prout(_("Available energy exceeded -- try again."))
2044                 chew()
2045                 return
2046             key = scan(); # scan for next value 
2047             k += 1
2048         if rpow == 0.0:
2049             # zero energy -- abort 
2050             chew()
2051             return
2052         if key == IHALPHA and isit("no"):
2053             no = True
2054         game.energy -= rpow
2055         chew()
2056         if ifast:
2057             game.energy -= 200.0
2058             if checkshctrl(rpow):
2059                 return
2060         hittem(hits)
2061         game.ididit = True
2062      # Say shield raised or malfunction, if necessary 
2063     if game.alldone:
2064         return
2065     if ifast:
2066         skip(1)
2067         if no == 0:
2068             if Rand() >= 0.99:
2069                 prout(_("Sulu-  \"Sir, the high-speed shield control has malfunctioned . . ."))
2070                 prouts(_("         CLICK   CLICK   POP  . . ."))
2071                 prout(_(" No response, sir!"))
2072                 game.shldup = False
2073             else:
2074                 prout(_("Shields raised."))
2075         else:
2076             game.shldup = False
2077     overheat(rpow);
2078
2079 # Code from events,c begins here.
2080
2081 # This isn't a real event queue a la BSD Trek yet -- you can only have one 
2082 # event of each type active at any given time.  Mostly these means we can 
2083 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
2084 # BSD Trek, from which we swiped the idea, can have up to 5.
2085
2086 import math
2087
2088 def unschedule(evtype):
2089     # remove an event from the schedule 
2090     game.future[evtype].date = FOREVER
2091     return game.future[evtype]
2092
2093 def is_scheduled(evtype):
2094     # is an event of specified type scheduled 
2095     return game.future[evtype].date != FOREVER
2096
2097 def scheduled(evtype):
2098     # when will this event happen? 
2099     return game.future[evtype].date
2100
2101 def schedule(evtype, offset):
2102     # schedule an event of specified type 
2103     game.future[evtype].date = game.state.date + offset
2104     return game.future[evtype]
2105
2106 def postpone(evtype, offset):
2107     # postpone a scheduled event 
2108     game.future[evtype].date += offset
2109
2110 def cancelrest():
2111     # rest period is interrupted by event 
2112     if game.resting:
2113         skip(1)
2114         proutn(_("Mr. Spock-  \"Captain, shall we cancel the rest period?\""))
2115         if ja() == True:
2116             game.resting = False
2117             game.optime = 0.0
2118             return True
2119
2120     return False
2121
2122 def events():
2123     # run through the event queue looking for things to do 
2124     i=0
2125     fintim = game.state.date + game.optime; yank=0
2126     ictbeam = False; istract = False
2127     w = coord(); hold = coord()
2128     ev = event(); ev2 = event()
2129
2130     def tractorbeam():
2131         # tractor beaming cases merge here 
2132         yank = math.sqrt(yank)
2133         announce()
2134         game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5) 
2135         skip(1)
2136         proutn("***")
2137         crmshp()
2138         prout(_(" caught in long range tractor beam--"))
2139         # If Kirk & Co. screwing around on planet, handle 
2140         atover(True) # atover(true) is Grab 
2141         if game.alldone:
2142             return
2143         if game.icraft: # Caught in Galileo? 
2144             finish(FSTRACTOR)
2145             return
2146         # Check to see if shuttle is aboard 
2147         if game.iscraft == "offship":
2148             skip(1)
2149             if Rand() > 0.5:
2150                 prout(_("Galileo, left on the planet surface, is captured"))
2151                 prout(_("by aliens and made into a flying McDonald's."))
2152                 game.damage[DSHUTTL] = -10
2153                 game.iscraft = "removed"
2154             else:
2155                 prout(_("Galileo, left on the planet surface, is well hidden."))
2156         if evcode==0:
2157             game.quadrant = game.state.kscmdr
2158         else:
2159             game.quadrant = game.state.kcmdr[i]
2160         game.sector = randplace(QUADSIZE)
2161         crmshp()
2162         prout(_(" is pulled to Quadrant %s, Sector %s") \
2163                % (game.quadrant, game.sector))
2164         if game.resting:
2165             prout(_("(Remainder of rest/repair period cancelled.)"))
2166             game.resting = False
2167         if not game.shldup:
2168             if not damaged(DSHIELD) and game.shield > 0:
2169                 doshield(True) # raise shields 
2170                 game.shldchg=False
2171             else:
2172                 prout(_("(Shields not currently useable.)"))
2173         newqad(False)
2174         # Adjust finish time to time of tractor beaming 
2175         fintim = game.state.date+game.optime
2176         attack(False)
2177         if game.state.remcom <= 0:
2178             unschedule(FTBEAM)
2179         else: 
2180             schedule(FTBEAM, game.optime+expran(1.5*game.intime/game.state.remcom))
2181
2182     def destroybase():
2183         # Code merges here for any commander destroying base 
2184         # Not perfect, but will have to do 
2185         # Handle case where base is in same quadrant as starship 
2186         if game.battle == game.quadrant:
2187             game.state.chart[game.battle.x][game.battle.y].starbase = False
2188             game.quad[game.base.x][game.base.y] = IHDOT
2189             game.base.x=game.base.y=0
2190             newcnd()
2191             skip(1)
2192             prout(_("Spock-  \"Captain, I believe the starbase has been destroyed.\""))
2193         elif game.state.rembase != 1 and communicating():
2194             # Get word via subspace radio 
2195             announce()
2196             skip(1)
2197             prout(_("Lt. Uhura-  \"Captain, Starfleet Command reports that"))
2198             proutn(_("   the starbase in Quadrant %s has been destroyed by") % game.battle)
2199             if game.isatb == 2: 
2200                 prout(_("the Klingon Super-Commander"))
2201             else:
2202                 prout(_("a Klingon Commander"))
2203             game.state.chart[game.battle.x][game.battle.y].starbase = False
2204         # Remove Starbase from galaxy 
2205         game.state.galaxy[game.battle.x][game.battle.y].starbase = False
2206         for i in range(1, game.state.rembase+1):
2207             if game.state.baseq[i] == game.battle:
2208                 game.state.baseq[i] = game.state.baseq[game.state.rembase]
2209         game.state.rembase -= 1
2210         if game.isatb == 2:
2211             # reinstate a commander's base attack 
2212             game.battle = hold
2213             game.isatb = 0
2214         else:
2215             invalidate(game.battle)
2216
2217     if idebug:
2218         prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2219         for i in range(1, NEVENTS):
2220             if   i == FSNOVA:  proutn("=== Supernova       ")
2221             elif i == FTBEAM:  proutn("=== T Beam          ")
2222             elif i == FSNAP:   proutn("=== Snapshot        ")
2223             elif i == FBATTAK: proutn("=== Base Attack     ")
2224             elif i == FCDBAS:  proutn("=== Base Destroy    ")
2225             elif i == FSCMOVE: proutn("=== SC Move         ")
2226             elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2227             elif i == FDSPROB: proutn("=== Probe Move      ")
2228             elif i == FDISTR:  proutn("=== Distress Call   ")
2229             elif i == FENSLV:  proutn("=== Enslavement     ")
2230             elif i == FREPRO:  proutn("=== Klingon Build   ")
2231             if is_scheduled(i):
2232                 prout("%.2f" % (scheduled(i)))
2233             else:
2234                 prout("never")
2235     radio_was_broken = damaged(DRADIO)
2236     hold.x = hold.y = 0
2237     while True:
2238         # Select earliest extraneous event, evcode==0 if no events 
2239         evcode = FSPY
2240         if game.alldone:
2241             return
2242         datemin = fintim
2243         for l in range(1, NEVENTS):
2244             if game.future[l].date < datemin:
2245                 evcode = l
2246                 if idebug:
2247                     prout("== Event %d fires" % evcode)
2248                 datemin = game.future[l].date
2249         xtime = datemin-game.state.date
2250         game.state.date = datemin
2251         # Decrement Federation resources and recompute remaining time 
2252         game.state.remres -= (game.state.remkl+4*game.state.remcom)*xtime
2253         game.recompute()
2254         if game.state.remtime <=0:
2255             finish(FDEPLETE)
2256             return
2257         # Any crew left alive? 
2258         if game.state.crew <=0:
2259             finish(FCREW)
2260             return
2261         # Is life support adequate? 
2262         if damaged(DLIFSUP) and game.condition != "docked":
2263             if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2264                 finish(FLIFESUP)
2265                 return
2266             game.lsupres -= xtime
2267             if game.damage[DLIFSUP] <= xtime:
2268                 game.lsupres = game.inlsr
2269         # Fix devices 
2270         repair = xtime
2271         if game.condition == "docked":
2272             repair /= game.docfac
2273         # Don't fix Deathray here 
2274         for l in range(0, NDEVICES):
2275             if game.damage[l] > 0.0 and l != DDRAY:
2276                 if game.damage[l]-repair > 0.0:
2277                     game.damage[l] -= repair
2278                 else:
2279                     game.damage[l] = 0.0
2280         # If radio repaired, update star chart and attack reports 
2281         if radio_was_broken and not damaged(DRADIO):
2282             prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2283             prout(_("   surveillance reports are coming in."))
2284             skip(1)
2285             if not game.iseenit:
2286                 attackreport(False)
2287                 game.iseenit = True
2288             rechart()
2289             prout(_("   The star chart is now up to date.\""))
2290             skip(1)
2291         # Cause extraneous event EVCODE to occur 
2292         game.optime -= xtime
2293         if evcode == FSNOVA: # Supernova 
2294             announce()
2295             supernova(False)
2296             schedule(FSNOVA, expran(0.5*game.intime))
2297             if game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
2298                 return
2299         elif evcode == FSPY: # Check with spy to see if SC should tractor beam 
2300             if game.state.nscrem == 0 or \
2301                 ictbeam or istract or \
2302                 game.condition=="docked" or game.isatb==1 or game.iscate:
2303                 return
2304             if game.ientesc or \
2305                 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2306                 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2307                 (damaged(DSHIELD) and \
2308                  (game.energy < 2500 or damaged(DPHASER)) and \
2309                  (game.torps < 5 or damaged(DPHOTON))):
2310                 # Tractor-beam her! 
2311                 istract = True
2312                 yank = distance(game.state.kscmdr, game.quadrant)
2313                 ictbeam = True
2314                 tractorbeam()
2315             else:
2316                 return
2317         elif evcode == FTBEAM: # Tractor beam 
2318             if game.state.remcom == 0:
2319                 unschedule(FTBEAM)
2320                 continue
2321             i = Rand()*game.state.remcom+1.0
2322             yank = square(game.state.kcmdr[i].x-game.quadrant.x) + square(game.state.kcmdr[i].y-game.quadrant.y)
2323             if istract or game.condition == "docked" or yank == 0:
2324                 # Drats! Have to reschedule 
2325                 schedule(FTBEAM, 
2326                          game.optime + expran(1.5*game.intime/game.state.remcom))
2327                 continue
2328             ictbeam = True
2329             tractorbeam()
2330         elif evcode == FSNAP: # Snapshot of the universe (for time warp) 
2331             game.snapsht = game.state
2332             game.state.snap = True
2333             schedule(FSNAP, expran(0.5 * game.intime))
2334         elif evcode == FBATTAK: # Commander attacks starbase 
2335             if game.state.remcom==0 or game.state.rembase==0:
2336                 # no can do 
2337                 unschedule(FBATTAK)
2338                 unschedule(FCDBAS)
2339                 continue
2340             i = 0
2341             for j in range(1, game.state.rembase+1):
2342                 for k in range(1, game.state.remcom+1):
2343                     if game.state.baseq[j] == game.state.kcmdr[k] and \
2344                         not game.state.baseq[j] == game.quadrant and \
2345                         not game.state.baseq[j] == game.state.kscmdr:
2346                         i = 1
2347                 if i == 1:
2348                     continue
2349             if j>game.state.rembase:
2350                 # no match found -- try later 
2351                 schedule(FBATTAK, expran(0.3*game.intime))
2352                 unschedule(FCDBAS)
2353                 continue
2354             # commander + starbase combination found -- launch attack 
2355             game.battle = game.state.baseq[j]
2356             schedule(FCDBAS, 1.0+3.0*Rand())
2357             if game.isatb: # extra time if SC already attacking 
2358                 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2359             game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2360             game.iseenit = False
2361             if not communicating():
2362                 continue # No warning :-( 
2363             game.iseenit = True
2364             announce()
2365             skip(1)
2366             proutn(_("Lt. Uhura-  \"Captain, the starbase in Quadrant %s") % game.battle)
2367             prout(_("   reports that it is under attack and that it can"))
2368             proutn(_("   hold out only until stardate %d") % (int(scheduled(FCDBAS))))
2369             prout(".\"")
2370             if cancelrest():
2371                 return
2372         elif evcode == FSCDBAS: # Supercommander destroys base 
2373             unschedule(FSCDBAS)
2374             game.isatb = 2
2375             if not game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].starbase: 
2376                 continue # WAS RETURN! 
2377             hold = game.battle
2378             game.battle = game.state.kscmdr
2379             destroybase()
2380         elif evcode == FCDBAS: # Commander succeeds in destroying base 
2381             if evcode==FCDBAS:
2382                 unschedule(FCDBAS)
2383                 # find the lucky pair 
2384                 for i in range(1, game.state.remcom+1):
2385                     if game.state.kcmdr[i] == game.battle: 
2386                         break
2387                 if i > game.state.remcom or game.state.rembase == 0 or \
2388                     not game.state.galaxy[game.battle.x][game.battle.y].starbase:
2389                     # No action to take after all 
2390                     invalidate(game.battle)
2391                     continue
2392             destroybase()
2393         elif evcode == FSCMOVE: # Supercommander moves 
2394             schedule(FSCMOVE, 0.2777)
2395             if not game.ientesc and not istract and game.isatb != 1 and \
2396                    (not game.iscate or not game.justin): 
2397                 supercommander()
2398         elif evcode == FDSPROB: # Move deep space probe 
2399             schedule(FDSPROB, 0.01)
2400             game.probex += game.probeinx
2401             game.probey += game.probeiny
2402             i = (int)(game.probex/QUADSIZE +0.05)
2403             j = (int)(game.probey/QUADSIZE + 0.05)
2404             if game.probec.x != i or game.probec.y != j:
2405                 game.probec.x = i
2406                 game.probec.y = j
2407                 if not VALID_QUADRANT(i, j) or \
2408                     game.state.galaxy[game.probec.x][game.probec.y].supernova:
2409                     # Left galaxy or ran into supernova
2410                     if comunicating():
2411                         announce()
2412                         skip(1)
2413                         proutn(_("Lt. Uhura-  \"The deep space probe "))
2414                         if not VALID_QUADRANT(j, i):
2415                             proutn(_("has left the galaxy"))
2416                         else:
2417                             proutn(_("is no longer transmitting"))
2418                         prout(".\"")
2419                     unschedule(FDSPROB)
2420                     continue
2421                 if not communicating():
2422                     announce()
2423                     skip(1)
2424                     proutn(_("Lt. Uhura-  \"The deep space probe is now in Quadrant %s.\"") % game.probec)
2425             pdest = game.state.galaxy[game.probec.x][game.probec.y]
2426             # Update star chart if Radio is working or have access to radio
2427             if communicating():
2428                 chp = game.state.chart[game.probec.x][game.probec.y]
2429                 chp.klingons = pdest.klingons
2430                 chp.starbase = pdest.starbase
2431                 chp.stars = pdest.stars
2432                 pdest.charted = True
2433             game.proben -= 1 # One less to travel
2434             if game.proben == 0 and game.isarmed and pdest.stars:
2435                 # lets blow the sucker! 
2436                 supernova(True, game.probec)
2437                 unschedule(FDSPROB)
2438                 if game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova: 
2439                     return
2440         elif evcode == FDISTR: # inhabited system issues distress call 
2441             unschedule(FDISTR)
2442             # try a whole bunch of times to find something suitable 
2443             for i in range(100):
2444                 # need a quadrant which is not the current one,
2445                 # which has some stars which are inhabited and
2446                 # not already under attack, which is not
2447                 # supernova'ed, and which has some Klingons in it
2448                 w = randplace(GALSIZE)
2449                 q = game.state.galaxy[w.x][w.y]
2450                 if not (game.quadrant == w or q.planet == NOPLANET or \
2451                       not game.state.planets[q.planet].inhabited or \
2452                       q.supernova or q.status!=secure or q.klingons<=0):
2453                     break
2454             else:
2455                 # can't seem to find one; ignore this call 
2456                 if idebug:
2457                     prout("=== Couldn't find location for distress event.")
2458                 continue
2459             # got one!!  Schedule its enslavement 
2460             ev = schedule(FENSLV, expran(game.intime))
2461             ev.quadrant = w
2462             q.status = distressed
2463
2464             # tell the captain about it if we can 
2465             if communicating():
2466                 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2467                         % (q.planet, `w`))
2468                 prout(_("by a Klingon invasion fleet."))
2469                 if cancelrest():
2470                     return
2471         elif evcode == FENSLV:          # starsystem is enslaved 
2472             ev = unschedule(FENSLV)
2473             # see if current distress call still active 
2474             q = game.state.galaxy[ev.quadrant.x][ev.quadrant.y]
2475             if q.klingons <= 0:
2476                 q.status = "secure"
2477                 continue
2478             q.status = "enslaved"
2479
2480             # play stork and schedule the first baby 
2481             ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2482             ev2.quadrant = ev.quadrant
2483
2484             # report the disaster if we can 
2485             if communicating():
2486                 prout(_("Uhura- We've lost contact with starsystem %s") % \
2487                         q.planet)
2488                 prout(_("in Quadrant %s.\n") % ev.quadrant)
2489         elif evcode == FREPRO:          # Klingon reproduces 
2490             # If we ever switch to a real event queue, we'll need to
2491             # explicitly retrieve and restore the x and y.
2492             ev = schedule(FREPRO, expran(1.0 * game.intime))
2493             # see if current distress call still active 
2494             q = game.state.galaxy[ev.quadrant.x][ev.quadrant.y]
2495             if q.klingons <= 0:
2496                 q.status = "secure"
2497                 continue
2498             if game.state.remkl >=MAXKLGAME:
2499                 continue                # full right now 
2500             # reproduce one Klingon 
2501             w = ev.quadrant
2502             if game.klhere >= MAXKLQUAD:
2503                 try:
2504                     # this quadrant not ok, pick an adjacent one 
2505                     for i in range(w.x - 1, w.x + 2):
2506                         for j in range(w.y - 1, w.y + 2):
2507                             if not VALID_QUADRANT(i, j):
2508                                 continue
2509                             q = game.state.galaxy[w.x][w.y]
2510                             # check for this quad ok (not full & no snova) 
2511                             if q.klingons >= MAXKLQUAD or q.supernova:
2512                                 continue
2513                             raise "FOUNDIT"
2514                     else:
2515                         continue        # search for eligible quadrant failed
2516                 except "FOUNDIT":
2517                     w.x = i
2518                     w.y = j
2519             # deliver the child 
2520             game.state.remkl += 1
2521             q.klingons += 1
2522             if game.quadrant == w:
2523                 game.klhere += 1
2524                 newkling(game.klhere)
2525             # recompute time left
2526             game.recompute()
2527             # report the disaster if we can 
2528             if communicating():
2529                 if game.quadrant == w:
2530                     prout(_("Spock- sensors indicate the Klingons have"))
2531                     prout(_("launched a warship from %s.") % q.planet)
2532                 else:
2533                     prout(_("Uhura- Starfleet reports increased Klingon activity"))
2534                     if q.planet != NOPLANET:
2535                         proutn(_("near %s") % q.planet)
2536                     prout(_("in Quadrant %s.") % w)
2537                                 
2538 def wait():
2539     # wait on events 
2540     game.ididit = False
2541     while True:
2542         key = scan()
2543         if key  != IHEOL:
2544             break
2545         proutn(_("How long? "))
2546     chew()
2547     if key != IHREAL:
2548         huh()
2549         return
2550     origTime = delay = aaitem
2551     if delay <= 0.0:
2552         return
2553     if delay >= game.state.remtime or game.nenhere != 0:
2554         proutn(_("Are you sure? "))
2555         if ja() == False:
2556             return
2557
2558     # Alternate resting periods (events) with attacks 
2559
2560     game.resting = True
2561     while True:
2562         if delay <= 0:
2563             game.resting = False
2564         if not game.resting:
2565             prout(_("%d stardates left.") % int(game.state.remtime))
2566             return
2567         temp = game.optime = delay
2568         if game.nenhere:
2569             rtime = 1.0 + Rand()
2570             if rtime < temp:
2571                 temp = rtime
2572             game.optime = temp
2573         if game.optime < delay:
2574             attack(False)
2575         if game.alldone:
2576             return
2577         events()
2578         game.ididit = True
2579         if game.alldone:
2580             return
2581         delay -= temp
2582         # Repair Deathray if long rest at starbase 
2583         if origTime-delay >= 9.99 and game.condition == "docked":
2584             game.damage[DDRAY] = 0.0
2585         # leave if quadrant supernovas
2586         if game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
2587             break
2588     game.resting = False
2589     game.optime = 0
2590
2591 # A nova occurs.  It is the result of having a star hit with a
2592 # photon torpedo, or possibly of a probe warhead going off.
2593 # Stars that go nova cause stars which surround them to undergo
2594 # the same probabilistic process.  Klingons next to them are
2595 # destroyed.  And if the starship is next to it, it gets zapped.
2596 # If the zap is too much, it gets destroyed.
2597         
2598 def nova(nov):
2599     # star goes nova 
2600     course = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2601     newc = coord(); scratch = coord()
2602
2603     if Rand() < 0.05:
2604         # Wow! We've supernova'ed 
2605         supernova(False, nov)
2606         return
2607
2608     # handle initial nova 
2609     game.quad[nov.x][nov.y] = IHDOT
2610     crmena(False, IHSTAR, sector, nov)
2611     prout(_(" novas."))
2612     game.state.galaxy[game.quadrant.x][game.quadrant.y].stars -= 1
2613     game.state.starkl += 1
2614         
2615     # Set up stack to recursively trigger adjacent stars 
2616     bot = top = top2 = 1
2617     kount = 0
2618     icx = icy = 0
2619     hits[1][1] = nov.x
2620     hits[1][2] = nov.y
2621     while True:
2622         for mm in range(bot, top+1): 
2623             for nn in range(1, 3+1):  # nn,j represents coordinates around current 
2624                 for j in range(1, 3+1):
2625                     if j==2 and nn== 2:
2626                         continue
2627                     scratch.x = hits[mm][1]+nn-2
2628                     scratch.y = hits[mm][2]+j-2
2629                     if not VALID_SECTOR(scratch.y, scratch.x):
2630                         continue
2631                     iquad = game.quad[scratch.x][scratch.y]
2632                     # Empty space ends reaction
2633                     if iquad in (IHDOT, IHQUEST, IHBLANK, IHT, IHWEB):
2634                         break
2635                     elif iquad == IHSTAR: # Affect another star 
2636                         if Rand() < 0.05:
2637                             # This star supernovas 
2638                             scratch = supernova(False)
2639                             return
2640                         top2 += 1
2641                         hits[top2][1]=scratch.x
2642                         hits[top2][2]=scratch.y
2643                         game.state.galaxy[game.quadrant.x][game.quadrant.y].stars -= 1
2644                         game.state.starkl += 1
2645                         crmena(True, IHSTAR, sector, scratch)
2646                         prout(_(" novas."))
2647                         game.quad[scratch.x][scratch.y] = IHDOT
2648                     elif iquad == IHP: # Destroy planet 
2649                         game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = NOPLANET
2650                         game.state.nplankl += 1
2651                         crmena(True, IHP, sector, scratch)
2652                         prout(_(" destroyed."))
2653                         game.state.planets[game.iplnet].pclass = destroyed
2654                         game.iplnet = 0
2655                         invalidate(game.plnet)
2656                         if game.landed:
2657                             finish(FPNOVA)
2658                             return
2659                         game.quad[scratch.x][scratch.y] = IHDOT
2660                     elif iquad == IHB: # Destroy base 
2661                         game.state.galaxy[game.quadrant.x][game.quadrant.y].starbase = False
2662                         for i in range(1, game.state.rembase+1):
2663                             if game.state.baseq[i] == game.quadrant: 
2664                                 break
2665                         game.state.baseq[i] = game.state.baseq[game.state.rembase]
2666                         game.state.rembase -= 1
2667                         invalidate(game.base)
2668                         game.state.basekl += 1
2669                         newcnd()
2670                         crmena(True, IHB, sector, scratch)
2671                         prout(_(" destroyed."))
2672                         game.quad[scratch.x][scratch.y] = IHDOT
2673                     elif iquad in (IHE, IHF): # Buffet ship 
2674                         prout(_("***Starship buffeted by nova."))
2675                         if game.shldup:
2676                             if game.shield >= 2000.0:
2677                                 game.shield -= 2000.0
2678                             else:
2679                                 diff = 2000.0 - game.shield
2680                                 game.energy -= diff
2681                                 game.shield = 0.0
2682                                 game.shldup = False
2683                                 prout(_("***Shields knocked out."))
2684                                 game.damage[DSHIELD] += 0.005*game.damfac*Rand()*diff
2685                         else:
2686                             game.energy -= 2000.0
2687                         if game.energy <= 0:
2688                             finish(FNOVA)
2689                             return
2690                         # add in course nova contributes to kicking starship
2691                         icx += game.sector.x-hits[mm][1]
2692                         icy += game.sector.y-hits[mm][2]
2693                         kount += 1
2694                     elif iquad == IHK: # kill klingon 
2695                         deadkl(scratch,iquad, scratch)
2696                     elif iquad in (IHC,IHS,IHR): # Damage/destroy big enemies 
2697                         for ll in range(1, game.nenhere+1):
2698                             if game.ks[ll] == scratch:
2699                                 break
2700                         game.kpower[ll] -= 800.0 # If firepower is lost, die 
2701                         if game.kpower[ll] <= 0.0:
2702                             deadkl(scratch, iquad, scratch)
2703                             break
2704                         newc.x = scratch.x + scratch.x - hits[mm][1]
2705                         newc.y = scratch.y + scratch.y - hits[mm][2]
2706                         crmena(True, iquad, sector, scratch)
2707                         proutn(_(" damaged"))
2708                         if not VALID_SECTOR(newc.x, newc.y):
2709                             # can't leave quadrant 
2710                             skip(1)
2711                             break
2712                         iquad1 = game.quad[newc.x][newc.y]
2713                         if iquad1 == IHBLANK:
2714                             proutn(_(", blasted into "))
2715                             crmena(False, IHBLANK, sector, newc)
2716                             skip(1)
2717                             deadkl(scratch, iquad, newc)
2718                             break
2719                         if iquad1 != IHDOT:
2720                             # can't move into something else 
2721                             skip(1)
2722                             break
2723                         proutn(_(", buffeted to Sector %s") % newc)
2724                         game.quad[scratch.x][scratch.y] = IHDOT
2725                         game.quad[newc.x][newc.y] = iquad
2726                         game.ks[ll] = newc
2727                         game.kdist[ll] = game.kavgd[ll] = distance(game.sector, newc)
2728                         skip(1)
2729         if top == top2: 
2730             break
2731         bot = top + 1
2732         top = top2
2733     if kount==0: 
2734         return
2735
2736     # Starship affected by nova -- kick it away. 
2737     game.dist = kount*0.1
2738     icx = sgn(icx)
2739     icy = sgn(icy)
2740     game.direc = course[3*(icx+1)+icy+2]
2741     if game.direc == 0.0:
2742         game.dist = 0.0
2743     if game.dist == 0.0:
2744         return
2745     game.optime = 10.0*game.dist/16.0
2746     skip(1)
2747     prout(_("Force of nova displaces starship."))
2748     imove(True)
2749     game.optime = 10.0*game.dist/16.0
2750     return
2751         
2752 def supernova(induced, w=None):
2753     # star goes supernova 
2754     num = 0; npdead = 0
2755     nq = coord()
2756
2757     if w != None: 
2758         nq = w
2759     else:
2760         stars = 0
2761         # Scheduled supernova -- select star 
2762         # logic changed here so that we won't favor quadrants in top
2763         # left of universe 
2764         for nq.x in range(1, GALSIZE+1):
2765             for nq.y in range(1, GALSIZE+1):
2766                 stars += game.state.galaxy[nq.x][nq.y].stars
2767         if stars == 0:
2768             return # nothing to supernova exists 
2769         num = Rand()*stars + 1
2770         for nq.x in range(1, GALSIZE+1):
2771             for nq.y in range(1, GALSIZE+1):
2772                 num -= game.state.galaxy[nq.x][nq.y].stars
2773                 if num <= 0:
2774                     break
2775             if num <=0:
2776                 break
2777         if idebug:
2778             proutn("=== Super nova here?")
2779             if ja() == True:
2780                 nq = game.quadrant
2781
2782     if not nq == game.quadrant or game.justin:
2783         # it isn't here, or we just entered (treat as enroute) 
2784         if communicating():
2785             skip(1)
2786             prout(_("Message from Starfleet Command       Stardate %.2f") % game.state.date)
2787             prout(_("     Supernova in Quadrant %s; caution advised.") % nq)
2788     else:
2789         ns = coord()
2790         # we are in the quadrant! 
2791         num = Rand()* game.state.galaxy[nq.x][nq.y].stars + 1
2792         for ns.x in range(1, QUADSIZE+1):
2793             for ns.y in range(1, QUADSIZE+1):
2794                 if game.quad[ns.x][ns.y]==IHSTAR:
2795                     num -= 1
2796                     if num==0:
2797                         break
2798             if num==0:
2799                 break
2800
2801         skip(1)
2802         prouts(_("***RED ALERT!  RED ALERT!"))
2803         skip(1)
2804         prout(_("***Incipient supernova detected at Sector %s") % ns)
2805         if square(ns.x-game.sector.x) + square(ns.y-game.sector.y) <= 2.1:
2806             proutn(_("Emergency override attempts t"))
2807             prouts("***************")
2808             skip(1)
2809             stars()
2810             game.alldone = True
2811
2812     # destroy any Klingons in supernovaed quadrant 
2813     kldead = game.state.galaxy[nq.x][nq.y].klingons
2814     game.state.galaxy[nq.x][nq.y].klingons = 0
2815     if nq == game.state.kscmdr:
2816         # did in the Supercommander! 
2817         game.state.nscrem = game.state.kscmdr.x = game.state.kscmdr.y = game.isatb =  0
2818         game.iscate = False
2819         unschedule(FSCMOVE)
2820         unschedule(FSCDBAS)
2821     if game.state.remcom:
2822         maxloop = game.state.remcom
2823         for l in range(1, maxloop+1):
2824             if game.state.kcmdr[l] == nq:
2825                 game.state.kcmdr[l] = game.state.kcmdr[game.state.remcom]
2826                 invalidate(game.state.kcmdr[game.state.remcom])
2827                 game.state.remcom -= 1
2828                 kldead -= 1
2829                 if game.state.remcom==0:
2830                     unschedule(FTBEAM)
2831                 break
2832     game.state.remkl -= kldead
2833     # destroy Romulans and planets in supernovaed quadrant 
2834     nrmdead = game.state.galaxy[nq.x][nq.y].romulans
2835     game.state.galaxy[nq.x][nq.y].romulans = 0
2836     game.state.nromrem -= nrmdead
2837     # Destroy planets 
2838     for loop in range(game.inplan):
2839         if game.state.planets[loop].w == nq:
2840             game.state.planets[loop].pclass = destroyed
2841             npdead += 1
2842     # Destroy any base in supernovaed quadrant 
2843     if game.state.rembase:
2844         maxloop = game.state.rembase
2845         for loop in range(1, maxloop+1):
2846             if game.state.baseq[loop] == nq:
2847                 game.state.baseq[loop] = game.state.baseq[game.state.rembase]
2848                 invalidate(game.state.baseq[game.state.rembase])
2849                 game.state.rembase -= 1
2850                 break
2851     # If starship caused supernova, tally up destruction 
2852     if induced:
2853         game.state.starkl += game.state.galaxy[nq.x][nq.y].stars
2854         game.state.basekl += game.state.galaxy[nq.x][nq.y].starbase
2855         game.state.nplankl += npdead
2856     # mark supernova in galaxy and in star chart 
2857     if game.quadrant == nq or communicating():
2858         game.state.galaxy[nq.x][nq.y].supernova = True
2859     # If supernova destroys last Klingons give special message 
2860     if (game.state.remkl + game.state.remcom + game.state.nscrem)==0 and not nq == game.quadrant:
2861         skip(2)
2862         if not induced:
2863             prout(_("Lucky you!"))
2864         proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2865         finish(FWON)
2866         return
2867     # if some Klingons remain, continue or die in supernova 
2868     if game.alldone:
2869         finish(FSNOVAED)
2870     return
2871
2872 # Code from finish.c ends here.
2873
2874 def selfdestruct():
2875     # self-destruct maneuver 
2876     # Finish with a BANG! 
2877     chew()
2878     if damaged(DCOMPTR):
2879         prout(_("Computer damaged; cannot execute destruct sequence."))
2880         return
2881     prouts(_("---WORKING---")); skip(1)
2882     prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2883     prouts("   10"); skip(1)
2884     prouts("       9"); skip(1)
2885     prouts("          8"); skip(1)
2886     prouts("             7"); skip(1)
2887     prouts("                6"); skip(1)
2888     skip(1)
2889     prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2890     skip(1)
2891     prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2892     skip(1)
2893     prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2894     skip(1)
2895     scan()
2896     chew()
2897     if game.passwd != citem:
2898         prouts(_("PASSWORD-REJECTED;"))
2899         skip(1)
2900         prouts(_("CONTINUITY-EFFECTED"))
2901         skip(2)
2902         return
2903     prouts(_("PASSWORD-ACCEPTED")); skip(1)
2904     prouts("                   5"); skip(1)
2905     prouts("                      4"); skip(1)
2906     prouts("                         3"); skip(1)
2907     prouts("                            2"); skip(1)
2908     prouts("                              1"); skip(1)
2909     if Rand() < 0.15:
2910         prouts(_("GOODBYE-CRUEL-WORLD"))
2911         skip(1)
2912     kaboom()
2913
2914 def kaboom():
2915     stars()
2916     if game.ship==IHE:
2917         prouts("***")
2918     prouts(_("********* Entropy of "))
2919     crmshp()
2920     prouts(_(" maximized *********"))
2921     skip(1)
2922     stars()
2923     skip(1)
2924     if game.nenhere != 0:
2925         whammo = 25.0 * game.energy
2926         l=1
2927         while l <= game.nenhere:
2928             if game.kpower[l]*game.kdist[l] <= whammo: 
2929                 deadkl(game.ks[l], game.quad[game.ks[l].x][game.ks[l].y], game.ks[l])
2930             l += 1
2931     finish(FDILITHIUM)
2932                                 
2933 def killrate():
2934     "Compute our rate of kils over time."
2935     return ((game.inkling + game.incom + game.inscom) - (game.state.remkl + game.state.remcom + game.state.nscrem))/(game.state.date-game.indate)
2936
2937 def badpoints():
2938     "Compute demerits."
2939     badpt = 5.0*game.state.starkl + \
2940             game.casual + \
2941             10.0*game.state.nplankl + \
2942             300*game.state.nworldkl + \
2943             45.0*game.nhelp +\
2944             100.0*game.state.basekl +\
2945             3.0*game.abandoned
2946     if game.ship == IHF:
2947         badpt += 100.0
2948     elif game.ship == None:
2949         badpt += 200.0
2950     return badpt
2951
2952
2953 def finish(ifin):
2954     # end the game, with appropriate notfications 
2955     igotit = False
2956     game.alldone = True
2957     skip(3)
2958     prout(_("It is stardate %.1f.") % game.state.date)
2959     skip(1)
2960     if ifin == FWON: # Game has been won
2961         if game.state.nromrem != 0:
2962             prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2963                   game.state.nromrem)
2964
2965         prout(_("You have smashed the Klingon invasion fleet and saved"))
2966         prout(_("the Federation."))
2967         game.gamewon = True
2968         if game.alive:
2969             badpt = badpoints()
2970             if badpt < 100.0:
2971                 badpt = 0.0     # Close enough!
2972             # killsPerDate >= RateMax
2973             if game.state.date-game.indate < 5.0 or \
2974                 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2975                 skip(1)
2976                 prout(_("In fact, you have done so well that Starfleet Command"))
2977                 if game.skill == SKILL_NOVICE:
2978                     prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2979                 elif game.skill == SKILL_FAIR:
2980                     prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2981                 elif game.skill == SKILL_GOOD:
2982                     prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2983                 elif game.skill == SKILL_EXPERT:
2984                     prout(_("promotes you to Commodore Emeritus."))
2985                     skip(1)
2986                     prout(_("Now that you think you're really good, try playing"))
2987                     prout(_("the \"Emeritus\" game. It will splatter your ego."))
2988                 elif game.skill == SKILL_EMERITUS:
2989                     skip(1)
2990                     proutn(_("Computer-  "))
2991                     prouts(_("ERROR-ERROR-ERROR-ERROR"))
2992                     skip(2)
2993                     prouts(_("  YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
2994                     skip(1)
2995                     prouts(_("  THIS-PROGRAM-MUST-SURVIVE"))
2996                     skip(1)
2997                     prouts(_("  THIS-PROGRAM-MUST-SURVIVE"))
2998                     skip(1)
2999                     prouts(_("  THIS-PROGRAM-MUST-SURVIVE"))
3000                     skip(1)
3001                     prouts(_("  THIS-PROGRAM-MUST?- MUST ? - SUR? ? -?  VI"))
3002                     skip(2)
3003                     prout(_("Now you can retire and write your own Star Trek game!"))
3004                     skip(1)
3005                 elif game.skill >= SKILL_EXPERT:
3006                     if game.thawed and not idebug:
3007                         prout(_("You cannot get a citation, so..."))
3008                     else:
3009                         proutn(_("Do you want your Commodore Emeritus Citation printed? "))
3010                         chew()
3011                         if ja() == True:
3012                             igotit = True
3013             # Only grant long life if alive (original didn't!)
3014             skip(1)
3015             prout(_("LIVE LONG AND PROSPER."))
3016         score()
3017         if igotit:
3018             plaque()        
3019         return
3020     elif ifin == FDEPLETE: # Federation Resources Depleted
3021         prout(_("Your time has run out and the Federation has been"))
3022         prout(_("conquered.  Your starship is now Klingon property,"))
3023         prout(_("and you are put on trial as a war criminal.  On the"))
3024         proutn(_("basis of your record, you are "))
3025         if (game.state.remkl + game.state.remcom + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
3026             prout(_("acquitted."))
3027             skip(1)
3028             prout(_("LIVE LONG AND PROSPER."))
3029         else:
3030             prout(_("found guilty and"))
3031             prout(_("sentenced to death by slow torture."))
3032             game.alive = False
3033         score()
3034         return
3035     elif ifin == FLIFESUP:
3036         prout(_("Your life support reserves have run out, and"))
3037         prout(_("you die of thirst, starvation, and asphyxiation."))
3038         prout(_("Your starship is a derelict in space."))
3039     elif ifin == FNRG:
3040         prout(_("Your energy supply is exhausted."))
3041         skip(1)
3042         prout(_("Your starship is a derelict in space."))
3043     elif ifin == FBATTLE:
3044         proutn(_("The "))
3045         crmshp()
3046         prout(_("has been destroyed in battle."))
3047         skip(1)
3048         prout(_("Dulce et decorum est pro patria mori."))
3049     elif ifin == FNEG3:
3050         prout(_("You have made three attempts to cross the negative energy"))
3051         prout(_("barrier which surrounds the galaxy."))
3052         skip(1)
3053         prout(_("Your navigation is abominable."))
3054         score()
3055     elif ifin == FNOVA:
3056         prout(_("Your starship has been destroyed by a nova."))
3057         prout(_("That was a great shot."))
3058         skip(1)
3059     elif ifin == FSNOVAED:
3060         proutn(_("The "))
3061         crmshp()
3062         prout(_(" has been fried by a supernova."))
3063         prout(_("...Not even cinders remain..."))
3064     elif ifin == FABANDN:
3065         prout(_("You have been captured by the Klingons. If you still"))
3066         prout(_("had a starbase to be returned to, you would have been"))
3067         prout(_("repatriated and given another chance. Since you have"))
3068         prout(_("no starbases, you will be mercilessly tortured to death."))
3069     elif ifin == FDILITHIUM:
3070         prout(_("Your starship is now an expanding cloud of subatomic particles"))
3071     elif ifin == FMATERIALIZE:
3072         prout(_("Starbase was unable to re-materialize your starship."))
3073         prout(_("Sic transit gloria mundi"))
3074     elif ifin == FPHASER:
3075         proutn(_("The "))
3076         crmshp()
3077         prout(_(" has been cremated by its own phasers."))
3078     elif ifin == FLOST:
3079         prout(_("You and your landing party have been"))
3080         prout(_("converted to energy, disipating through space."))
3081     elif ifin == FMINING:
3082         prout(_("You are left with your landing party on"))
3083         prout(_("a wild jungle planet inhabited by primitive cannibals."))
3084         skip(1)
3085         prout(_("They are very fond of \"Captain Kirk\" soup."))
3086         skip(1)
3087         proutn(_("Without your leadership, the "))
3088         crmshp()
3089         prout(_(" is destroyed."))
3090     elif ifin == FDPLANET:
3091         prout(_("You and your mining party perish."))
3092         skip(1)
3093         prout(_("That was a great shot."))
3094         skip(1)
3095     elif ifin == FSSC:
3096         prout(_("The Galileo is instantly annihilated by the supernova."))
3097         prout(_("You and your mining party are atomized."))
3098         skip(1)
3099         proutn(_("Mr. Spock takes command of the "))
3100         crmshp()
3101         prout(_(" and"))
3102         prout(_("joins the Romulans, reigning terror on the Federation."))
3103     elif ifin == FPNOVA:
3104         prout(_("You and your mining party are atomized."))
3105         skip(1)
3106         proutn(_("Mr. Spock takes command of the "))
3107         crmshp()
3108         prout(_(" and"))
3109         prout(_("joins the Romulans, reigning terror on the Federation."))
3110     elif ifin == FSTRACTOR:
3111         prout(_("The shuttle craft Galileo is also caught,"))
3112         prout(_("and breaks up under the strain."))
3113         skip(1)
3114         prout(_("Your debris is scattered for millions of miles."))
3115         proutn(_("Without your leadership, the "))
3116         crmshp()
3117         prout(_(" is destroyed."))
3118     elif ifin == FDRAY:
3119         prout(_("The mutants attack and kill Spock."))
3120         prout(_("Your ship is captured by Klingons, and"))
3121         prout(_("your crew is put on display in a Klingon zoo."))
3122     elif ifin == FTRIBBLE:
3123         prout(_("Tribbles consume all remaining water,"))
3124         prout(_("food, and oxygen on your ship."))
3125         skip(1)
3126         prout(_("You die of thirst, starvation, and asphyxiation."))
3127         prout(_("Your starship is a derelict in space."))
3128     elif ifin == FHOLE:
3129         prout(_("Your ship is drawn to the center of the black hole."))
3130         prout(_("You are crushed into extremely dense matter."))
3131     elif ifin == FCREW:
3132         prout(_("Your last crew member has died."))
3133     if game.ship == IHF:
3134         game.ship = None
3135     elif game.ship == IHE:
3136         game.ship = IHF
3137     game.alive = False
3138     if (game.state.remkl + game.state.remcom + game.state.nscrem) != 0:
3139         goodies = game.state.remres/game.inresor
3140         baddies = (game.state.remkl + 2.0*game.state.remcom)/(game.inkling+2.0*game.incom)
3141         if goodies/baddies >= 1.0+0.5*Rand():
3142             prout(_("As a result of your actions, a treaty with the Klingon"))
3143             prout(_("Empire has been signed. The terms of the treaty are"))
3144             if goodies/baddies >= 3.0+Rand():
3145                 prout(_("favorable to the Federation."))
3146                 skip(1)
3147                 prout(_("Congratulations!"))
3148             else:
3149                 prout(_("highly unfavorable to the Federation."))
3150         else:
3151             prout(_("The Federation will be destroyed."))
3152     else:
3153         prout(_("Since you took the last Klingon with you, you are a"))
3154         prout(_("martyr and a hero. Someday maybe they'll erect a"))
3155         prout(_("statue in your memory. Rest in peace, and try not"))
3156         prout(_("to think about pigeons."))
3157         game.gamewon = True
3158     score()
3159
3160 def score():
3161     # compute player's score 
3162     timused = game.state.date - game.indate
3163
3164     iskill = game.skill
3165     if (timused == 0 or (game.state.remkl + game.state.remcom + game.state.nscrem) != 0) and timused < 5.0:
3166         timused = 5.0
3167     perdate = killrate()
3168     ithperd = 500*perdate + 0.5
3169     iwon = 0
3170     if game.gamewon:
3171         iwon = 100*game.skill
3172     if game.ship == IHE: 
3173         klship = 0
3174     elif game.ship == IHF: 
3175         klship = 1
3176     else:
3177         klship = 2
3178     if not game.gamewon:
3179         game.state.nromrem = 0 # None captured if no win
3180     iscore = 10*(game.inkling - game.state.remkl) \
3181              + 50*(game.incom - game.state.remcom) \
3182              + ithperd + iwon \
3183              + 20*(game.inrom - game.state.nromrem) \
3184              + 200*(game.inscom - game.state.nscrem) \
3185              - game.state.nromrem \
3186              - badpoints()
3187     if not game.alive:
3188         iscore -= 200
3189     skip(2)
3190     prout(_("Your score --"))
3191     if game.inrom - game.state.nromrem:
3192         prout(_("%6d Romulans destroyed                 %5d") %
3193               (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
3194     if game.state.nromrem:
3195         prout(_("%6d Romulans captured                  %5d") %
3196               (game.state.nromrem, game.state.nromrem))
3197     if game.inkling - game.state.remkl:
3198         prout(_("%6d ordinary Klingons destroyed        %5d") %
3199               (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
3200     if game.incom - game.state.remcom:
3201         prout(_("%6d Klingon commanders destroyed       %5d") %
3202               (game.incom - game.state.remcom, 50*(game.incom - game.state.remcom)))
3203     if game.inscom - game.state.nscrem:
3204         prout(_("%6d Super-Commander destroyed          %5d") %
3205               (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3206     if ithperd:
3207         prout(_("%6.2f Klingons per stardate              %5d") %
3208               (perdate, ithperd))
3209     if game.state.starkl:
3210         prout(_("%6d stars destroyed by your action     %5d") %
3211               (game.state.starkl, -5*game.state.starkl))
3212     if game.state.nplankl:
3213         prout(_("%6d planets destroyed by your action   %5d") %
3214               (game.state.nplankl, -10*game.state.nplankl))
3215     if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3216         prout(_("%6d inhabited planets destroyed by your action   %5d") %
3217               (game.state.nplankl, -300*game.state.nworldkl))
3218     if game.state.basekl:
3219         prout(_("%6d bases destroyed by your action     %5d") %
3220               (game.state.basekl, -100*game.state.basekl))
3221     if game.nhelp:
3222         prout(_("%6d calls for help from starbase       %5d") %
3223               (game.nhelp, -45*game.nhelp))
3224     if game.casual:
3225         prout(_("%6d casualties incurred                %5d") %
3226               (game.casual, -game.casual))
3227     if game.abandoned:
3228         prout(_("%6d crew abandoned in space            %5d") %
3229               (game.abandoned, -3*game.abandoned))
3230     if klship:
3231         prout(_("%6d ship(s) lost or destroyed          %5d") %
3232               (klship, -100*klship))
3233     if not game.alive:
3234         prout(_("Penalty for getting yourself killed        -200"))
3235     if game.gamewon:
3236         proutn(_("Bonus for winning "))
3237         if game.skill   == SKILL_NOVICE:        proutn(_("Novice game  "))
3238         elif game.skill == SKILL_FAIR:          proutn(_("Fair game    "))
3239         elif game.skill ==  SKILL_GOOD:         proutn(_("Good game    "))
3240         elif game.skill ==  SKILL_EXPERT:       proutn(_("Expert game  "))
3241         elif game.skill ==  SKILL_EMERITUS:     proutn(_("Emeritus game"))
3242         prout("           %5d" % iwon)
3243     skip(1)
3244     prout(_("TOTAL SCORE                               %5d") % iscore)
3245
3246 def plaque():
3247     # emit winner's commemmorative plaque 
3248     skip(2)
3249     while True:
3250         proutn(_("File or device name for your plaque: "))
3251         cgetline(winner, sizeof(winner))
3252         try:
3253             fp = open(winner, "w")
3254             break
3255         except IOError:
3256             prout(_("Invalid name."))
3257
3258     proutn(_("Enter name to go on plaque (up to 30 characters): "))
3259     cgetline(winner, sizeof(winner))
3260     # The 38 below must be 64 for 132-column paper 
3261     nskip = 38 - len(winner)/2
3262
3263     fp.write("\n\n\n\n")
3264     # --------DRAW ENTERPRISE PICTURE. 
3265     fp.write("                                       EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3266     fp.write("                                      EEE                      E  : :                                         :  E\n" )
3267     fp.write("                                    EE   EEE                   E  : :                   NCC-1701              :  E\n")
3268     fp.write("EEEEEEEEEEEEEEEE        EEEEEEEEEEEEEEE  : :                              : E\n")
3269     fp.write(" E                                     EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3270     fp.write("                      EEEEEEEEE               EEEEEEEEEEEEE                 E  E\n")
3271     fp.write("                               EEEEEEE   EEEEE    E          E              E  E\n")
3272     fp.write("                                      EEE           E          E            E  E\n")
3273     fp.write("                                                       E         E          E  E\n")
3274     fp.write("                                                         EEEEEEEEEEEEE      E  E\n")
3275     fp.write("                                                      EEE :           EEEEEEE  EEEEEEEE\n")
3276     fp.write("                                                    :E    :                 EEEE       E\n")
3277     fp.write("                                                   .-E   -:-----                       E\n")
3278     fp.write("                                                    :E    :                            E\n")
3279     fp.write("                                                      EE  :                    EEEEEEEE\n")
3280     fp.write("                                                       EEEEEEEEEEEEEEEEEEEEEEE\n")
3281     fp.write("\n\n\n")
3282     fp.write(_("                                                       U. S. S. ENTERPRISE\n"))
3283     fp.write("\n\n\n\n")
3284     fp.write(_("                                  For demonstrating outstanding ability as a starship captain\n"))
3285     fp.write("\n")
3286     fp.write(_("                                                Starfleet Command bestows to you\n"))
3287     fp.write("\n")
3288     fp.write("%*s%s\n\n" % (nskip, "", winner))
3289     fp.write(_("                                                           the rank of\n\n"))
3290     fp.write(_("                                                       \"Commodore Emeritus\"\n\n"))
3291     fp.write("                                                          ")
3292     if game.skill ==  SKILL_EXPERT:
3293         fp.write(_(" Expert level\n\n"))
3294     elif game.skill == SKILL_EMERITUS:
3295         fp.write(_("Emeritus level\n\n"))
3296     else:
3297         fp.write(_(" Cheat level\n\n"))
3298     timestring = ctime()
3299     fp.write(_("                                                 This day of %.6s %.4s, %.8s\n\n") %
3300                     (timestring+4, timestring+20, timestring+11))
3301     fp.write(_("                                                        Your score:  %d\n\n") % iscore)
3302     fp.write(_("                                                    Klingons per stardate:  %.2f\n") % perdate)
3303     fp.close()
3304
3305 # Code from io.c begins here
3306
3307 rows = linecount = 0    # for paging 
3308 stdscr = None
3309 fullscreen_window = None
3310 srscan_window     = None
3311 report_window     = None
3312 status_window     = None
3313 lrscan_window     = None
3314 message_window    = None
3315 prompt_window     = None
3316
3317 def outro():
3318     "wrap up, either normally or due to signal"
3319     if game.options & OPTION_CURSES:
3320         #clear()
3321         #curs_set(1)
3322         #refresh()
3323         #resetterm()
3324         #echo()
3325         curses.endwin()
3326         stdout.write('\n')
3327     if logfp:
3328         logfp.close()
3329
3330 def iostart():
3331     global stdscr
3332     #setlocale(LC_ALL, "")
3333     #bindtextdomain(PACKAGE, LOCALEDIR)
3334     #textdomain(PACKAGE)
3335     if atexit.register(outro):
3336         sys.stderr.write("Unable to register outro(), exiting...\n")
3337         os.exit(1)
3338     if not (game.options & OPTION_CURSES):
3339         ln_env = os.getenv("LINES")
3340         if ln_env:
3341             rows = ln_env
3342         else:
3343             rows = 25
3344     else:
3345         stdscr = curses.initscr()
3346         stdscr.keypad(True)
3347         #saveterm()
3348         curses.nonl()
3349         curses.cbreak()
3350         curses.start_color()
3351         curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, curses.COLOR_BLACK)
3352         curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, curses.COLOR_BLACK)
3353         curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, curses.COLOR_BLACK)
3354         curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, curses.COLOR_BLACK)
3355         curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, curses.COLOR_BLACK)
3356         curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, curses.COLOR_BLACK)
3357         curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, curses.COLOR_BLACK)
3358         curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, curses.COLOR_BLACK)
3359         #noecho()
3360         global fullscreen_window, srscan_window, report_window, status_window
3361         global lrscan_window, message_window, prompt_window
3362         fullscreen_window = stdscr
3363         srscan_window     = curses.newwin(12, 25, 0,       0)
3364         report_window     = curses.newwin(11, 0,  1,       25)
3365         status_window     = curses.newwin(10, 0,  1,       39)
3366         lrscan_window     = curses.newwin(5,  0,  0,       64) 
3367         message_window    = curses.newwin(0,  0,  12,      0)
3368         prompt_window     = curses.newwin(1,  0,  rows-2,  0) 
3369         message_window.scrollok(True)
3370         setwnd(fullscreen_window)
3371         textcolor(DEFAULT)
3372
3373
3374 def waitfor():
3375     "wait for user action -- OK to do nothing if on a TTY"
3376     if game.options & OPTION_CURSES:
3377         stsdcr.getch()
3378
3379 def announce():
3380     skip(1)
3381     if game.skill > SKILL_FAIR:
3382         prouts(_("[ANOUNCEMENT ARRIVING...]"))
3383     else:
3384         prouts(_("[IMPORTANT ANNOUNCEMENT ARRIVING -- PRESS ENTER TO CONTINUE]"))
3385     skip(1)
3386
3387 def pause_game():
3388     if game.skill > SKILL_FAIR:
3389         prompt = _("[CONTINUE?]")
3390     else:
3391         prompt = _("[PRESS ENTER TO CONTINUE]")
3392
3393     if game.options & OPTION_CURSES:
3394         drawmaps(0)
3395         setwnd(prompt_window)
3396         prompt_window.wclear()
3397         prompt_window.addstr(prompt)
3398         prompt_window.getstr()
3399         prompt_window.clear()
3400         prompt_window.refresh()
3401         setwnd(message_window)
3402     else:
3403         global linecount
3404         stdout.write('\n')
3405         proutn(prompt)
3406         raw_input()
3407         for j in range(0, rows):
3408             stdout.write('\n')
3409         linecount = 0
3410
3411 def skip(i):
3412     "Skip i lines.  Pause game if this would cause a scrolling event."
3413     while dummy in range(i):
3414         if game.options & OPTION_CURSES:
3415             (y, x) = curwnd.getyx()
3416             (my, mx) = curwnd.getmaxyx()
3417             if curwnd == message_window and y >= my - 3:
3418                 pause_game()
3419                 clrscr()
3420             else:
3421                 proutn("\n")
3422         else:
3423             global linecount
3424             linecount += 1
3425             if linecount >= rows:
3426                 pause_game()
3427             else:
3428                 stdout.write('\n')
3429
3430 def proutn(line):
3431     "Utter a line with no following line feed."
3432     if game.options & OPTION_CURSES:
3433         curwnd.addstr(line)
3434         curwnd.refresh()
3435     else:
3436         stdout.write(line)
3437
3438 def prout(line):
3439     proutn(line)
3440     skip(1)
3441
3442 def prouts(line):
3443     "print slowly!" 
3444     for c in line:
3445         curses.delay_output(30)
3446         proutn(c)
3447         if game.options & OPTION_CURSES:
3448             wrefresh(curwnd)
3449         else:
3450             sys.stdout.flush()
3451     curses.delay_output(300)
3452
3453 def cgetline(line, max):
3454     "Get a line of input."
3455     if game.options & OPTION_CURSES:
3456         line = curwnd.getstr() + "\n"
3457         curwnd.refresh()
3458     else:
3459         if replayfp and not replayfp.closed:
3460             line = replayfp.readline()
3461         else:
3462             sys.stdin.readline()
3463     if logfp:
3464         logfp.write(line)
3465
3466 def setwnd(wnd):
3467     "Change windows -- OK for this to be a no-op in tty mode." 
3468     if game.options & OPTION_CURSES:
3469         curwnd = wnd
3470         curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window)
3471
3472 def clreol():
3473     "Clear to end of line -- can be a no-op in tty mode" 
3474     if game.options & OPTION_CURSES:
3475         wclrtoeol(curwnd)
3476         wrefresh(curwnd)
3477
3478 def clrscr():
3479     "Clear screen -- can be a no-op in tty mode."
3480     global linecount
3481     if game.options & OPTION_CURSES:
3482        curwnd.clear()
3483        curwnd.move(0, 0)
3484        curwnd.refresh()
3485     linecount = 0
3486
3487 def textcolor(color):
3488     "Set the current text color"
3489     if game.options & OPTION_CURSES:
3490         if color == DEFAULT: 
3491             curwnd.attrset(0)
3492         elif color == BLACK: 
3493             curwnd.attron(curses.COLOR_PAIR(curses.COLOR_BLACK))
3494         elif color == BLUE: 
3495             curwnd.attron(curses.COLOR_PAIR(curses.COLOR_BLUE))
3496         elif color == GREEN: 
3497             curwnd.attron(curses.COLOR_PAIR(curses.COLOR_GREEN))
3498         elif color == CYAN: 
3499             curwnd.attron(curses.COLOR_PAIR(curses.COLOR_CYAN))
3500         elif color == RED: 
3501             curwnd.attron(curses.COLOR_PAIR(curses.COLOR_RED))
3502         elif color == MAGENTA: 
3503             curwnd.attron(curses.COLOR_PAIR(curses.COLOR_MAGENTA))
3504         elif color == BROWN: 
3505             curwnd.attron(curses.COLOR_PAIR(curses.COLOR_YELLOW))
3506         elif color == LIGHTGRAY: 
3507             curwnd.attron(curses.COLOR_PAIR(curses.COLOR_WHITE))
3508         elif color == DARKGRAY: 
3509             curwnd.attron(curses.COLOR_PAIR(curses.COLOR_BLACK) | curses.A_BOLD)
3510         elif color == LIGHTBLUE: 
3511             curwnd.attron(curses.COLOR_PAIR(curses.COLOR_BLUE) | curses.A_BOLD)
3512         elif color == LIGHTGREEN: 
3513             curwnd.attron(curses.COLOR_PAIR(curses.COLOR_GREEN) | curses.A_BOLD)
3514         elif color == LIGHTCYAN: 
3515             curwnd.attron(curses.COLOR_PAIR(curses.COLOR_CYAN) | curses.A_BOLD)
3516         elif color == LIGHTRED: 
3517             curwnd.attron(curses.COLOR_PAIR(curses.COLOR_RED) | curses.A_BOLD)
3518         elif color == LIGHTMAGENTA: 
3519             curwnd.attron(curses.COLOR_PAIR(curses.COLOR_MAGENTA) | curses.A_BOLD)
3520         elif color == YELLOW: 
3521             curwnd.attron(curses.COLOR_PAIR(curses.COLOR_YELLOW) | curses.A_BOLD)
3522         elif color == WHITE:
3523             curwnd.attron(curses.COLOR_PAIR(curses.COLOR_WHITE) | curses.A_BOLD)
3524
3525 def highvideo():
3526     "Set highlight video, if this is reasonable."
3527     if game.options & OPTION_CURSES:
3528         curwnd.attron(curses.A_REVERSE)
3529  
3530 def commandhook(cmd, before):
3531     pass
3532
3533 #
3534 # Things past this point have policy implications.
3535
3536
3537 def drawmaps(mode):
3538     "Hook to be called after moving to redraw maps."
3539     if game.options & OPTION_CURSES:
3540         if mode == 1:
3541             sensor()
3542         setwnd(srscan_window)
3543         curwnd.move(0, 0)
3544         srscan()
3545         if mode != 2:
3546             setwnd(status_window)
3547             status_window.clear()
3548             status_window.move(0, 0)
3549             setwnd(report_window)
3550             report_window.clear()
3551             report_window.move(0, 0)
3552             status(0)
3553             setwnd(lrscan_window)
3554             lrscan_window.clear()
3555             lrscan_window.move(0, 0)
3556             lrscan()
3557
3558 def put_srscan_sym(w, sym):
3559     "Emit symbol for short-range scan."
3560     srscan_window.move(w.x+1, w.y*2+2)
3561     srscan_window.addch(sym)
3562     srscan_window.refresh()
3563
3564 def boom(w):
3565     "Enemy fall down, go boom."  
3566     if game.options & OPTION_CURSES:
3567         drawmaps(2)
3568         setwnd(srscan_window)
3569         srscan_window.attron(curses.A_REVERSE)
3570         put_srscan_sym(w, game.quad[w.x][w.y])
3571         #sound(500)
3572         #delay(1000)
3573         #nosound()
3574         srscan_window.attroff(curses.A_REVERSE)
3575         put_srscan_sym(w, game.quad[w.x][w.y])
3576         curses.delay_output(500)
3577         setwnd(message_window) 
3578
3579 def warble():
3580     "Sound and visual effects for teleportation."
3581     if game.options & OPTION_CURSES:
3582         drawmaps(2)
3583         setwnd(message_window)
3584         #sound(50)
3585     prouts("     . . . . .     ")
3586     if game.options & OPTION_CURSES:
3587         #curses.delay_output(1000)
3588         #nosound()
3589         pass
3590
3591 def tracktorpedo(w, l, i, n, iquad):
3592     "Torpedo-track animation." 
3593     if not game.options & OPTION_CURSES:
3594         if l == 1:
3595             if n != 1:
3596                 skip(1)
3597                 proutn(_("Track for torpedo number %d-  ") % i)
3598             else:
3599                 skip(1)
3600                 proutn(_("Torpedo track- "))
3601         elif l==4 or l==9: 
3602             skip(1)
3603         proutn("%d - %d   " % (w.x, w.y))
3604     else:
3605         if not damaged(DSRSENS) or game.condition=="docked":
3606             if i != 1 and l == 1:
3607                 drawmaps(2)
3608                 curses.delay_output(400)
3609             if (iquad==IHDOT) or (iquad==IHBLANK):
3610                 put_srscan_sym(w, '+')
3611                 #sound(l*10)
3612                 #curses.delay_output(100)
3613                 #nosound()
3614                 put_srscan_sym(w, iquad)
3615             else:
3616                 curwnd.attron(curses.A_REVERSE)
3617                 put_srscan_sym(w, iquad)
3618                 #sound(500)
3619                 #curses.delay_output(1000)
3620                 #nosound()
3621                 curwnd.attroff(curses.A_REVERSE)
3622                 put_srscan_sym(w, iquad)
3623         else:
3624             proutn("%d - %d   " % (w.x, w.y))
3625
3626 def makechart():
3627     "Display the current galaxy chart."
3628     if game.options & OPTION_CURSES:
3629         setwnd(message_window)
3630         message_window.clear()
3631     chart()
3632     if game.options & OPTION_TTY:
3633         skip(1)
3634
3635 NSYM    = 14
3636
3637 def prstat(txt, data):
3638     proutn(txt)
3639     if game.options & OPTION_CURSES:
3640         skip(1)
3641         setwnd(status_window)
3642     else:
3643         proutn(" " * NSYM - len(tx))
3644     vproutn(data)
3645     skip(1)
3646     if game.options & OPTION_CURSES:
3647         setwnd(report_window)
3648
3649 # Code from moving.c begins here
3650
3651 def imove(novapush):
3652     # movement execution for warp, impulse, supernova, and tractor-beam events 
3653     w = coord(); final = coord()
3654     trbeam = False
3655
3656     def no_quad_change():
3657         # No quadrant change -- compute new avg enemy distances 
3658         game.quad[game.sector.x][game.sector.y] = game.ship
3659         if game.nenhere:
3660             for m in range(1, game.nenhere+1):
3661                 finald = distance(w, game.ks[m])
3662                 game.kavgd[m] = 0.5 * (finald+game.kdist[m])
3663                 game.kdist[m] = finald
3664             sortklings()
3665             if not game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
3666                 attack(False)
3667             for m in range(1, game.nenhere+1):
3668                 game.kavgd[m] = game.kdist[m]
3669         newcnd()
3670         drawmaps(0)
3671         setwnd(message_window)
3672
3673     w.x = w.y = 0
3674     if game.inorbit:
3675         prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3676         game.inorbit = False
3677
3678     angle = ((15.0 - game.direc) * 0.5235988)
3679     deltax = -math.sin(angle)
3680     deltay = math.cos(angle)
3681     if math.fabs(deltax) > math.fabs(deltay):
3682         bigger = math.fabs(deltax)
3683     else:
3684         bigger = math.fabs(deltay)
3685                 
3686     deltay /= bigger
3687     deltax /= bigger
3688
3689     # If tractor beam is to occur, don't move full distance 
3690     if game.state.date+game.optime >= scheduled(FTBEAM):
3691         trbeam = True
3692         game.condition = "red"
3693         game.dist = game.dist*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3694         game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3695     # Move within the quadrant 
3696     game.quad[game.sector.x][game.sector.y] = IHDOT
3697     x = game.sector.x
3698     y = game.sector.y
3699     n = 10.0*game.dist*bigger+0.5
3700
3701     if n > 0:
3702         for m in range(1, n+1):
3703             x += deltax
3704             y += deltay
3705             w.x = x + 0.5
3706             w.y = y + 0.5
3707             if not VALID_SECTOR(w.x, w.y):
3708                 # Leaving quadrant -- allow final enemy attack 
3709                 # Don't do it if being pushed by Nova 
3710                 if game.nenhere != 0 and not novapush:
3711                     newcnd()
3712                     for m in range(1, game.nenhere+1):
3713                         finald = distance(w, game.ks[m])
3714                         game.kavgd[m] = 0.5 * (finald + game.kdist[m])
3715                     #
3716                     # Stas Sergeev added the condition
3717                     # that attacks only happen if Klingons
3718                     # are present and your skill is good.
3719                     # 
3720                     if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
3721                         attack(False)
3722                     if game.alldone:
3723                         return
3724                 # compute final position -- new quadrant and sector 
3725                 x = QUADSIZE*(game.quadrant.x-1)+game.sector.x
3726                 y = QUADSIZE*(game.quadrant.y-1)+game.sector.y
3727                 w.x = x+10.0*game.dist*bigger*deltax+0.5
3728                 w.y = y+10.0*game.dist*bigger*deltay+0.5
3729                 # check for edge of galaxy 
3730                 kinks = 0
3731                 while True:
3732                     kink = 0
3733                     if w.x <= 0:
3734                         w.x = -w.x + 1
3735                         kink = 1
3736                     if w.y <= 0:
3737                         w.y = -w.y + 1
3738                         kink = 1
3739                     if w.x > GALSIZE*QUADSIZE:
3740                         w.x = (GALSIZE*QUADSIZE*2)+1 - w.x
3741                         kink = 1
3742                     if w.y > GALSIZE*QUADSIZE:
3743                         w.y = (GALSIZE*QUADSIZE*2)+1 - w.y
3744                         kink = 1
3745                     if kink:
3746                         kinks = 1
3747                 if not kink:
3748                     break
3749
3750                 if kinks:
3751                     game.nkinks += 1
3752                     if game.nkinks == 3:
3753                         # Three strikes -- you're out! 
3754                         finish(FNEG3)
3755                         return
3756                     skip(1)
3757                     prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3758                     prout(_("AT THE EDGE OF THE GALAXY.  THE THIRD TIME YOU TRY THIS,"))
3759                     prout(_("YOU WILL BE DESTROYED."))
3760                 # Compute final position in new quadrant 
3761                 if trbeam: # Don't bother if we are to be beamed 
3762                     return
3763                 game.quadrant.x = (w.x+(QUADSIZE-1))/QUADSIZE
3764                 game.quadrant.y = (w.y+(QUADSIZE-1))/QUADSIZE
3765                 game.sector.x = w.x - QUADSIZE*(game.quadrant.x-1)
3766                 game.sector.y = w.y - QUADSIZE*(game.quadrant.y-1)
3767                 skip(1)
3768                 prout(_("Entering Quadrant %s.") % game.quadrant)
3769                 game.quad[game.sector.x][game.sector.y] = game.ship
3770                 newqad(False)
3771                 if game.skill>SKILL_NOVICE:
3772                     attack(False)  
3773                 return
3774             iquad = game.quad[w.x][w.y]
3775             if iquad != IHDOT:
3776                 # object encountered in flight path 
3777                 stopegy = 50.0*game.dist/game.optime
3778                 game.dist = distance(game.sector, w) / (QUADSIZE * 1.0)
3779                 if iquad in (IHT. IHK, OHC, IHS, IHR, IHQUEST):
3780                     game.sector = w
3781                     ram(False, iquad, game.sector)
3782                     final = game.sector
3783                 elif iquad == IHBLANK:
3784                     skip(1)
3785                     prouts(_("***RED ALERT!  RED ALERT!"))
3786                     skip(1)
3787                     proutn("***")
3788                     crmshp()
3789                     proutn(_(" pulled into black hole at Sector %s") % w)
3790                     #
3791                     # Getting pulled into a black hole was certain
3792                     # death in Almy's original.  Stas Sergeev added a
3793                     # possibility that you'll get timewarped instead.
3794                     # 
3795                     n=0
3796                     for m in range(0, NDEVICES):
3797                         if game.damage[m]>0: 
3798                             n += 1
3799                     probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3800                     if (game.options & OPTION_BLKHOLE) and Rand()>probf: 
3801                         timwrp()
3802                     else: 
3803                         finish(FHOLE)
3804                     return
3805                 else:
3806                     # something else 
3807                     skip(1)
3808                     crmshp()
3809                     if iquad == IHWEB:
3810                         proutn(_(" encounters Tholian web at %s;") % w)
3811                     else:
3812                         proutn(_(" blocked by object at %s;") % w)
3813                     proutn(_("Emergency stop required "))
3814                     prout(_("%2d units of energy.") % int(stopegy))
3815                     game.energy -= stopegy
3816                     final.x = x-deltax+0.5
3817                     final.y = y-deltay+0.5
3818                     game.sector = final
3819                     if game.energy <= 0:
3820                         finish(FNRG)
3821                         return
3822                 # We're here!
3823                 no_quad_change()
3824                 return
3825         game.dist = distance(game.sector, w) / (QUADSIZE * 1.0)
3826         game.sector = w
3827     final = game.sector
3828     no_quad_change()
3829     return
3830
3831 def dock(verbose):
3832     # dock our ship at a starbase 
3833     chew()
3834     if game.condition == "docked" and verbose:
3835         prout(_("Already docked."))
3836         return
3837     if game.inorbit:
3838         prout(_("You must first leave standard orbit."))
3839         return
3840     if not is_valid(game.base) or abs(game.sector.x-game.base.x) > 1 or abs(game.sector.y-game.base.y) > 1:
3841         crmshp()
3842         prout(_(" not adjacent to base."))
3843         return
3844     game.condition = "docked"
3845     if "verbose":
3846         prout(_("Docked."))
3847     game.ididit = True
3848     if game.energy < game.inenrg:
3849         game.energy = game.inenrg
3850     game.shield = game.inshld
3851     game.torps = game.intorps
3852     game.lsupres = game.inlsr
3853     game.state.crew = FULLCREW
3854     if not damaged(DRADIO) and \
3855         ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3856         # get attack report from base 
3857         prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3858         attackreport(False)
3859         game.iseenit = True
3860
3861
3862 # This program originally required input in terms of a (clock)
3863 # direction and distance. Somewhere in history, it was changed to
3864 # cartesian coordinates. So we need to convert.  Probably
3865 # "manual" input should still be done this way -- it's a real
3866 # pain if the computer isn't working! Manual mode is still confusing
3867 # because it involves giving x and y motions, yet the coordinates
3868 # are always displayed y - x, where +y is downward!
3869
3870
3871 def getcd(isprobe, akey):
3872     # get course and distance 
3873     irowq=game.quadrant.x; icolq=game.quadrant.y; key=0
3874     navmode = "unspecified"
3875     itemp = "curt"
3876     incr = coord()
3877     iprompt = False
3878
3879     # Get course direction and distance. If user types bad values, return
3880     # with DIREC = -1.0.
3881     game.direc = -1.0
3882         
3883     if game.landed and not isprobe:
3884         prout(_("Dummy! You can't leave standard orbit until you"))
3885         proutn(_("are back aboard the ship."))
3886         chew()
3887         return
3888     while navmode == "unspecified":
3889         if damaged(DNAVSYS):
3890             if isprobe:
3891                 prout(_("Computer damaged; manual navigation only"))
3892             else:
3893                 prout(_("Computer damaged; manual movement only"))
3894             chew()
3895             navmode = "manual"
3896             key = IHEOL
3897             break
3898         if isprobe and akey != -1:
3899             # For probe launch, use pre-scanned value first time 
3900             key = akey
3901             akey = -1
3902         else: 
3903             key = scan()
3904
3905         if key == IHEOL:
3906             proutn(_("Manual or automatic- "))
3907             iprompt = True
3908             chew()
3909         elif key == IHALPHA:
3910             if isit("manual"):
3911                 navmode = "manual"
3912                 key = scan()
3913                 break
3914             elif isit("automatic"):
3915                 navmode = "automatic"
3916                 key = scan()
3917                 break
3918             else:
3919                 huh()
3920                 chew()
3921                 return
3922         else: # numeric 
3923             if isprobe:
3924                 prout(_("(Manual navigation assumed.)"))
3925             else:
3926                 prout(_("(Manual movement assumed.)"))
3927             navmode = "manual"
3928             break
3929
3930     if navmode == "automatic":
3931         while key == IHEOL:
3932             if isprobe:
3933                 proutn(_("Target quadrant or quadrant&sector- "))
3934             else:
3935                 proutn(_("Destination sector or quadrant&sector- "))
3936             chew()
3937             iprompt = True
3938             key = scan()
3939
3940         if key != IHREAL:
3941             huh()
3942             return
3943         xi = aaitem
3944         key = scan()
3945         if key != IHREAL:
3946             huh()
3947             return
3948         xj = aaitem
3949         key = scan()
3950         if key == IHREAL:
3951             # both quadrant and sector specified 
3952             xk = aaitem
3953             key = scan()
3954             if key != IHREAL:
3955                 huh()
3956                 return
3957             xl = aaitem
3958
3959             irowq = xi + 0.5
3960             icolq = xj + 0.5
3961             incr.y = xk + 0.5
3962             incr.x = xl + 0.5
3963         else:
3964             if isprobe:
3965                 # only quadrant specified -- go to center of dest quad 
3966                 irowq = xi + 0.5
3967                 icolq = xj + 0.5
3968                 incr.y = incr.x = 5
3969             else:
3970                 incr.y = xi + 0.5
3971                 incr.x = xj + 0.5
3972             itemp = "normal"
3973         if not VALID_QUADRANT(icolq,irowq) or not VALID_SECTOR(incr.x,incr.y):
3974             huh()
3975             return
3976         skip(1)
3977         if not isprobe:
3978             if itemp > "curt":
3979                 if iprompt:
3980                     prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % incr)
3981             else:
3982                 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3983         deltax = icolq - game.quadrant.y + 0.1*(incr.x-game.sector.y)
3984         deltay = game.quadrant.x - irowq + 0.1*(game.sector.x-incr.y)
3985     else: # manual 
3986         while key == IHEOL:
3987             proutn(_("X and Y displacements- "))
3988             chew()
3989             iprompt = True
3990             key = scan()
3991         itemp = "verbose"
3992         if key != IHREAL:
3993             huh()
3994             return
3995         deltax = aaitem
3996         key = scan()
3997         if key != IHREAL:
3998             huh()
3999             return
4000         deltay = aaitem
4001     # Check for zero movement 
4002     if deltax == 0 and deltay == 0:
4003         chew()
4004         return
4005     if itemp == "verbose" and not isprobe:
4006         skip(1)
4007         prout(_("Helmsman Sulu- \"Aye, Sir.\""))
4008     game.dist = math.sqrt(deltax*deltax + deltay*deltay)
4009     game.direc = math.atan2(deltax, deltay)*1.90985932
4010     if game.direc < 0.0:
4011         game.direc += 12.0
4012     chew()
4013     return
4014
4015 def impulse():
4016     # move under impulse power 
4017     game.ididit = False
4018     if damaged(DIMPULS):
4019         chew()
4020         skip(1)
4021         prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4022         return
4023     if game.energy > 30.0:
4024         getcd(False, 0)
4025         if game.direc == -1.0:
4026             return
4027         power = 20.0 + 100.0*game.dist
4028     else:
4029         power = 30.0
4030
4031     if power >= game.energy:
4032         # Insufficient power for trip 
4033         skip(1)
4034         prout(_("First Officer Spock- \"Captain, the impulse engines"))
4035         prout(_("require 20.0 units to engage, plus 100.0 units per"))
4036         if game.energy > 30:
4037             proutn(_("quadrant.  We can go, therefore, a maximum of %d") %
4038                      int(0.01 * (game.energy-20.0)-0.05))
4039             prout(_(" quadrants.\""))
4040         else:
4041             prout(_("quadrant.  They are, therefore, useless.\""))
4042         chew()
4043         return
4044     # Make sure enough time is left for the trip 
4045     game.optime = game.dist/0.095
4046     if game.optime >= game.state.remtime:
4047         prout(_("First Officer Spock- \"Captain, our speed under impulse"))
4048         prout(_("power is only 0.95 sectors per stardate. Are you sure"))
4049         proutn(_("we dare spend the time?\" "))
4050         if ja() == False:
4051             return
4052     # Activate impulse engines and pay the cost 
4053     imove(False)
4054     game.ididit = True
4055     if game.alldone:
4056         return
4057     power = 20.0 + 100.0*game.dist
4058     game.energy -= power
4059     game.optime = game.dist/0.095
4060     if game.energy <= 0:
4061         finish(FNRG)
4062     return
4063
4064 def warp(timewarp):
4065     # move under warp drive 
4066     blooey = False; twarp = False
4067     if not timewarp: # Not WARPX entry 
4068         game.ididit = False
4069         if game.damage[DWARPEN] > 10.0:
4070             chew()
4071             skip(1)
4072             prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4073             return
4074         if damaged(DWARPEN) and game.warpfac > 4.0:
4075             chew()
4076             skip(1)
4077             prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4078             prout(_("  is repaired, I can only give you warp 4.\""))
4079             return
4080                         
4081         # Read in course and distance 
4082         getcd(False, 0)
4083         if game.direc == -1.0:
4084             return
4085
4086         # Make sure starship has enough energy for the trip 
4087         power = (game.dist+0.05)*game.warpfac*game.warpfac*game.warpfac*(game.shldup+1)
4088         if power >= game.energy:
4089             # Insufficient power for trip 
4090             game.ididit = False
4091             skip(1)
4092             prout(_("Engineering to bridge--"))
4093             if not game.shldup or 0.5*power > game.energy:
4094                 iwarp = math.pow((game.energy/(game.dist+0.05)), 0.333333333)
4095                 if iwarp <= 0:
4096                     prout(_("We can't do it, Captain. We don't have enough energy."))
4097                 else:
4098                     proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4099                     if game.shldup:
4100                         prout(",")
4101                         prout(_("if you'll lower the shields."))
4102                     else:
4103                         prout(".")
4104             else:
4105                 prout(_("We haven't the energy to go that far with the shields up."))
4106             return
4107                                                 
4108         # Make sure enough time is left for the trip 
4109         game.optime = 10.0*game.dist/game.wfacsq
4110         if game.optime >= 0.8*game.state.remtime:
4111             skip(1)
4112             prout(_("First Officer Spock- \"Captain, I compute that such"))
4113             proutn(_("  a trip would require approximately %2.0f") %
4114                    (100.0*game.optime/game.state.remtime))
4115             prout(_(" percent of our"))
4116             proutn(_("  remaining time.  Are you sure this is wise?\" "))
4117             if ja() == False:
4118                 game.ididit = False
4119                 game.optime=0 
4120                 return
4121     # Entry WARPX 
4122     if game.warpfac > 6.0:
4123         # Decide if engine damage will occur 
4124         prob = game.dist*(6.0-game.warpfac)*(6.0-game.warpfac)/66.666666666
4125         if prob > Rand():
4126             blooey = True
4127             game.dist = Rand()*game.dist
4128         # Decide if time warp will occur 
4129         if 0.5*game.dist*math.pow(7.0,game.warpfac-10.0) > Rand():
4130             twarp = True
4131         if idebug and game.warpfac==10 and not twarp:
4132             blooey = False
4133             proutn("=== Force time warp? ")
4134             if ja() == True:
4135                 twarp = True
4136         if blooey or twarp:
4137             # If time warp or engine damage, check path 
4138             # If it is obstructed, don't do warp or damage 
4139             angle = ((15.0-game.direc)*0.5235998)
4140             deltax = -math.sin(angle)
4141             deltay = math.cos(angle)
4142             if math.fabs(deltax) > math.fabs(deltay):
4143                 bigger = math.fabs(deltax)
4144             else:
4145                 bigger = math.fabs(deltay)
4146                         
4147             deltax /= bigger
4148             deltay /= bigger
4149             n = 10.0 * game.dist * bigger +0.5
4150             x = game.sector.x
4151             y = game.sector.y
4152             for l in range(1, n+1):
4153                 x += deltax
4154                 ix = x + 0.5
4155                 y += deltay
4156                 iy = y +0.5
4157                 if not VALID_SECTOR(ix, iy):
4158                     break
4159                 if game.quad[ix][iy] != IHDOT:
4160                     blooey = False
4161                     twarp = False
4162                                 
4163
4164     # Activate Warp Engines and pay the cost 
4165     imove(False)
4166     if game.alldone:
4167         return
4168     game.energy -= game.dist*game.warpfac*game.warpfac*game.warpfac*(game.shldup+1)
4169     if game.energy <= 0:
4170         finish(FNRG)
4171     game.optime = 10.0*game.dist/game.wfacsq
4172     if twarp:
4173         timwrp()
4174     if blooey:
4175         game.damage[DWARPEN] = game.damfac*(3.0*Rand()+1.0)
4176         skip(1)
4177         prout(_("Engineering to bridge--"))
4178         prout(_("  Scott here.  The warp engines are damaged."))
4179         prout(_("  We'll have to reduce speed to warp 4."))
4180     game.ididit = True
4181     return
4182
4183 def setwarp():
4184     # change the warp factor    
4185     while True:
4186         key=scan()
4187         if key != IHEOL:
4188             break
4189         chew()
4190         proutn(_("Warp factor- "))
4191     chew()
4192     if key != IHREAL:
4193         huh()
4194         return
4195     if game.damage[DWARPEN] > 10.0:
4196         prout(_("Warp engines inoperative."))
4197         return
4198     if damaged(DWARPEN) and aaitem > 4.0:
4199         prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4200         prout(_("  but right now we can only go warp 4.\""))
4201         return
4202     if aaitem > 10.0:
4203         prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4204         return
4205     if aaitem < 1.0:
4206         prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4207         return
4208     oldfac = game.warpfac
4209     game.warpfac = aaitem
4210     game.wfacsq=game.warpfac*game.warpfac
4211     if game.warpfac <= oldfac or game.warpfac <= 6.0:
4212         prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4213                int(game.warpfac))
4214         return
4215     if game.warpfac < 8.00:
4216         prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4217         return
4218     if game.warpfac == 10.0:
4219         prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4220         return
4221     prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4222     return
4223
4224 def atover(igrab):
4225     # cope with being tossed out of quadrant by supernova or yanked by beam 
4226
4227     chew()
4228     # is captain on planet? 
4229     if game.landed:
4230         if damaged(DTRANSP):
4231             finish(FPNOVA)
4232             return
4233         prout(_("Scotty rushes to the transporter controls."))
4234         if game.shldup:
4235             prout(_("But with the shields up it's hopeless."))
4236             finish(FPNOVA)
4237         prouts(_("His desperate attempt to rescue you . . ."))
4238         if Rand() <= 0.5:
4239             prout(_("fails."))
4240             finish(FPNOVA)
4241             return
4242         prout(_("SUCCEEDS!"))
4243         if game.imine:
4244             game.imine = False
4245             proutn(_("The crystals mined were "))
4246             if Rand() <= 0.25:
4247                 prout(_("lost."))
4248             else:
4249                 prout(_("saved."))
4250                 game.icrystl = True
4251     if igrab:
4252         return
4253
4254     # Check to see if captain in shuttle craft 
4255     if game.icraft:
4256         finish(FSTRACTOR)
4257     if game.alldone:
4258         return
4259
4260     # Inform captain of attempt to reach safety 
4261     skip(1)
4262     while True:
4263         if game.justin:
4264             prouts(_("***RED ALERT!  RED ALERT!"))
4265             skip(1)
4266             proutn(_("The "))
4267             crmshp()
4268             prout(_(" has stopped in a quadrant containing"))
4269             prouts(_("   a supernova."))
4270             skip(2)
4271         proutn(_("***Emergency automatic override attempts to hurl "))
4272         crmshp()
4273         skip(1)
4274         prout(_("safely out of quadrant."))
4275         if not damaged(DRADIO):
4276             game.state.galaxy[game.quadrant.x][game.quadrant.y].charted = True
4277         # Try to use warp engines 
4278         if damaged(DWARPEN):
4279             skip(1)
4280             prout(_("Warp engines damaged."))
4281             finish(FSNOVAED)
4282             return
4283         game.warpfac = 6.0+2.0*Rand()
4284         game.wfacsq = game.warpfac * game.warpfac
4285         prout(_("Warp factor set to %d") % int(game.warpfac))
4286         power = 0.75*game.energy
4287         game.dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4288         distreq = 1.4142+Rand()
4289         if distreq < game.dist:
4290             game.dist = distreq
4291         game.optime = 10.0*game.dist/game.wfacsq
4292         game.direc = 12.0*Rand()        # How dumb! 
4293         game.justin = False
4294         game.inorbit = False
4295         warp(True)
4296         if not game.justin:
4297             # This is bad news, we didn't leave quadrant. 
4298             if game.alldone:
4299                 return
4300             skip(1)
4301             prout(_("Insufficient energy to leave quadrant."))
4302             finish(FSNOVAED)
4303             return
4304         # Repeat if another snova
4305         if not game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
4306             break
4307     if (game.state.remkl + game.state.remcom + game.state.nscrem)==0: 
4308         finish(FWON) # Snova killed remaining enemy. 
4309
4310 def timwrp():
4311     # let's do the time warp again 
4312     prout(_("***TIME WARP ENTERED."))
4313     if game.state.snap and Rand() < 0.5:
4314         # Go back in time 
4315         prout(_("You are traveling backwards in time %d stardates.") %
4316               int(game.state.date-game.snapsht.date))
4317         game.state = game.snapsht
4318         game.state.snap = False
4319         if game.state.remcom:
4320             schedule(FTBEAM, expran(game.intime/game.state.remcom))
4321             schedule(FBATTAK, expran(0.3*game.intime))
4322         schedule(FSNOVA, expran(0.5*game.intime))
4323         # next snapshot will be sooner 
4324         schedule(FSNAP, expran(0.25*game.state.remtime))
4325                                 
4326         if game.state.nscrem:
4327             schedule(FSCMOVE, 0.2777)       
4328         game.isatb = 0
4329         unschedule(FCDBAS)
4330         unschedule(FSCDBAS)
4331         invalidate(game.battle)
4332
4333         # Make sure Galileo is consistant -- Snapshot may have been taken
4334         # when on planet, which would give us two Galileos! 
4335         gotit = False
4336         for l in range(game.inplan):
4337             if game.state.planets[l].known == "shuttle_down":
4338                 gotit = True
4339                 if game.iscraft == "onship" and game.ship==IHE:
4340                     prout(_("Chekov-  \"Security reports the Galileo has disappeared, Sir!"))
4341                     game.iscraft = "offship"
4342         # Likewise, if in the original time the Galileo was abandoned, but
4343         # was on ship earlier, it would have vanished -- let's restore it.
4344         if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4345             prout(_("Checkov-  \"Security reports the Galileo has reappeared in the dock!\""))
4346             game.iscraft = "onship"
4347         # 
4348 #        * There used to be code to do the actual reconstrction here,
4349 #        * but the starchart is now part of the snapshotted galaxy state.
4350 #        
4351         prout(_("Spock has reconstructed a correct star chart from memory"))
4352     else:
4353         # Go forward in time 
4354         game.optime = -0.5*game.intime*math.log(Rand())
4355         prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4356         # cheat to make sure no tractor beams occur during time warp 
4357         postpone(FTBEAM, game.optime)
4358         game.damage[DRADIO] += game.optime
4359     newqad(False)
4360     events()    # Stas Sergeev added this -- do pending events 
4361
4362 def probe():
4363     # launch deep-space probe 
4364     # New code to launch a deep space probe 
4365     if game.nprobes == 0:
4366         chew()
4367         skip(1)
4368         if game.ship == IHE: 
4369             prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4370         else:
4371             prout(_("Ye Faerie Queene has no deep space probes."))
4372         return
4373     if damaged(DDSP):
4374         chew()
4375         skip(1)
4376         prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4377         return
4378     if is_scheduled(FDSPROB):
4379         chew()
4380         skip(1)
4381         if damaged(DRADIO) and game.condition != "docked":
4382             prout(_("Spock-  \"Records show the previous probe has not yet"))
4383             prout(_("   reached its destination.\""))
4384         else:
4385             prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4386         return
4387     key = scan()
4388
4389     if key == IHEOL:
4390         # slow mode, so let Kirk know how many probes there are left
4391         if game.nprobes == 1:
4392             prout(_("1 probe left."))
4393         else:
4394             prout(_("%d probes left") % game.nprobes)
4395         proutn(_("Are you sure you want to fire a probe? "))
4396         if ja() == False:
4397             return
4398
4399     game.isarmed = False
4400     if key == IHALPHA and citem == "armed":
4401         game.isarmed = True
4402         key = scan()
4403     elif key == IHEOL:
4404         proutn(_("Arm NOVAMAX warhead? "))
4405         game.isarmed = ja()
4406     getcd(True, key)
4407     if game.direc == -1.0:
4408         return
4409     game.nprobes -= 1
4410     angle = ((15.0 - game.direc) * 0.5235988)
4411     game.probeinx = -math.sin(angle)
4412     game.probeiny = math.cos(angle)
4413     if math.fabs(game.probeinx) > math.fabs(game.probeiny):
4414         bigger = math.fabs(game.probeinx)
4415     else:
4416         bigger = math.fabs(game.probeiny)
4417                 
4418     game.probeiny /= bigger
4419     game.probeinx /= bigger
4420     game.proben = 10.0*game.dist*bigger +0.5
4421     game.probex = game.quadrant.x*QUADSIZE + game.sector.x - 1  # We will use better packing than original
4422     game.probey = game.quadrant.y*QUADSIZE + game.sector.y - 1
4423     game.probec = game.quadrant
4424     schedule(FDSPROB, 0.01) # Time to move one sector
4425     prout(_("Ensign Chekov-  \"The deep space probe is launched, Captain.\""))
4426     game.ididit = True
4427     return
4428
4429 # Here's how the mayday code works:
4430
4431 # First, the closest starbase is selected.  If there is a a starbase
4432 # in your own quadrant, you are in good shape.  This distance takes
4433 # quadrant distances into account only.
4434 #
4435 # A magic number is computed based on the distance which acts as the
4436 # probability that you will be rematerialized.  You get three tries.
4437 #
4438 # When it is determined that you should be able to be rematerialized
4439 # (i.e., when the probability thing mentioned above comes up
4440 # positive), you are put into that quadrant (anywhere).  Then, we try
4441 # to see if there is a spot adjacent to the star- base.  If not, you
4442 # can't be rematerialized!!!  Otherwise, it drops you there.  It only
4443 # tries five times to find a spot to drop you.  After that, it's your
4444 # problem.
4445
4446 def mayday():
4447     # yell for help from nearest starbase 
4448     # There's more than one way to move in this game! 
4449     line = 0
4450
4451     chew()
4452     # Test for conditions which prevent calling for help 
4453     if game.condition == "docked":
4454         prout(_("Lt. Uhura-  \"But Captain, we're already docked.\""))
4455         return
4456     if damaged(DRADIO):
4457         prout(_("Subspace radio damaged."))
4458         return
4459     if game.state.rembase==0:
4460         prout(_("Lt. Uhura-  \"Captain, I'm not getting any response from Starbase.\""))
4461         return
4462     if game.landed:
4463         proutn(_("You must be aboard the "))
4464         crmshp()
4465         prout(".")
4466         return
4467     # OK -- call for help from nearest starbase 
4468     game.nhelp += 1
4469     if game.base.x!=0:
4470         # There's one in this quadrant 
4471         ddist = distance(game.base, game.sector)
4472     else:
4473         ddist = FOREVER
4474         for m in range(1, game.state.rembase+1):
4475             xdist = QUADSIZE * distance(game.state.baseq[m], game.quadrant)
4476             if xdist < ddist:
4477                 ddist = xdist
4478                 line = m
4479         # Since starbase not in quadrant, set up new quadrant 
4480         game.quadrant = game.state.baseq[line]
4481         newqad(True)
4482     # dematerialize starship 
4483     game.quad[game.sector.x][game.sector.y]=IHDOT
4484     proutn(_("Starbase in Quadrant %s responds--") % game.quadrant)
4485     crmshp()
4486     prout(_(" dematerializes."))
4487     game.sector.x=0
4488     for m in range(1, 5+1):
4489         ix = game.base.x+3.0*Rand()-1
4490         iy = game.base.y+3.0*Rand()-1
4491         if VALID_SECTOR(ix,iy) and game.quad[ix][iy]==IHDOT:
4492             # found one -- finish up 
4493             game.sector.x=ix
4494             game.sector.y=iy
4495             break
4496     if not is_valid(game.sector):
4497         prout(_("You have been lost in space..."))
4498         finish(FMATERIALIZE)
4499         return
4500     # Give starbase three chances to rematerialize starship 
4501     probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4502     for m in range(1, 3+1):
4503         if m == 1: proutn(_("1st"))
4504         elif m == 2: proutn(_("2nd"))
4505         elif m == 3: proutn(_("3rd"))
4506         proutn(_(" attempt to re-materialize "))
4507         crmshp()
4508         game.quad[ix][iy]=(IHMATER0,IHMATER1,IHMATER2)[m-1]
4509         textcolor(RED)
4510         warble()
4511         if Rand() > probf:
4512             break
4513         prout(_("fails."))
4514         curses.delay_output(500)
4515         textcolor(DEFAULT)
4516     if m > 3:
4517         game.quad[ix][iy]=IHQUEST
4518         game.alive = False
4519         drawmaps(1)
4520         setwnd(message_window)
4521         finish(FMATERIALIZE)
4522         return
4523     game.quad[ix][iy]=game.ship
4524     textcolor(GREEN)
4525     prout(_("succeeds."))
4526     textcolor(DEFAULT)
4527     dock(False)
4528     skip(1)
4529     prout(_("Lt. Uhura-  \"Captain, we made it!\""))
4530
4531 # Abandon Ship (the BSD-Trek description)
4532
4533 # The ship is abandoned.  If your current ship is the Faire
4534 # Queene, or if your shuttlecraft is dead, you're out of
4535 # luck.  You need the shuttlecraft in order for the captain
4536 # (that's you!!) to escape.
4537
4538 # Your crew can beam to an inhabited starsystem in the
4539 # quadrant, if there is one and if the transporter is working.
4540 # If there is no inhabited starsystem, or if the transporter
4541 # is out, they are left to die in outer space.
4542
4543 # If there are no starbases left, you are captured by the
4544 # Klingons, who torture you mercilessly.  However, if there
4545 # is at least one starbase, you are returned to the
4546 # Federation in a prisoner of war exchange.  Of course, this
4547 # can't happen unless you have taken some prisoners.
4548
4549 def abandon():
4550     # abandon ship 
4551     chew()
4552     if game.condition=="docked":
4553         if game.ship!=IHE:
4554             prout(_("You cannot abandon Ye Faerie Queene."))
4555             return
4556     else:
4557         # Must take shuttle craft to exit 
4558         if game.damage[DSHUTTL]==-1:
4559             prout(_("Ye Faerie Queene has no shuttle craft."))
4560             return
4561         if game.damage[DSHUTTL]<0:
4562             prout(_("Shuttle craft now serving Big Macs."))
4563             return
4564         if game.damage[DSHUTTL]>0:
4565             prout(_("Shuttle craft damaged."))
4566             return
4567         if game.landed:
4568             prout(_("You must be aboard the ship."))
4569             return
4570         if game.iscraft != "onship":
4571             prout(_("Shuttle craft not currently available."))
4572             return
4573         # Print abandon ship messages 
4574         skip(1)
4575         prouts(_("***ABANDON SHIP!  ABANDON SHIP!"))
4576         skip(1)
4577         prouts(_("***ALL HANDS ABANDON SHIP!"))
4578         skip(2)
4579         prout(_("Captain and crew escape in shuttle craft."))
4580         if game.state.rembase==0:
4581             # Oops! no place to go... 
4582             finish(FABANDN)
4583             return
4584         q = game.state.galaxy[game.quadrant.x][game.quadrant.y]
4585         # Dispose of crew 
4586         if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4587             prout(_("Remainder of ship's complement beam down"))
4588             prout(_("to nearest habitable planet."))
4589         elif q.planet != NOPLANET and not damaged(DTRANSP):
4590             prout(_("Remainder of ship's complement beam down to %s.") %
4591                     q.planet)
4592         else:
4593             prout(_("Entire crew of %d left to die in outer space.") %
4594                     game.state.crew)
4595             game.casual += game.state.crew
4596             game.abandoned += game.state.crew
4597
4598         # If at least one base left, give 'em the Faerie Queene 
4599         skip(1)
4600         game.icrystl = False # crystals are lost 
4601         game.nprobes = 0 # No probes 
4602         prout(_("You are captured by Klingons and released to"))
4603         prout(_("the Federation in a prisoner-of-war exchange."))
4604         nb = Rand()*game.state.rembase+1
4605         # Set up quadrant and position FQ adjacient to base 
4606         if not game.quadrant == game.state.baseq[nb]:
4607             game.quadrant = game.state.baseq[nb]
4608             game.sector.x = game.sector.y = 5
4609             newqad(True)
4610         while True:
4611             # position next to base by trial and error 
4612             game.quad[game.sector.x][game.sector.y] = IHDOT
4613             for l in range(1, QUADSIZE+1):
4614                 game.sector.x = 3.0*Rand() - 1.0 + game.base.x
4615                 game.sector.y = 3.0*Rand() - 1.0 + game.base.y
4616                 if VALID_SECTOR(game.sector.x, game.sector.y) and \
4617                        game.quad[game.sector.x][game.sector.y] == IHDOT:
4618                     break
4619             if l < QUADSIZE+1:
4620                 break # found a spot 
4621             game.sector.x=QUADSIZE/2
4622             game.sector.y=QUADSIZE/2
4623             newqad(True)
4624     # Get new commission 
4625     game.quad[game.sector.x][game.sector.y] = game.ship = IHF
4626     game.state.crew = FULLCREW
4627     prout(_("Starfleet puts you in command of another ship,"))
4628     prout(_("the Faerie Queene, which is antiquated but,"))
4629     prout(_("still useable."))
4630     if game.icrystl:
4631         prout(_("The dilithium crystals have been moved."))
4632     game.imine = False
4633     game.iscraft = "offship" # Galileo disappears 
4634     # Resupply ship 
4635     game.condition="docked"
4636     for l in range(0, NDEVICES): 
4637         game.damage[l] = 0.0
4638     game.damage[DSHUTTL] = -1
4639     game.energy = game.inenrg = 3000.0
4640     game.shield = game.inshld = 1250.0
4641     game.torps = game.intorps = 6
4642     game.lsupres=game.inlsr=3.0
4643     game.shldup=False
4644     game.warpfac=5.0
4645     game.wfacsq=25.0
4646     return
4647
4648 # Code from planets.c begins here.
4649
4650 def consumeTime():
4651     # abort a lengthy operation if an event interrupts it 
4652     game.ididit = True
4653     events()
4654     if game.alldone or game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova or game.justin: 
4655         return True
4656     return False
4657
4658 def survey():
4659     # report on (uninhabited) planets in the galaxy 
4660     iknow = False
4661     skip(1)
4662     chew()
4663     prout(_("Spock-  \"Planet report follows, Captain.\""))
4664     skip(1)
4665     for i in range(game.inplan):
4666         if game.state.planets[i].pclass == destroyed:
4667             continue
4668         if (game.state.planets[i].known != "unknown" \
4669             and not game.state.planets[i].inhabited) \
4670             or idebug:
4671             iknow = True
4672             if idebug and game.state.planets[i].known=="unknown":
4673                 proutn("(Unknown) ")
4674             proutn(_("Quadrant %s") % game.state.planets[i].w)
4675             proutn(_("   class "))
4676             proutn(game.state.planets[i].pclass)
4677             proutn("   ")
4678             if game.state.planets[i].crystals != present:
4679                 proutn(_("no "))
4680             prout(_("dilithium crystals present."))
4681             if game.state.planets[i].known=="shuttle_down": 
4682                 prout(_("    Shuttle Craft Galileo on surface."))
4683     if not iknow:
4684         prout(_("No information available."))
4685
4686 def orbit():
4687     # enter standard orbit 
4688     skip(1)
4689     chew()
4690     if game.inorbit:
4691         prout(_("Already in standard orbit."))
4692         return
4693     if damaged(DWARPEN) and damaged(DIMPULS):
4694         prout(_("Both warp and impulse engines damaged."))
4695         return
4696     if not is_valid(game.plnet) or abs(game.sector.x-game.plnet.x) > 1 or abs(game.sector.y-game.plnet.y) > 1:
4697         crmshp()
4698         prout(_(" not adjacent to planet."))
4699         skip(1)
4700         return
4701     game.optime = 0.02+0.03*Rand()
4702     prout(_("Helmsman Sulu-  \"Entering standard orbit, Sir.\""))
4703     newcnd()
4704     if consumeTime():
4705         return
4706     game.height = (1400.0+7200.0*Rand())
4707     prout(_("Sulu-  \"Entered orbit at altitude %.2f kilometers.\"") % game.height)
4708     game.inorbit = True
4709     game.ididit = True
4710
4711 def sensor():
4712     # examine planets in this quadrant 
4713     if damaged(DSRSENS):
4714         if game.options & OPTION_TTY:
4715             prout(_("Short range sensors damaged."))
4716         return
4717     if not is_valid(game.plnet):
4718         if game.options & OPTION_TTY:
4719             prout(_("Spock- \"No planet in this quadrant, Captain.\""))
4720         return
4721     if game.state.planets[game.iplnet].known == "unknown":
4722         prout(_("Spock-  \"Sensor scan for Quadrant %s-") % game.quadrant)
4723         skip(1)
4724         prout(_("         Planet at Sector %s is of class %s.") %
4725               (sector,game.plnet, game.state.planets[game.iplnet]))
4726         if game.state.planets[game.iplnet].known=="shuttle_down": 
4727             prout(_("         Sensors show Galileo still on surface."))
4728         proutn(_("         Readings indicate"))
4729         if game.state.planets[game.iplnet].crystals != present:
4730             proutn(_(" no"))
4731         prout(_(" dilithium crystals present.\""))
4732         if game.state.planets[game.iplnet].known == "unknown":
4733             game.state.planets[game.iplnet].known = "known"
4734
4735 def beam():
4736     # use the transporter 
4737     nrgneed = 0
4738     chew()
4739     skip(1)
4740     if damaged(DTRANSP):
4741         prout(_("Transporter damaged."))
4742         if not damaged(DSHUTTL) and (game.state.planets[game.iplnet].known=="shuttle_down" or game.iscraft == "onship"):
4743             skip(1)
4744             proutn(_("Spock-  \"May I suggest the shuttle craft, Sir?\" "))
4745             if ja() == True:
4746                 shuttle()
4747         return
4748     if not game.inorbit:
4749         crmshp()
4750         prout(_(" not in standard orbit."))
4751         return
4752     if game.shldup:
4753         prout(_("Impossible to transport through shields."))
4754         return
4755     if game.state.planets[game.iplnet].known=="unknown":
4756         prout(_("Spock-  \"Captain, we have no information on this planet"))
4757         prout(_("  and Starfleet Regulations clearly state that in this situation"))
4758         prout(_("  you may not go down.\""))
4759         return
4760     if not game.landed and game.state.planets[game.iplnet].crystals==absent:
4761         prout(_("Spock-  \"Captain, I fail to see the logic in"))
4762         prout(_("  exploring a planet with no dilithium crystals."))
4763         proutn(_("  Are you sure this is wise?\" "))
4764         if ja() == False:
4765             chew()
4766             return
4767     if not (game.options & OPTION_PLAIN):
4768         nrgneed = 50 * game.skill + game.height / 100.0
4769         if nrgneed > game.energy:
4770             prout(_("Engineering to bridge--"))
4771             prout(_("  Captain, we don't have enough energy for transportation."))
4772             return
4773         if not game.landed and nrgneed * 2 > game.energy:
4774             prout(_("Engineering to bridge--"))
4775             prout(_("  Captain, we have enough energy only to transport you down to"))
4776             prout(_("  the planet, but there wouldn't be an energy for the trip back."))
4777             if game.state.planets[game.iplnet].known == "shuttle_down":
4778                 prout(_("  Although the Galileo shuttle craft may still be on a surface."))
4779             proutn(_("  Are you sure this is wise?\" "))
4780             if ja() == False:
4781                 chew()
4782                 return
4783     if game.landed:
4784         # Coming from planet 
4785         if game.state.planets[game.iplnet].known=="shuttle_down":
4786             proutn(_("Spock-  \"Wouldn't you rather take the Galileo?\" "))
4787             if ja() == True:
4788                 chew()
4789                 return
4790             prout(_("Your crew hides the Galileo to prevent capture by aliens."))
4791         prout(_("Landing party assembled, ready to beam up."))
4792         skip(1)
4793         prout(_("Kirk whips out communicator..."))
4794         prouts(_("BEEP  BEEP  BEEP"))
4795         skip(2)
4796         prout(_("\"Kirk to enterprise-  Lock on coordinates...energize.\""))
4797     else:
4798         # Going to planet 
4799         prout(_("Scotty-  \"Transporter room ready, Sir.\""))
4800         skip(1)
4801         prout(_("Kirk and landing party prepare to beam down to planet surface."))
4802         skip(1)
4803         prout(_("Kirk-  \"Energize.\""))
4804     game.ididit = True
4805     skip(1)
4806     prouts("WWHOOOIIIIIRRRRREEEE.E.E.  .  .  .  .   .    .")
4807     skip(2)
4808     if Rand() > 0.98:
4809         prouts("BOOOIIIOOOIIOOOOIIIOIING . . .")
4810         skip(2)
4811         prout(_("Scotty-  \"Oh my God!  I've lost them.\""))
4812         finish(FLOST)
4813         return
4814     prouts(".    .   .  .  .  .  .E.E.EEEERRRRRIIIIIOOOHWW")
4815     game.landed = not game.landed
4816     game.energy -= nrgneed
4817     skip(2)
4818     prout(_("Transport complete."))
4819     if game.landed and game.state.planets[game.iplnet].known=="shuttle_down":
4820         prout(_("The shuttle craft Galileo is here!"))
4821     if not game.landed and game.imine:
4822         game.icrystl = True
4823         game.cryprob = 0.05
4824     game.imine = False
4825     return
4826
4827 def mine():
4828     # strip-mine a world for dilithium 
4829     skip(1)
4830     chew()
4831     if not game.landed:
4832         prout(_("Mining party not on planet."))
4833         return
4834     if game.state.planets[game.iplnet].crystals == mined:
4835         prout(_("This planet has already been strip-mined for dilithium."))
4836         return
4837     elif game.state.planets[game.iplnet].crystals == absent:
4838         prout(_("No dilithium crystals on this planet."))
4839         return
4840     if game.imine:
4841         prout(_("You've already mined enough crystals for this trip."))
4842         return
4843     if game.icrystl and game.cryprob == 0.05:
4844         proutn(_("With all those fresh crystals aboard the "))
4845         crmshp()
4846         skip(1)
4847         prout(_("there's no reason to mine more at this time."))
4848         return
4849     game.optime = (0.1+0.2*Rand())*game.state.planets[game.iplnet].pclass
4850     if consumeTime():
4851         return
4852     prout(_("Mining operation complete."))
4853     game.state.planets[game.iplnet].crystals = mined
4854     game.imine = game.ididit = True
4855
4856 def usecrystals():
4857     # use dilithium crystals 
4858     game.ididit = False
4859     skip(1)
4860     chew()
4861     if not game.icrystl:
4862         prout(_("No dilithium crystals available."))
4863         return
4864     if game.energy >= 1000:
4865         prout(_("Spock-  \"Captain, Starfleet Regulations prohibit such an operation"))
4866         prout(_("  except when Condition Yellow exists."))
4867         return
4868     prout(_("Spock- \"Captain, I must warn you that loading"))
4869     prout(_("  raw dilithium crystals into the ship's power"))
4870     prout(_("  system may risk a severe explosion."))
4871     proutn(_("  Are you sure this is wise?\" "))
4872     if ja() == False:
4873         chew()
4874         return
4875     skip(1)
4876     prout(_("Engineering Officer Scott-  \"(GULP) Aye Sir."))
4877     prout(_("  Mr. Spock and I will try it.\""))
4878     skip(1)
4879     prout(_("Spock-  \"Crystals in place, Sir."))
4880     prout(_("  Ready to activate circuit.\""))
4881     skip(1)
4882     prouts(_("Scotty-  \"Keep your fingers crossed, Sir!\""))
4883     skip(1)
4884     if Rand() <= game.cryprob:
4885         prouts(_("  \"Activating now! - - No good!  It's***"))
4886         skip(2)
4887         prouts(_("***RED ALERT!  RED A*L********************************"))
4888         skip(1)
4889         stars()
4890         prouts(_("******************   KA-BOOM!!!!   *******************"))
4891         skip(1)
4892         kaboom()
4893         return
4894     game.energy += 5000.0*(1.0 + 0.9*Rand())
4895     prouts(_("  \"Activating now! - - "))
4896     prout(_("The instruments"))
4897     prout(_("   are going crazy, but I think it's"))
4898     prout(_("   going to work!!  Congratulations, Sir!\""))
4899     game.cryprob *= 2.0
4900     game.ididit = True
4901
4902 def shuttle():
4903     # use shuttlecraft for planetary jaunt 
4904     chew()
4905     skip(1)
4906     if damaged(DSHUTTL):
4907         if game.damage[DSHUTTL] == -1.0:
4908             if game.inorbit and game.state.planets[game.iplnet].known == "shuttle_down":
4909                 prout(_("Ye Faerie Queene has no shuttle craft bay to dock it at."))
4910             else:
4911                 prout(_("Ye Faerie Queene had no shuttle craft."))
4912         elif game.damage[DSHUTTL] > 0:
4913             prout(_("The Galileo is damaged."))
4914         else: # game.damage[DSHUTTL] < 0  
4915             prout(_("Shuttle craft is now serving Big Macs."))
4916         return
4917     if not game.inorbit:
4918         crmshp()
4919         prout(_(" not in standard orbit."))
4920         return
4921     if (game.state.planets[game.iplnet].known != "shuttle_down") and game.iscraft != "onship":
4922         prout(_("Shuttle craft not currently available."))
4923         return
4924     if not game.landed and game.state.planets[game.iplnet].known=="shuttle_down":
4925         prout(_("You will have to beam down to retrieve the shuttle craft."))
4926         return
4927     if game.shldup or game.condition == "docked":
4928         prout(_("Shuttle craft cannot pass through shields."))
4929         return
4930     if game.state.planets[game.iplnet].known=="unknown":
4931         prout(_("Spock-  \"Captain, we have no information on this planet"))
4932         prout(_("  and Starfleet Regulations clearly state that in this situation"))
4933         prout(_("  you may not fly down.\""))
4934         return
4935     game.optime = 3.0e-5*game.height
4936     if game.optime >= 0.8*game.state.remtime:
4937         prout(_("First Officer Spock-  \"Captain, I compute that such"))
4938         proutn(_("  a maneuver would require approximately %2d%% of our") % \
4939                int(100*game.optime/game.state.remtime))
4940         prout(_("remaining time."))
4941         proutn(_("Are you sure this is wise?\" "))
4942         if ja() == False:
4943             game.optime = 0.0
4944             return
4945     if game.landed:
4946         # Kirk on planet 
4947         if game.iscraft == "onship":
4948             # Galileo on ship! 
4949             if not damaged(DTRANSP):
4950                 proutn(_("Spock-  \"Would you rather use the transporter?\" "))
4951                 if ja() == True:
4952                     beam()
4953                     return
4954                 proutn(_("Shuttle crew"))
4955             else:
4956                 proutn(_("Rescue party"))
4957             prout(_(" boards Galileo and swoops toward planet surface."))
4958             game.iscraft = "offship"
4959             skip(1)
4960             if consumeTime():
4961                 return
4962             game.state.planets[game.iplnet].known="shuttle_down"
4963             prout(_("Trip complete."))
4964             return
4965         else:
4966             # Ready to go back to ship 
4967             prout(_("You and your mining party board the"))
4968             prout(_("shuttle craft for the trip back to the Enterprise."))
4969             skip(1)
4970             prouts(_("The short hop begins . . ."))
4971             skip(1)
4972             game.state.planets[game.iplnet].known="known"
4973             game.icraft = True
4974             skip(1)
4975             game.landed = False
4976             if consumeTime():
4977                 return
4978             game.iscraft = "onship"
4979             game.icraft = False
4980             if game.imine:
4981                 game.icrystl = True
4982                 game.cryprob = 0.05
4983             game.imine = False
4984             prout(_("Trip complete."))
4985             return
4986     else:
4987         # Kirk on ship 
4988         # and so is Galileo 
4989         prout(_("Mining party assembles in the hangar deck,"))
4990         prout(_("ready to board the shuttle craft \"Galileo\"."))
4991         skip(1)
4992         prouts(_("The hangar doors open; the trip begins."))
4993         skip(1)
4994         game.icraft = True
4995         game.iscraft = "offship"
4996         if consumeTime():
4997             return
4998         game.state.planets[game.iplnet].known = "shuttle_down"
4999         game.landed = True
5000         game.icraft = False
5001         prout(_("Trip complete."))
5002         return
5003
5004 def deathray():
5005     # use the big zapper 
5006     r = Rand()
5007         
5008     game.ididit = False
5009     skip(1)
5010     chew()
5011     if game.ship != IHE:
5012         prout(_("Ye Faerie Queene has no death ray."))
5013         return
5014     if game.nenhere==0:
5015         prout(_("Sulu-  \"But Sir, there are no enemies in this quadrant.\""))
5016         return
5017     if damaged(DDRAY):
5018         prout(_("Death Ray is damaged."))
5019         return
5020     prout(_("Spock-  \"Captain, the 'Experimental Death Ray'"))
5021     prout(_("  is highly unpredictible.  Considering the alternatives,"))
5022     proutn(_("  are you sure this is wise?\" "))
5023     if ja() == False:
5024         return
5025     prout(_("Spock-  \"Acknowledged.\""))
5026     skip(1)
5027     game.ididit = True
5028     prouts(_("WHOOEE ... WHOOEE ... WHOOEE ... WHOOEE"))
5029     skip(1)
5030     prout(_("Crew scrambles in emergency preparation."))
5031     prout(_("Spock and Scotty ready the death ray and"))
5032     prout(_("prepare to channel all ship's power to the device."))
5033     skip(1)
5034     prout(_("Spock-  \"Preparations complete, sir.\""))
5035     prout(_("Kirk-  \"Engage!\""))
5036     skip(1)
5037     prouts(_("WHIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"))
5038     skip(1)
5039     dprob = .30
5040     if game.options & OPTION_PLAIN:
5041         dprob = .5
5042     if r > dprob:
5043         prouts(_("Sulu- \"Captain!  It's working!\""))
5044         skip(2)
5045         while game.nenhere > 0:
5046             deadkl(game.ks[1], game.quad[game.ks[1].x][game.ks[1].y],game.ks[1])
5047         prout(_("Ensign Chekov-  \"Congratulations, Captain!\""))
5048         if (game.state.remkl + game.state.remcom + game.state.nscrem) == 0:
5049             finish(FWON)    
5050         if (game.options & OPTION_PLAIN) == 0:
5051             prout(_("Spock-  \"Captain, I believe the `Experimental Death Ray'"))
5052             if Rand() <= 0.05:
5053                 prout(_("   is still operational.\""))
5054             else:
5055                 prout(_("   has been rendered nonfunctional.\""))
5056                 game.damage[DDRAY] = 39.95
5057         return
5058     r = Rand()  # Pick failure method 
5059     if r <= .30:
5060         prouts(_("Sulu- \"Captain!  It's working!\""))
5061         skip(1)
5062         prouts(_("***RED ALERT!  RED ALERT!"))
5063         skip(1)
5064         prout(_("***MATTER-ANTIMATTER IMPLOSION IMMINENT!"))
5065         skip(1)
5066         prouts(_("***RED ALERT!  RED A*L********************************"))
5067         skip(1)
5068         stars()
5069         prouts(_("******************   KA-BOOM!!!!   *******************"))
5070         skip(1)
5071         kaboom()
5072         return
5073     if r <= .55:
5074         prouts(_("Sulu- \"Captain!  Yagabandaghangrapl, brachriigringlanbla!\""))
5075         skip(1)
5076         prout(_("Lt. Uhura-  \"Graaeek!  Graaeek!\""))
5077         skip(1)
5078         prout(_("Spock-  \"Fascinating!  . . . All humans aboard"))
5079         prout(_("  have apparently been transformed into strange mutations."))
5080         prout(_("  Vulcans do not seem to be affected."))
5081         skip(1)
5082         prout(_("Kirk-  \"Raauch!  Raauch!\""))
5083         finish(FDRAY)
5084         return
5085     if r <= 0.75:
5086         intj
5087         prouts(_("Sulu- \"Captain!  It's   --WHAT?!?!\""))
5088         skip(2)
5089         proutn(_("Spock-  \"I believe the word is"))
5090         prouts(_(" *ASTONISHING*"))
5091         prout(_(" Mr. Sulu."))
5092         for i in range(1, QUADSIZE+1):
5093             for j in range(1, QUADSIZE+1):
5094                 if game.quad[i][j] == IHDOT:
5095                     game.quad[i][j] = IHQUEST
5096         prout(_("  Captain, our quadrant is now infested with"))
5097         prouts(_(" - - - - - -  *THINGS*."))
5098         skip(1)
5099         prout(_("  I have no logical explanation.\""))
5100         return
5101     prouts(_("Sulu- \"Captain!  The Death Ray is creating tribbles!\""))
5102     skip(1)
5103     prout(_("Scotty-  \"There are so many tribbles down here"))
5104     prout(_("  in Engineering, we can't move for 'em, Captain.\""))
5105     finish(FTRIBBLE)
5106     return
5107
5108 # Code from reports.c begins here
5109
5110 def attackreport(curt):
5111     # report status of bases under attack 
5112     if not curt:
5113         if is_scheduled(FCDBAS):
5114             prout(_("Starbase in Quadrant %s is currently under Commander attack.") % game.battle)
5115             prout(_("It can hold out until Stardate %d.") % int(scheduled(FCDBAS)))
5116         elif game.isatb == 1:
5117             prout(_("Starbase in Quadrant %s is under Super-commander attack.") % game.state.kscmdr)
5118             prout(_("It can hold out until Stardate %d.") % int(scheduled(FSCDBAS)))
5119         else:
5120             prout(_("No Starbase is currently under attack."))
5121     else:
5122         if is_scheduled(FCDBAS):
5123             proutn(_("Base in %s attacked by C. Alive until %.1f") % (game.battle, scheduled(FCDBAS)))
5124         if game.isatb:
5125             proutn(_("Base in %s attacked by S. Alive until %.1f") % (game.state.kscmdr, scheduled(FSCDBAS)))
5126         clreol()
5127
5128 def report():
5129     # report on general game status 
5130     chew()
5131     s1 = "" and game.thawed and _("thawed ")
5132     s2 = {1:"short", 2:"medium", 4:"long"}[game.length]
5133     s3 = (None, _("novice"). _("fair"),
5134           _("good"), _("expert"), _("emeritus"))[game.skill]
5135     prout(_("You %s a %s%s %s game.") % ((_("were playing"), _("are playing"))[game.alldone], s1, s2, s3))
5136     if game.skill>SKILL_GOOD and game.thawed and not game.alldone:
5137         prout(_("No plaque is allowed."))
5138     if game.tourn:
5139         prout(_("This is tournament game %d.") % game.tourn)
5140     prout(_("Your secret password is \"%s\"") % game.passwd)
5141     proutn(_("%d of %d Klingons have been killed") % (((game.inkling + game.incom + game.inscom) - (game.state.remkl + game.state.remcom + game.state.nscrem)), 
5142            (game.inkling + game.incom + game.inscom)))
5143     if game.incom - game.state.remcom:
5144         prout(_(", including %d Commander%s.") % (game.incom - game.state.remcom, (_("s"), "")[(game.incom - game.state.remcom)==1]))
5145     elif game.inkling - game.state.remkl + (game.inscom - game.state.nscrem) > 0:
5146         prout(_(", but no Commanders."))
5147     else:
5148         prout(".")
5149     if game.skill > SKILL_FAIR:
5150         prout(_("The Super Commander has %sbeen destroyed.") % ("", _("not "))[game.state.nscrem])
5151     if game.state.rembase != game.inbase:
5152         proutn(_("There "))
5153         if game.inbase-game.state.rembase==1:
5154             proutn(_("has been 1 base"))
5155         else:
5156             proutn(_("have been %d bases") % (game.inbase-game.state.rembase))
5157         prout(_(" destroyed, %d remaining.") % game.state.rembase)
5158     else:
5159         prout(_("There are %d bases.") % game.inbase)
5160     if communicating() or game.iseenit:
5161         # Don't report this if not seen and
5162         # either the radio is dead or not at base!
5163         attackreport(False)
5164         game.iseenit = True
5165     if game.casual: 
5166         prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1]))
5167     if game.nhelp:
5168         prout(_("There were %d call%s for help.") % (game.nhelp,  ("" , _("s"))[game.nhelp!=1]))
5169     if game.ship == IHE:
5170         proutn(_("You have "))
5171         if game.nprobes:
5172             proutn("%d" % (game.nprobes))
5173         else:
5174             proutn(_("no"))
5175         proutn(_(" deep space probe"))
5176         if game.nprobes!=1:
5177             proutn(_("s"))
5178         prout(".")
5179     if communicating() and is_scheduled(FDSPROB):
5180         if game.isarmed: 
5181             proutn(_("An armed deep space probe is in "))
5182         else:
5183             proutn(_("A deep space probe is in "))
5184         prout("Quadrant %s." % game.probec)
5185     if game.icrystl:
5186         if game.cryprob <= .05:
5187             prout(_("Dilithium crystals aboard ship... not yet used."))
5188         else:
5189             i=0
5190             ai = 0.05
5191             while game.cryprob > ai:
5192                 ai *= 2.0
5193                 i += 1
5194             prout(_("Dilithium crystals have been used %d time%s.") % \
5195                   (i, (_("s"), "")[i==1]))
5196     skip(1)
5197         
5198 def lrscan():
5199     # long-range sensor scan 
5200     if damaged(DLRSENS):
5201         # Now allow base's sensors if docked 
5202         if game.condition != "docked":
5203             prout(_("LONG-RANGE SENSORS DAMAGED."))
5204             return
5205         prout(_("Starbase's long-range scan"))
5206     else:
5207         prout(_("Long-range scan"))
5208     for x in range(game.quadrant.x-1, game.quadrant.x+2):
5209         proutn(" ")
5210         for y in range(game.quadrant.y-1, game.quadrant.y+2):
5211             if not VALID_QUADRANT(x, y):
5212                 proutn("  -1")
5213             else:
5214                 if not damaged(DRADIO):
5215                     game.state.galaxy[x][y].charted = True
5216                 game.state.chart[x][y].klingons = game.state.galaxy[x][y].klingons
5217                 game.state.chart[x][y].starbase = game.state.galaxy[x][y].starbase
5218                 game.state.chart[x][y].stars = game.state.galaxy[x][y].stars
5219                 if game.state.galaxy[x][y].supernova: 
5220                     proutn(" ***")
5221                 else:
5222                     proutn(" %3d" % (game.state.chart[x][y].klingons*100 + game.state.chart[x][y].starbase * 10 + game.state.chart[x][y].stars))
5223         prout(" ")
5224
5225 def damagereport():
5226     # damage report 
5227     jdam = False
5228     chew()
5229
5230     for i in range(NDEVICES):
5231         if damaged(i):
5232             if not jdam:
5233                 prout(_("\tDEVICE\t\t\t-REPAIR TIMES-"))
5234                 prout(_("\t\t\tIN FLIGHT\t\tDOCKED"))
5235                 jdam = True
5236             prout("  %-26s\t%8.2f\t\t%8.2f" % (device[i],
5237                                                game.damage[i]+0.05,
5238                                                game.docfac*game.damage[i]+0.005))
5239     if not jdam:
5240         prout(_("All devices functional."))
5241
5242 def rechart():
5243     # update the chart in the Enterprise's computer from galaxy data 
5244     game.lastchart = game.state.date
5245     for i in range(1, GALSIZE+1):
5246         for j in range(1, GALSIZE+1):
5247             if game.state.galaxy[i][j].charted:
5248                 game.state.chart[i][j].klingons = game.state.galaxy[i][j].klingons
5249                 game.state.chart[i][j].starbase = game.state.galaxy[i][j].starbase
5250                 game.state.chart[i][j].stars = game.state.galaxy[i][j].stars
5251
5252 def chart():
5253     # display the star chart  
5254     chew()
5255     if not damaged(DRADIO):
5256         rechart()
5257     if game.lastchart < game.state.date and game.condition == "docked":
5258         prout(_("Spock-  \"I revised the Star Chart from the starbase's records.\""))
5259         rechart()
5260
5261     prout(_("       STAR CHART FOR THE KNOWN GALAXY"))
5262     if game.state.date > game.lastchart:
5263         prout(_("(Last surveillance update %d stardates ago).") % ((int)(game.state.date-game.lastchart)))
5264     prout("      1    2    3    4    5    6    7    8")
5265     for i in range(1, GALSIZE+1):
5266         proutn("%d |" % (i))
5267         for j in range(1, GALSIZE+1):
5268             if (game.options & OPTION_SHOWME) and i == game.quadrant.x and j == game.quadrant.y:
5269                 proutn("<")
5270             else:
5271                 proutn(" ")
5272             if game.state.galaxy[i][j].supernova:
5273                 strcpy(buf, "***")
5274             elif not game.state.galaxy[i][j].charted and game.state.galaxy[i][j].starbase:
5275                 strcpy(buf, ".1.")
5276             elif game.state.galaxy[i][j].charted:
5277                 sprintf(buf, "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars))
5278             else:
5279                 strcpy(buf, "...")
5280             proutn(buf)
5281             if (game.options & OPTION_SHOWME) and i == game.quadrant.x and j == game.quadrant.y:
5282                 proutn(">")
5283             else:
5284                 proutn(" ")
5285         proutn("  |")
5286         if i<GALSIZE:
5287             skip(1)
5288
5289 def sectscan(goodScan, i, j):
5290     # light up an individual dot in a sector 
5291     if goodScan or (abs(i-game.sector.x)<= 1 and abs(j-game.sector.y) <= 1):
5292         if (game.quad[i][j]==IHMATER0) or (game.quad[i][j]==IHMATER1) or (game.quad[i][j]==IHMATER2) or (game.quad[i][j]==IHE) or (game.quad[i][j]==IHF):
5293             if game.condition   == "red": textcolor(RED)
5294             elif game.condition == "green": textcolor(GREEN)
5295             elif game.condition == "yellow": textcolor(YELLOW)
5296             elif game.condition == "docked": textcolor(CYAN)
5297             elif game.condition == "dead": textcolor(BROWN)
5298             if game.quad[i][j] != game.ship: 
5299                 highvideo()
5300         proutn("%c " % game.quad[i][j])
5301         textcolor(DEFAULT)
5302     else:
5303         proutn("- ")
5304
5305 def status(req):
5306     # print status report lines 
5307
5308     if not req or req == 1:
5309         prstat(_("Stardate"), _("%.1f, Time Left %.2f") \
5310                % (game.state.date, game.state.remtime))
5311     elif not req or req == 2:
5312         if game.condition != "docked":
5313             newcnd()
5314         dam = 0
5315         for t in range(0, NDEVICES):
5316             if game.damage[t]>0: 
5317                 dam += 1
5318         prstat(_("Condition"), _("%s, %i DAMAGES") % (game.condition.upper(), dam))
5319     elif not req or req == 3:
5320         prstat(_("Position"), "%s , %s" % (game.quadrant, game.sector))
5321     elif not req or req == 4:
5322         if damaged(DLIFSUP):
5323             if game.condition == "docked":
5324                 sprintf(s, _("DAMAGED, Base provides"))
5325             else:
5326                 sprintf(s, _("DAMAGED, reserves=%4.2f") % game.lsupres)
5327         else:
5328             sprintf(s, _("ACTIVE"))
5329         prstat(_("Life Support"), s)
5330     elif not req or req == 5:
5331         prstat(_("Warp Factor"), "%.1f" % (game.warpfac))
5332     elif not req or req == 6:
5333         extra = ""
5334         if game.icrystl and (game.options & OPTION_SHOWME):
5335             extra = _(" (have crystals)")
5336         prstat(_("Energy"), "%.2f%s" % game.energy, extra)
5337     elif not req or req == 7:
5338         prstat(_("Torpedoes"), "%d" % (game.torps))
5339     elif not req or req == 8:
5340         if damaged(DSHIELD):
5341             strcpy(s, _("DAMAGED,"))
5342         elif game.shldup:
5343             strcpy(s, _("UP,"))
5344         else:
5345             strcpy(s, _("DOWN,"))
5346         data = _(" %d%% %.1f units") \
5347                % (int((100.0*game.shield)/game.inshld + 0.5), game.shield)
5348         prstat(_("Shields"), s)
5349     elif not req or req == 9:
5350         prstat(_("Klingons Left"), "%d" \
5351                % (game.state.remkl + game.state.remcom + game.state.nscrem))
5352     elif not req or req == 10:
5353         if game.options & OPTION_WORLDS:
5354             plnet = game.state.galaxy[game.quadrant.x][game.quadrant.y].planet
5355             if plnet != NOPLANET and game.state.planets[plnet].inhabited:
5356                 prstat(_("Major system"), plnet.name)
5357             else:
5358                 prout(_("Sector is uninhabited"))
5359     elif not req or req == 11:
5360         attackreport(not req)
5361
5362 def request():
5363     requests = ("da","co","po","ls","wa","en","to","sh","kl","sy", "ti")
5364     while scan() == IHEOL:
5365         proutn(_("Information desired? "))
5366     chew()
5367     if citem in requests:
5368         status(requests.index(citem))
5369     else:
5370         prout(_("UNRECOGNIZED REQUEST. Legal requests are:"))
5371         prout(("  date, condition, position, lsupport, warpfactor,"))
5372         prout(("  energy, torpedoes, shields, klingons, system, time."))
5373                 
5374 def srscan():
5375     # short-range scan 
5376     goodScan=True
5377     if damaged(DSRSENS):
5378         # Allow base's sensors if docked 
5379         if game.condition != "docked":
5380             prout(_("   S.R. SENSORS DAMAGED!"))
5381             goodScan=False
5382         else:
5383             prout(_("  [Using Base's sensors]"))
5384     else:
5385         prout(_("     Short-range scan"))
5386     if goodScan and not damaged(DRADIO): 
5387         game.state.chart[game.quadrant.x][game.quadrant.y].klingons = game.state.galaxy[game.quadrant.x][game.quadrant.y].klingons
5388         game.state.chart[game.quadrant.x][game.quadrant.y].starbase = game.state.galaxy[game.quadrant.x][game.quadrant.y].starbase
5389         game.state.chart[game.quadrant.x][game.quadrant.y].stars = game.state.galaxy[game.quadrant.x][game.quadrant.y].stars
5390         game.state.galaxy[game.quadrant.x][game.quadrant.y].charted = True
5391     prout("    1 2 3 4 5 6 7 8 9 10")
5392     if game.condition != "docked":
5393         newcnd()
5394     for i in range(1, QUADSIZE+1):
5395         proutn("%2d  " % (i))
5396         for j in range(1, QUADSIZE+1):
5397             sectscan(goodScan, i, j)
5398         skip(1)
5399                         
5400                         
5401 def eta():
5402     # use computer to get estimated time of arrival for a warp jump 
5403     w1 = coord(); w2 = coord()
5404     prompt = False
5405     if damaged(DCOMPTR):
5406         prout(_("COMPUTER DAMAGED, USE A POCKET CALCULATOR."))
5407         skip(1)
5408         return
5409     if scan() != IHREAL:
5410         prompt = True
5411         chew()
5412         proutn(_("Destination quadrant and/or sector? "))
5413         if scan()!=IHREAL:
5414             huh()
5415             return
5416     w1.y = aaitem +0.5
5417     if scan() != IHREAL:
5418         huh()
5419         return
5420     w1.x = aaitem + 0.5
5421     if scan() == IHREAL:
5422         w2.y = aaitem + 0.5
5423         if scan() != IHREAL:
5424             huh()
5425             return
5426         w2.x = aaitem + 0.5
5427     else:
5428         if game.quadrant.y>w1.x:
5429             w2.x = 1
5430         else:
5431             w2.x=QUADSIZE
5432         if game.quadrant.x>w1.y:
5433             w2.y = 1
5434         else:
5435             w2.y=QUADSIZE
5436
5437     if not VALID_QUADRANT(w1.x, w1.y) or not VALID_SECTOR(w2.x, w2.y):
5438         huh()
5439         return
5440     game.dist = math.sqrt(square(w1.y-game.quadrant.y+0.1*(w2.y-game.sector.y))+
5441                 square(w1.x-game.quadrant.x+0.1*(w2.x-game.sector.x)))
5442     wfl = False
5443
5444     if prompt:
5445         prout(_("Answer \"no\" if you don't know the value:"))
5446     while True:
5447         chew()
5448         proutn(_("Time or arrival date? "))
5449         if scan()==IHREAL:
5450             ttime = aaitem
5451             if ttime > game.state.date:
5452                 ttime -= game.state.date # Actually a star date
5453             twarp=(math.floor(math.sqrt((10.0*game.dist)/ttime)*10.0)+1.0)/10.0
5454             if ttime <= 1e-10 or twarp > 10:
5455                 prout(_("We'll never make it, sir."))
5456                 chew()
5457                 return
5458             if twarp < 1.0:
5459                 twarp = 1.0
5460             break
5461         chew()
5462         proutn(_("Warp factor? "))
5463         if scan()== IHREAL:
5464             wfl = True
5465             twarp = aaitem
5466             if twarp<1.0 or twarp > 10.0:
5467                 huh()
5468                 return
5469             break
5470         prout(_("Captain, certainly you can give me one of these."))
5471     while True:
5472         chew()
5473         ttime = (10.0*game.dist)/square(twarp)
5474         tpower = game.dist*twarp*twarp*twarp*(game.shldup+1)
5475         if tpower >= game.energy:
5476             prout(_("Insufficient energy, sir."))
5477             if not game.shldup or tpower > game.energy*2.0:
5478                 if not wfl:
5479                     return
5480                 proutn(_("New warp factor to try? "))
5481                 if scan() == IHREAL:
5482                     wfl = True
5483                     twarp = aaitem
5484                     if twarp<1.0 or twarp > 10.0:
5485                         huh()
5486                         return
5487                     continue
5488                 else:
5489                     chew()
5490                     skip(1)
5491                     return
5492             prout(_("But if you lower your shields,"))
5493             proutn(_("remaining"))
5494             tpower /= 2
5495         else:
5496             proutn(_("Remaining"))
5497         prout(_(" energy will be %.2f.") % (game.energy-tpower))
5498         if wfl:
5499             prout(_("And we will arrive at stardate %.2f.") % (game.state.date+ttime))
5500         elif twarp==1.0:
5501             prout(_("Any warp speed is adequate."))
5502         else:
5503             prout(_("Minimum warp needed is %.2f,") % (twarp))
5504             prout(_("and we will arrive at stardate %.2f.") % (game.state.date+ttime))
5505         if game.state.remtime < ttime:
5506             prout(_("Unfortunately, the Federation will be destroyed by then."))
5507         if twarp > 6.0:
5508             prout(_("You'll be taking risks at that speed, Captain"))
5509         if (game.isatb==1 and game.state.kscmdr == w1 and \
5510              scheduled(FSCDBAS)< ttime+game.state.date) or \
5511             (scheduled(FCDBAS)<ttime+game.state.date and game.battle == w1):
5512             prout(_("The starbase there will be destroyed by then."))
5513         proutn(_("New warp factor to try? "))
5514         if scan() == IHREAL:
5515             wfl = True
5516             twarp = aaitem
5517             if twarp<1.0 or twarp > 10.0:
5518                 huh()
5519                 return
5520         else:
5521             chew()
5522             skip(1)
5523             return
5524                         
5525
5526 #ifdef BSD_BUG_FOR_BUG
5527 # A visual scan is made in a particular direction of three sectors
5528 # in the general direction specified.  This takes time, and
5529 # Klingons can attack you, so it should be done only when sensors
5530 # are out.  Code swiped from BSD-Trek.  Not presently used, as we
5531 # automatically display all adjacent sectors on the short-range
5532 # scan even when short-range sensors are out.
5533
5534 # This struct[] has the delta x, delta y for particular directions
5535
5536 visdelta = (
5537     (-1,-1),
5538     (-1, 0),
5539     (-1, 1),
5540     (0,  1),
5541     (1,  1),
5542     (1,  0),
5543     (1, -1),
5544     (0, -1),
5545     (-1,-1),
5546     (-1, 0),
5547     (-1, 1),
5548 )
5549
5550 def visual():
5551     v = coord()
5552     if scan() != IHREAL:
5553         chew()
5554         proutn(_("Direction? "))
5555         if scan()!=IHREAL:
5556             huh()
5557             return
5558     if aaitem < 0.0 or aaitem > 360.0:
5559         return
5560     co = (aaitem + 22) / 45
5561     v = visdelta[co]
5562     ix = game.sector.x + v.x
5563     iy = game.sector.y + v.y
5564     if ix < 0 or ix >= QUADSIZE or iy < 0 or iy >= QUADSIZE:
5565         co = '?'
5566     else:
5567         co = game.quad[ix][iy]
5568     printf("%d,%d %c " % (ix, iy, co))
5569     v += 1
5570     ix = game.sector.x + v.x
5571     iy = game.sector.y + v.y
5572     if ix < 0 or ix >= QUADSIZE or iy < 0 or iy >= QUADSIZE:
5573         co = '?'
5574     else:
5575         co = game.quad[ix][iy]
5576     printf("%c " % (co))
5577     v += 1
5578     ix = game.sector.x + v.x
5579     iy = game.sector.y + v.y
5580     if ix < 0 or ix >= QUADSIZE or iy < 0 or iy >= QUADSIZE:
5581         co = '?'
5582     else:
5583         co = game.quad[ix][iy]
5584     prout("%c %d,%d\n" % (co, ix, iy))
5585     game.optime = 0.5
5586     game.ididit = True
5587 #endif
5588
5589 # Code from setup.c begins here
5590
5591 def filelength(fd):
5592     return os.fstat(fd).st_size
5593
5594 def prelim():
5595     # issue a historically correct banner 
5596     skip(2)
5597     prout(_("-SUPER- STAR TREK"))
5598     skip(1)
5599 #ifdef __HISTORICAL__
5600 #    prout(_("Latest update-21 Sept 78"))
5601 #    skip(1)
5602 #endif __HISTORICAL__ 
5603
5604 def freeze(boss):
5605     # save game 
5606     if boss:
5607         citem = "emsave.trk"
5608     else:
5609         key = scan()
5610         if key == IHEOL:
5611             proutn(_("File name: "))
5612             key = scan()
5613         if key != IHALPHA:
5614             huh()
5615             return
5616         chew()
5617         if '.' not in citem:
5618             citem += ".trk"
5619     try:
5620         fp = open(citem, "wb")
5621     except IOError:
5622         prout(_("Can't freeze game as file %s") % citem)
5623         return
5624     cPickle.dump(game, fp)
5625     fp.close()
5626
5627 def thaw():
5628     # retrieve saved game 
5629     game.passwd[0] = '\0'
5630     key = scan()
5631     if key == IHEOL:
5632         proutn(_("File name: "))
5633         key = scan()
5634     if key != IHALPHA:
5635         huh()
5636         return True
5637     chew()
5638     if '.' not in citem:
5639         citem += ".trk"
5640     try:
5641         fp = open(citem, "rb")
5642     except IOError:
5643         prout(_("Can't thaw game in %s") % citem)
5644         return
5645     game = cPickle.load(fp)
5646     fp.close()
5647     return False
5648
5649 # I used <http://www.memory-alpha.org> to find planets
5650 # with references in ST:TOS.  Eath and the Alpha Centauri
5651 # Colony have been omitted.
5652
5653 # Some planets marked Class G and P here will be displayed as class M
5654 # because of the way planets are generated. This is a known bug.
5655 systnames = (
5656     # Federation Worlds 
5657     _("Andoria (Fesoan)"),      # several episodes 
5658     _("Tellar Prime (Miracht)"),        # TOS: "Journey to Babel" 
5659     _("Vulcan (T'Khasi)"),      # many episodes 
5660     _("Medusa"),                # TOS: "Is There in Truth No Beauty?" 
5661     _("Argelius II (Nelphia)"),# TOS: "Wolf in the Fold" ("IV" in BSD) 
5662     _("Ardana"),                # TOS: "The Cloud Minders" 
5663     _("Catulla (Cendo-Prae)"),  # TOS: "The Way to Eden" 
5664     _("Gideon"),                # TOS: "The Mark of Gideon" 
5665     _("Aldebaran III"), # TOS: "The Deadly Years" 
5666     _("Alpha Majoris I"),       # TOS: "Wolf in the Fold" 
5667     _("Altair IV"),             # TOS: "Amok Time 
5668     _("Ariannus"),              # TOS: "Let That Be Your Last Battlefield" 
5669     _("Benecia"),               # TOS: "The Conscience of the King" 
5670     _("Beta Niobe I (Sarpeidon)"),      # TOS: "All Our Yesterdays" 
5671     _("Alpha Carinae II"),      # TOS: "The Ultimate Computer" 
5672     _("Capella IV (Kohath)"),   # TOS: "Friday's Child" (Class G) 
5673     _("Daran V"),               # TOS: "For the World is Hollow and I Have Touched the Sky" 
5674     _("Deneb II"),              # TOS: "Wolf in the Fold" ("IV" in BSD) 
5675     _("Eminiar VII"),           # TOS: "A Taste of Armageddon" 
5676     _("Gamma Canaris IV"),      # TOS: "Metamorphosis" 
5677     _("Gamma Tranguli VI (Vaalel)"),    # TOS: "The Apple" 
5678     _("Ingraham B"),            # TOS: "Operation: Annihilate" 
5679     _("Janus IV"),              # TOS: "The Devil in the Dark" 
5680     _("Makus III"),             # TOS: "The Galileo Seven" 
5681     _("Marcos XII"),            # TOS: "And the Children Shall Lead", 
5682     _("Omega IV"),              # TOS: "The Omega Glory" 
5683     _("Regulus V"),             # TOS: "Amok Time 
5684     _("Deneva"),                # TOS: "Operation -- Annihilate!" 
5685     # Worlds from BSD Trek 
5686     _("Rigel II"),              # TOS: "Shore Leave" ("III" in BSD) 
5687     _("Beta III"),              # TOS: "The Return of the Archons" 
5688     _("Triacus"),               # TOS: "And the Children Shall Lead", 
5689     _("Exo III"),               # TOS: "What Are Little Girls Made Of?" (Class P) 
5690 #       # Others 
5691 #    _("Hansen's Planet"),      # TOS: "The Galileo Seven" 
5692 #    _("Taurus IV"),            # TOS: "The Galileo Seven" (class G) 
5693 #    _("Antos IV (Doraphane)"), # TOS: "Whom Gods Destroy", "Who Mourns for Adonais?" 
5694 #    _("Izar"),                 # TOS: "Whom Gods Destroy" 
5695 #    _("Tiburon"),              # TOS: "The Way to Eden" 
5696 #    _("Merak II"),             # TOS: "The Cloud Minders" 
5697 #    _("Coridan (Desotriana)"), # TOS: "Journey to Babel" 
5698 #    _("Iotia"),                # TOS: "A Piece of the Action" 
5699 )
5700
5701 device = (
5702         _("S. R. Sensors"), \
5703         _("L. R. Sensors"), \
5704         _("Phasers"), \
5705         _("Photon Tubes"), \
5706         _("Life Support"), \
5707         _("Warp Engines"), \
5708         _("Impulse Engines"), \
5709         _("Shields"), \
5710         _("Subspace Radio"), \
5711         _("Shuttle Craft"), \
5712         _("Computer"), \
5713         _("Navigation System"), \
5714         _("Transporter"), \
5715         _("Shield Control"), \
5716         _("Death Ray"), \
5717         _("D. S. Probe"), \
5718 )
5719
5720 def setup(needprompt):
5721     # prepare to play, set up cosmos 
5722     intj, krem, klumper
5723     w = coord()
5724
5725     #  Decide how many of everything
5726     if choose(needprompt):
5727         return # frozen game
5728     # Prepare the Enterprise
5729     game.alldone = game.gamewon = False
5730     game.ship = IHE
5731     game.state.crew = FULLCREW
5732     game.energy = game.inenrg = 5000.0
5733     game.shield = game.inshld = 2500.0
5734     game.shldchg = False
5735     game.shldup = False
5736     game.inlsr = 4.0
5737     game.lsupres = 4.0
5738     game.quadrant = randplace(GALSIZE)
5739     game.sector = randplace(QUADSIZE)
5740     game.torps = game.intorps = 10
5741     game.nprobes = int(3.0*Rand() + 2.0)        # Give them 2-4 of these
5742     game.warpfac = 5.0
5743     game.wfacsq = game.warpfac * game.warpfac
5744     for i in range(0, NDEVICES): 
5745         game.damage[i] = 0.0
5746     # Set up assorted game parameters
5747     invalidate(game.battle)
5748     game.state.date = game.indate = 100.0*int(31.0*Rand()+20.0)
5749     game.nkinks = game.nhelp = game.casual = game.abandoned = 0
5750     game.iscate = game.resting = game.imine = game.icrystl = game.icraft = False
5751     game.isatb = game.state.nplankl = 0
5752     game.state.starkl = game.state.basekl = 0
5753     game.iscraft = "onship"
5754     game.landed = False
5755     game.alive = True
5756     game.docfac = 0.25
5757     for i in range(1, GALSIZE+1):
5758         for j in range(1, GALSIZE+1):
5759             quad = game.state.galaxy[i][j]
5760             quad.charted = 0
5761             quad.planet = NOPLANET
5762             quad.romulans = 0
5763             quad.klingons = 0
5764             quad.starbase = False
5765             quad.supernova = False
5766             quad.status = "secure"
5767     # Initialize times for extraneous events
5768     schedule(FSNOVA, expran(0.5 * game.intime))
5769     schedule(FTBEAM, expran(1.5 * (game.intime / game.state.remcom)))
5770     schedule(FSNAP, 1.0 + Rand()) # Force an early snapshot
5771     schedule(FBATTAK, expran(0.3*game.intime))
5772     unschedule(FCDBAS)
5773     if game.state.nscrem:
5774         schedule(FSCMOVE, 0.2777)
5775     else:
5776         unschedule(FSCMOVE)
5777     unschedule(FSCDBAS)
5778     unschedule(FDSPROB)
5779     if (game.options & OPTION_WORLDS) and game.skill >= SKILL_GOOD:
5780         schedule(FDISTR, expran(1.0 + game.intime))
5781     else:
5782         unschedule(FDISTR)
5783     unschedule(FENSLV)
5784     unschedule(FREPRO)
5785     # Starchart is functional but we've never seen it
5786     game.lastchart = FOREVER
5787     # Put stars in the galaxy
5788     game.instar = 0
5789     for i in range(1, GALSIZE+1):
5790         for j in range(1, GALSIZE+1):
5791             k = Rand()*9.0 + 1.0
5792             game.instar += k
5793             game.state.galaxy[i][j].stars = k
5794     # Locate star bases in galaxy
5795     for i in range(1, game.inbase+1):
5796         while True:
5797             while True:
5798                 w = randplace(GALSIZE)
5799                 if not game.state.galaxy[w.x][w.y].starbase:
5800                     break
5801             contflag = False
5802             # C version: for (j = i-1; j > 0; j--)
5803             # so it did them in the opposite order.
5804             for j in range(i):
5805                 # Improved placement algorithm to spread out bases 
5806                 distq = w.distance(baseq[j])
5807                 if distq < 6.0*(BASEMAX+1-game.inbase) and Rand() < 0.75:
5808                     contflag = True
5809                     if idebug:
5810                         prout("=== Abandoning base #%d at %s" % (i, w))
5811                     break
5812                 elif distq < 6.0 * (BASEMAX+1-game.inbase):
5813                     if idebug:
5814                         prout("=== Saving base #%d, close to #%d" % (i, j))
5815             if not contflag:
5816                 break
5817         game.state.baseq[i] = w
5818         game.state.galaxy[w.x][w.y].starbase = True
5819         game.state.chart[w.x][w.y].starbase = True
5820     # Position ordinary Klingon Battle Cruisers
5821     krem = game.inkling
5822     klumper = 0.25*game.skill*(9.0-game.length)+1.0
5823     if klumper > MAXKLQUAD: 
5824         klumper = MAXKLQUAD
5825     while True:
5826         r = Rand()
5827         klump = (1.0 - r*r)*klumper
5828         if klump > krem:
5829             klump = krem
5830         krem -= klump
5831         while True:
5832             w = randplace(GALSIZE)
5833             if not game.state.galaxy[w.x][w.y].supernova and \
5834                game.state.galaxy[w.x][w.y].klingons + klump <= MAXKLQUAD:
5835                 break
5836         game.state.galaxy[w.x][w.y].klingons += klump
5837         if krem <= 0:
5838             break
5839     # Position Klingon Commander Ships
5840     for i in range(1, game.incom+1):
5841         while True:
5842             w = randplace(GALSIZE)
5843             if (game.state.galaxy[w.x][w.y].klingons or Rand()>=0.75) and \
5844                    not game.state.galaxy[w.x][w.y].supernova and \
5845                    game.state.galaxy[w.x][w.y].klingons <= MAXKLQUAD-1 and \
5846                    not w in game.state.kcmdr[:i]:
5847                 break
5848         game.state.galaxy[w.x][w.y].klingons += 1
5849         game.state.kcmdr[i] = w
5850     # Locate planets in galaxy
5851     for i in range(game.inplan):
5852         while True:
5853             w = randplace(GALSIZE) 
5854             if game.state.galaxy[w.x][w.y].planet == NOPLANET:
5855                 break
5856         new = planet()
5857         new.w = w
5858         new.crystals = "absent"
5859         if (game.options & OPTION_WORLDS) and i < NINHAB:
5860             new.pclass = "M"    # All inhabited planets are class M
5861             new.crystals = "absent"
5862             new.known = "known"
5863             new.name = systnames[i]
5864             new.inhabited = True
5865         else:
5866             new.pclass = ("M", "N", "O")[Rand()*3.0]
5867             if Rand()*1.5:              # 1 in 3 chance of crystals
5868                 new.crystals = "present"
5869             new.known = "unknown"
5870             new.inhabited = False
5871         game.state.galaxy[w.x][w.y].planet = new
5872         game.state.plnets.append(new)
5873     # Locate Romulans
5874     for i in range(1, game.state.nromrem+1):
5875         w = randplace(GALSIZE)
5876         game.state.galaxy[w.x][w.y].romulans += 1
5877     # Locate the Super Commander
5878     if game.state.nscrem > 0:
5879         while True:
5880             w = randplace(GALSIZE)
5881             if not game.state.galaxy[w.x][w.y].supernova and game.state.galaxy[w.x][w.y].klingons <= MXKLQUAD:
5882                 break
5883         game.state.kscmdr = w
5884         game.state.galaxy[w.x][w.y].klingons += 1
5885     # Place thing (in tournament game, thingx == -1, don't want one!)
5886     if thing.x != -1:
5887         thing = randplace(GALSIZE)
5888     else:
5889         invalidate(thing)
5890     skip(2)
5891     game.state.snap = False
5892     if game.skill == SKILL_NOVICE:
5893         prout(_("It is stardate %d. The Federation is being attacked by") % int(game.state.date))
5894         prout(_("a deadly Klingon invasion force. As captain of the United"))
5895         prout(_("Starship U.S.S. Enterprise, it is your mission to seek out"))
5896         prout(_("and destroy this invasion force of %d battle cruisers.") % ((game.inkling + game.incom + game.inscom)))
5897         prout(_("You have an initial allotment of %d stardates to complete") % int(game.intime))
5898         prout(_("your mission.  As you proceed you may be given more time."))
5899         skip(1)
5900         prout(_("You will have %d supporting starbases.") % (game.inbase))
5901         proutn(_("Starbase locations-  "))
5902     else:
5903         prout(_("Stardate %d.") % int(game.state.date))
5904         skip(1)
5905         prout(_("%d Klingons.") % (game.inkling + game.incom + game.inscom))
5906         prout(_("An unknown number of Romulans."))
5907         if game.state.nscrem:
5908             prout(_("And one (GULP) Super-Commander."))
5909         prout(_("%d stardates.") % int(game.intime))
5910         proutn(_("%d starbases in ") % game.inbase)
5911     for i in range(1, game.inbase+1):
5912         proutn(`game.state.baseq[i]`)
5913         proutn("  ")
5914     skip(2)
5915     proutn(_("The Enterprise is currently in Quadrant %s") % game.quadrant)
5916     proutn(_(" Sector %s") % game.sector)
5917     skip(2)
5918     prout(_("Good Luck!"))
5919     if game.state.nscrem:
5920         prout(_("  YOU'LL NEED IT."))
5921     waitfor()
5922     newqad(False)
5923     if game.nenhere - iqhere-game.ithere:
5924         game.shldup = True
5925     if game.neutz:      # bad luck to start in a Romulan Neutral Zone
5926         attack(False)
5927
5928 def choose(needprompt):
5929     # choose your game type 
5930     while True:
5931         game.tourn = 0
5932         game.thawed = False
5933         game.skill = SKILL_NONE
5934         game.length = 0
5935         if needprompt: # Can start with command line options 
5936             proutn(_("Would you like a regular, tournament, or saved game? "))
5937         scan()
5938         if len(citem)==0: # Try again
5939             continue
5940         if isit("tournament"):
5941             while scan() == IHEOL:
5942                 proutn(_("Type in tournament number-"))
5943             if aaitem == 0:
5944                 chew()
5945                 continue # We don't want a blank entry
5946             game.tourn = int(aaitem)
5947             thing.x = -1
5948             random.seed(aaitem)
5949             break
5950         if isit("saved") or isit("frozen"):
5951             if thaw():
5952                 continue
5953             chew()
5954             if game.passwd == None:
5955                 continue
5956             if not game.alldone:
5957                 game.thawed = True # No plaque if not finished
5958             report()
5959             waitfor()
5960             return True
5961         if isit("regular"):
5962             break
5963         proutn(_("What is \""))
5964         proutn(citem)
5965         prout("\"?")
5966         chew()
5967     while game.length==0 or game.skill==SKILL_NONE:
5968         if scan() == IHALPHA:
5969             if isit("short"):
5970                 game.length = 1
5971             elif isit("medium"):
5972                 game.length = 2
5973             elif isit("long"):
5974                 game.length = 4
5975             elif isit("novice"):
5976                 game.skill = SKILL_NOVICE
5977             elif isit("fair"):
5978                 game.skill = SKILL_FAIR
5979             elif isit("good"):
5980                 game.skill = SKILL_GOOD
5981             elif isit("expert"):
5982                 game.skill = SKILL_EXPERT
5983             elif isit("emeritus"):
5984                 game.skill = SKILL_EMERITUS
5985             else:
5986                 proutn(_("What is \""))
5987                 proutn(citem)
5988                 prout("\"?")
5989         else:
5990             chew()
5991             if game.length==0:
5992                 proutn(_("Would you like a Short, Medium, or Long game? "))
5993             elif game.skill == SKILL_NONE:
5994                 proutn(_("Are you a Novice, Fair, Good, Expert, or Emeritus player? "))
5995     # Choose game options -- added by ESR for SST2K
5996     if scan() != IHALPHA:
5997         chew()
5998         proutn(_("Choose your game style (or just press enter): "))
5999         scan()
6000     if isit("plain"):
6001         # Approximates the UT FORTRAN version.
6002         game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
6003         game.options |= OPTION_PLAIN
6004     elif isit("almy"):
6005         # Approximates Tom Almy's version.
6006         game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS)
6007         game.options |= OPTION_ALMY
6008     elif isit("fancy"):
6009         pass
6010     elif len(citem):
6011         proutn(_("What is \"%s\"?") % citem)
6012     setpassword()
6013     if game.passwd == "debug":
6014         idebug = True
6015         fputs("=== Debug mode enabled\n", sys.stdout)
6016
6017     # Use parameters to generate initial values of things
6018     game.damfac = 0.5 * game.skill
6019     game.state.rembase = 2.0 + Rand()*(BASEMAX-2.0)
6020     game.inbase = game.state.rembase
6021     game.inplan = 0
6022     if game.options & OPTION_PLANETS:
6023         game.inplan += (MAXUNINHAB/2) + (MAXUNINHAB/2+1)*Rand()
6024     if game.options & OPTION_WORLDS:
6025         game.inplan += NINHAB
6026     game.state.nromrem = game.inrom = (2.0+Rand())*game.skill
6027     game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR)
6028     game.state.remtime = 7.0 * game.length
6029     game.intime = game.state.remtime
6030     game.state.remkl = game.inkling = 2.0*game.intime*((game.skill+1 - 2*Rand())*game.skill*0.1+.15)
6031     game.incom = game.skill + 0.0625*game.inkling*Rand()
6032     game.state.remcom = min(10, game.incom)
6033     game.incom = game.state.remcom
6034     game.state.remres = (game.inkling+4*game.incom)*game.intime
6035     game.inresor = game.state.remres
6036     if game.inkling > 50:
6037         game.state.rembase += 1
6038         game.inbase = game.state.rembase
6039     return False
6040
6041 def dropin(iquad):
6042     # drop a feature on a random dot in the current quadrant 
6043     w = coord()
6044     while True:
6045         w = randplace(QUADSIZE)
6046         if game.quad[w.x][w.y] == IHDOT:
6047             break
6048     game.quad[w.x][w.y] = iquad
6049     return w
6050
6051 def newcnd():
6052     # update our alert status 
6053     game.condition = "green"
6054     if game.energy < 1000.0:
6055         game.condition = "yellow"
6056     if game.state.galaxy[game.quadrant.x][game.quadrant.y].klingons or game.state.galaxy[game.quadrant.x][game.quadrant.y].romulans:
6057         game.condition = "red"
6058     if not game.alive:
6059         game.condition="dead"
6060
6061 def newkling(i):
6062     # drop new Klingon into current quadrant 
6063     pi = dropin(IHK)
6064     game.ks[i] = pi
6065     game.kdist[i] = game.kavgd[i] = distance(game.sector, pi)
6066     game.kpower[i] = Rand()*150.0 +300.0 +25.0*game.skill
6067     return pi
6068
6069 def newqad(shutup):
6070     # set up a new state of quadrant, for when we enter or re-enter it 
6071     w = coord()
6072     game.justin = True
6073     invalidate(game.base)
6074     game.klhere = 0
6075     game.comhere = False
6076     invalidate(game.plnet)
6077     game.ishere = False
6078     game.irhere = 0
6079     game.iplnet = 0
6080     game.nenhere = 0
6081     game.neutz = False
6082     game.inorbit = False
6083     game.landed = False
6084     game.ientesc = False
6085     game.ithere = False
6086     iqhere = False
6087     iqengry = False
6088     game.iseenit = False
6089     if game.iscate:
6090         # Attempt to escape Super-commander, so tbeam back!
6091         game.iscate = False
6092         game.ientesc = True
6093     # Clear quadrant
6094     for i in range(1, QUADSIZE+1):
6095         for j in range(1, QUADSIZE+1):
6096             game.quad[i][j] = IHDOT
6097     q = game.state.galaxy[game.quadrant.x][game.quadrant.y]
6098     # cope with supernova
6099     if q.supernova:
6100         return
6101     game.klhere = q.klingons
6102     game.irhere = q.romulans
6103     game.nenhere = game.klhere + game.irhere
6104
6105     # Position Starship
6106     game.quad[game.sector.x][game.sector.y] = game.ship
6107
6108     if q.klingons:
6109         w.x = w.y = 0   # quiet a gcc warning 
6110         # Position ordinary Klingons
6111         for i in range(1, game.klhere+1):
6112             w = newkling(i)
6113         # If we need a commander, promote a Klingon
6114         for i in range(1, game.state.remcom+1):
6115             if same(game.state.kcmdr[i], game.quadrant):
6116                 break
6117                         
6118         if i <= game.state.remcom:
6119             game.quad[w.x][w.y] = IHC
6120             game.kpower[game.klhere] = 950.0+400.0*Rand()+50.0*game.skill
6121             game.comhere = True
6122
6123         # If we need a super-commander, promote a Klingon
6124         if same(game.quadrant, game.state.kscmdr):
6125             game.quad[game.ks[1].x][game.ks[1].y] = IHS
6126             game.kpower[1] = 1175.0 + 400.0*Rand() + 125.0*game.skill
6127             game.iscate = (game.state.remkl > 1)
6128             game.ishere = True
6129     # Put in Romulans if needed
6130     for i in range(game.klhere+1, game.nenhere+1):
6131         w = dropin(IHR)
6132         game.ks[i] = w
6133         game.kdist[i] = game.kavgd[i] = distance(game.sector, w)
6134         game.kpower[i] = Rand()*400.0 + 450.0 + 50.0*game.skill
6135     # If quadrant needs a starbase, put it in
6136     if q.starbase:
6137         game.base = dropin(IHB)
6138         
6139     # If quadrant needs a planet, put it in
6140     if q.planet != NOPLANET:
6141         game.iplnet = q.planet
6142         if game.state.planets[q.planet].inhabited == UNINHABITED:
6143             game.plnet = dropin(IHP)
6144         else:
6145             game.plnet = dropin(IHW)
6146     # Check for condition
6147     newcnd()
6148     # And finally the stars
6149     for i in range(1, q.stars+1): 
6150         dropin(IHSTAR)
6151
6152     # Check for RNZ
6153     if game.irhere > 0 and game.klhere == 0:
6154         game.neutz = True
6155         if not damaged(DRADIO):
6156             skip(1)
6157             prout(_("LT. Uhura- \"Captain, an urgent message."))
6158             prout(_("  I'll put it on audio.\"  CLICK"))
6159             skip(1)
6160             prout(_("INTRUDER! YOU HAVE VIOLATED THE ROMULAN NEUTRAL ZONE."))
6161             prout(_("LEAVE AT ONCE, OR YOU WILL BE DESTROYED!"))
6162
6163     if shutup==0:
6164         # Put in THING if needed
6165         if same(thing, game.quadrant):
6166             w = dropin(IHQUEST)
6167             thing = randplace(GALSIZE)
6168             game.nenhere += 1
6169             iqhere = True
6170             game.ks[game.nenhere] = w
6171             game.kdist[game.nenhere] = game.kavgd[game.nenhere] = \
6172                 distance(game.sector, w)
6173             game.kpower[game.nenhere] = Rand()*6000.0 +500.0 +250.0*game.skill
6174             if not damaged(DSRSENS):
6175                 skip(1)
6176                 prout(_("Mr. Spock- \"Captain, this is most unusual."))
6177                 prout(_("    Please examine your short-range scan.\""))
6178
6179     # Decide if quadrant needs a Tholian; lighten up if skill is low 
6180     if game.options & OPTION_THOLIAN:
6181         if (game.skill < SKILL_GOOD and Rand() <= 0.02) or \
6182             (game.skill == SKILL_GOOD and Rand() <= 0.05) or \
6183             (game.skill > SKILL_GOOD and Rand() <= 0.08):
6184             while True:
6185                 game.tholian.x = random.choice((1, QUADSIZE))
6186                 game.tholian.y = random.choice((1, QUADSIZE))
6187                 if game.quad[game.tholian.x][game.tholian.y] == IHDOT:
6188                     break
6189             game.quad[game.tholian.x][game.tholian.y] = IHT
6190             game.ithere = True
6191             game.nenhere += 1
6192             game.ks[game.nenhere] = game.tholian
6193             game.kdist[game.nenhere] = game.kavgd[game.nenhere] = \
6194                 distance(game.sector, game.tholian)
6195             game.kpower[game.nenhere] = Rand()*400.0 +100.0 +25.0*game.skill
6196             # Reserve unoccupied corners 
6197             if game.quad[1][1]==IHDOT:
6198                 game.quad[1][1] = 'X'
6199             if game.quad[1][QUADSIZE]==IHDOT:
6200                 game.quad[1][QUADSIZE] = 'X'
6201             if game.quad[QUADSIZE][1]==IHDOT:
6202                 game.quad[QUADSIZE][1] = 'X'
6203             if game.quad[QUADSIZE][QUADSIZE]==IHDOT:
6204                 game.quad[QUADSIZE][QUADSIZE] = 'X'
6205     sortklings()
6206
6207     # Put in a few black holes
6208     for i in range(1, 3+1):
6209         if Rand() > 0.5: 
6210             dropin(IHBLANK)
6211
6212     # Take out X's in corners if Tholian present
6213     if game.ithere:
6214         if game.quad[1][1]=='X':
6215             game.quad[1][1] = IHDOT
6216         if game.quad[1][QUADSIZE]=='X':
6217             game.quad[1][QUADSIZE] = IHDOT
6218         if game.quad[QUADSIZE][1]=='X':
6219             game.quad[QUADSIZE][1] = IHDOT
6220         if game.quad[QUADSIZE][QUADSIZE]=='X':
6221             game.quad[QUADSIZE][QUADSIZE] = IHDOT
6222
6223 def sortklings():
6224     # sort Klingons by distance from us 
6225     # The author liked bubble sort. So we will use it. :-(
6226     if game.nenhere-iqhere-game.ithere < 2:
6227         return
6228     while True:
6229         sw = False
6230         for j in range(1, game.nenhere):
6231             if game.kdist[j] > game.kdist[j+1]:
6232                 sw = True
6233                 t = game.kdist[j]
6234                 game.kdist[j] = game.kdist[j+1]
6235                 game.kdist[j+1] = t
6236                 t = game.kavgd[j]
6237                 game.kavgd[j] = game.kavgd[j+1]
6238                 game.kavgd[j+1] = t
6239                 k = game.ks[j].x
6240                 game.ks[j].x = game.ks[j+1].x
6241                 game.ks[j+1].x = k
6242                 k = game.ks[j].y
6243                 game.ks[j].y = game.ks[j+1].y
6244                 game.ks[j+1].y = k
6245                 t = game.kpower[j]
6246                 game.kpower[j] = game.kpower[j+1]
6247                 game.kpower[j+1] = t
6248         if not sw:
6249             break
6250
6251 def setpassword():
6252     # set the self-destruct password 
6253     if game.options & OPTION_PLAIN:
6254         while True:
6255             chew()
6256             proutn(_("Please type in a secret password- "))
6257             scan()
6258             game.passwd = citem
6259             if game.passwd != None:
6260                 break
6261     else:
6262         game.passwd = ""
6263         for i in range(3):
6264             game.passwd[i] += chr(97+int(Rand()*25))