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