2 sst.py =-- Super Star Trek in Python
5 import os, sys, math, curses
7 SSTDOC = "/usr/share/doc/sst/sst.doc"
10 def _(str): return str
14 NINHAB = (GALSIZE * GALSIZE / 2)
16 PLNETMAX = (NINHAB + MAXUNINHAB)
18 BASEMAX = (GALSIZE * GALSIZE / 12)
21 FULLCREW = 428 # BSD Trek was 387, that's wrong
24 # These functions hide the difference between 0-origin and 1-origin addressing.
25 def VALID_QUADRANT(x, y): return ((x)>=1 and (x)<=GALSIZE and (y)>=1 and (y)<=GALSIZE)
26 def VALID_SECTOR(x, y): return ((x)>=1 and (x)<=QUADSIZE and (y)>=1 and (y)<=QUADSIZE)
28 def square(i): return ((i)*(i))
29 def distance(c1, c2): return math.sqrt(square(c1.x - c2.x) + square(c1.y - c2.y))
30 def invalidate(w): w.x = w.y = 0
31 def is_valid(w): return (w.x != 0 and w.y != 0)
34 def __init(self, x=None, y=None):
38 self.x = self.y = None
40 return self.x != None and self.y != None
41 def __eq__(self, other):
42 return self.x == other.y and self.x == other.y
43 def __add__(self, other):
44 return coord(self.x+self.x, self.y+self.y)
45 def __sub__(self, other):
46 return coord(self.x-self.x, self.y-self.y)
47 def distance(self, other):
48 return math.sqrt((self.x - other.x)**2 + (self.y - other.y)**2)
50 return coord(self.x / abs(x), self.y / abs(y));
54 return "%d - %d" % (self.x, self.y)
58 self.name = None # string-valued if inhabited
59 self.w = coord() # quadrant located
60 self.pclass = None # could be ""M", "N", "O", or "destroyed"
61 self.crystals = None # could be "mined", "present", "absent"
62 self.known = None # could be "unknown", "known", "shuttle_down"
64 # How to represent features
94 self.status = None # Could be "secure", "distressed", "enslaved"
104 self.snap = False # snapshot taken
105 self.crew = None # crew complement
106 self.remkl = None # remaining klingons
107 self.remcom = None # remaining commanders
108 self.nscrem = None # remaining super commanders
109 self.rembase = None # remaining bases
110 self.starkl = None # destroyed stars
111 self.basekl = None # destroyed bases
112 self.nromrem = None # Romulans remaining
113 self.nplankl = None # destroyed uninhabited planets
114 self.nworldkl = None # destroyed inhabited planets
115 self.planets = [] # Planet information
116 for i in range(PLNETMAX):
117 self.planets.append(planet())
118 self.date = None # stardate
119 self.remres = None # remaining resources
120 self.remtime = None # remaining time
121 self.baseq = [] # Base quadrant coordinates
122 for i in range(BASEMAX+1):
123 self.baseq.append(coord())
124 self.kcmdr = [] # Commander quadrant coordinates
125 for i in range(QUADSIZE+1):
126 self.kcmdr.append(coord())
127 self.kscmdr = coord() # Supercommander quadrant coordinates
128 self.galaxy = [] # The Galaxy (subscript 0 not used)
129 for i in range(GALSIZE+1):
130 self.chart.append([])
131 for j in range(GALSIZE+1):
132 self.galaxy[i].append(quadrant())
133 self.chart = [] # the starchart (subscript 0 not used)
134 for i in range(GALSIZE+1):
135 self.chart.append([])
136 for j in range(GALSIZE+1):
137 self.chart[i].append(page())
141 self.date = None # A real number
142 self.quadrant = None # A coord structure
145 OPTION_ALL = 0xffffffff
146 OPTION_TTY = 0x00000001 # old interface
147 OPTION_CURSES = 0x00000002 # new interface
148 OPTION_IOMODES = 0x00000003 # cover both interfaces
149 OPTION_PLANETS = 0x00000004 # planets and mining
150 OPTION_THOLIAN = 0x00000008 # Tholians and their webs
151 OPTION_THINGY = 0x00000010 # Space Thingy can shoot back
152 OPTION_PROBE = 0x00000020 # deep-space probes
153 OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart
154 OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise
155 OPTION_MVBADDY = 0x00000100 # more enemies can move
156 OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you
157 OPTION_BASE = 0x00000400 # bases have good shields
158 OPTION_WORLDS = 0x00000800 # logic for inhabited worlds
159 OPTION_PLAIN = 0x01000000 # user chose plain game
160 OPTION_ALMY = 0x02000000 # user chose Almy variant
179 NDEVICES= 16 # Number of devices
181 def damaged(dev): return (game.damage[dev] != 0.0)
183 # Define future events
184 FSPY = 0 # Spy event happens always (no future[] entry)
185 # can cause SC to tractor beam Enterprise
186 FSNOVA = 1 # Supernova
187 FTBEAM = 2 # Commander tractor beams Enterprise
188 FSNAP = 3 # Snapshot for time warp
189 FBATTAK = 4 # Commander attacks base
190 FCDBAS = 5 # Commander destroys base
191 FSCMOVE = 6 # Supercommander moves (might attack base)
192 FSCDBAS = 7 # Supercommander destroys base
193 FDSPROB = 8 # Move deep space probe
194 FDISTR = 9 # Emit distress call from an inhabited world
195 FENSLV = 10 # Inhabited word is enslaved */
196 FREPRO = 11 # Klingons build a ship in an enslaved system
200 # abstract out the event handling -- underlying data structures will change
201 # when we implement stateful events
203 def findevent(evtype): return game.future[evtype]
207 self.options = None # Game options
208 self.state = None # A snapshot structure
209 self.snapsht = None # Last snapshot taken for time-travel purposes
210 self.quad = [[IHDOT * (QUADSIZE+1)] * (QUADSIZE+1)] # contents of our quadrant
211 self.kpower = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)] # enemy energy levels
212 self.kdist = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)] # enemy distances
213 self.kavgd = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)] # average distances
214 self.damage = [0] * NDEVICES # damage encountered
215 self.future = [0.0] * NEVENTS # future events
216 for i in range(NEVENTS):
217 self.future.append(event())
218 self.passwd = None; # Self Destruct password
219 self.ks = [[None * (QUADSIZE+1)] * (QUADSIZE+1)] # enemy sector locations
220 self.quadrant = None # where we are in the large
221 self.sector = None # where we are in the small
222 self.tholian = None # coordinates of Tholian
223 self.base = None # position of base in current quadrant
224 self.battle = None # base coordinates being attacked
225 self.plnet = None # location of planet in quadrant
226 self.probec = None # current probe quadrant
227 self.gamewon = False # Finished!
228 self.ididit = False # action taken -- allows enemy to attack
229 self.alive = False # we are alive (not killed)
230 self.justin = False # just entered quadrant
231 self.shldup = False # shields are up
232 self.shldchg = False # shield is changing (affects efficiency)
233 self.comhere = False # commander here
234 self.ishere = False # super-commander in quadrant
235 self.iscate = False # super commander is here
236 self.ientesc = False # attempted escape from supercommander
237 self.ithere = False # Tholian is here
238 self.resting = False # rest time
239 self.icraft = False # Kirk in Galileo
240 self.landed = False # party on planet (true), on ship (false)
241 self.alldone = False # game is now finished
242 self.neutz = False # Romulan Neutral Zone
243 self.isarmed = False # probe is armed
244 self.inorbit = False # orbiting a planet
245 self.imine = False # mining
246 self.icrystl = False # dilithium crystals aboard
247 self.iseenit = False # seen base attack report
248 self.thawed = False # thawed game
249 self.condition = None # "green", "yellow", "red", "docked", "dead"
250 self.iscraft = None # "onship", "offship", "removed"
251 self.skill = None # Player skill level
252 self.inkling = 0 # initial number of klingons
253 self.inbase = 0 # initial number of bases
254 self.incom = 0 # initial number of commanders
255 self.inscom = 0 # initial number of commanders
256 self.inrom = 0 # initial number of commanders
257 self.instar = 0 # initial stars
258 self.intorps = 0 # initial/max torpedoes
259 self.torps = 0 # number of torpedoes
260 self.ship = 0 # ship type -- 'E' is Enterprise
261 self.abandoned = 0 # count of crew abandoned in space
262 self.length = 0 # length of game
263 self.klhere = 0 # klingons here
264 self.casual = 0 # causalties
265 self.nhelp = 0 # calls for help
266 self.nkinks = 0 # count of energy-barrier crossings
267 self.iplnet = 0 # planet # in quadrant
268 self.inplan = 0 # initial planets
269 self.nenhere = 0 # number of enemies in quadrant
270 self.irhere = 0 # Romulans in quadrant
271 self.isatb = 0 # =1 if super commander is attacking base
272 self.tourn = 0 # tournament number
273 self.proben = 0 # number of moves for probe
274 self.nprobes = 0 # number of probes available
275 self.inresor = 0.0 # initial resources
276 self.intime = 0.0 # initial time
277 self.inenrg = 0.0 # initial/max energy
278 self.inshld = 0.0 # initial/max shield
279 self.inlsr = 0.0 # initial life support resources
280 self.indate = 0.0 # initial date
281 self.energy = 0.0 # energy level
282 self.shield = 0.0 # shield level
283 self.warpfac = 0.0 # warp speed
284 self.wfacsq = 0.0 # squared warp factor
285 self.lsupres = 0.0 # life support reserves
286 self.dist = 0.0 # movement distance
287 self.direc = 0.0 # movement direction
288 self.optime = 0.0 # time taken by current operation
289 self.docfac = 0.0 # repair factor when docking (constant?)
290 self.damfac = 0.0 # damage factor
291 self.lastchart = 0.0 # time star chart was last updated
292 self.cryprob = 0.0 # probability that crystal will work
293 self.probex = 0.0 # location of probe
295 self.probeinx = 0.0 # probe x,y increment
296 self.probeiny = 0.0 #
297 self.height = 0.0 # height of orbit around planet
299 # From enumerated type 'feature'
320 # From enumerated type 'FINTYPE'
344 # From enumerated type 'COLORS'
363 # Code from ai.c begins here
365 def tryexit(look, ienm, loccom, irun):
366 # a bad guy attempts to bug out
369 iq.x = game.quadrant.x+(look.x+(QUADSIZE-1))/QUADSIZE - 1
370 iq.y = game.quadrant.y+(look.y+(QUADSIZE-1))/QUADSIZE - 1
371 if not VALID_QUADRANT(iq.x,iq.y) or \
372 game.state.galaxy[iq.x][iq.y].supernova or \
373 game.state.galaxy[iq.x][iq.y].klingons > MAXKLQUAD-1:
374 return False; # no can do -- neg energy, supernovae, or >MAXKLQUAD-1 Klingons
376 return False; # Romulans cannot escape!
378 # avoid intruding on another commander's territory
380 for n in range(1, game.state.remcom+1):
381 if same(game.state.kcmdr[n],iq):
383 # refuse to leave if currently attacking starbase
384 if same(game.battle, game.quadrant):
386 # don't leave if over 1000 units of energy
387 if game.kpower[loccom] > 1000.0:
389 # print escape message and move out of quadrant.
390 # We know this if either short or long range sensors are working
391 if not damaged(DSRSENS) or not damaged(DLRSENS) or \
392 game.condition == docked:
393 crmena(True, ienm, sector, game.ks[loccom])
394 prout(_(" escapes to %s (and regains strength)."),
395 cramlc(quadrant, iq))
396 # handle local matters related to escape
397 game.quad[game.ks[loccom].x][game.ks[loccom].y] = IHDOT
398 game.ks[loccom] = game.ks[game.nenhere]
399 game.kavgd[loccom] = game.kavgd[game.nenhere]
400 game.kpower[loccom] = game.kpower[game.nenhere]
401 game.kdist[loccom] = game.kdist[game.nenhere]
404 if game.condition != docked:
406 # Handle global matters related to escape
407 game.state.galaxy[game.quadrant.x][game.quadrant.y].klingons -= 1
408 game.state.galaxy[iq.x][iq.y].klingons += 1
414 schedule(FSCMOVE, 0.2777)
418 for n in range(1, game.state.remcom+1):
419 if same(game.state.kcmdr[n], game.quadrant):
420 game.state.kcmdr[n]=iq
423 return True; # success
426 # The bad-guy movement algorithm:
428 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
429 # If both are operating full strength, force is 1000. If both are damaged,
430 # force is -1000. Having shields down subtracts an additional 1000.
432 # 2. Enemy has forces equal to the energy of the attacker plus
433 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
434 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
436 # Attacker Initial energy levels (nominal):
437 # Klingon Romulan Commander Super-Commander
438 # Novice 400 700 1200
440 # Good 450 800 1300 1750
441 # Expert 475 850 1350 1875
442 # Emeritus 500 900 1400 2000
443 # VARIANCE 75 200 200 200
445 # Enemy vessels only move prior to their attack. In Novice - Good games
446 # only commanders move. In Expert games, all enemy vessels move if there
447 # is a commander present. In Emeritus games all enemy vessels move.
449 # 3. If Enterprise is not docked, an agressive action is taken if enemy
450 # forces are 1000 greater than Enterprise.
452 # Agressive action on average cuts the distance between the ship and
453 # the enemy to 1/4 the original.
455 # 4. At lower energy advantage, movement units are proportional to the
456 # advantage with a 650 advantage being to hold ground, 800 to move forward
457 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
459 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
460 # retreat, especially at high skill levels.
462 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
465 def movebaddy(com, loccom, ienm):
466 # tactical movement for the bad guys
467 next = coord(); look = coord()
469 # This should probably be just game.comhere + game.ishere
470 if game.skill >= SKILL_EXPERT:
471 nbaddys = ((game.comhere*2 + game.ishere*2+game.klhere*1.23+game.irhere*1.5)/2.0)
473 nbaddys = game.comhere + game.ishere
475 dist1 = game.kdist[loccom]
476 mdist = dist1 + 0.5; # Nearest integer distance
478 # If SC, check with spy to see if should hi-tail it
480 (game.kpower[loccom] <= 500.0 or (game.condition==docked and not damaged(DPHOTON))):
484 # decide whether to advance, retreat, or hold position
485 forces = game.kpower[loccom]+100.0*game.nenhere+400*(nbaddys-1)
487 forces += 1000; # Good for enemy if shield is down!
488 if not damaged(DPHASER) or not damaged(DPHOTON):
489 if damaged(DPHASER): # phasers damaged
492 forces -= 0.2*(game.energy - 2500.0)
493 if damaged(DPHOTON): # photon torpedoes damaged
496 forces -= 50.0*game.torps
498 # phasers and photon tubes both out!
501 if forces <= 1000.0 and game.condition != docked: # Typical situation
502 motion = ((forces+200.0*Rand())/150.0) - 5.0
504 if forces > 1000.0: # Very strong -- move in for kill
505 motion = (1.0-square(Rand()))*dist1 + 1.0
506 if game.condition=="docked" and (game.options & OPTION_BASE): # protected by base -- back off !
507 motion -= game.skill*(2.0-square(Rand()))
509 proutn("=== MOTION = %d, FORCES = %1.2f, ", motion, forces)
510 # don't move if no motion
513 # Limit motion according to skill
514 if abs(motion) > game.skill:
519 # calculate preferred number of steps
524 if motion > 0 and nsteps > mdist:
525 nsteps = mdist; # don't overshoot
526 if nsteps > QUADSIZE:
527 nsteps = QUADSIZE; # This shouldn't be necessary
529 nsteps = 1; # This shouldn't be necessary
531 proutn("NSTEPS = %d:", nsteps)
532 # Compute preferred values of delta X and Y
533 mx = game.sector.x - com.x
534 my = game.sector.y - com.y
535 if 2.0 * abs(mx) < abs(my):
537 if 2.0 * abs(my) < abs(game.sector.x-com.x):
551 for ll in range(nsteps):
554 # Check if preferred position available
566 attempts = 0; # Settle mysterious hang problem
567 while attempts < 20 and not success:
569 if look.x < 1 or look.x > QUADSIZE:
570 if motion < 0 and tryexit(look, ienm, loccom, irun):
572 if krawlx == mx or my == 0:
574 look.x = next.x + krawlx
576 elif look.y < 1 or look.y > QUADSIZE:
577 if motion < 0 and tryexit(look, ienm, loccom, irun):
579 if krawly == my or mx == 0:
581 look.y = next.y + krawly
583 elif (game.options & OPTION_RAMMING) and game.quad[look.x][look.y] != IHDOT:
584 # See if we should ram ship
585 if game.quad[look.x][look.y] == game.ship and \
586 (ienm == IHC or ienm == IHS):
589 if krawlx != mx and my != 0:
590 look.x = next.x + krawlx
592 elif krawly != my and mx != 0:
593 look.y = next.y + krawly
596 break; # we have failed
602 proutn(cramlc(neither, next))
608 # Put commander in place within same quadrant
609 game.quad[com.x][com.y] = IHDOT
610 game.quad[next.x][next.y] = ienm
611 if not same(next, com):
613 game.ks[loccom] = next
614 game.kdist[loccom] = game.kavgd[loccom] = distance(game.sector, next)
615 if not damaged(DSRSENS) or game.condition == docked:
618 proutn(_(" from %s"), cramlc(2, com))
619 if game.kdist[loccom] < dist1:
620 proutn(_(" advances to "))
622 proutn(_(" retreats to "))
623 prout(cramlc(sector, next))
626 # Klingon tactical movement
632 # Figure out which Klingon is the commander (or Supercommander)
635 for i in range(1, game.nenhere+1):
637 if game.quad[w.x][w.y] == IHC:
641 for i in range(1, game.nenhere+1):
643 if game.quad[w.x][w.y] == IHS:
646 # if skill level is high, move other Klingons and Romulans too!
647 # Move these last so they can base their actions on what the
649 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
650 for i in range(1, game.nenhere+1):
652 if game.quad[w.x][w.y] == IHK or game.quad[w.x][w.y] == IHR:
653 movebaddy(w, i, game.quad[w.x][w.y])
656 def movescom(iq, avoid):
657 # commander movement helper
659 if same(iq, game.quadrant) or not VALID_QUADRANT(iq.x, iq.y) or \
660 game.state.galaxy[iq.x][iq.y].supernova or \
661 game.state.galaxy[iq.x][iq.y].klingons > MAXKLQUAD-1:
664 # Avoid quadrants with bases if we want to avoid Enterprise
665 for i in range(1, game.state.rembase+1):
666 if same(game.state.baseq[i], iq):
668 if game.justin and not game.iscate:
671 game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].klingons -= 1
672 game.state.kscmdr = iq
673 game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].klingons += 1
675 # SC has scooted, Remove him from current quadrant
681 for i in range(1, game.nenhere+1):
682 if game.quad[game.ks[i].x][game.ks[i].y] == IHS:
684 game.quad[game.ks[i].x][game.ks[i].y] = IHDOT
685 game.ks[i] = game.ks[game.nenhere]
686 game.kdist[i] = game.kdist[game.nenhere]
687 game.kavgd[i] = game.kavgd[game.nenhere]
688 game.kpower[i] = game.kpower[game.nenhere]
691 if game.condition!=docked:
694 # check for a helpful planet
695 for i in range(game.inplan):
696 if same(game.state.planets[i].w, game.state.kscmdr) and \
697 game.state.planets[i].crystals == present:
699 game.state.planets[i].pclass = destroyed
700 game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].planet = NOPLANET
701 if not damaged(DRADIO) or game.condition == docked:
703 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
704 proutn(_(" a planet in "))
705 proutn(cramlc(quadrant, game.state.kscmdr))
706 prout(_(" has been destroyed"))
707 prout(_(" by the Super-commander.\""))
709 return False; # looks good!
711 def supercommander():
712 # move the Super Commander
713 iq = coord(); sc = coord(); ibq = coord()
717 prout("== SUPERCOMMANDER")
719 # Decide on being active or passive
720 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 \
721 (game.state.date-game.indate) < 3.0)
722 if not game.iscate and avoid:
723 # compute move away from Enterprise
724 ideltax = game.state.kscmdr.x-game.quadrant.x
725 ideltay = game.state.kscmdr.y-game.quadrant.y
726 if math.sqrt(ideltax*ideltax+ideltay*ideltay) > 2.0:
728 ideltax = game.state.kscmdr.y-game.quadrant.y
729 ideltay = game.quadrant.x-game.state.kscmdr.x
731 # compute distances to starbases
732 if game.state.rembase <= 0:
736 sc = game.state.kscmdr
737 for i in range(1, game.state.rembase+1):
738 basetbl.append((i, distance(game.state.baseq[i], sc)))
739 if game.state.rembase > 1:
740 basetbl.sort(lambda x, y: cmp(x[1]. y[1]))
741 # look for nearest base without a commander, no Enterprise, and
742 # without too many Klingons, and not already under attack.
743 ifindit = iwhichb = 0
745 for i2 in range(1, game.state.rembase+1):
746 i = basetbl[i2][0]; # bug in original had it not finding nearest
747 ibq = game.state.baseq[i]
748 if same(ibq, game.quadrant) or same(ibq, game.battle) or \
749 game.state.galaxy[ibq.x][ibq.y].supernova or \
750 game.state.galaxy[ibq.x][ibq.y].klingons > MAXKLQUAD-1:
752 # if there is a commander, and no other base is appropriate,
753 # we will take the one with the commander
754 for j in range(1, game.state.remcom+1):
755 if same(ibq, game.state.kcmdr[j]) and ifindit!= 2:
759 if j > game.state.remcom: # no commander -- use this one
764 return; # Nothing suitable -- wait until next time
765 ibq = game.state.baseq[iwhichb]
766 # decide how to move toward base
767 ideltax = ibq.x - game.state.kscmdr.x
768 ideltay = ibq.y - game.state.kscmdr.y
769 # Maximum movement is 1 quadrant in either or both axis
779 # try moving in both x and y directions
780 iq.x = game.state.kscmdr.x + ideltax
781 iq.y = game.state.kscmdr.y + ideltax
782 if movescom(iq, avoid):
783 # failed -- try some other maneuvers
784 if ideltax==0 or ideltay==0:
787 iq.y = game.state.kscmdr.y + 1
788 if movescom(iq, avoid):
789 iq.y = game.state.kscmdr.y - 1
792 iq.x = game.state.kscmdr.x + 1
793 if movescom(iq, avoid):
794 iq.x = game.state.kscmdr.x - 1
797 # try moving just in x or y
798 iq.y = game.state.kscmdr.y
799 if movescom(iq, avoid):
800 iq.y = game.state.kscmdr.y + ideltay
801 iq.x = game.state.kscmdr.x
804 if game.state.rembase == 0:
807 for i in range(1, game.state.rembase+1):
808 ibq = game.state.baseq[i]
809 if same(ibq, game.state.kscmdr) and same(game.state.kscmdr, game.battle):
812 return; # no, don't attack base!
815 schedule(FSCDBAS, 1.0 +2.0*Rand())
816 if is_scheduled(FCDBAS):
817 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
818 if damaged(DRADIO) and game.condition != docked:
822 proutn(_("Lt. Uhura- \"Captain, the starbase in "))
823 proutn(cramlc(quadrant, game.state.kscmdr))
825 prout(_(" reports that it is under attack from the Klingon Super-commander."))
826 proutn(_(" It can survive until stardate %d.\""),
827 int(scheduled(FSCDBAS)))
830 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
834 game.optime = 0.0; # actually finished
836 # Check for intelligence report
839 (damaged(DRADIO) and game.condition != docked) or \
840 not game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].charted):
843 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
844 proutn(_(" the Super-commander is in "))
845 proutn(cramlc(quadrant, game.state.kscmdr))
851 if not game.ithere or game.justin:
854 if game.tholian.x == 1 and game.tholian.y == 1:
855 idx = 1; idy = QUADSIZE
856 elif game.tholian.x == 1 and game.tholian.y == QUADSIZE:
857 idx = QUADSIZE; idy = QUADSIZE
858 elif game.tholian.x == QUADSIZE and game.tholian.y == QUADSIZE:
859 idx = QUADSIZE; idy = 1
860 elif game.tholian.x == QUADSIZE and game.tholian.y == 1:
863 # something is wrong!
867 # do nothing if we are blocked
868 if game.quad[idx][idy]!= IHDOT and game.quad[idx][idy]!= IHWEB:
870 game.quad[game.tholian.x][game.tholian.y] = IHWEB
872 if game.tholian.x != idx:
874 im = math.fabs(idx - game.tholian.x)*1.0/(idx - game.tholian.x)
875 while game.tholian.x != idx:
877 if game.quad[game.tholian.x][game.tholian.y]==IHDOT:
878 game.quad[game.tholian.x][game.tholian.y] = IHWEB
879 elif game.tholian.y != idy:
881 im = math.fabs(idy - game.tholian.y)*1.0/(idy - game.tholian.y)
882 while game.tholian.y != idy:
884 if game.quad[game.tholian.x][game.tholian.y]==IHDOT:
885 game.quad[game.tholian.x][game.tholian.y] = IHWEB
886 game.quad[game.tholian.x][game.tholian.y] = IHT
887 game.ks[game.nenhere] = game.tholian
889 # check to see if all holes plugged
890 for i in range(1, QUADSIZE+1):
891 if game.quad[1][i]!=IHWEB and game.quad[1][i]!=IHT:
893 if game.quad[QUADSIZE][i]!=IHWEB and game.quad[QUADSIZE][i]!=IHT:
895 if game.quad[i][1]!=IHWEB and game.quad[i][1]!=IHT:
897 if game.quad[i][QUADSIZE]!=IHWEB and game.quad[i][QUADSIZE]!=IHT:
899 # All plugged up -- Tholian splits
900 game.quad[game.tholian.x][game.tholian.y]=IHWEB
902 crmena(True, IHT, sector, game.tholian)
903 prout(_(" completes web."))