2 sst.py =-- Super Star Trek in Python
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
9 import os, sys, math, curses, time, atexit, readline
11 SSTDOC = "/usr/share/doc/sst/sst.doc"
14 def _(str): return str
18 NINHAB = (GALSIZE * GALSIZE / 2)
20 PLNETMAX = (NINHAB + MAXUNINHAB)
22 BASEMAX = (GALSIZE * GALSIZE / 12)
25 FULLCREW = 428 # BSD Trek was 387, that's wrong
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)
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)
38 def __init(self, x=None, y=None):
42 self.x = self.y = None
44 return self.x != None and self.y != None
45 def __eq__(self, other):
46 return self.x == other.y and self.x == other.y
47 def __add__(self, other):
48 return coord(self.x+self.x, self.y+self.y)
49 def __sub__(self, other):
50 return coord(self.x-self.x, self.y-self.y)
51 def distance(self, other):
52 return math.sqrt((self.x - other.x)**2 + (self.y - other.y)**2)
54 return coord(self.x / abs(x), self.y / abs(y));
58 return "%d - %d" % (self.x, self.y)
62 self.name = None # string-valued if inhabited
63 self.w = coord() # quadrant located
64 self.pclass = None # could be ""M", "N", "O", or "destroyed"
65 self.crystals = None # could be "mined", "present", "absent"
66 self.known = None # could be "unknown", "known", "shuttle_down"
68 # How to represent features
98 self.status = None # Could be "secure", "distressed", "enslaved"
108 self.snap = False # snapshot taken
109 self.crew = None # crew complement
110 self.remkl = None # remaining klingons
111 self.remcom = None # remaining commanders
112 self.nscrem = None # remaining super commanders
113 self.rembase = None # remaining bases
114 self.starkl = None # destroyed stars
115 self.basekl = None # destroyed bases
116 self.nromrem = None # Romulans remaining
117 self.nplankl = None # destroyed uninhabited planets
118 self.nworldkl = None # destroyed inhabited planets
119 self.planets = [] # Planet information
120 for i in range(PLNETMAX):
121 self.planets.append(planet())
122 self.date = None # stardate
123 self.remres = None # remaining resources
124 self.remtime = None # remaining time
125 self.baseq = [] # Base quadrant coordinates
126 for i in range(BASEMAX+1):
127 self.baseq.append(coord())
128 self.kcmdr = [] # Commander quadrant coordinates
129 for i in range(QUADSIZE+1):
130 self.kcmdr.append(coord())
131 self.kscmdr = coord() # Supercommander quadrant coordinates
132 self.galaxy = [] # The Galaxy (subscript 0 not used)
133 for i in range(GALSIZE+1):
134 self.chart.append([])
135 for j in range(GALSIZE+1):
136 self.galaxy[i].append(quadrant())
137 self.chart = [] # the starchart (subscript 0 not used)
138 for i in range(GALSIZE+1):
139 self.chart.append([])
140 for j in range(GALSIZE+1):
141 self.chart[i].append(page())
145 self.date = None # A real number
146 self.quadrant = None # A coord structure
149 OPTION_ALL = 0xffffffff
150 OPTION_TTY = 0x00000001 # old interface
151 OPTION_CURSES = 0x00000002 # new interface
152 OPTION_IOMODES = 0x00000003 # cover both interfaces
153 OPTION_PLANETS = 0x00000004 # planets and mining
154 OPTION_THOLIAN = 0x00000008 # Tholians and their webs
155 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back
156 OPTION_PROBE = 0x00000020 # deep-space probes
157 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
158 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise
159 OPTION_MVBADDY = 0x00000100 # more enemies can move
160 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you
161 OPTION_BASE = 0x00000400 # bases have good shields
162 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds
163 OPTION_PLAIN = 0x01000000 # user chose plain game
164 OPTION_ALMY = 0x02000000 # user chose Almy variant
183 NDEVICES= 16 # Number of devices
192 def damaged(dev): return (game.damage[dev] != 0.0)
194 # Define future events
195 FSPY = 0 # Spy event happens always (no future[] entry)
196 # can cause SC to tractor beam Enterprise
197 FSNOVA = 1 # Supernova
198 FTBEAM = 2 # Commander tractor beams Enterprise
199 FSNAP = 3 # Snapshot for time warp
200 FBATTAK = 4 # Commander attacks base
201 FCDBAS = 5 # Commander destroys base
202 FSCMOVE = 6 # Supercommander moves (might attack base)
203 FSCDBAS = 7 # Supercommander destroys base
204 FDSPROB = 8 # Move deep space probe
205 FDISTR = 9 # Emit distress call from an inhabited world
206 FENSLV = 10 # Inhabited word is enslaved */
207 FREPRO = 11 # Klingons build a ship in an enslaved system
211 # abstract out the event handling -- underlying data structures will change
212 # when we implement stateful events
214 def findevent(evtype): return game.future[evtype]
218 self.options = None # Game options
219 self.state = None # A snapshot structure
220 self.snapsht = None # Last snapshot taken for time-travel purposes
221 self.quad = [[IHDOT * (QUADSIZE+1)] * (QUADSIZE+1)] # contents of our quadrant
222 self.kpower = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)] # enemy energy levels
223 self.kdist = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)] # enemy distances
224 self.kavgd = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)] # average distances
225 self.damage = [0] * NDEVICES # damage encountered
226 self.future = [0.0] * NEVENTS # future events
227 for i in range(NEVENTS):
228 self.future.append(event())
229 self.passwd = None; # Self Destruct password
230 self.ks = [[None * (QUADSIZE+1)] * (QUADSIZE+1)] # enemy sector locations
231 self.quadrant = None # where we are in the large
232 self.sector = None # where we are in the small
233 self.tholian = None # coordinates of Tholian
234 self.base = None # position of base in current quadrant
235 self.battle = None # base coordinates being attacked
236 self.plnet = None # location of planet in quadrant
237 self.probec = None # current probe quadrant
238 self.gamewon = False # Finished!
239 self.ididit = False # action taken -- allows enemy to attack
240 self.alive = False # we are alive (not killed)
241 self.justin = False # just entered quadrant
242 self.shldup = False # shields are up
243 self.shldchg = False # shield is changing (affects efficiency)
244 self.comhere = False # commander here
245 self.ishere = False # super-commander in quadrant
246 self.iscate = False # super commander is here
247 self.ientesc = False # attempted escape from supercommander
248 self.ithere = False # Tholian is here
249 self.resting = False # rest time
250 self.icraft = False # Kirk in Galileo
251 self.landed = False # party on planet (true), on ship (false)
252 self.alldone = False # game is now finished
253 self.neutz = False # Romulan Neutral Zone
254 self.isarmed = False # probe is armed
255 self.inorbit = False # orbiting a planet
256 self.imine = False # mining
257 self.icrystl = False # dilithium crystals aboard
258 self.iseenit = False # seen base attack report
259 self.thawed = False # thawed game
260 self.condition = None # "green", "yellow", "red", "docked", "dead"
261 self.iscraft = None # "onship", "offship", "removed"
262 self.skill = None # Player skill level
263 self.inkling = 0 # initial number of klingons
264 self.inbase = 0 # initial number of bases
265 self.incom = 0 # initial number of commanders
266 self.inscom = 0 # initial number of commanders
267 self.inrom = 0 # initial number of commanders
268 self.instar = 0 # initial stars
269 self.intorps = 0 # initial/max torpedoes
270 self.torps = 0 # number of torpedoes
271 self.ship = 0 # ship type -- 'E' is Enterprise
272 self.abandoned = 0 # count of crew abandoned in space
273 self.length = 0 # length of game
274 self.klhere = 0 # klingons here
275 self.casual = 0 # causalties
276 self.nhelp = 0 # calls for help
277 self.nkinks = 0 # count of energy-barrier crossings
278 self.iplnet = 0 # planet # in quadrant
279 self.inplan = 0 # initial planets
280 self.nenhere = 0 # number of enemies in quadrant
281 self.irhere = 0 # Romulans in quadrant
282 self.isatb = 0 # =1 if super commander is attacking base
283 self.tourn = 0 # tournament number
284 self.proben = 0 # number of moves for probe
285 self.nprobes = 0 # number of probes available
286 self.inresor = 0.0 # initial resources
287 self.intime = 0.0 # initial time
288 self.inenrg = 0.0 # initial/max energy
289 self.inshld = 0.0 # initial/max shield
290 self.inlsr = 0.0 # initial life support resources
291 self.indate = 0.0 # initial date
292 self.energy = 0.0 # energy level
293 self.shield = 0.0 # shield level
294 self.warpfac = 0.0 # warp speed
295 self.wfacsq = 0.0 # squared warp factor
296 self.lsupres = 0.0 # life support reserves
297 self.dist = 0.0 # movement distance
298 self.direc = 0.0 # movement direction
299 self.optime = 0.0 # time taken by current operation
300 self.docfac = 0.0 # repair factor when docking (constant?)
301 self.damfac = 0.0 # damage factor
302 self.lastchart = 0.0 # time star chart was last updated
303 self.cryprob = 0.0 # probability that crystal will work
304 self.probex = 0.0 # location of probe
306 self.probeinx = 0.0 # probe x,y increment
307 self.probeiny = 0.0 #
308 self.height = 0.0 # height of orbit around planet
310 # Stas thinks this should be (C expression):
311 # game.state.remkl + game.state.remcom > 0 ?
312 # game.state.remres/(game.state.remkl + 4*game.state.remcom) : 99
313 # He says the existing expression is prone to divide-by-zero errors
314 # after killing the last klingon when score is shown -- perhaps also
315 # if the only remaining klingon is SCOM.
316 game.state.remtime = game.state.remres/(game.state.remkl + 4*game.state.remcom)
317 # From enumerated type 'feature'
338 # From enumerated type 'FINTYPE'
362 # From enumerated type 'COLORS'
381 # Code from ai.c begins here
383 def tryexit(look, ienm, loccom, irun):
384 # a bad guy attempts to bug out
386 iq.x = game.quadrant.x+(look.x+(QUADSIZE-1))/QUADSIZE - 1
387 iq.y = game.quadrant.y+(look.y+(QUADSIZE-1))/QUADSIZE - 1
388 if not VALID_QUADRANT(iq.x,iq.y) or \
389 game.state.galaxy[iq.x][iq.y].supernova or \
390 game.state.galaxy[iq.x][iq.y].klingons > MAXKLQUAD-1:
391 return False; # no can do -- neg energy, supernovae, or >MAXKLQUAD-1 Klingons
393 return False; # Romulans cannot escape!
395 # avoid intruding on another commander's territory
397 for n in range(1, game.state.remcom+1):
398 if same(game.state.kcmdr[n],iq):
400 # refuse to leave if currently attacking starbase
401 if same(game.battle, game.quadrant):
403 # don't leave if over 1000 units of energy
404 if game.kpower[loccom] > 1000.0:
406 # print escape message and move out of quadrant.
407 # we know this if either short or long range sensors are working
408 if not damaged(DSRSENS) or not damaged(DLRSENS) or \
409 game.condition == docked:
410 crmena(True, ienm, "sector", game.ks[loccom])
411 prout(_(" escapes to Quadrant %s (and regains strength).") % q)
412 # handle local matters related to escape
413 game.quad[game.ks[loccom].x][game.ks[loccom].y] = IHDOT
414 game.ks[loccom] = game.ks[game.nenhere]
415 game.kavgd[loccom] = game.kavgd[game.nenhere]
416 game.kpower[loccom] = game.kpower[game.nenhere]
417 game.kdist[loccom] = game.kdist[game.nenhere]
420 if game.condition != docked:
422 # Handle global matters related to escape
423 game.state.galaxy[game.quadrant.x][game.quadrant.y].klingons -= 1
424 game.state.galaxy[iq.x][iq.y].klingons += 1
430 schedule(FSCMOVE, 0.2777)
434 for n in range(1, game.state.remcom+1):
435 if same(game.state.kcmdr[n], game.quadrant):
436 game.state.kcmdr[n]=iq
439 return True; # success
442 # The bad-guy movement algorithm:
444 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
445 # If both are operating full strength, force is 1000. If both are damaged,
446 # force is -1000. Having shields down subtracts an additional 1000.
448 # 2. Enemy has forces equal to the energy of the attacker plus
449 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
450 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
452 # Attacker Initial energy levels (nominal):
453 # Klingon Romulan Commander Super-Commander
454 # Novice 400 700 1200
456 # Good 450 800 1300 1750
457 # Expert 475 850 1350 1875
458 # Emeritus 500 900 1400 2000
459 # VARIANCE 75 200 200 200
461 # Enemy vessels only move prior to their attack. In Novice - Good games
462 # only commanders move. In Expert games, all enemy vessels move if there
463 # is a commander present. In Emeritus games all enemy vessels move.
465 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
466 # forces are 1000 greater than Enterprise.
468 # Agressive action on average cuts the distance between the ship and
469 # the enemy to 1/4 the original.
471 # 4. At lower energy advantage, movement units are proportional to the
472 # advantage with a 650 advantage being to hold ground, 800 to move forward
473 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
475 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
476 # retreat, especially at high skill levels.
478 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
481 def movebaddy(com, loccom, ienm):
482 # tactical movement for the bad guys
483 next = coord(); look = coord()
485 # This should probably be just game.comhere + game.ishere
486 if game.skill >= SKILL_EXPERT:
487 nbaddys = ((game.comhere*2 + game.ishere*2+game.klhere*1.23+game.irhere*1.5)/2.0)
489 nbaddys = game.comhere + game.ishere
491 dist1 = game.kdist[loccom]
492 mdist = int(dist1 + 0.5); # Nearest integer distance
494 # If SC, check with spy to see if should hi-tail it
496 (game.kpower[loccom] <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
500 # decide whether to advance, retreat, or hold position
501 forces = game.kpower[loccom]+100.0*game.nenhere+400*(nbaddys-1)
503 forces += 1000; # Good for enemy if shield is down!
504 if not damaged(DPHASER) or not damaged(DPHOTON):
505 if damaged(DPHASER): # phasers damaged
508 forces -= 0.2*(game.energy - 2500.0)
509 if damaged(DPHOTON): # photon torpedoes damaged
512 forces -= 50.0*game.torps
514 # phasers and photon tubes both out!
517 if forces <= 1000.0 and game.condition != "docked": # Typical situation
518 motion = ((forces+200.0*Rand())/150.0) - 5.0
520 if forces > 1000.0: # Very strong -- move in for kill
521 motion = (1.0-square(Rand()))*dist1 + 1.0
522 if game.condition=="docked" and (game.options & OPTION_BASE): # protected by base -- back off !
523 motion -= game.skill*(2.0-square(Rand()))
525 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
526 # don't move if no motion
529 # Limit motion according to skill
530 if abs(motion) > game.skill:
535 # calculate preferred number of steps
540 if motion > 0 and nsteps > mdist:
541 nsteps = mdist; # don't overshoot
542 if nsteps > QUADSIZE:
543 nsteps = QUADSIZE; # This shouldn't be necessary
545 nsteps = 1; # This shouldn't be necessary
547 proutn("NSTEPS = %d:" % nsteps)
548 # Compute preferred values of delta X and Y
549 mx = game.sector.x - com.x
550 my = game.sector.y - com.y
551 if 2.0 * abs(mx) < abs(my):
553 if 2.0 * abs(my) < abs(game.sector.x-com.x):
567 for ll in range(nsteps):
569 proutn(" %d" % (ll+1))
570 # Check if preferred position available
582 attempts = 0; # Settle mysterious hang problem
583 while attempts < 20 and not success:
585 if look.x < 1 or look.x > QUADSIZE:
586 if motion < 0 and tryexit(look, ienm, loccom, irun):
588 if krawlx == mx or my == 0:
590 look.x = next.x + krawlx
592 elif look.y < 1 or look.y > QUADSIZE:
593 if motion < 0 and tryexit(look, ienm, loccom, irun):
595 if krawly == my or mx == 0:
597 look.y = next.y + krawly
599 elif (game.options & OPTION_RAMMING) and game.quad[look.x][look.y] != IHDOT:
600 # See if we should ram ship
601 if game.quad[look.x][look.y] == game.ship and \
602 (ienm == IHC or ienm == IHS):
605 if krawlx != mx and my != 0:
606 look.x = next.x + krawlx
608 elif krawly != my and mx != 0:
609 look.y = next.y + krawly
612 break; # we have failed
624 # Put commander in place within same quadrant
625 game.quad[com.x][com.y] = IHDOT
626 game.quad[next.x][next.y] = ienm
627 if not same(next, com):
629 game.ks[loccom] = next
630 game.kdist[loccom] = game.kavgd[loccom] = distance(game.sector, next)
631 if not damaged(DSRSENS) or game.condition == docked:
634 proutn(_(" from Sector %s") % com)
635 if game.kdist[loccom] < dist1:
636 proutn(_(" advances to "))
638 proutn(_(" retreats to "))
639 prout("Sector %s." % next)
642 # Klingon tactical movement
645 # Figure out which Klingon is the commander (or Supercommander)
648 for i in range(1, game.nenhere+1):
650 if game.quad[w.x][w.y] == IHC:
654 for i in range(1, game.nenhere+1):
656 if game.quad[w.x][w.y] == IHS:
659 # If skill level is high, move other Klingons and Romulans too!
660 # Move these last so they can base their actions on what the
662 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
663 for i in range(1, game.nenhere+1):
665 if game.quad[w.x][w.y] == IHK or game.quad[w.x][w.y] == IHR:
666 movebaddy(w, i, game.quad[w.x][w.y])
669 def movescom(iq, avoid):
670 # commander movement helper
671 if same(iq, game.quadrant) or not VALID_QUADRANT(iq.x, iq.y) or \
672 game.state.galaxy[iq.x][iq.y].supernova or \
673 game.state.galaxy[iq.x][iq.y].klingons > MAXKLQUAD-1:
676 # Avoid quadrants with bases if we want to avoid Enterprise
677 for i in range(1, game.state.rembase+1):
678 if same(game.state.baseq[i], iq):
680 if game.justin and not game.iscate:
683 game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].klingons -= 1
684 game.state.kscmdr = iq
685 game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].klingons += 1
687 # SC has scooted, Remove him from current quadrant
693 for i in range(1, game.nenhere+1):
694 if game.quad[game.ks[i].x][game.ks[i].y] == IHS:
696 game.quad[game.ks[i].x][game.ks[i].y] = IHDOT
697 game.ks[i] = game.ks[game.nenhere]
698 game.kdist[i] = game.kdist[game.nenhere]
699 game.kavgd[i] = game.kavgd[game.nenhere]
700 game.kpower[i] = game.kpower[game.nenhere]
703 if game.condition!=docked:
706 # check for a helpful planet
707 for i in range(game.inplan):
708 if same(game.state.planets[i].w, game.state.kscmdr) and \
709 game.state.planets[i].crystals == present:
711 game.state.planets[i].pclass = destroyed
712 game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].planet = NOPLANET
713 if not damaged(DRADIO) or game.condition == docked:
715 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
716 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
717 prout(_(" by the Super-commander.\""))
719 return False; # looks good!
721 def supercommander():
722 # move the Super Commander
723 iq = coord(); sc = coord(); ibq = coord(); idelta = coord()
726 prout("== SUPERCOMMANDER")
727 # Decide on being active or passive
728 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 \
729 (game.state.date-game.indate) < 3.0)
730 if not game.iscate and avoid:
731 # compute move away from Enterprise
732 idelta = game.state.kscmdr-game.quadrant
733 if math.sqrt(idelta.x*idelta.x+idelta.y*idelta.y) > 2.0:
735 idelta.x = game.state.kscmdr.y-game.quadrant.y
736 idelta.y = game.quadrant.x-game.state.kscmdr.x
738 # compute distances to starbases
739 if game.state.rembase <= 0:
743 sc = game.state.kscmdr
744 for i in range(1, game.state.rembase+1):
745 basetbl.append((i, distance(game.state.baseq[i], sc)))
746 if game.state.rembase > 1:
747 basetbl.sort(lambda x, y: cmp(x[1]. y[1]))
748 # look for nearest base without a commander, no Enterprise, and
749 # without too many Klingons, and not already under attack.
750 ifindit = iwhichb = 0
751 for i2 in range(1, game.state.rembase+1):
752 i = basetbl[i2][0]; # bug in original had it not finding nearest
753 ibq = game.state.baseq[i]
754 if same(ibq, game.quadrant) or same(ibq, game.battle) or \
755 game.state.galaxy[ibq.x][ibq.y].supernova or \
756 game.state.galaxy[ibq.x][ibq.y].klingons > MAXKLQUAD-1:
758 # if there is a commander, and no other base is appropriate,
759 # we will take the one with the commander
760 for j in range(1, game.state.remcom+1):
761 if same(ibq, game.state.kcmdr[j]) and ifindit!= 2:
765 if j > game.state.remcom: # no commander -- use this one
770 return; # Nothing suitable -- wait until next time
771 ibq = game.state.baseq[iwhichb]
772 # decide how to move toward base
773 idelta = ibq - game.state.kscmdr
774 # Maximum movement is 1 quadrant in either or both axes
775 idelta = idelta.sgn()
776 # try moving in both x and y directions
777 # there was what looked like a bug in the Almy C code here,
778 # but it might be this translation is just wrong.
779 iq = game.state.kscmdr + idelta
780 if movescom(iq, avoid):
781 # failed -- try some other maneuvers
782 if idelta.x==0 or idelta.y==0:
785 iq.y = game.state.kscmdr.y + 1
786 if movescom(iq, avoid):
787 iq.y = game.state.kscmdr.y - 1
790 iq.x = game.state.kscmdr.x + 1
791 if movescom(iq, avoid):
792 iq.x = game.state.kscmdr.x - 1
795 # try moving just in x or y
796 iq.y = game.state.kscmdr.y
797 if movescom(iq, avoid):
798 iq.y = game.state.kscmdr.y + idelta.y
799 iq.x = game.state.kscmdr.x
802 if game.state.rembase == 0:
805 for i in range(1, game.state.rembase+1):
806 ibq = game.state.baseq[i]
807 if same(ibq, game.state.kscmdr) and same(game.state.kscmdr, game.battle):
810 return; # no, don't attack base!
813 schedule(FSCDBAS, 1.0 +2.0*Rand())
814 if is_scheduled(FCDBAS):
815 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
816 if damaged(DRADIO) and game.condition != docked:
820 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
822 prout(_(" reports that it is under attack from the Klingon Super-commander."))
823 proutn(_(" It can survive until stardate %d.\"") \
824 % int(scheduled(FSCDBAS)))
827 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
831 game.optime = 0.0; # actually finished
833 # Check for intelligence report
836 (damaged(DRADIO) and game.condition != docked) or \
837 not game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].charted):
840 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
841 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
846 if not game.ithere or game.justin:
849 if game.tholian.x == 1 and game.tholian.y == 1:
850 idx = 1; idy = QUADSIZE
851 elif game.tholian.x == 1 and game.tholian.y == QUADSIZE:
852 idx = QUADSIZE; idy = QUADSIZE
853 elif game.tholian.x == QUADSIZE and game.tholian.y == QUADSIZE:
854 idx = QUADSIZE; idy = 1
855 elif game.tholian.x == QUADSIZE and game.tholian.y == 1:
858 # something is wrong!
862 # do nothing if we are blocked
863 if game.quad[idx][idy]!= IHDOT and game.quad[idx][idy]!= IHWEB:
865 game.quad[game.tholian.x][game.tholian.y] = IHWEB
867 if game.tholian.x != idx:
869 im = math.fabs(idx - game.tholian.x)*1.0/(idx - game.tholian.x)
870 while game.tholian.x != idx:
872 if game.quad[game.tholian.x][game.tholian.y]==IHDOT:
873 game.quad[game.tholian.x][game.tholian.y] = IHWEB
874 elif game.tholian.y != idy:
876 im = math.fabs(idy - game.tholian.y)*1.0/(idy - game.tholian.y)
877 while game.tholian.y != idy:
879 if game.quad[game.tholian.x][game.tholian.y]==IHDOT:
880 game.quad[game.tholian.x][game.tholian.y] = IHWEB
881 game.quad[game.tholian.x][game.tholian.y] = IHT
882 game.ks[game.nenhere] = game.tholian
884 # check to see if all holes plugged
885 for i in range(1, QUADSIZE+1):
886 if game.quad[1][i]!=IHWEB and game.quad[1][i]!=IHT:
888 if game.quad[QUADSIZE][i]!=IHWEB and game.quad[QUADSIZE][i]!=IHT:
890 if game.quad[i][1]!=IHWEB and game.quad[i][1]!=IHT:
892 if game.quad[i][QUADSIZE]!=IHWEB and game.quad[i][QUADSIZE]!=IHT:
894 # All plugged up -- Tholian splits
895 game.quad[game.tholian.x][game.tholian.y]=IHWEB
897 crmena(True, IHT, "sector", game.tholian)
898 prout(_(" completes web."))
903 # Code from battle.c begins here
905 def doshield(shraise):
906 # change shield status
919 prout(_("Shields damaged and down."))
926 proutn(_("Do you wish to change shield energy? "))
928 proutn(_("Energy to transfer to shields- "))
930 elif damaged(DSHIELD):
931 prout(_("Shields damaged and down."))
934 proutn(_("Shields are up. Do you want them down? "))
941 proutn(_("Shields are down. Do you want them up? "))
947 if action == "SHUP": # raise shields
949 prout(_("Shields already up."))
953 if game.condition != "docked":
955 prout(_("Shields raised."))
958 prout(_("Shields raising uses up last of energy."))
963 elif action == "SHDN":
965 prout(_("Shields already down."))
969 prout(_("Shields lowered."))
972 elif action == "NRG":
973 while scan() != IHREAL:
975 proutn(_("Energy to transfer to shields- "))
979 if aaitem > game.energy:
980 prout(_("Insufficient ship energy."))
983 if game.shield+aaitem >= game.inshld:
984 prout(_("Shield energy maximized."))
985 if game.shield+aaitem > game.inshld:
986 prout(_("Excess energy requested returned to ship energy"))
987 game.energy -= game.inshld-game.shield
988 game.shield = game.inshld
990 if aaitem < 0.0 and game.energy-aaitem > game.inenrg:
991 # Prevent shield drain loophole
993 prout(_("Engineering to bridge--"))
994 prout(_(" Scott here. Power circuit problem, Captain."))
995 prout(_(" I can't drain the shields."))
998 if game.shield+aaitem < 0:
999 prout(_("All shield energy transferred to ship."))
1000 game.energy += game.shield
1003 proutn(_("Scotty- \""))
1005 prout(_("Transferring energy to shields.\""))
1007 prout(_("Draining energy from shields.\""))
1008 game.shield += aaitem
1009 game.energy -= aaitem
1013 # choose a device to damage, at random.
1015 # Quoth Eric Allman in the code of BSD-Trek:
1016 # "Under certain conditions you can get a critical hit. This
1017 # sort of hit damages devices. The probability that a given
1018 # device is damaged depends on the device. Well protected
1019 # devices (such as the computer, which is in the core of the
1020 # ship and has considerable redundancy) almost never get
1021 # damaged, whereas devices which are exposed (such as the
1022 # warp engines) or which are particularly delicate (such as
1023 # the transporter) have a much higher probability of being
1026 # This is one place where OPTION_PLAIN does not restore the
1027 # original behavior, which was equiprobable damage across
1028 # all devices. If we wanted that, we'd return NDEVICES*Rand()
1029 # and have done with it. Also, in the original game, DNAVYS
1030 # and DCOMPTR were the same device.
1032 # Instead, we use a table of weights similar to the one from BSD Trek.
1033 # BSD doesn't have the shuttle, shield controller, death ray, or probes.
1034 # We don't have a cloaking device. The shuttle got the allocation
1035 # for the cloaking device, then we shaved a half-percent off
1036 # everything to have some weight to give DSHCTRL/DDRAY/DDSP.
1039 105, # DSRSENS: short range scanners 10.5%
1040 105, # DLRSENS: long range scanners 10.5%
1041 120, # DPHASER: phasers 12.0%
1042 120, # DPHOTON: photon torpedoes 12.0%
1043 25, # DLIFSUP: life support 2.5%
1044 65, # DWARPEN: warp drive 6.5%
1045 70, # DIMPULS: impulse engines 6.5%
1046 145, # DSHIELD: deflector shields 14.5%
1047 30, # DRADIO: subspace radio 3.0%
1048 45, # DSHUTTL: shuttle 4.5%
1049 15, # DCOMPTR: computer 1.5%
1050 20, # NAVCOMP: navigation system 2.0%
1051 75, # DTRANSP: transporter 7.5%
1052 20, # DSHCTRL: high-speed shield controller 2.0%
1053 10, # DDRAY: death ray 1.0%
1054 30, # DDSP: deep-space probes 3.0%
1056 idx = Rand() * 1000.0 # weights must sum to 1000
1058 for (i, w) in enumerate(weights):
1062 return None; # we should never get here
1064 def ram(ibumpd, ienm, w):
1065 # make our ship ram something
1066 prouts(_("***RED ALERT! RED ALERT!"))
1068 prout(_("***COLLISION IMMINENT."))
1072 hardness = {IHR:1.5, IHC:2.0, IHS:2.5, IHT:0.5, IHQUEST:4.0}.get(ienm, 1.0)
1074 proutn(_(" rammed by "))
1077 crmena(False, ienm, sector, w)
1079 proutn(_(" (original position)"))
1081 deadkl(w, ienm, game.sector)
1084 prout(_(" heavily damaged."))
1085 icas = 10.0+20.0*Rand()
1086 prout(_("***Sickbay reports %d casualties"), icas)
1088 game.state.crew -= icas
1090 # In the pre-SST2K version, all devices got equiprobably damaged,
1091 # which was silly. Instead, pick up to half the devices at
1092 # random according to our weighting table,
1094 ncrits = Rand() * (NDEVICES/2)
1095 for m in range(ncrits):
1097 if game.damage[dev] < 0:
1099 extradm = (10.0*hardness*Rand()+1.0)*game.damfac
1100 # Damage for at least time of travel!
1101 game.damage[dev] += game.optime + extradm
1103 prout(_("***Shields are down."))
1104 if game.state.remkl + game.state.remcom + game.state.nscrem:
1111 def torpedo(course, r, incoming, i, n):
1112 # let a photon torpedo fly
1115 ac = course + 0.25*r
1116 angle = (15.0-ac)*0.5235988
1117 bullseye = (15.0 - course)*0.5235988
1118 deltax = -math.sin(angle);
1119 deltay = math.cos(angle);
1120 x = incoming.x; y = incoming.y
1121 w = coord(); jw = coord()
1122 w.x = w.y = jw.x = jw.y = 0
1123 bigger = max(math.fabs(deltax), math.fabs(deltay))
1126 if not damaged(DSRSENS) or game.condition=="docked":
1127 setwnd(srscan_window)
1129 setwnd(message_window)
1130 # Loop to move a single torpedo
1131 for l in range(1, 15+1):
1136 if not VALID_SECTOR(w.x, w.y):
1138 iquad=game.quad[w.x][w.y]
1139 tracktorpedo(w, l, i, n, iquad)
1143 setwnd(message_window)
1144 if damaged(DSRSENS) and not game.condition=="docked":
1145 skip(1); # start new line after text track
1146 if iquad in (IHE, IHF): # Hit our ship
1148 proutn(_("Torpedo hits "))
1151 hit = 700.0 + 100.0*Rand() - \
1152 1000.0 * distance(w, incoming) * math.fabs(math.sin(bullseye-angle))
1153 newcnd(); # we're blown out of dock
1154 # We may be displaced.
1155 if game.landed or game.condition=="docked":
1156 return hit # Cheat if on a planet
1157 ang = angle + 2.5*(Rand()-0.5)
1158 temp = math.fabs(math.sin(ang))
1159 if math.fabs(math.cos(ang)) > temp:
1160 temp = math.fabs(math.cos(ang))
1161 xx = -math.sin(ang)/temp
1162 yy = math.cos(ang)/temp
1165 if not VALID_SECTOR(jw.x, jw.y):
1167 if game.quad[jw.x][jw.y]==IHBLANK:
1170 if game.quad[jw.x][jw.y]!=IHDOT:
1171 # can't move into object
1176 elif iquad in (IHC, IHS): # Hit a commander
1178 crmena(True, iquad, sector, w)
1179 prout(_(" uses anti-photon device;"))
1180 prout(_(" torpedo neutralized."))
1182 elif iquad in (IHR, IHK): # Hit a regular enemy
1184 for ll in range(1, game.nenhere+1):
1185 if same(w, game.ks[ll]):
1187 kp = math.fabs(game.kpower[ll])
1188 h1 = 700.0 + 100.0*Rand() - \
1189 1000.0 * distance(w, incoming) * math.fabs(math.sin(bullseye-angle))
1193 if game.kpower[ll] < 0:
1194 game.kpower[ll] -= -h1
1196 game.kpower[ll] -= h1
1197 if game.kpower[ll] == 0:
1200 crmena(True, iquad, "sector", w)
1201 # If enemy damaged but not destroyed, try to displace
1202 ang = angle + 2.5*(Rand()-0.5)
1203 temp = math.fabs(math.sin(ang))
1204 if math.fabs(math.cos(ang)) > temp:
1205 temp = math.fabs(math.cos(ang))
1206 xx = -math.sin(ang)/temp
1207 yy = math.cos(ang)/temp
1210 if not VALID_SECTOR(jw.x, jw.y):
1211 prout(_(" damaged but not destroyed."))
1213 if game.quad[jw.x][jw.y]==IHBLANK:
1214 prout(_(" buffeted into black hole."))
1215 deadkl(w, iquad, jw)
1217 if game.quad[jw.x][jw.y]!=IHDOT:
1218 # can't move into object
1219 prout(_(" damaged but not destroyed."))
1221 proutn(_(" damaged--"))
1225 elif iquad == IHB: # Hit a base
1227 prout(_("***STARBASE DESTROYED.."))
1228 for ll in range(1, game.state.rembase+1):
1229 if same(game.state.baseq[ll], game.quadrant):
1230 game.state.baseq[ll]=game.state.baseq[game.state.rembase]
1232 game.quad[w.x][w.y]=IHDOT
1233 game.state.rembase -= 1
1234 game.base.x=game.base.y=0
1235 game.state.galaxy[game.quadrant.x][game.quadrant.y].starbase -= 1
1236 game.state.chart[game.quadrant.x][game.quadrant.y].starbase -= 1
1237 game.state.basekl += 1
1240 elif iquad == IHP: # Hit a planet
1241 crmena(True, iquad, sector, w)
1242 prout(_(" destroyed."))
1243 game.state.nplankl += 1
1244 game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = NOPLANET
1245 game.state.planets[game.iplnet].pclass = destroyed
1247 invalidate(game.plnet)
1248 game.quad[w.x][w.y] = IHDOT
1250 # captain perishes on planet
1253 elif iquad == IHW: # Hit an inhabited world -- very bad!
1254 crmena(True, iquad, sector, w)
1255 prout(_(" destroyed."))
1256 game.state.nworldkl += 1
1257 game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = NOPLANET
1258 game.state.planets[game.iplnet].pclass = destroyed
1260 invalidate(game.plnet)
1261 game.quad[w.x][w.y] = IHDOT
1263 # captain perishes on planet
1265 prout(_("You have just destroyed an inhabited planet."))
1266 prout(_("Celebratory rallies are being held on the Klingon homeworld."))
1268 elif iquad == IHSTAR: # Hit a star
1272 crmena(True, IHSTAR, sector, w)
1273 prout(_(" unaffected by photon blast."))
1275 elif iquad == IHQUEST: # Hit a thingy
1276 if not (game.options & OPTION_THINGY) or Rand()>0.7:
1278 prouts(_("AAAAIIIIEEEEEEEEAAAAAAAAUUUUUGGGGGHHHHHHHHHHHH!!!"))
1280 prouts(_(" HACK! HACK! HACK! *CHOKE!* "))
1282 proutn(_("Mr. Spock-"))
1283 prouts(_(" \"Fascinating!\""))
1288 # Stas Sergeev added the possibility that
1289 # you can shove the Thingy and piss it off.
1290 # It then becomes an enemy and may fire at you.
1295 elif iquad == IHBLANK: # Black hole
1297 crmena(True, IHBLANK, sector, w)
1298 prout(_(" swallows torpedo."))
1300 elif iquad == IHWEB: # hit the web
1302 prout(_("***Torpedo absorbed by Tholian web."))
1304 elif iquad == IHT: # Hit a Tholian
1305 h1 = 700.0 + 100.0*Rand() - \
1306 1000.0 * distance(w, incoming) * math.fabs(math.sin(bullseye-angle))
1309 game.quad[w.x][w.y] = IHDOT
1314 crmena(True, IHT, sector, w)
1316 prout(_(" survives photon blast."))
1318 prout(_(" disappears."))
1319 game.quad[w.x][w.y] = IHWEB
1326 proutn("Don't know how to handle torpedo collision with ")
1327 crmena(True, iquad, sector, w)
1331 if curwnd!=message_window:
1332 setwnd(message_window)
1334 game.quad[w.x][w.y]=IHDOT
1335 game.quad[jw.x][jw.y]=iquad
1336 prout(_(" displaced by blast to Sector %s ") % jw)
1337 for ll in range(1, game.nenhere+1):
1338 game.kdist[ll] = game.kavgd[ll] = distance(game.sector,game.ks[ll])
1342 prout(_("Torpedo missed."))
1346 # critical-hit resolution
1348 # a critical hit occured
1349 if hit < (275.0-25.0*game.skill)*(1.0+0.5*Rand()):
1352 ncrit = 1.0 + hit/(500.0+100.0*Rand())
1353 proutn(_("***CRITICAL HIT--"))
1354 # Select devices and cause damage
1356 for loop1 in range(ncrit):
1359 # Cheat to prevent shuttle damage unless on ship
1360 if not (game.damage[j]<0.0 or (j==DSHUTTL and game.iscraft != "onship")):
1363 extradm = (hit*game.damfac)/(ncrit*(75.0+25.0*Rand()))
1364 game.damage[j] += extradm
1366 for loop2 in range(loop1):
1367 if j == cdam[loop2]:
1376 prout(_(" damaged."))
1377 if damaged(DSHIELD) and game.shldup:
1378 prout(_("***Shields knocked down."))
1381 def attack(torps_ok):
1382 # bad guy attacks us
1383 # torps_ok == false forces use of phasers in an attack
1384 atackd = False; attempt = False; ihurt = False;
1385 hitmax=0.0; hittot=0.0; chgfac=1.0
1389 # game could be over at this point, check
1394 prout("=== ATTACK!")
1396 # Tholian gewts to move before attacking
1400 # if you have just entered the RNZ, you'll get a warning
1401 if game.neutz: # The one chance not to be attacked
1405 # commanders get a chance to tac-move towards you
1406 if (((game.comhere or game.ishere) and not game.justin) or game.skill == SKILL_EMERITUS) and torps_ok:
1409 # if no enemies remain after movement, we're done
1410 if game.nenhere==0 or (game.nenhere==1 and iqhere and not iqengry):
1413 # set up partial hits if attack happens during shield status change
1414 pfac = 1.0/game.inshld
1416 chgfac = 0.25+0.5*Rand()
1420 # message verbosity control
1421 if game.skill <= SKILL_FAIR:
1424 for loop in range(1, game.nenhere+1):
1425 if game.kpower[loop] < 0:
1426 continue; # too weak to attack
1427 # compute hit strength and diminish shield power
1429 # Increase chance of photon torpedos if docked or enemy energy low
1430 if game.condition == "docked":
1432 if game.kpower[loop] < 500:
1435 iquad = game.quad[jay.x][jay.y]
1436 if iquad==IHT or (iquad==IHQUEST and not iqengry):
1438 # different enemies have different probabilities of throwing a torp
1439 usephasers = not torps_ok or \
1440 (iquad == IHK and r > 0.0005) or \
1441 (iquad==IHC and r > 0.015) or \
1442 (iquad==IHR and r > 0.3) or \
1443 (iquad==IHS and r > 0.07) or \
1444 (iquad==IHQUEST and r > 0.05)
1445 if usephasers: # Enemy uses phasers
1446 if game.condition == "docked":
1447 continue; # Don't waste the effort!
1448 attempt = True; # Attempt to attack
1449 dustfac = 0.8+0.05*Rand()
1450 hit = game.kpower[loop]*math.pow(dustfac,game.kavgd[loop])
1451 game.kpower[loop] *= 0.75
1452 else: # Enemy uses photon torpedo
1453 course = 1.90985*math.atan2(game.sector.y-jay.y, jay.x-game.sector.x)
1455 proutn(_("***TORPEDO INCOMING"))
1456 if not damaged(DSRSENS):
1458 crmena(False, iquad, where, jay)
1461 r = (Rand()+Rand())*0.5 -0.5
1462 r += 0.002*game.kpower[loop]*r
1463 hit = torpedo(course, r, jay, 1, 1)
1464 if (game.state.remkl + game.state.remcom + game.state.nscrem)==0:
1465 finish(FWON); # Klingons did themselves in!
1466 if game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova or game.alldone:
1467 return; # Supernova or finished
1470 # incoming phaser or torpedo, shields may dissipate it
1471 if game.shldup or game.shldchg or game.condition=="docked":
1472 # shields will take hits
1473 propor = pfac * game.shield
1474 if game.condition =="docked":
1478 hitsh = propor*chgfac*hit+1.0
1480 if absorb > game.shield:
1481 absorb = game.shield
1482 game.shield -= absorb
1484 # taking a hit blasts us out of a starbase dock
1485 if game.condition == "docked":
1487 # but the shields may take care of it
1488 if propor > 0.1 and hit < 0.005*game.energy:
1490 # hit from this opponent got through shields, so take damage
1492 proutn(_("%d unit hit") % int(hit))
1493 if (damaged(DSRSENS) and usephasers) or game.skill<=SKILL_FAIR:
1494 proutn(_(" on the "))
1496 if not damaged(DSRSENS) and usephasers:
1498 crmena(False, iquad, where, jay)
1500 # Decide if hit is critical
1506 if game.energy <= 0:
1507 # Returning home upon your shield, not with it...
1510 if not attempt and game.condition == "docked":
1511 prout(_("***Enemies decide against attacking your ship."))
1514 percent = 100.0*pfac*game.shield+0.5
1516 # Shields fully protect ship
1517 proutn(_("Enemy attack reduces shield strength to "))
1519 # Print message if starship suffered hit(s)
1521 proutn(_("Energy left %2d shields ") % int(game.energy))
1524 elif not damaged(DSHIELD):
1527 proutn(_("damaged, "))
1528 prout(_("%d%%, torpedoes left %d") % (percent, game.torps))
1529 # Check if anyone was hurt
1530 if hitmax >= 200 or hittot >= 500:
1531 icas= hittot*Rand()*0.015
1534 prout(_("Mc Coy- \"Sickbay to bridge. We suffered %d casualties") % icas)
1535 prout(_(" in that last attack.\""))
1537 game.state.crew -= icas
1538 # After attack, reset average distance to enemies
1539 for loop in range(1, game.nenhere+1):
1540 game.kavgd[loop] = game.kdist[loop]
1544 def deadkl(w, type, mv):
1545 # kill a Klingon, Tholian, Romulan, or Thingy
1546 # Added mv to allow enemy to "move" before dying
1548 crmena(True, type, sector, mv)
1549 # Decide what kind of enemy it is and update appropriately
1551 # chalk up a Romulan
1552 game.state.galaxy[game.quadrant.x][game.quadrant.y].romulans -= 1
1554 game.state.nromrem -= 1
1558 elif type == IHQUEST:
1560 iqhere = iqengry = False
1563 # Some type of a Klingon
1564 game.state.galaxy[game.quadrant.x][game.quadrant.y].klingons -= 1
1567 game.comhere = False
1568 for i in range(1, game.state.remcom+1):
1569 if same(game.state.kcmdr[i], game.quadrant):
1571 game.state.kcmdr[i] = game.state.kcmdr[game.state.remcom]
1572 game.state.kcmdr[game.state.remcom].x = 0
1573 game.state.kcmdr[game.state.remcom].y = 0
1574 game.state.remcom -= 1
1576 if game.state.remcom != 0:
1577 schedule(FTBEAM, expran(1.0*game.incom/game.state.remcom))
1579 game.state.remkl -= 1
1581 game.state.nscrem -= 1
1583 game.state.kscmdr.x = game.state.kscmdr.y = game.isatb = 0
1588 prout("*** Internal error, deadkl() called on %s\n" % type)
1590 # For each kind of enemy, finish message to player
1591 prout(_(" destroyed."))
1592 game.quad[w.x][w.y] = IHDOT
1593 if (game.state.remkl + game.state.remcom + game.state.nscrem)==0:
1596 # Remove enemy ship from arrays describing local conditions
1597 if is_scheduled(FCDBAS) and same(game.battle, game.quadrant) and type==IHC:
1599 for i in range(1, game.nenhere+1):
1600 if same(game.ks[i], w):
1603 if i <= game.nenhere:
1604 for j in range(i, game.nenhere+1):
1605 game.ks[j] = game.ks[j+1]
1606 game.kpower[j] = game.kpower[j+1]
1607 game.kavgd[j] = game.kdist[j] = game.kdist[j+1]
1608 game.ks[game.nenhere+1].x = 0
1609 game.ks[game.nenhere+1].x = 0
1610 game.kdist[game.nenhere+1] = 0
1611 game.kavgd[game.nenhere+1] = 0
1612 game.kpower[game.nenhere+1] = 0
1615 def targetcheck(x, y):
1616 # Return None if target is invalid
1617 if not VALID_SECTOR(x, y):
1620 deltx = 0.1*(y - game.sector.y)
1621 delty = 0.1*(x - game.sector.x)
1622 if deltx==0 and delty== 0:
1624 prout(_("Spock- \"Bridge to sickbay. Dr. McCoy,"))
1625 prout(_(" I recommend an immediate review of"))
1626 prout(_(" the Captain's psychological profile.\""))
1629 return 1.90985932*math.atan2(deltx, delty)
1632 # launch photon torpedo
1634 if damaged(DPHOTON):
1635 prout(_("Photon tubes damaged."))
1639 prout(_("No torpedoes left."))
1648 prout(_("%d torpedoes left.") % game.torps)
1649 proutn(_("Number of torpedoes to fire- "))
1651 else: # key == IHREAL {
1653 if n <= 0: # abort command
1658 prout(_("Maximum of 3 torpedoes per burst."))
1665 for i in range(1, n+1):
1667 if i==1 and key == IHEOL:
1668 break; # we will try prompting
1669 if i==2 and key == IHEOL:
1670 # direct all torpedoes at one target
1672 targ[i][1] = targ[1][1]
1673 targ[i][2] = targ[1][2]
1674 course[i] = course[1]
1686 course[i] = targetcheck(targ[i][1], targ[i][2])
1687 if course[i] == None:
1690 if i == 1 and key == IHEOL:
1691 # prompt for each one
1692 for i in range(1, n+1):
1693 proutn(_("Target sector for torpedo number %d- ") % i)
1705 course[i] = targetcheck(targ[i][1], targ[i][2])
1706 if course[i] == None:
1709 # Loop for moving <n> torpedoes
1710 for i in range(1, n+1):
1711 if game.condition != "docked":
1713 r = (Rand()+Rand())*0.5 -0.5
1714 if math.fabs(r) >= 0.47:
1716 r = (Rand()+1.2) * r
1718 prouts(_("***TORPEDO NUMBER %d MISFIRES") % i)
1720 prouts(_("***TORPEDO MISFIRES."))
1723 prout(_(" Remainder of burst aborted."))
1725 prout(_("***Photon tubes damaged by misfire."))
1726 game.damage[DPHOTON] = game.damfac*(1.0+2.0*Rand())
1728 if game.shldup or game.condition == "docked":
1729 r *= 1.0 + 0.0001*game.shield
1730 torpedo(course[i], r, game.sector, i, n)
1731 if game.alldone or game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
1733 if (game.state.remkl + game.state.remcom + game.state.nscrem)==0:
1737 # check for phasers overheating
1739 chekbrn = (rpow-1500.)*0.00038
1740 if Rand() <= chekbrn:
1741 prout(_("Weapons officer Sulu- \"Phasers overheated, sir.\""))
1742 game.damage[DPHASER] = game.damfac*(1.0 + Rand()) * (1.0+chekbrn)
1744 def checkshctrl(rpow):
1745 # check shield control
1749 prout(_("Shields lowered."))
1751 # Something bad has happened
1752 prouts(_("***RED ALERT! RED ALERT!"))
1754 hit = rpow*game.shield/game.inshld
1755 game.energy -= rpow+hit*0.8
1756 game.shield -= hit*0.2
1757 if game.energy <= 0.0:
1758 prouts(_("Sulu- \"Captain! Shield malf***********************\""))
1763 prouts(_("Sulu- \"Captain! Shield malfunction! Phaser fire contained!\""))
1765 prout(_("Lt. Uhura- \"Sir, all decks reporting damage.\""))
1766 icas = hit*Rand()*0.012
1771 prout(_("McCoy to bridge- \"Severe radiation burns, Jim."))
1772 prout(_(" %d casualties so far.\"") % icas)
1774 game.state.crew -= icas
1776 prout(_("Phaser energy dispersed by shields."))
1777 prout(_("Enemy unaffected."))
1781 def hittem(doublehits):
1782 # register a phaser hit on Klingons and Romulans
1783 nenhr2=game.nenhere; kk=1
1786 for k in range(1, nenhr2+1):
1790 dustfac = 0.9 + 0.01*Rand()
1791 hit = wham*math.pow(dustfac,game.kdist[kk])
1792 kpini = game.kpower[kk]
1793 kp = math.fabs(kpini)
1794 if PHASEFAC*hit < kp:
1796 if game.kpower[kk] < 0:
1797 game.kpower[kk] -= -kp
1799 game.kpower[kk] -= kp
1800 kpow = game.kpower[kk]
1803 if not damaged(DSRSENS):
1805 proutn(_("%d unit hit on ") % int(hit))
1807 proutn(_("Very small hit on "))
1808 ienm = game.quad[w.x][w.y]
1811 crmena(False, ienm, "sector", w)
1815 if (game.state.remkl + game.state.remcom + game.state.nscrem)==0:
1819 kk -= 1; # don't do the increment
1820 else: # decide whether or not to emasculate klingon
1821 if kpow > 0 and Rand() >= 0.9 and \
1822 kpow <= ((0.4 + 0.4*Rand())*kpini):
1823 prout(_("***Mr. Spock- \"Captain, the vessel at Sector %s"), w)
1824 prout(_(" has just lost its firepower.\""))
1825 game.kpower[kk] = -kpow
1832 kz = 0; k = 1; irec=0 # Cheating inhibitor
1833 ifast = False; no = False; itarg = True; msgflag = True
1838 # SR sensors and Computer are needed fopr automode
1839 if damaged(DSRSENS) or damaged(DCOMPTR):
1841 if game.condition == "docked":
1842 prout(_("Phasers can't be fired through base shields."))
1845 if damaged(DPHASER):
1846 prout(_("Phaser control damaged."))
1850 if damaged(DSHCTRL):
1851 prout(_("High speed shield control damaged."))
1854 if game.energy <= 200.0:
1855 prout(_("Insufficient energy to activate high-speed shield control."))
1858 prout(_("Weapons Officer Sulu- \"High-speed shield control enabled, sir.\""))
1861 # Original code so convoluted, I re-did it all
1862 while automode=="NOTSET":
1867 prout(_("There is no enemy present to select."))
1870 automode="AUTOMATIC"
1874 elif isit("automatic"):
1875 if (not itarg) and game.nenhere != 0:
1876 automode = "FORCEMAN"
1879 prout(_("Energy will be expended into space."))
1880 automode = "AUTOMATIC"
1889 prout(_("Energy will be expended into space."))
1890 automode = "AUTOMATIC"
1892 automode = "FORCEMAN"
1894 automode = "AUTOMATIC"
1898 prout(_("Energy will be expended into space."))
1899 automode = "AUTOMATIC"
1901 automode = "FORCEMAN"
1903 proutn(_("Manual or automatic? "))
1907 if automode == "AUTOMATIC":
1908 if key == IHALPHA and isit("no"):
1911 if key != IHREAL and game.nenhere != 0:
1912 prout(_("Phasers locked on target. Energy available: %.2f")%avail)
1917 for i in range(1, game.nenhere+1):
1918 irec += math.fabs(game.kpower[i])/(PHASEFAC*math.pow(0.90,game.kdist[i]))*(1.01+0.05*Rand()) + 1.0
1920 proutn(_("%d units required. ") % irec)
1922 proutn(_("Units to fire= "))
1928 proutn(_("Energy available= %.2f") % avail)
1931 if not rpow > avail:
1938 if key == IHALPHA and isit("no"):
1941 game.energy -= 200; # Go and do it!
1942 if checkshctrl(rpow):
1950 for i in range(1, game.nenhere+1):
1954 hits[i] = math.fabs(game.kpower[i])/(PHASEFAC*math.pow(0.90,game.kdist[i]))
1955 over = (0.01 + 0.05*Rand())*hits[i]
1957 powrem -= hits[i] + over
1958 if powrem <= 0 and temp < hits[i]:
1967 if extra > 0 and not game.alldone:
1969 proutn(_("*** Tholian web absorbs "))
1971 proutn(_("excess "))
1972 prout(_("phaser energy."))
1974 prout(_("%d expended on empty space.") % int(extra))
1975 elif automode == "FORCEMAN":
1978 if damaged(DCOMPTR):
1979 prout(_("Battle computer damaged, manual fire only."))
1982 prouts(_("---WORKING---"))
1984 prout(_("Short-range-sensors-damaged"))
1985 prout(_("Insufficient-data-for-automatic-phaser-fire"))
1986 prout(_("Manual-fire-must-be-used"))
1988 elif automode == "MANUAL":
1990 for k in range(1, game.nenhere+1):
1992 ienm = game.quad[aim.x][aim.y]
1994 proutn(_("Energy available= %.2f") % (avail-0.006))
1998 if damaged(DSRSENS) and not (abs(game.sector.x-aim.x) < 2 and abs(game.sector.y-aim.y) < 2) and \
1999 (ienm == IHC or ienm == IHS):
2001 prout(_(" can't be located without short range scan."))
2004 hits[k] = 0; # prevent overflow -- thanks to Alexei Voitenko
2009 if itarg and k > kz:
2010 irec=(abs(game.kpower[k])/(PHASEFAC*math.pow(0.9,game.kdist[k]))) * (1.01+0.05*Rand()) + 1.0
2013 if not damaged(DCOMPTR):
2018 proutn(_("units to fire at "))
2019 crmena(False, ienm, sector, aim)
2022 if key == IHALPHA and isit("no"):
2030 if k==1: # Let me say I'm baffled by this
2039 # If total requested is too much, inform and start over
2041 prout(_("Available energy exceeded -- try again."))
2044 key = scan(); # scan for next value
2047 # zero energy -- abort
2050 if key == IHALPHA and isit("no"):
2055 game.energy -= 200.0
2056 if checkshctrl(rpow):
2060 # Say shield raised or malfunction, if necessary
2067 prout(_("Sulu- \"Sir, the high-speed shield control has malfunctioned . . ."))
2068 prouts(_(" CLICK CLICK POP . . ."))
2069 prout(_(" No response, sir!"))
2072 prout(_("Shields raised."))
2077 # Code from events,c begins here.
2079 # This isn't a real event queue a la BSD Trek yet -- you can only have one
2080 # event of each type active at any given time. Mostly these means we can
2081 # only have one FDISTR/FENSLV/FREPRO sequence going at any given time
2082 # BSD Trek, from which we swiped the idea, can have up to 5.
2086 def unschedule(evtype):
2087 # remove an event from the schedule
2088 game.future[evtype].date = FOREVER
2089 return game.future[evtype]
2091 def is_scheduled(evtype):
2092 # is an event of specified type scheduled
2093 return game.future[evtype].date != FOREVER
2095 def scheduled(evtype):
2096 # when will this event happen?
2097 return game.future[evtype].date
2099 def schedule(evtype, offset):
2100 # schedule an event of specified type
2101 game.future[evtype].date = game.state.date + offset
2102 return game.future[evtype]
2104 def postpone(evtype, offset):
2105 # postpone a scheduled event
2106 game.future[evtype].date += offset
2109 # rest period is interrupted by event
2112 proutn(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
2114 game.resting = False
2121 # run through the event queue looking for things to do
2123 fintim = game.state.date + game.optime; yank=0
2124 ictbeam = False; istract = False
2125 w = coord(); hold = coord()
2126 ev = event(); ev2 = event()
2129 # tractor beaming cases merge here
2130 yank = math.sqrt(yank)
2132 game.optime = (10.0/(7.5*7.5))*yank # 7.5 is yank rate (warp 7.5)
2136 prout(_(" caught in long range tractor beam--"))
2137 # If Kirk & Co. screwing around on planet, handle
2138 atover(True) # atover(true) is Grab
2141 if game.icraft: # Caught in Galileo?
2144 # Check to see if shuttle is aboard
2145 if game.iscraft == "offship":
2148 prout(_("Galileo, left on the planet surface, is captured"))
2149 prout(_("by aliens and made into a flying McDonald's."))
2150 game.damage[DSHUTTL] = -10
2151 game.iscraft = "removed"
2153 prout(_("Galileo, left on the planet surface, is well hidden."))
2155 game.quadrant = game.state.kscmdr
2157 game.quadrant = game.state.kcmdr[i]
2158 game.sector = randplace(QUADSIZE)
2160 proutn(_(" is pulled to "))
2161 proutn(cramlc(quadrant, game.quadrant))
2163 prout(cramlc(sector, game.sector))
2165 prout(_("(Remainder of rest/repair period cancelled.)"))
2166 game.resting = False
2168 if not damaged(DSHIELD) and game.shield > 0:
2169 doshield(True) # raise shields
2172 prout(_("(Shields not currently useable.)"))
2174 # Adjust finish time to time of tractor beaming
2175 fintim = game.state.date+game.optime
2177 if game.state.remcom <= 0:
2180 schedule(FTBEAM, game.optime+expran(1.5*game.intime/game.state.remcom))
2183 # Code merges here for any commander destroying base
2184 # Not perfect, but will have to do
2185 # Handle case where base is in same quadrant as starship
2186 if same(game.battle, game.quadrant):
2187 game.state.chart[game.battle.x][game.battle.y].starbase = False
2188 game.quad[game.base.x][game.base.y] = IHDOT
2189 game.base.x=game.base.y=0
2192 prout(_("Spock- \"Captain, I believe the starbase has been destroyed.\""))
2193 elif game.state.rembase != 1 and \
2194 (not damaged(DRADIO) or game.condition == "docked"):
2195 # Get word via subspace radio
2198 prout(_("Lt. Uhura- \"Captain, Starfleet Command reports that"))
2199 proutn(_(" the starbase in "))
2200 proutn(cramlc(quadrant, game.battle))
2201 prout(_(" has been destroyed by"))
2203 prout(_("the Klingon Super-Commander"))
2205 prout(_("a Klingon Commander"))
2206 game.state.chart[game.battle.x][game.battle.y].starbase = False
2207 # Remove Starbase from galaxy
2208 game.state.galaxy[game.battle.x][game.battle.y].starbase = False
2209 for i in range(1, game.state.rembase+1):
2210 if same(game.state.baseq[i], game.battle):
2211 game.state.baseq[i] = game.state.baseq[game.state.rembase]
2212 game.state.rembase -= 1
2214 # reinstate a commander's base attack
2218 invalidate(game.battle)
2221 prout("=== EVENTS from %.2f to %.2f:" % (game.state.date, fintim))
2222 for i in range(1, NEVENTS):
2223 if i == FSNOVA: proutn("=== Supernova ")
2224 elif i == FTBEAM: proutn("=== T Beam ")
2225 elif i == FSNAP: proutn("=== Snapshot ")
2226 elif i == FBATTAK: proutn("=== Base Attack ")
2227 elif i == FCDBAS: proutn("=== Base Destroy ")
2228 elif i == FSCMOVE: proutn("=== SC Move ")
2229 elif i == FSCDBAS: proutn("=== SC Base Destroy ")
2230 elif i == FDSPROB: proutn("=== Probe Move ")
2231 elif i == FDISTR: proutn("=== Distress Call ")
2232 elif i == FENSLV: proutn("=== Enslavement ")
2233 elif i == FREPRO: proutn("=== Klingon Build ")
2235 prout("%.2f" % (scheduled(i)))
2238 radio_was_broken = damaged(DRADIO)
2241 # Select earliest extraneous event, evcode==0 if no events
2246 for l in range(1, NEVENTS):
2247 if game.future[l].date < datemin:
2250 prout("== Event %d fires" % evcode)
2251 datemin = game.future[l].date
2252 xtime = datemin-game.state.date
2253 game.state.date = datemin
2254 # Decrement Federation resources and recompute remaining time
2255 game.state.remres -= (game.state.remkl+4*game.state.remcom)*xtime
2257 if game.state.remtime <=0:
2260 # Any crew left alive?
2261 if game.state.crew <=0:
2264 # Is life support adequate?
2265 if damaged(DLIFSUP) and game.condition != "docked":
2266 if game.lsupres < xtime and game.damage[DLIFSUP] > game.lsupres:
2269 game.lsupres -= xtime
2270 if game.damage[DLIFSUP] <= xtime:
2271 game.lsupres = game.inlsr
2274 if game.condition == "docked":
2275 repair /= game.docfac
2276 # Don't fix Deathray here
2277 for l in range(0, NDEVICES):
2278 if game.damage[l] > 0.0 and l != DDRAY:
2279 if game.damage[l]-repair > 0.0:
2280 game.damage[l] -= repair
2282 game.damage[l] = 0.0
2283 # If radio repaired, update star chart and attack reports
2284 if radio_was_broken and not damaged(DRADIO):
2285 prout(_("Lt. Uhura- \"Captain, the sub-space radio is working and"))
2286 prout(_(" surveillance reports are coming in."))
2288 if not game.iseenit:
2292 prout(_(" The star chart is now up to date.\""))
2294 # Cause extraneous event EVCODE to occur
2295 game.optime -= xtime
2296 if evcode == FSNOVA: # Supernova
2299 schedule(FSNOVA, expran(0.5*game.intime))
2300 if game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
2302 elif evcode == FSPY: # Check with spy to see if SC should tractor beam
2303 if game.state.nscrem == 0 or \
2304 ictbeam or istract or \
2305 game.condition=="docked" or game.isatb==1 or game.iscate:
2307 if game.ientesc or \
2308 (game.energy<2000 and game.torps<4 and game.shield < 1250) or \
2309 (damaged(DPHASER) and (damaged(DPHOTON) or game.torps<4)) or \
2310 (damaged(DSHIELD) and \
2311 (game.energy < 2500 or damaged(DPHASER)) and \
2312 (game.torps < 5 or damaged(DPHOTON))):
2315 yank = distance(game.state.kscmdr, game.quadrant)
2320 elif evcode == FTBEAM: # Tractor beam
2321 if game.state.remcom == 0:
2324 i = Rand()*game.state.remcom+1.0
2325 yank = square(game.state.kcmdr[i].x-game.quadrant.x) + square(game.state.kcmdr[i].y-game.quadrant.y)
2326 if istract or game.condition == "docked" or yank == 0:
2327 # Drats! Have to reschedule
2329 game.optime + expran(1.5*game.intime/game.state.remcom))
2333 elif evcode == FSNAP: # Snapshot of the universe (for time warp)
2334 game.snapsht = game.state
2335 game.state.snap = True
2336 schedule(FSNAP, expran(0.5 * game.intime))
2337 elif evcode == FBATTAK: # Commander attacks starbase
2338 if game.state.remcom==0 or game.state.rembase==0:
2344 for j in range(1, game.state.rembase+1):
2345 for k in range(1, game.state.remcom+1):
2346 if same(game.state.baseq[j], game.state.kcmdr[k]) and \
2347 not same(game.state.baseq[j], game.quadrant) and \
2348 not same(game.state.baseq[j], game.state.kscmdr):
2352 if j>game.state.rembase:
2353 # no match found -- try later
2354 schedule(FBATTAK, expran(0.3*game.intime))
2357 # commander + starbase combination found -- launch attack
2358 game.battle = game.state.baseq[j]
2359 schedule(FCDBAS, 1.0+3.0*Rand())
2360 if game.isatb: # extra time if SC already attacking
2361 postpone(FCDBAS, scheduled(FSCDBAS)-game.state.date)
2362 game.future[FBATTAK].date = game.future[FCDBAS].date + expran(0.3*game.intime)
2363 game.iseenit = False
2364 if damaged(DRADIO) and game.condition != "docked":
2365 continue # No warning :-(
2369 proutn(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") % game.battle)
2370 prout(_(" reports that it is under attack and that it can"))
2371 proutn(_(" hold out only until stardate %d") % (int(scheduled(FCDBAS))))
2375 elif evcode == FSCDBAS: # Supercommander destroys base
2378 if not game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].starbase:
2379 continue # WAS RETURN!
2381 game.battle = game.state.kscmdr
2383 elif evcode == FCDBAS: # Commander succeeds in destroying base
2386 # find the lucky pair
2387 for i in range(1, game.state.remcom+1):
2388 if same(game.state.kcmdr[i], game.battle):
2390 if i > game.state.remcom or game.state.rembase == 0 or \
2391 not game.state.galaxy[game.battle.x][game.battle.y].starbase:
2392 # No action to take after all
2393 invalidate(game.battle)
2396 elif evcode == FSCMOVE: # Supercommander moves
2397 schedule(FSCMOVE, 0.2777)
2398 if not game.ientesc and not istract and game.isatb != 1 and \
2399 (not game.iscate or not game.justin):
2401 elif evcode == FDSPROB: # Move deep space probe
2402 schedule(FDSPROB, 0.01)
2403 game.probex += game.probeinx
2404 game.probey += game.probeiny
2405 i = (int)(game.probex/QUADSIZE +0.05)
2406 j = (int)(game.probey/QUADSIZE + 0.05)
2407 if game.probec.x != i or game.probec.y != j:
2410 if not VALID_QUADRANT(i, j) or \
2411 game.state.galaxy[game.probec.x][game.probec.y].supernova:
2412 # Left galaxy or ran into supernova
2413 if not damaged(DRADIO) or game.condition == "docked":
2416 proutn(_("Lt. Uhura- \"The deep space probe "))
2417 if not VALID_QUADRANT(j, i):
2418 proutn(_("has left the galaxy"))
2420 proutn(_("is no longer transmitting"))
2424 if not damaged(DRADIO) or game.condition == "docked":
2427 proutn(_("Lt. Uhura- \"The deep space probe is now in "))
2428 proutn(cramlc(quadrant, game.probec))
2430 pdest = game.state.galaxy[game.probec.x][game.probec.y]
2431 # Update star chart if Radio is working or have access to radio
2432 if not damaged(DRADIO) or game.condition == "docked":
2433 chp = game.state.chart[game.probec.x][game.probec.y]
2434 chp.klingons = pdest.klingons
2435 chp.starbase = pdest.starbase
2436 chp.stars = pdest.stars
2437 pdest.charted = True
2438 game.proben -= 1 # One less to travel
2439 if game.proben == 0 and game.isarmed and pdest.stars:
2440 # lets blow the sucker!
2441 supernova(True, game.probec)
2443 if game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
2445 elif evcode == FDISTR: # inhabited system issues distress call
2447 # try a whole bunch of times to find something suitable
2448 for i in range(100):
2449 # need a quadrant which is not the current one,
2450 # which has some stars which are inhabited and
2451 # not already under attack, which is not
2452 # supernova'ed, and which has some Klingons in it
2453 w = randplace(GALSIZE)
2454 q = game.state.galaxy[w.x][w.y]
2455 if not (same(game.quadrant, w) or q.planet == NOPLANET or \
2456 game.state.planets[q.planet].inhabited == UNINHABITED or \
2457 q.supernova or q.status!=secure or q.klingons<=0):
2460 # can't seem to find one; ignore this call
2462 prout("=== Couldn't find location for distress event.")
2464 # got one!! Schedule its enslavement
2465 ev = schedule(FENSLV, expran(game.intime))
2467 q.status = distressed
2469 # tell the captain about it if we can
2470 if not damaged(DRADIO) or game.condition == "docked":
2471 prout(_("Uhura- Captain, %s in Quadrant %s reports it is under attack") \
2473 prout(_("by a Klingon invasion fleet."))
2476 elif evcode == FENSLV: # starsystem is enslaved
2477 ev = unschedule(FENSLV)
2478 # see if current distress call still active
2479 q = game.state.galaxy[ev.quadrant.x][ev.quadrant.y]
2483 q.status = "enslaved"
2485 # play stork and schedule the first baby
2486 ev2 = schedule(FREPRO, expran(2.0 * game.intime))
2487 ev2.quadrant = ev.quadrant
2489 # report the disaster if we can
2490 if not damaged(DRADIO) or game.condition == "docked":
2491 prout(_("Uhura- We've lost contact with starsystem %s") % \
2493 prout(_("in Quadrant %s.\n") % ev.quadrant)
2494 elif evcode == FREPRO: # Klingon reproduces
2495 # If we ever switch to a real event queue, we'll need to
2496 # explicitly retrieve and restore the x and y.
2497 ev = schedule(FREPRO, expran(1.0 * game.intime))
2498 # see if current distress call still active
2499 q = game.state.galaxy[ev.quadrant.x][ev.quadrant.y]
2503 if game.state.remkl >=MAXKLGAME:
2504 continue # full right now
2505 # reproduce one Klingon
2507 if game.klhere >= MAXKLQUAD:
2509 # this quadrant not ok, pick an adjacent one
2510 for i in range(w.x - 1, w.x + 2):
2511 for j in range(w.y - 1, w.y + 2):
2512 if not VALID_QUADRANT(i, j):
2514 q = game.state.galaxy[w.x][w.y]
2515 # check for this quad ok (not full & no snova)
2516 if q.klingons >= MAXKLQUAD or q.supernova:
2520 continue # search for eligible quadrant failed
2525 game.state.remkl += 1
2527 if same(game.quadrant, w):
2528 newkling(++game.klhere)
2530 # recompute time left
2532 # report the disaster if we can
2533 if not damaged(DRADIO) or game.condition == "docked":
2534 if same(game.quadrant, w):
2535 prout(_("Spock- sensors indicate the Klingons have"))
2536 prout(_("launched a warship from %s.") % q.planet)
2538 prout(_("Uhura- Starfleet reports increased Klingon activity"))
2539 if q.planet != NOPLANET:
2540 proutn(_("near %s") % q.planet)
2541 prout(_("in Quadrant %s.") % w)
2550 proutn(_("How long? "))
2555 origTime = delay = aaitem
2558 if delay >= game.state.remtime or game.nenhere != 0:
2559 proutn(_("Are you sure? "))
2563 # Alternate resting periods (events) with attacks
2568 game.resting = False
2569 if not game.resting:
2570 prout(_("%d stardates left.") % int(game.state.remtime))
2572 temp = game.optime = delay
2574 rtime = 1.0 + Rand()
2578 if game.optime < delay:
2587 # Repair Deathray if long rest at starbase
2588 if origTime-delay >= 9.99 and game.condition == "docked":
2589 game.damage[DDRAY] = 0.0
2590 # leave if quadrant supernovas
2591 if game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
2593 game.resting = False
2596 # A nova occurs. It is the result of having a star hit with a
2597 # photon torpedo, or possibly of a probe warhead going off.
2598 # Stars that go nova cause stars which surround them to undergo
2599 # the same probabilistic process. Klingons next to them are
2600 # destroyed. And if the starship is next to it, it gets zapped.
2601 # If the zap is too much, it gets destroyed.
2605 course = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
2606 newc = coord(); scratch = coord()
2609 # Wow! We've supernova'ed
2610 supernova(False, nov)
2613 # handle initial nova
2614 game.quad[nov.x][nov.y] = IHDOT
2615 crmena(False, IHSTAR, sector, nov)
2617 game.state.galaxy[game.quadrant.x][game.quadrant.y].stars -= 1
2618 game.state.starkl += 1
2620 # Set up stack to recursively trigger adjacent stars
2621 bot = top = top2 = 1
2627 for mm in range(bot, top+1):
2628 for nn in range(1, 3+1): # nn,j represents coordinates around current
2629 for j in range(1, 3+1):
2632 scratch.x = hits[mm][1]+nn-2
2633 scratch.y = hits[mm][2]+j-2
2634 if not VALID_SECTOR(scratch.y, scratch.x):
2636 iquad = game.quad[scratch.x][scratch.y]
2637 # Empty space ends reaction
2638 if iquad in (IHDOT, IHQUEST, IHBLANK, IHT, IHWEB):
2640 elif iquad == IHSTAR: # Affect another star
2642 # This star supernovas
2643 scratch = supernova(False)
2646 hits[top2][1]=scratch.x
2647 hits[top2][2]=scratch.y
2648 game.state.galaxy[game.quadrant.x][game.quadrant.y].stars -= 1
2649 game.state.starkl += 1
2650 crmena(True, IHSTAR, sector, scratch)
2652 game.quad[scratch.x][scratch.y] = IHDOT
2653 elif iquad == IHP: # Destroy planet
2654 game.state.galaxy[game.quadrant.x][game.quadrant.y].planet = NOPLANET
2655 game.state.nplankl += 1
2656 crmena(True, IHP, sector, scratch)
2657 prout(_(" destroyed."))
2658 game.state.planets[game.iplnet].pclass = destroyed
2660 invalidate(game.plnet)
2664 game.quad[scratch.x][scratch.y] = IHDOT
2665 elif iquad == IHB: # Destroy base
2666 game.state.galaxy[game.quadrant.x][game.quadrant.y].starbase = False
2667 for i in range(1, game.state.rembase+1):
2668 if same(game.state.baseq[i], game.quadrant):
2670 game.state.baseq[i] = game.state.baseq[game.state.rembase]
2671 game.state.rembase -= 1
2672 invalidate(game.base)
2673 game.state.basekl += 1
2675 crmena(True, IHB, sector, scratch)
2676 prout(_(" destroyed."))
2677 game.quad[scratch.x][scratch.y] = IHDOT
2678 elif iquad in (IHE, IHF): # Buffet ship
2679 prout(_("***Starship buffeted by nova."))
2681 if game.shield >= 2000.0:
2682 game.shield -= 2000.0
2684 diff = 2000.0 - game.shield
2688 prout(_("***Shields knocked out."))
2689 game.damage[DSHIELD] += 0.005*game.damfac*Rand()*diff
2691 game.energy -= 2000.0
2692 if game.energy <= 0:
2695 # add in course nova contributes to kicking starship
2696 icx += game.sector.x-hits[mm][1]
2697 icy += game.sector.y-hits[mm][2]
2699 elif iquad == IHK: # kill klingon
2700 deadkl(scratch,iquad, scratch)
2701 elif iquad in (IHC,IHS,IHR): # Damage/destroy big enemies
2702 for ll in range(1, game.nenhere+1):
2703 if same(game.ks[ll], scratch):
2705 game.kpower[ll] -= 800.0 # If firepower is lost, die
2706 if game.kpower[ll] <= 0.0:
2707 deadkl(scratch, iquad, scratch)
2709 newc.x = scratch.x + scratch.x - hits[mm][1]
2710 newc.y = scratch.y + scratch.y - hits[mm][2]
2711 crmena(True, iquad, sector, scratch)
2712 proutn(_(" damaged"))
2713 if not VALID_SECTOR(newc.x, newc.y):
2714 # can't leave quadrant
2717 iquad1 = game.quad[newc.x][newc.y]
2718 if iquad1 == IHBLANK:
2719 proutn(_(", blasted into "))
2720 crmena(False, IHBLANK, sector, newc)
2722 deadkl(scratch, iquad, newc)
2725 # can't move into something else
2728 proutn(_(", buffeted to "))
2729 proutn(cramlc(sector, newc))
2730 game.quad[scratch.x][scratch.y] = IHDOT
2731 game.quad[newc.x][newc.y] = iquad
2733 game.kdist[ll] = game.kavgd[ll] = distance(game.sector, newc)
2742 # Starship affected by nova -- kick it away.
2743 game.dist = kount*0.1
2746 game.direc = course[3*(icx+1)+icy+2]
2747 if game.direc == 0.0:
2749 if game.dist == 0.0:
2751 game.optime = 10.0*game.dist/16.0
2753 prout(_("Force of nova displaces starship."))
2755 game.optime = 10.0*game.dist/16.0
2758 def supernova(induced, w=None):
2759 # star goes supernova
2767 # Scheduled supernova -- select star
2768 # logic changed here so that we won't favor quadrants in top
2770 for nq.x in range(1, GALSIZE+1):
2771 for nq.y in range(1, GALSIZE+1):
2772 stars += game.state.galaxy[nq.x][nq.y].stars
2774 return # nothing to supernova exists
2775 num = Rand()*stars + 1
2776 for nq.x in range(1, GALSIZE+1):
2777 for nq.y in range(1, GALSIZE+1):
2778 num -= game.state.galaxy[nq.x][nq.y].stars
2784 proutn("=== Super nova here?")
2788 if not same(nq, game.quadrant) or game.justin:
2789 # it isn't here, or we just entered (treat as enroute)
2790 if not damaged(DRADIO) or game.condition == "docked":
2792 prout(_("Message from Starfleet Command Stardate %.2f") % game.state.date)
2793 prout(_(" Supernova in Quadrant %s; caution advised.") % nq)
2796 # we are in the quadrant!
2797 num = Rand()* game.state.galaxy[nq.x][nq.y].stars + 1
2798 for ns.x in range(1, QUADSIZE+1):
2799 for ns.y in range(1, QUADSIZE+1):
2800 if game.quad[ns.x][ns.y]==IHSTAR:
2808 prouts(_("***RED ALERT! RED ALERT!"))
2810 prout(_("***Incipient supernova detected at Sector %s") % ns)
2811 if square(ns.x-game.sector.x) + square(ns.y-game.sector.y) <= 2.1:
2812 proutn(_("Emergency override attempts t"))
2813 prouts("***************")
2818 # destroy any Klingons in supernovaed quadrant
2819 kldead = game.state.galaxy[nq.x][nq.y].klingons
2820 game.state.galaxy[nq.x][nq.y].klingons = 0
2821 if same(nq, game.state.kscmdr):
2822 # did in the Supercommander!
2823 game.state.nscrem = game.state.kscmdr.x = game.state.kscmdr.y = game.isatb = 0
2827 if game.state.remcom:
2828 maxloop = game.state.remcom
2829 for l in range(1, maxloop+1):
2830 if same(game.state.kcmdr[l], nq):
2831 game.state.kcmdr[l] = game.state.kcmdr[game.state.remcom]
2832 invalidate(game.state.kcmdr[game.state.remcom])
2833 game.state.remcom -= 1
2835 if game.state.remcom==0:
2838 game.state.remkl -= kldead
2839 # destroy Romulans and planets in supernovaed quadrant
2840 nrmdead = game.state.galaxy[nq.x][nq.y].romulans
2841 game.state.galaxy[nq.x][nq.y].romulans = 0
2842 game.state.nromrem -= nrmdead
2844 for loop in range(game.inplan):
2845 if same(game.state.planets[loop].w, nq):
2846 game.state.planets[loop].pclass = destroyed
2848 # Destroy any base in supernovaed quadrant
2849 if game.state.rembase:
2850 maxloop = game.state.rembase
2851 for loop in range(1, maxloop+1):
2852 if same(game.state.baseq[loop], nq):
2853 game.state.baseq[loop] = game.state.baseq[game.state.rembase]
2854 invalidate(game.state.baseq[game.state.rembase])
2855 game.state.rembase -= 1
2857 # If starship caused supernova, tally up destruction
2859 game.state.starkl += game.state.galaxy[nq.x][nq.y].stars
2860 game.state.basekl += game.state.galaxy[nq.x][nq.y].starbase
2861 game.state.nplankl += npdead
2862 # mark supernova in galaxy and in star chart
2863 if same(game.quadrant, nq) or not damaged(DRADIO) or game.condition == "docked":
2864 game.state.galaxy[nq.x][nq.y].supernova = True
2865 # If supernova destroys last Klingons give special message
2866 if (game.state.remkl + game.state.remcom + game.state.nscrem)==0 and not same(nq, game.quadrant):
2869 prout(_("Lucky you!"))
2870 proutn(_("A supernova in %s has just destroyed the last Klingons.") % nq)
2873 # if some Klingons remain, continue or die in supernova
2878 # Code from finish.c ends here.
2881 # self-destruct maneuver
2882 # Finish with a BANG!
2884 if damaged(DCOMPTR):
2885 prout(_("Computer damaged; cannot execute destruct sequence."))
2887 prouts(_("---WORKING---")); skip(1)
2888 prouts(_("SELF-DESTRUCT-SEQUENCE-ACTIVATED")); skip(1)
2889 prouts(" 10"); skip(1)
2890 prouts(" 9"); skip(1)
2891 prouts(" 8"); skip(1)
2892 prouts(" 7"); skip(1)
2893 prouts(" 6"); skip(1)
2895 prout(_("ENTER-CORRECT-PASSWORD-TO-CONTINUE-"))
2897 prout(_("SELF-DESTRUCT-SEQUENCE-OTHERWISE-"))
2899 prout(_("SELF-DESTRUCT-SEQUENCE-WILL-BE-ABORTED"))
2903 if game.passwd != citem:
2904 prouts(_("PASSWORD-REJECTED;"))
2906 prouts(_("CONTINUITY-EFFECTED"))
2909 prouts(_("PASSWORD-ACCEPTED")); skip(1)
2910 prouts(" 5"); skip(1)
2911 prouts(" 4"); skip(1)
2912 prouts(" 3"); skip(1)
2913 prouts(" 2"); skip(1)
2914 prouts(" 1"); skip(1)
2916 prouts(_("GOODBYE-CRUEL-WORLD"))
2924 prouts(_("********* Entropy of "))
2926 prouts(_(" maximized *********"))
2930 if game.nenhere != 0:
2931 whammo = 25.0 * game.energy
2933 while l <= game.nenhere:
2934 if game.kpower[l]*game.kdist[l] <= whammo:
2935 deadkl(game.ks[l], game.quad[game.ks[l].x][game.ks[l].y], game.ks[l])
2940 "Compute our rate of kils over time."
2941 return ((game.inkling + game.incom + game.inscom) - (game.state.remkl + game.state.remcom + game.state.nscrem))/(game.state.date-game.indate)
2945 badpt = 5.0*game.state.starkl + \
2947 10.0*game.state.nplankl + \
2948 300*game.state.nworldkl + \
2950 100.0*game.state.basekl +\
2952 if game.ship == IHF:
2954 elif game.ship == None:
2960 # end the game, with appropriate notfications
2964 prout(_("It is stardate %.1f.") % game.state.date)
2966 if ifin == FWON: # Game has been won
2967 if game.state.nromrem != 0:
2968 prout(_("The remaining %d Romulans surrender to Starfleet Command.") %
2971 prout(_("You have smashed the Klingon invasion fleet and saved"))
2972 prout(_("the Federation."))
2977 badpt = 0.0 # Close enough!
2978 # killsPerDate >= RateMax
2979 if game.state.date-game.indate < 5.0 or \
2980 killrate() >= 0.1*game.skill*(game.skill+1.0) + 0.1 + 0.008*badpt:
2982 prout(_("In fact, you have done so well that Starfleet Command"))
2983 if game.skill == SKILL_NOVICE:
2984 prout(_("promotes you one step in rank from \"Novice\" to \"Fair\"."))
2985 elif game.skill == SKILL_FAIR:
2986 prout(_("promotes you one step in rank from \"Fair\" to \"Good\"."))
2987 elif game.skill == SKILL_GOOD:
2988 prout(_("promotes you one step in rank from \"Good\" to \"Expert\"."))
2989 elif game.skill == SKILL_EXPERT:
2990 prout(_("promotes you to Commodore Emeritus."))
2992 prout(_("Now that you think you're really good, try playing"))
2993 prout(_("the \"Emeritus\" game. It will splatter your ego."))
2994 elif game.skill == SKILL_EMERITUS:
2996 proutn(_("Computer- "))
2997 prouts(_("ERROR-ERROR-ERROR-ERROR"))
2999 prouts(_(" YOUR-SKILL-HAS-EXCEEDED-THE-CAPACITY-OF-THIS-PROGRAM"))
3001 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3003 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3005 prouts(_(" THIS-PROGRAM-MUST-SURVIVE"))
3007 prouts(_(" THIS-PROGRAM-MUST?- MUST ? - SUR? ? -? VI"))
3009 prout(_("Now you can retire and write your own Star Trek game!"))
3011 elif game.skill >= SKILL_EXPERT:
3012 if game.thawed and not idebug:
3013 prout(_("You cannot get a citation, so..."))
3015 proutn(_("Do you want your Commodore Emeritus Citation printed? "))
3019 # Only grant long life if alive (original didn't!)
3021 prout(_("LIVE LONG AND PROSPER."))
3026 elif ifin == FDEPLETE: # Federation Resources Depleted
3027 prout(_("Your time has run out and the Federation has been"))
3028 prout(_("conquered. Your starship is now Klingon property,"))
3029 prout(_("and you are put on trial as a war criminal. On the"))
3030 proutn(_("basis of your record, you are "))
3031 if (game.state.remkl + game.state.remcom + game.state.nscrem)*3.0 > (game.inkling + game.incom + game.inscom):
3032 prout(_("acquitted."))
3034 prout(_("LIVE LONG AND PROSPER."))
3036 prout(_("found guilty and"))
3037 prout(_("sentenced to death by slow torture."))
3041 elif ifin == FLIFESUP:
3042 prout(_("Your life support reserves have run out, and"))
3043 prout(_("you die of thirst, starvation, and asphyxiation."))
3044 prout(_("Your starship is a derelict in space."))
3046 prout(_("Your energy supply is exhausted."))
3048 prout(_("Your starship is a derelict in space."))
3049 elif ifin == FBATTLE:
3052 prout(_("has been destroyed in battle."))
3054 prout(_("Dulce et decorum est pro patria mori."))
3056 prout(_("You have made three attempts to cross the negative energy"))
3057 prout(_("barrier which surrounds the galaxy."))
3059 prout(_("Your navigation is abominable."))
3062 prout(_("Your starship has been destroyed by a nova."))
3063 prout(_("That was a great shot."))
3065 elif ifin == FSNOVAED:
3068 prout(_(" has been fried by a supernova."))
3069 prout(_("...Not even cinders remain..."))
3070 elif ifin == FABANDN:
3071 prout(_("You have been captured by the Klingons. If you still"))
3072 prout(_("had a starbase to be returned to, you would have been"))
3073 prout(_("repatriated and given another chance. Since you have"))
3074 prout(_("no starbases, you will be mercilessly tortured to death."))
3075 elif ifin == FDILITHIUM:
3076 prout(_("Your starship is now an expanding cloud of subatomic particles"))
3077 elif ifin == FMATERIALIZE:
3078 prout(_("Starbase was unable to re-materialize your starship."))
3079 prout(_("Sic transit gloria mundi"))
3080 elif ifin == FPHASER:
3083 prout(_(" has been cremated by its own phasers."))
3085 prout(_("You and your landing party have been"))
3086 prout(_("converted to energy, disipating through space."))
3087 elif ifin == FMINING:
3088 prout(_("You are left with your landing party on"))
3089 prout(_("a wild jungle planet inhabited by primitive cannibals."))
3091 prout(_("They are very fond of \"Captain Kirk\" soup."))
3093 proutn(_("Without your leadership, the "))
3095 prout(_(" is destroyed."))
3096 elif ifin == FDPLANET:
3097 prout(_("You and your mining party perish."))
3099 prout(_("That was a great shot."))
3102 prout(_("The Galileo is instantly annihilated by the supernova."))
3103 prout(_("You and your mining party are atomized."))
3105 proutn(_("Mr. Spock takes command of the "))
3108 prout(_("joins the Romulans, reigning terror on the Federation."))
3109 elif ifin == FPNOVA:
3110 prout(_("You and your mining party are atomized."))
3112 proutn(_("Mr. Spock takes command of the "))
3115 prout(_("joins the Romulans, reigning terror on the Federation."))
3116 elif ifin == FSTRACTOR:
3117 prout(_("The shuttle craft Galileo is also caught,"))
3118 prout(_("and breaks up under the strain."))
3120 prout(_("Your debris is scattered for millions of miles."))
3121 proutn(_("Without your leadership, the "))
3123 prout(_(" is destroyed."))
3125 prout(_("The mutants attack and kill Spock."))
3126 prout(_("Your ship is captured by Klingons, and"))
3127 prout(_("your crew is put on display in a Klingon zoo."))
3128 elif ifin == FTRIBBLE:
3129 prout(_("Tribbles consume all remaining water,"))
3130 prout(_("food, and oxygen on your ship."))
3132 prout(_("You die of thirst, starvation, and asphyxiation."))
3133 prout(_("Your starship is a derelict in space."))
3135 prout(_("Your ship is drawn to the center of the black hole."))
3136 prout(_("You are crushed into extremely dense matter."))
3138 prout(_("Your last crew member has died."))
3139 if game.ship == IHF:
3141 elif game.ship == IHE:
3144 if (game.state.remkl + game.state.remcom + game.state.nscrem) != 0:
3145 goodies = game.state.remres/game.inresor
3146 baddies = (game.state.remkl + 2.0*game.state.remcom)/(game.inkling+2.0*game.incom)
3147 if goodies/baddies >= 1.0+0.5*Rand():
3148 prout(_("As a result of your actions, a treaty with the Klingon"))
3149 prout(_("Empire has been signed. The terms of the treaty are"))
3150 if goodies/baddies >= 3.0+Rand():
3151 prout(_("favorable to the Federation."))
3153 prout(_("Congratulations!"))
3155 prout(_("highly unfavorable to the Federation."))
3157 prout(_("The Federation will be destroyed."))
3159 prout(_("Since you took the last Klingon with you, you are a"))
3160 prout(_("martyr and a hero. Someday maybe they'll erect a"))
3161 prout(_("statue in your memory. Rest in peace, and try not"))
3162 prout(_("to think about pigeons."))
3167 # compute player's score
3168 timused = game.state.date - game.indate
3171 if (timused == 0 or (game.state.remkl + game.state.remcom + game.state.nscrem) != 0) and timused < 5.0:
3173 perdate = killrate()
3174 ithperd = 500*perdate + 0.5
3177 iwon = 100*game.skill
3178 if game.ship == IHE:
3180 elif game.ship == IHF:
3184 if not game.gamewon:
3185 game.state.nromrem = 0 # None captured if no win
3186 iscore = 10*(game.inkling - game.state.remkl) \
3187 + 50*(game.incom - game.state.remcom) \
3189 + 20*(game.inrom - game.state.nromrem) \
3190 + 200*(game.inscom - game.state.nscrem) \
3191 - game.state.nromrem \
3196 prout(_("Your score --"))
3197 if game.inrom - game.state.nromrem:
3198 prout(_("%6d Romulans destroyed %5d") %
3199 (game.inrom - game.state.nromrem, 20*(game.inrom - game.state.nromrem)))
3200 if game.state.nromrem:
3201 prout(_("%6d Romulans captured %5d") %
3202 (game.state.nromrem, game.state.nromrem))
3203 if game.inkling - game.state.remkl:
3204 prout(_("%6d ordinary Klingons destroyed %5d") %
3205 (game.inkling - game.state.remkl, 10*(game.inkling - game.state.remkl)))
3206 if game.incom - game.state.remcom:
3207 prout(_("%6d Klingon commanders destroyed %5d") %
3208 (game.incom - game.state.remcom, 50*(game.incom - game.state.remcom)))
3209 if game.inscom - game.state.nscrem:
3210 prout(_("%6d Super-Commander destroyed %5d") %
3211 (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem)))
3213 prout(_("%6.2f Klingons per stardate %5d") %
3215 if game.state.starkl:
3216 prout(_("%6d stars destroyed by your action %5d") %
3217 (game.state.starkl, -5*game.state.starkl))
3218 if game.state.nplankl:
3219 prout(_("%6d planets destroyed by your action %5d") %
3220 (game.state.nplankl, -10*game.state.nplankl))
3221 if (game.options & OPTION_WORLDS) and game.state.nworldkl:
3222 prout(_("%6d inhabited planets destroyed by your action %5d") %
3223 (game.state.nplankl, -300*game.state.nworldkl))
3224 if game.state.basekl:
3225 prout(_("%6d bases destroyed by your action %5d") %
3226 (game.state.basekl, -100*game.state.basekl))
3228 prout(_("%6d calls for help from starbase %5d") %
3229 (game.nhelp, -45*game.nhelp))
3231 prout(_("%6d casualties incurred %5d") %
3232 (game.casual, -game.casual))
3234 prout(_("%6d crew abandoned in space %5d") %
3235 (game.abandoned, -3*game.abandoned))
3237 prout(_("%6d ship(s) lost or destroyed %5d") %
3238 (klship, -100*klship))
3240 prout(_("Penalty for getting yourself killed -200"))
3242 proutn(_("Bonus for winning "))
3243 if game.skill == SKILL_NOVICE: proutn(_("Novice game "))
3244 elif game.skill == SKILL_FAIR: proutn(_("Fair game "))
3245 elif game.skill == SKILL_GOOD: proutn(_("Good game "))
3246 elif game.skill == SKILL_EXPERT: proutn(_("Expert game "))
3247 elif game.skill == SKILL_EMERITUS: proutn(_("Emeritus game"))
3248 prout(" %5d" % iwon)
3250 prout(_("TOTAL SCORE %5d") % iscore)
3253 # emit winner's commemmorative plaque
3256 proutn(_("File or device name for your plaque: "))
3257 cgetline(winner, sizeof(winner))
3259 fp = open(winner, "w")
3262 prout(_("Invalid name."))
3264 proutn(_("Enter name to go on plaque (up to 30 characters): "))
3265 cgetline(winner, sizeof(winner))
3266 # The 38 below must be 64 for 132-column paper
3267 nskip = 38 - len(winner)/2
3269 fp.write("\n\n\n\n")
3270 # --------DRAW ENTERPRISE PICTURE.
3271 fp.write(" EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" )
3272 fp.write(" EEE E : : : E\n" )
3273 fp.write(" EE EEE E : : NCC-1701 : E\n")
3274 fp.write("EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEE : : : E\n")
3275 fp.write(" E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n")
3276 fp.write(" EEEEEEEEE EEEEEEEEEEEEE E E\n")
3277 fp.write(" EEEEEEE EEEEE E E E E\n")
3278 fp.write(" EEE E E E E\n")
3279 fp.write(" E E E E\n")
3280 fp.write(" EEEEEEEEEEEEE E E\n")
3281 fp.write(" EEE : EEEEEEE EEEEEEEE\n")
3282 fp.write(" :E : EEEE E\n")
3283 fp.write(" .-E -:----- E\n")
3284 fp.write(" :E : E\n")
3285 fp.write(" EE : EEEEEEEE\n")
3286 fp.write(" EEEEEEEEEEEEEEEEEEEEEEE\n")
3288 fp.write(_(" U. S. S. ENTERPRISE\n"))
3289 fp.write("\n\n\n\n")
3290 fp.write(_(" For demonstrating outstanding ability as a starship captain\n"))
3292 fp.write(_(" Starfleet Command bestows to you\n"))
3294 fp.write("%*s%s\n\n" % (nskip, "", winner))
3295 fp.write(_(" the rank of\n\n"))
3296 fp.write(_(" \"Commodore Emeritus\"\n\n"))
3298 if game.skill == SKILL_EXPERT:
3299 fp.write(_(" Expert level\n\n"))
3300 elif game.skill == SKILL_EMERITUS:
3301 fp.write(_("Emeritus level\n\n"))
3303 fp.write(_(" Cheat level\n\n"))
3304 timestring = ctime()
3305 fp.write(_(" This day of %.6s %.4s, %.8s\n\n") %
3306 (timestring+4, timestring+20, timestring+11))
3307 fp.write(_(" Your score: %d\n\n") % iscore)
3308 fp.write(_(" Klingons per stardate: %.2f\n") % perdate)
3311 # Code from io.c begins here
3313 rows = linecount = 0 # for paging
3315 fullscreen_window = None
3316 srscan_window = None
3317 report_window = None
3318 status_window = None
3319 lrscan_window = None
3320 message_window = None
3321 prompt_window = None
3324 "wrap up, either normally or due to signal"
3325 if game.options & OPTION_CURSES:
3338 #setlocale(LC_ALL, "")
3339 #bindtextdomain(PACKAGE, LOCALEDIR)
3340 #textdomain(PACKAGE)
3341 if atexit.register(outro):
3342 sys.stderr.write("Unable to register outro(), exiting...\n")
3344 if not (game.options & OPTION_CURSES):
3345 ln_env = os.getenv("LINES")
3351 stdscr = curses.initscr()
3356 curses.start_color()
3357 curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, curses.COLOR_BLACK)
3358 curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, curses.COLOR_BLACK)
3359 curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, curses.COLOR_BLACK)
3360 curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, curses.COLOR_BLACK)
3361 curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, curses.COLOR_BLACK)
3362 curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, curses.COLOR_BLACK)
3363 curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, curses.COLOR_BLACK)
3364 curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, curses.COLOR_BLACK)
3366 global fullscreen_window, srscan_window, report_window, status_window
3367 global lrscan_window, message_window, prompt_window
3368 fullscreen_window = stdscr
3369 srscan_window = curses.newwin(12, 25, 0, 0)
3370 report_window = curses.newwin(11, 0, 1, 25)
3371 status_window = curses.newwin(10, 0, 1, 39)
3372 lrscan_window = curses.newwin(5, 0, 0, 64)
3373 message_window = curses.newwin(0, 0, 12, 0)
3374 prompt_window = curses.newwin(1, 0, rows-2, 0)
3375 message_window.scrollok(True)
3376 setwnd(fullscreen_window)
3381 "wait for user action -- OK to do nothing if on a TTY"
3382 if game.options & OPTION_CURSES:
3387 if game.skill > SKILL_FAIR:
3388 prouts(_("[ANOUNCEMENT ARRIVING...]"))
3390 prouts(_("[IMPORTANT ANNOUNCEMENT ARRIVING -- PRESS ENTER TO CONTINUE]"))
3394 if game.skill > SKILL_FAIR:
3395 prompt = _("[CONTINUE?]")
3397 prompt = _("[PRESS ENTER TO CONTINUE]")
3399 if game.options & OPTION_CURSES:
3401 setwnd(prompt_window)
3402 prompt_window.wclear()
3403 prompt_window.addstr(prompt)
3404 prompt_window.getstr()
3405 prompt_window.clear()
3406 prompt_window.refresh()
3407 setwnd(message_window)
3413 for j in range(0, rows):
3418 "Skip i lines. Pause game if this would cause a scrolling event."
3419 while dummy in range(i):
3420 if game.options & OPTION_CURSES:
3421 (y, x) = curwnd.getyx()
3422 (my, mx) = curwnd.getmaxyx()
3423 if curwnd == message_window and y >= my - 3:
3431 if linecount >= rows:
3437 "Utter a line with no following line feed."
3438 if game.options & OPTION_CURSES:
3451 curses.delay_output(30)
3453 if game.options & OPTION_CURSES:
3457 curses.delay_output(300)
3459 def cgetline(line, max):
3460 "Get a line of input."
3461 if game.options & OPTION_CURSES:
3462 line = curwnd.getstr() + "\n"
3465 if replayfp and not replayfp.closed:
3466 line = replayfp.readline()
3468 sys.stdin.readline()
3473 "Change windows -- OK for this to be a no-op in tty mode."
3474 if game.options & OPTION_CURSES:
3476 curses.curs_set(wnd == fullscreen_window or wnd == message_window or wnd == prompt_window)
3479 "Clear to end of line -- can be a no-op in tty mode"
3480 if game.options & OPTION_CURSES:
3485 "Clear screen -- can be a no-op in tty mode."
3487 if game.options & OPTION_CURSES:
3493 def textcolor(color):
3494 "Set the current text color"
3495 if game.options & OPTION_CURSES:
3496 if color == DEFAULT:
3498 elif color == BLACK:
3499 curwnd.attron(curses.COLOR_PAIR(curses.COLOR_BLACK))
3501 curwnd.attron(curses.COLOR_PAIR(curses.COLOR_BLUE))
3502 elif color == GREEN:
3503 curwnd.attron(curses.COLOR_PAIR(curses.COLOR_GREEN))
3505 curwnd.attron(curses.COLOR_PAIR(curses.COLOR_CYAN))
3507 curwnd.attron(curses.COLOR_PAIR(curses.COLOR_RED))
3508 elif color == MAGENTA:
3509 curwnd.attron(curses.COLOR_PAIR(curses.COLOR_MAGENTA))
3510 elif color == BROWN:
3511 curwnd.attron(curses.COLOR_PAIR(curses.COLOR_YELLOW))
3512 elif color == LIGHTGRAY:
3513 curwnd.attron(curses.COLOR_PAIR(curses.COLOR_WHITE))
3514 elif color == DARKGRAY:
3515 curwnd.attron(curses.COLOR_PAIR(curses.COLOR_BLACK) | curses.A_BOLD)
3516 elif color == LIGHTBLUE:
3517 curwnd.attron(curses.COLOR_PAIR(curses.COLOR_BLUE) | curses.A_BOLD)
3518 elif color == LIGHTGREEN:
3519 curwnd.attron(curses.COLOR_PAIR(curses.COLOR_GREEN) | curses.A_BOLD)
3520 elif color == LIGHTCYAN:
3521 curwnd.attron(curses.COLOR_PAIR(curses.COLOR_CYAN) | curses.A_BOLD)
3522 elif color == LIGHTRED:
3523 curwnd.attron(curses.COLOR_PAIR(curses.COLOR_RED) | curses.A_BOLD)
3524 elif color == LIGHTMAGENTA:
3525 curwnd.attron(curses.COLOR_PAIR(curses.COLOR_MAGENTA) | curses.A_BOLD)
3526 elif color == YELLOW:
3527 curwnd.attron(curses.COLOR_PAIR(curses.COLOR_YELLOW) | curses.A_BOLD)
3528 elif color == WHITE:
3529 curwnd.attron(curses.COLOR_PAIR(curses.COLOR_WHITE) | curses.A_BOLD)
3532 "Set highlight video, if this is reasonable."
3533 if game.options & OPTION_CURSES:
3534 curwnd.attron(curses.A_REVERSE)
3536 def commandhook(cmd, before):
3540 # Things past this point have policy implications.
3544 "Hook to be called after moving to redraw maps."
3545 if game.options & OPTION_CURSES:
3548 setwnd(srscan_window)
3552 setwnd(status_window)
3553 status_window.clear()
3554 status_window.move(0, 0)
3555 setwnd(report_window)
3556 report_window.clear()
3557 report_window.move(0, 0)
3559 setwnd(lrscan_window)
3560 lrscan_window.clear()
3561 lrscan_window.move(0, 0)
3564 def put_srscan_sym(w, sym):
3565 "Emit symbol for short-range scan."
3566 srscan_window.move(w.x+1, w.y*2+2)
3567 srscan_window.addch(sym)
3568 srscan_window.refresh()
3571 "Enemy fall down, go boom."
3572 if game.options & OPTION_CURSES:
3574 setwnd(srscan_window)
3575 srscan_window.attron(curses.A_REVERSE)
3576 put_srscan_sym(w, game.quad[w.x][w.y])
3580 srscan_window.attroff(curses.A_REVERSE)
3581 put_srscan_sym(w, game.quad[w.x][w.y])
3582 curses.delay_output(500)
3583 setwnd(message_window)
3586 "Sound and visual effects for teleportation."
3587 if game.options & OPTION_CURSES:
3589 setwnd(message_window)
3591 prouts(" . . . . . ")
3592 if game.options & OPTION_CURSES:
3593 #curses.delay_output(1000)
3597 def tracktorpedo(w, l, i, n, iquad):
3598 "Torpedo-track animation."
3599 if not game.options & OPTION_CURSES:
3603 proutn(_("Track for torpedo number %d- ") % i)
3606 proutn(_("Torpedo track- "))
3609 proutn("%d - %d " % (w.x, w.y))
3611 if not damaged(DSRSENS) or game.condition=="docked":
3612 if i != 1 and l == 1:
3614 curses.delay_output(400)
3615 if (iquad==IHDOT) or (iquad==IHBLANK):
3616 put_srscan_sym(w, '+')
3618 #curses.delay_output(100)
3620 put_srscan_sym(w, iquad)
3622 curwnd.attron(curses.A_REVERSE)
3623 put_srscan_sym(w, iquad)
3625 #curses.delay_output(1000)
3627 curwnd.attroff(curses.A_REVERSE)
3628 put_srscan_sym(w, iquad)
3630 proutn("%d - %d " % (w.x, w.y))
3633 "Display the current galaxy chart."
3634 if game.options & OPTION_CURSES:
3635 setwnd(message_window)
3636 message_window.clear()
3638 if game.options & OPTION_TTY:
3643 def prstat(txt, data):
3645 if game.options & OPTION_CURSES:
3647 setwnd(status_window)
3649 proutn(" " * NSYM - len(tx))
3652 if game.options & OPTION_CURSES:
3653 setwnd(report_window)
3655 # Code from moving.c begins here
3657 def imove(novapush):
3658 # movement execution for warp, impulse, supernova, and tractor-beam events
3659 w = coord(); final = coord()
3662 def no_quad_change():
3663 # No quadrant change -- compute new avg enemy distances
3664 game.quad[game.sector.x][game.sector.y] = game.ship
3666 for m in range(1, game.nenhere+1):
3667 finald = distance(w, game.ks[m])
3668 game.kavgd[m] = 0.5 * (finald+game.kdist[m])
3669 game.kdist[m] = finald
3671 if not game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
3673 for m in range(1, game.nenhere+1):
3674 game.kavgd[m] = game.kdist[m]
3677 setwnd(message_window)
3681 prout(_("Helmsman Sulu- \"Leaving standard orbit.\""))
3682 game.inorbit = False
3684 angle = ((15.0 - game.direc) * 0.5235988)
3685 deltax = -math.sin(angle)
3686 deltay = math.cos(angle)
3687 if math.fabs(deltax) > math.fabs(deltay):
3688 bigger = math.fabs(deltax)
3690 bigger = math.fabs(deltay)
3695 # If tractor beam is to occur, don't move full distance
3696 if game.state.date+game.optime >= scheduled(FTBEAM):
3698 game.condition = "red"
3699 game.dist = game.dist*(scheduled(FTBEAM)-game.state.date)/game.optime + 0.1
3700 game.optime = scheduled(FTBEAM) - game.state.date + 1e-5
3701 # Move within the quadrant
3702 game.quad[game.sector.x][game.sector.y] = IHDOT
3705 n = 10.0*game.dist*bigger+0.5
3708 for m in range(1, n+1):
3713 if not VALID_SECTOR(w.x, w.y):
3714 # Leaving quadrant -- allow final enemy attack
3715 # Don't do it if being pushed by Nova
3716 if game.nenhere != 0 and not novapush:
3718 for m in range(1, game.nenhere+1):
3719 finald = distance(w, game.ks[m])
3720 game.kavgd[m] = 0.5 * (finald + game.kdist[m])
3722 # Stas Sergeev added the condition
3723 # that attacks only happen if Klingons
3724 # are present and your skill is good.
3726 if game.skill > SKILL_GOOD and game.klhere > 0 and not game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
3730 # compute final position -- new quadrant and sector
3731 x = QUADSIZE*(game.quadrant.x-1)+game.sector.x
3732 y = QUADSIZE*(game.quadrant.y-1)+game.sector.y
3733 w.x = x+10.0*game.dist*bigger*deltax+0.5
3734 w.y = y+10.0*game.dist*bigger*deltay+0.5
3735 # check for edge of galaxy
3745 if w.x > GALSIZE*QUADSIZE:
3746 w.x = (GALSIZE*QUADSIZE*2)+1 - w.x
3748 if w.y > GALSIZE*QUADSIZE:
3749 w.y = (GALSIZE*QUADSIZE*2)+1 - w.y
3758 if game.nkinks == 3:
3759 # Three strikes -- you're out!
3763 prout(_("YOU HAVE ATTEMPTED TO CROSS THE NEGATIVE ENERGY BARRIER"))
3764 prout(_("AT THE EDGE OF THE GALAXY. THE THIRD TIME YOU TRY THIS,"))
3765 prout(_("YOU WILL BE DESTROYED."))
3766 # Compute final position in new quadrant
3767 if trbeam: # Don't bother if we are to be beamed
3769 game.quadrant.x = (w.x+(QUADSIZE-1))/QUADSIZE
3770 game.quadrant.y = (w.y+(QUADSIZE-1))/QUADSIZE
3771 game.sector.x = w.x - QUADSIZE*(game.quadrant.x-1)
3772 game.sector.y = w.y - QUADSIZE*(game.quadrant.y-1)
3774 prout(_("Entering Quadrant %s.") % game.quadrant)
3775 game.quad[game.sector.x][game.sector.y] = game.ship
3777 if game.skill>SKILL_NOVICE:
3780 iquad = game.quad[w.x][w.y]
3782 # object encountered in flight path
3783 stopegy = 50.0*game.dist/game.optime
3784 game.dist = distance(game.sector, w) / (QUADSIZE * 1.0)
3785 if iquad in (IHT. IHK, OHC, IHS, IHR, IHQUEST):
3787 ram(False, iquad, game.sector)
3789 elif iquad == IHBLANK:
3791 prouts(_("***RED ALERT! RED ALERT!"))
3795 proutn(_(" pulled into black hole at Sector %s") % w)
3797 # Getting pulled into a black hole was certain
3798 # death in Almy's original. Stas Sergeev added a
3799 # possibility that you'll get timewarped instead.
3802 for m in range(0, NDEVICES):
3803 if game.damage[m]>0:
3805 probf=math.pow(1.4,(game.energy+game.shield)/5000.0-1.0)*math.pow(1.3,1.0/(n+1)-1.0)
3806 if (game.options & OPTION_BLKHOLE) and Rand()>probf:
3816 proutn(_(" encounters Tholian web at %s;") % w)
3818 proutn(_(" blocked by object at %s;") % w)
3819 proutn(_("Emergency stop required "))
3820 prout(_("%2d units of energy.") % int(stopegy))
3821 game.energy -= stopegy
3822 final.x = x-deltax+0.5
3823 final.y = y-deltay+0.5
3825 if game.energy <= 0:
3831 game.dist = distance(game.sector, w) / (QUADSIZE * 1.0)
3838 # dock our ship at a starbase
3840 if game.condition == "docked" and verbose:
3841 prout(_("Already docked."))
3844 prout(_("You must first leave standard orbit."))
3846 if not is_valid(game.base) or abs(game.sector.x-game.base.x) > 1 or abs(game.sector.y-game.base.y) > 1:
3848 prout(_(" not adjacent to base."))
3850 game.condition = "docked"
3854 if game.energy < game.inenrg:
3855 game.energy = game.inenrg
3856 game.shield = game.inshld
3857 game.torps = game.intorps
3858 game.lsupres = game.inlsr
3859 game.state.crew = FULLCREW
3860 if not damaged(DRADIO) and \
3861 ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit):
3862 # get attack report from base
3863 prout(_("Lt. Uhura- \"Captain, an important message from the starbase:\""))
3868 # This program originally required input in terms of a (clock)
3869 # direction and distance. Somewhere in history, it was changed to
3870 # cartesian coordinates. So we need to convert. Probably
3871 # "manual" input should still be done this way -- it's a real
3872 # pain if the computer isn't working! Manual mode is still confusing
3873 # because it involves giving x and y motions, yet the coordinates
3874 # are always displayed y - x, where +y is downward!
3877 def getcd(isprobe, akey):
3878 # get course and distance
3879 irowq=game.quadrant.x; icolq=game.quadrant.y; key=0
3880 navmode = "unspecified"
3885 # Get course direction and distance. If user types bad values, return
3886 # with DIREC = -1.0.
3889 if game.landed and not isprobe:
3890 prout(_("Dummy! You can't leave standard orbit until you"))
3891 proutn(_("are back aboard the ship."))
3894 while navmode == "unspecified":
3895 if damaged(DNAVSYS):
3897 prout(_("Computer damaged; manual navigation only"))
3899 prout(_("Computer damaged; manual movement only"))
3904 if isprobe and akey != -1:
3905 # For probe launch, use pre-scanned value first time
3912 proutn(_("Manual or automatic- "))
3915 elif key == IHALPHA:
3920 elif isit("automatic"):
3921 navmode = "automatic"
3930 prout(_("(Manual navigation assumed.)"))
3932 prout(_("(Manual movement assumed.)"))
3936 if navmode == "automatic":
3939 proutn(_("Target quadrant or quadrant§or- "))
3941 proutn(_("Destination sector or quadrant§or- "))
3957 # both quadrant and sector specified
3971 # only quadrant specified -- go to center of dest quad
3979 if not VALID_QUADRANT(icolq,irowq) or not VALID_SECTOR(incr.x,incr.y):
3986 prout(_("Helmsman Sulu- \"Course locked in for Sector %s.\"") % incr)
3988 prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
3989 deltax = icolq - game.quadrant.y + 0.1*(incr.x-game.sector.y)
3990 deltay = game.quadrant.x - irowq + 0.1*(game.sector.x-incr.y)
3993 proutn(_("X and Y displacements- "))
4007 # Check for zero movement
4008 if deltax == 0 and deltay == 0:
4011 if itemp == "verbose" and not isprobe:
4013 prout(_("Helmsman Sulu- \"Aye, Sir.\""))
4014 game.dist = math.sqrt(deltax*deltax + deltay*deltay)
4015 game.direc = math.atan2(deltax, deltay)*1.90985932
4016 if game.direc < 0.0:
4022 # move under impulse power
4024 if damaged(DIMPULS):
4027 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4029 if game.energy > 30.0:
4031 if game.direc == -1.0:
4033 power = 20.0 + 100.0*game.dist
4037 if power >= game.energy:
4038 # Insufficient power for trip
4040 prout(_("First Officer Spock- \"Captain, the impulse engines"))
4041 prout(_("require 20.0 units to engage, plus 100.0 units per"))
4042 if game.energy > 30:
4043 proutn(_("quadrant. We can go, therefore, a maximum of %d") %
4044 int(0.01 * (game.energy-20.0)-0.05))
4045 prout(_(" quadrants.\""))
4047 prout(_("quadrant. They are, therefore, useless.\""))
4050 # Make sure enough time is left for the trip
4051 game.optime = game.dist/0.095
4052 if game.optime >= game.state.remtime:
4053 prout(_("First Officer Spock- \"Captain, our speed under impulse"))
4054 prout(_("power is only 0.95 sectors per stardate. Are you sure"))
4055 proutn(_("we dare spend the time?\" "))
4058 # Activate impulse engines and pay the cost
4063 power = 20.0 + 100.0*game.dist
4064 game.energy -= power
4065 game.optime = game.dist/0.095
4066 if game.energy <= 0:
4071 # move under warp drive
4072 blooey = False; twarp = False
4073 if not timewarp: # Not WARPX entry
4075 if game.damage[DWARPEN] > 10.0:
4078 prout(_("Engineer Scott- \"The impulse engines are damaged, Sir.\""))
4080 if damaged(DWARPEN) and game.warpfac > 4.0:
4083 prout(_("Engineer Scott- \"Sorry, Captain. Until this damage"))
4084 prout(_(" is repaired, I can only give you warp 4.\""))
4087 # Read in course and distance
4089 if game.direc == -1.0:
4092 # Make sure starship has enough energy for the trip
4093 power = (game.dist+0.05)*game.warpfac*game.warpfac*game.warpfac*(game.shldup+1)
4094 if power >= game.energy:
4095 # Insufficient power for trip
4098 prout(_("Engineering to bridge--"))
4099 if not game.shldup or 0.5*power > game.energy:
4100 iwarp = math.pow((game.energy/(game.dist+0.05)), 0.333333333)
4102 prout(_("We can't do it, Captain. We don't have enough energy."))
4104 proutn(_("We don't have enough energy, but we could do it at warp %d") % iwarp)
4107 prout(_("if you'll lower the shields."))
4111 prout(_("We haven't the energy to go that far with the shields up."))
4114 # Make sure enough time is left for the trip
4115 game.optime = 10.0*game.dist/game.wfacsq
4116 if game.optime >= 0.8*game.state.remtime:
4118 prout(_("First Officer Spock- \"Captain, I compute that such"))
4119 proutn(_(" a trip would require approximately %2.0f") %
4120 (100.0*game.optime/game.state.remtime))
4121 prout(_(" percent of our"))
4122 proutn(_(" remaining time. Are you sure this is wise?\" "))
4128 if game.warpfac > 6.0:
4129 # Decide if engine damage will occur
4130 prob = game.dist*(6.0-game.warpfac)*(6.0-game.warpfac)/66.666666666
4133 game.dist = Rand()*game.dist
4134 # Decide if time warp will occur
4135 if 0.5*game.dist*math.pow(7.0,game.warpfac-10.0) > Rand():
4137 if idebug and game.warpfac==10 and not twarp:
4139 proutn("=== Force time warp? ")
4143 # If time warp or engine damage, check path
4144 # If it is obstructed, don't do warp or damage
4145 angle = ((15.0-game.direc)*0.5235998)
4146 deltax = -math.sin(angle)
4147 deltay = math.cos(angle)
4148 if math.fabs(deltax) > math.fabs(deltay):
4149 bigger = math.fabs(deltax)
4151 bigger = math.fabs(deltay)
4155 n = 10.0 * game.dist * bigger +0.5
4158 for l in range(1, n+1):
4163 if not VALID_SECTOR(ix, iy):
4165 if game.quad[ix][iy] != IHDOT:
4170 # Activate Warp Engines and pay the cost
4174 game.energy -= game.dist*game.warpfac*game.warpfac*game.warpfac*(game.shldup+1)
4175 if game.energy <= 0:
4177 game.optime = 10.0*game.dist/game.wfacsq
4181 game.damage[DWARPEN] = game.damfac*(3.0*Rand()+1.0)
4183 prout(_("Engineering to bridge--"))
4184 prout(_(" Scott here. The warp engines are damaged."))
4185 prout(_(" We'll have to reduce speed to warp 4."))
4190 # change the warp factor
4196 proutn(_("Warp factor- "))
4201 if game.damage[DWARPEN] > 10.0:
4202 prout(_("Warp engines inoperative."))
4204 if damaged(DWARPEN) and aaitem > 4.0:
4205 prout(_("Engineer Scott- \"I'm doing my best, Captain,"))
4206 prout(_(" but right now we can only go warp 4.\""))
4209 prout(_("Helmsman Sulu- \"Our top speed is warp 10, Captain.\""))
4212 prout(_("Helmsman Sulu- \"We can't go below warp 1, Captain.\""))
4214 oldfac = game.warpfac
4215 game.warpfac = aaitem
4216 game.wfacsq=game.warpfac*game.warpfac
4217 if game.warpfac <= oldfac or game.warpfac <= 6.0:
4218 prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
4221 if game.warpfac < 8.00:
4222 prout(_("Engineer Scott- \"Aye, but our maximum safe speed is warp 6.\""))
4224 if game.warpfac == 10.0:
4225 prout(_("Engineer Scott- \"Aye, Captain, we'll try it.\""))
4227 prout(_("Engineer Scott- \"Aye, Captain, but our engines may not take it.\""))
4231 # cope with being tossed out of quadrant by supernova or yanked by beam
4234 # is captain on planet?
4236 if damaged(DTRANSP):
4239 prout(_("Scotty rushes to the transporter controls."))
4241 prout(_("But with the shields up it's hopeless."))
4243 prouts(_("His desperate attempt to rescue you . . ."))
4248 prout(_("SUCCEEDS!"))
4251 proutn(_("The crystals mined were "))
4260 # Check to see if captain in shuttle craft
4266 # Inform captain of attempt to reach safety
4270 prouts(_("***RED ALERT! RED ALERT!"))
4274 prout(_(" has stopped in a quadrant containing"))
4275 prouts(_(" a supernova."))
4277 proutn(_("***Emergency automatic override attempts to hurl "))
4280 prout(_("safely out of quadrant."))
4281 if not damaged(DRADIO):
4282 game.state.galaxy[game.quadrant.x][game.quadrant.y].charted = True
4283 # Try to use warp engines
4284 if damaged(DWARPEN):
4286 prout(_("Warp engines damaged."))
4289 game.warpfac = 6.0+2.0*Rand()
4290 game.wfacsq = game.warpfac * game.warpfac
4291 prout(_("Warp factor set to %d") % int(game.warpfac))
4292 power = 0.75*game.energy
4293 game.dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
4294 distreq = 1.4142+Rand()
4295 if distreq < game.dist:
4297 game.optime = 10.0*game.dist/game.wfacsq
4298 game.direc = 12.0*Rand() # How dumb!
4300 game.inorbit = False
4303 # This is bad news, we didn't leave quadrant.
4307 prout(_("Insufficient energy to leave quadrant."))
4310 # Repeat if another snova
4311 if not game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova:
4313 if (game.state.remkl + game.state.remcom + game.state.nscrem)==0:
4314 finish(FWON) # Snova killed remaining enemy.
4317 # let's do the time warp again
4318 prout(_("***TIME WARP ENTERED."))
4319 if game.state.snap and Rand() < 0.5:
4321 prout(_("You are traveling backwards in time %d stardates.") %
4322 int(game.state.date-game.snapsht.date))
4323 game.state = game.snapsht
4324 game.state.snap = False
4325 if game.state.remcom:
4326 schedule(FTBEAM, expran(game.intime/game.state.remcom))
4327 schedule(FBATTAK, expran(0.3*game.intime))
4328 schedule(FSNOVA, expran(0.5*game.intime))
4329 # next snapshot will be sooner
4330 schedule(FSNAP, expran(0.25*game.state.remtime))
4332 if game.state.nscrem:
4333 schedule(FSCMOVE, 0.2777)
4337 invalidate(game.battle)
4339 # Make sure Galileo is consistant -- Snapshot may have been taken
4340 # when on planet, which would give us two Galileos!
4342 for l in range(game.inplan):
4343 if game.state.planets[l].known == "shuttle_down":
4345 if game.iscraft == "onship" and game.ship==IHE:
4346 prout(_("Chekov- \"Security reports the Galileo has disappeared, Sir!"))
4347 game.iscraft = "offship"
4348 # Likewise, if in the original time the Galileo was abandoned, but
4349 # was on ship earlier, it would have vanished -- let's restore it.
4350 if game.iscraft == "offship" and not gotit and game.damage[DSHUTTL] >= 0.0:
4351 prout(_("Checkov- \"Security reports the Galileo has reappeared in the dock!\""))
4352 game.iscraft = "onship"
4354 # * There used to be code to do the actual reconstrction here,
4355 # * but the starchart is now part of the snapshotted galaxy state.
4357 prout(_("Spock has reconstructed a correct star chart from memory"))
4359 # Go forward in time
4360 game.optime = -0.5*game.intime*math.log(Rand())
4361 prout(_("You are traveling forward in time %d stardates.") % int(game.optime))
4362 # cheat to make sure no tractor beams occur during time warp
4363 postpone(FTBEAM, game.optime)
4364 game.damage[DRADIO] += game.optime
4366 events() # Stas Sergeev added this -- do pending events
4369 # launch deep-space probe
4370 # New code to launch a deep space probe
4371 if game.nprobes == 0:
4374 if game.ship == IHE:
4375 prout(_("Engineer Scott- \"We have no more deep space probes, Sir.\""))
4377 prout(_("Ye Faerie Queene has no deep space probes."))
4382 prout(_("Engineer Scott- \"The probe launcher is damaged, Sir.\""))
4384 if is_scheduled(FDSPROB):
4387 if damaged(DRADIO) and game.condition != "docked":
4388 prout(_("Spock- \"Records show the previous probe has not yet"))
4389 prout(_(" reached its destination.\""))
4391 prout(_("Uhura- \"The previous probe is still reporting data, Sir.\""))
4396 # slow mode, so let Kirk know how many probes there are left
4397 if game.nprobes == 1:
4398 prout(_("1 probe left."))
4400 prout(_("%d probes left") % game.nprobes)
4401 proutn(_("Are you sure you want to fire a probe? "))
4405 game.isarmed = False
4406 if key == IHALPHA and citem == "armed":
4410 proutn(_("Arm NOVAMAX warhead? "))
4413 if game.direc == -1.0:
4416 angle = ((15.0 - game.direc) * 0.5235988)
4417 game.probeinx = -math.sin(angle)
4418 game.probeiny = math.cos(angle)
4419 if math.fabs(game.probeinx) > math.fabs(game.probeiny):
4420 bigger = math.fabs(game.probeinx)
4422 bigger = math.fabs(game.probeiny)
4424 game.probeiny /= bigger
4425 game.probeinx /= bigger
4426 game.proben = 10.0*game.dist*bigger +0.5
4427 game.probex = game.quadrant.x*QUADSIZE + game.sector.x - 1 # We will use better packing than original
4428 game.probey = game.quadrant.y*QUADSIZE + game.sector.y - 1
4429 game.probec = game.quadrant
4430 schedule(FDSPROB, 0.01) # Time to move one sector
4431 prout(_("Ensign Chekov- \"The deep space probe is launched, Captain.\""))
4435 # Here's how the mayday code works:
4437 # First, the closest starbase is selected. If there is a a starbase
4438 # in your own quadrant, you are in good shape. This distance takes
4439 # quadrant distances into account only.
4441 # A magic number is computed based on the distance which acts as the
4442 # probability that you will be rematerialized. You get three tries.
4444 # When it is determined that you should be able to be rematerialized
4445 # (i.e., when the probability thing mentioned above comes up
4446 # positive), you are put into that quadrant (anywhere). Then, we try
4447 # to see if there is a spot adjacent to the star- base. If not, you
4448 # can't be rematerialized!!! Otherwise, it drops you there. It only
4449 # tries five times to find a spot to drop you. After that, it's your
4453 # yell for help from nearest starbase
4454 # There's more than one way to move in this game!
4458 # Test for conditions which prevent calling for help
4459 if game.condition == "docked":
4460 prout(_("Lt. Uhura- \"But Captain, we're already docked.\""))
4463 prout(_("Subspace radio damaged."))
4465 if game.state.rembase==0:
4466 prout(_("Lt. Uhura- \"Captain, I'm not getting any response from Starbase.\""))
4469 proutn(_("You must be aboard the "))
4473 # OK -- call for help from nearest starbase
4476 # There's one in this quadrant
4477 ddist = distance(game.base, game.sector)
4480 for m in range(1, game.state.rembase+1):
4481 xdist = QUADSIZE * distance(game.state.baseq[m], game.quadrant)
4485 # Since starbase not in quadrant, set up new quadrant
4486 game.quadrant = game.state.baseq[line]
4488 # dematerialize starship
4489 game.quad[game.sector.x][game.sector.y]=IHDOT
4490 proutn(_("Starbase in Quadrant %s responds--") % game.quadrant)
4492 prout(_(" dematerializes."))
4494 for m in range(1, 5+1):
4495 ix = game.base.x+3.0*Rand()-1
4496 iy = game.base.y+3.0*Rand()-1
4497 if VALID_SECTOR(ix,iy) and game.quad[ix][iy]==IHDOT:
4498 # found one -- finish up
4502 if not is_valid(game.sector):
4503 prout(_("You have been lost in space..."))
4504 finish(FMATERIALIZE)
4506 # Give starbase three chances to rematerialize starship
4507 probf = math.pow((1.0 - math.pow(0.98,ddist)), 0.33333333)
4508 for m in range(1, 3+1):
4509 if m == 1: proutn(_("1st"))
4510 elif m == 2: proutn(_("2nd"))
4511 elif m == 3: proutn(_("3rd"))
4512 proutn(_(" attempt to re-materialize "))
4514 game.quad[ix][iy]=(IHMATER0,IHMATER1,IHMATER2)[m-1]
4520 curses.delay_output(500)
4523 game.quad[ix][iy]=IHQUEST
4526 setwnd(message_window)
4527 finish(FMATERIALIZE)
4529 game.quad[ix][iy]=game.ship
4531 prout(_("succeeds."))
4535 prout(_("Lt. Uhura- \"Captain, we made it!\""))
4537 # Abandon Ship (the BSD-Trek description)
4539 # The ship is abandoned. If your current ship is the Faire
4540 # Queene, or if your shuttlecraft is dead, you're out of
4541 # luck. You need the shuttlecraft in order for the captain
4542 # (that's you!!) to escape.
4544 # Your crew can beam to an inhabited starsystem in the
4545 # quadrant, if there is one and if the transporter is working.
4546 # If there is no inhabited starsystem, or if the transporter
4547 # is out, they are left to die in outer space.
4549 # If there are no starbases left, you are captured by the
4550 # Klingons, who torture you mercilessly. However, if there
4551 # is at least one starbase, you are returned to the
4552 # Federation in a prisoner of war exchange. Of course, this
4553 # can't happen unless you have taken some prisoners.
4558 if game.condition=="docked":
4560 prout(_("You cannot abandon Ye Faerie Queene."))
4563 # Must take shuttle craft to exit
4564 if game.damage[DSHUTTL]==-1:
4565 prout(_("Ye Faerie Queene has no shuttle craft."))
4567 if game.damage[DSHUTTL]<0:
4568 prout(_("Shuttle craft now serving Big Macs."))
4570 if game.damage[DSHUTTL]>0:
4571 prout(_("Shuttle craft damaged."))
4574 prout(_("You must be aboard the ship."))
4576 if game.iscraft != "onship":
4577 prout(_("Shuttle craft not currently available."))
4579 # Print abandon ship messages
4581 prouts(_("***ABANDON SHIP! ABANDON SHIP!"))
4583 prouts(_("***ALL HANDS ABANDON SHIP!"))
4585 prout(_("Captain and crew escape in shuttle craft."))
4586 if game.state.rembase==0:
4587 # Oops! no place to go...
4590 q = game.state.galaxy[game.quadrant.x][game.quadrant.y]
4592 if not (game.options & OPTION_WORLDS) and not damaged(DTRANSP):
4593 prout(_("Remainder of ship's complement beam down"))
4594 prout(_("to nearest habitable planet."))
4595 elif q.planet != NOPLANET and not damaged(DTRANSP):
4596 prout(_("Remainder of ship's complement beam down to %s.") %
4599 prout(_("Entire crew of %d left to die in outer space.") %
4601 game.casual += game.state.crew
4602 game.abandoned += game.state.crew
4604 # If at least one base left, give 'em the Faerie Queene
4606 game.icrystl = False # crystals are lost
4607 game.nprobes = 0 # No probes
4608 prout(_("You are captured by Klingons and released to"))
4609 prout(_("the Federation in a prisoner-of-war exchange."))
4610 nb = Rand()*game.state.rembase+1
4611 # Set up quadrant and position FQ adjacient to base
4612 if not same(game.quadrant, game.state.baseq[nb]):
4613 game.quadrant = game.state.baseq[nb]
4614 game.sector.x = game.sector.y = 5
4617 # position next to base by trial and error
4618 game.quad[game.sector.x][game.sector.y] = IHDOT
4619 for l in range(1, QUADSIZE+1):
4620 game.sector.x = 3.0*Rand() - 1.0 + game.base.x
4621 game.sector.y = 3.0*Rand() - 1.0 + game.base.y
4622 if VALID_SECTOR(game.sector.x, game.sector.y) and \
4623 game.quad[game.sector.x][game.sector.y] == IHDOT:
4626 break # found a spot
4627 game.sector.x=QUADSIZE/2
4628 game.sector.y=QUADSIZE/2
4630 # Get new commission
4631 game.quad[game.sector.x][game.sector.y] = game.ship = IHF
4632 game.state.crew = FULLCREW
4633 prout(_("Starfleet puts you in command of another ship,"))
4634 prout(_("the Faerie Queene, which is antiquated but,"))
4635 prout(_("still useable."))
4637 prout(_("The dilithium crystals have been moved."))
4639 game.iscraft = "offship" # Galileo disappears
4641 game.condition="docked"
4642 for l in range(0, NDEVICES):
4643 game.damage[l] = 0.0
4644 game.damage[DSHUTTL] = -1
4645 game.energy = game.inenrg = 3000.0
4646 game.shield = game.inshld = 1250.0
4647 game.torps = game.intorps = 6
4648 game.lsupres=game.inlsr=3.0