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
368 iq.x = game.quadrant.x+(look.x+(QUADSIZE-1))/QUADSIZE - 1
369 iq.y = game.quadrant.y+(look.y+(QUADSIZE-1))/QUADSIZE - 1
370 if not VALID_QUADRANT(iq.x,iq.y) or \
371 game.state.galaxy[iq.x][iq.y].supernova or \
372 game.state.galaxy[iq.x][iq.y].klingons > MAXKLQUAD-1:
373 return False; # no can do -- neg energy, supernovae, or >MAXKLQUAD-1 Klingons
375 return False; # Romulans cannot escape!
377 # avoid intruding on another commander's territory
379 for n in range(1, game.state.remcom+1):
380 if same(game.state.kcmdr[n],iq):
382 # refuse to leave if currently attacking starbase
383 if same(game.battle, game.quadrant):
385 # don't leave if over 1000 units of energy
386 if game.kpower[loccom] > 1000.0:
388 # print escape message and move out of quadrant.
389 # we know this if either short or long range sensors are working
390 if not damaged(DSRSENS) or not damaged(DLRSENS) or \
391 game.condition == docked:
392 crmena(True, ienm, "sector", game.ks[loccom])
393 prout(_(" escapes to Quadrant %s (and regains strength).") % q)
394 # handle local matters related to escape
395 game.quad[game.ks[loccom].x][game.ks[loccom].y] = IHDOT
396 game.ks[loccom] = game.ks[game.nenhere]
397 game.kavgd[loccom] = game.kavgd[game.nenhere]
398 game.kpower[loccom] = game.kpower[game.nenhere]
399 game.kdist[loccom] = game.kdist[game.nenhere]
402 if game.condition != docked:
404 # Handle global matters related to escape
405 game.state.galaxy[game.quadrant.x][game.quadrant.y].klingons -= 1
406 game.state.galaxy[iq.x][iq.y].klingons += 1
412 schedule(FSCMOVE, 0.2777)
416 for n in range(1, game.state.remcom+1):
417 if same(game.state.kcmdr[n], game.quadrant):
418 game.state.kcmdr[n]=iq
421 return True; # success
424 # The bad-guy movement algorithm:
426 # 1. Enterprise has "force" based on condition of phaser and photon torpedoes.
427 # If both are operating full strength, force is 1000. If both are damaged,
428 # force is -1000. Having shields down subtracts an additional 1000.
430 # 2. Enemy has forces equal to the energy of the attacker plus
431 # 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR
432 # 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.
434 # Attacker Initial energy levels (nominal):
435 # Klingon Romulan Commander Super-Commander
436 # Novice 400 700 1200
438 # Good 450 800 1300 1750
439 # Expert 475 850 1350 1875
440 # Emeritus 500 900 1400 2000
441 # VARIANCE 75 200 200 200
443 # Enemy vessels only move prior to their attack. In Novice - Good games
444 # only commanders move. In Expert games, all enemy vessels move if there
445 # is a commander present. In Emeritus games all enemy vessels move.
447 # 3. If Enterprise is not docked, an aggressive action is taken if enemy
448 # forces are 1000 greater than Enterprise.
450 # Agressive action on average cuts the distance between the ship and
451 # the enemy to 1/4 the original.
453 # 4. At lower energy advantage, movement units are proportional to the
454 # advantage with a 650 advantage being to hold ground, 800 to move forward
455 # 1, 950 for two, 150 for back 4, etc. Variance of 100.
457 # If docked, is reduced by roughly 1.75*game.skill, generally forcing a
458 # retreat, especially at high skill levels.
460 # 5. Motion is limited to skill level, except for SC hi-tailing it out.
463 def movebaddy(com, loccom, ienm):
464 # tactical movement for the bad guys
465 next = coord(); look = coord()
467 # This should probably be just game.comhere + game.ishere
468 if game.skill >= SKILL_EXPERT:
469 nbaddys = ((game.comhere*2 + game.ishere*2+game.klhere*1.23+game.irhere*1.5)/2.0)
471 nbaddys = game.comhere + game.ishere
473 dist1 = game.kdist[loccom]
474 mdist = int(dist1 + 0.5); # Nearest integer distance
476 # If SC, check with spy to see if should hi-tail it
478 (game.kpower[loccom] <= 500.0 or (game.condition=="docked" and not damaged(DPHOTON))):
482 # decide whether to advance, retreat, or hold position
483 forces = game.kpower[loccom]+100.0*game.nenhere+400*(nbaddys-1)
485 forces += 1000; # Good for enemy if shield is down!
486 if not damaged(DPHASER) or not damaged(DPHOTON):
487 if damaged(DPHASER): # phasers damaged
490 forces -= 0.2*(game.energy - 2500.0)
491 if damaged(DPHOTON): # photon torpedoes damaged
494 forces -= 50.0*game.torps
496 # phasers and photon tubes both out!
499 if forces <= 1000.0 and game.condition != "docked": # Typical situation
500 motion = ((forces+200.0*Rand())/150.0) - 5.0
502 if forces > 1000.0: # Very strong -- move in for kill
503 motion = (1.0-square(Rand()))*dist1 + 1.0
504 if game.condition=="docked" and (game.options & OPTION_BASE): # protected by base -- back off !
505 motion -= game.skill*(2.0-square(Rand()))
507 proutn("=== MOTION = %d, FORCES = %1.2f, " % (motion, forces))
508 # don't move if no motion
511 # Limit motion according to skill
512 if abs(motion) > game.skill:
517 # calculate preferred number of steps
522 if motion > 0 and nsteps > mdist:
523 nsteps = mdist; # don't overshoot
524 if nsteps > QUADSIZE:
525 nsteps = QUADSIZE; # This shouldn't be necessary
527 nsteps = 1; # This shouldn't be necessary
529 proutn("NSTEPS = %d:" % nsteps)
530 # Compute preferred values of delta X and Y
531 mx = game.sector.x - com.x
532 my = game.sector.y - com.y
533 if 2.0 * abs(mx) < abs(my):
535 if 2.0 * abs(my) < abs(game.sector.x-com.x):
549 for ll in range(nsteps):
551 proutn(" %d" % (ll+1))
552 # Check if preferred position available
564 attempts = 0; # Settle mysterious hang problem
565 while attempts < 20 and not success:
567 if look.x < 1 or look.x > QUADSIZE:
568 if motion < 0 and tryexit(look, ienm, loccom, irun):
570 if krawlx == mx or my == 0:
572 look.x = next.x + krawlx
574 elif look.y < 1 or look.y > QUADSIZE:
575 if motion < 0 and tryexit(look, ienm, loccom, irun):
577 if krawly == my or mx == 0:
579 look.y = next.y + krawly
581 elif (game.options & OPTION_RAMMING) and game.quad[look.x][look.y] != IHDOT:
582 # See if we should ram ship
583 if game.quad[look.x][look.y] == game.ship and \
584 (ienm == IHC or ienm == IHS):
587 if krawlx != mx and my != 0:
588 look.x = next.x + krawlx
590 elif krawly != my and mx != 0:
591 look.y = next.y + krawly
594 break; # we have failed
606 # Put commander in place within same quadrant
607 game.quad[com.x][com.y] = IHDOT
608 game.quad[next.x][next.y] = ienm
609 if not same(next, com):
611 game.ks[loccom] = next
612 game.kdist[loccom] = game.kavgd[loccom] = distance(game.sector, next)
613 if not damaged(DSRSENS) or game.condition == docked:
616 proutn(_(" from Sector %s") % com)
617 if game.kdist[loccom] < dist1:
618 proutn(_(" advances to "))
620 proutn(_(" retreats to "))
621 prout("Sector %s." % next)
624 # Klingon tactical movement
627 # Figure out which Klingon is the commander (or Supercommander)
630 for i in range(1, game.nenhere+1):
632 if game.quad[w.x][w.y] == IHC:
636 for i in range(1, game.nenhere+1):
638 if game.quad[w.x][w.y] == IHS:
641 # If skill level is high, move other Klingons and Romulans too!
642 # Move these last so they can base their actions on what the
644 if game.skill >= SKILL_EXPERT and (game.options & OPTION_MVBADDY):
645 for i in range(1, game.nenhere+1):
647 if game.quad[w.x][w.y] == IHK or game.quad[w.x][w.y] == IHR:
648 movebaddy(w, i, game.quad[w.x][w.y])
651 def movescom(iq, avoid):
652 # commander movement helper
653 if same(iq, game.quadrant) or not VALID_QUADRANT(iq.x, iq.y) or \
654 game.state.galaxy[iq.x][iq.y].supernova or \
655 game.state.galaxy[iq.x][iq.y].klingons > MAXKLQUAD-1:
658 # Avoid quadrants with bases if we want to avoid Enterprise
659 for i in range(1, game.state.rembase+1):
660 if same(game.state.baseq[i], iq):
662 if game.justin and not game.iscate:
665 game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].klingons -= 1
666 game.state.kscmdr = iq
667 game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].klingons += 1
669 # SC has scooted, Remove him from current quadrant
675 for i in range(1, game.nenhere+1):
676 if game.quad[game.ks[i].x][game.ks[i].y] == IHS:
678 game.quad[game.ks[i].x][game.ks[i].y] = IHDOT
679 game.ks[i] = game.ks[game.nenhere]
680 game.kdist[i] = game.kdist[game.nenhere]
681 game.kavgd[i] = game.kavgd[game.nenhere]
682 game.kpower[i] = game.kpower[game.nenhere]
685 if game.condition!=docked:
688 # check for a helpful planet
689 for i in range(game.inplan):
690 if same(game.state.planets[i].w, game.state.kscmdr) and \
691 game.state.planets[i].crystals == present:
693 game.state.planets[i].pclass = destroyed
694 game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].planet = NOPLANET
695 if not damaged(DRADIO) or game.condition == docked:
697 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
698 proutn(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
699 prout(_(" by the Super-commander.\""))
701 return False; # looks good!
703 def supercommander():
704 # move the Super Commander
705 iq = coord(); sc = coord(); ibq = coord(); idelta = coord()
708 prout("== SUPERCOMMANDER")
709 # Decide on being active or passive
710 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 \
711 (game.state.date-game.indate) < 3.0)
712 if not game.iscate and avoid:
713 # compute move away from Enterprise
714 idelta = game.state.kscmdr-game.quadrant
715 if math.sqrt(idelta.x*idelta.x+idelta.y*idelta.y) > 2.0:
717 idelta.x = game.state.kscmdr.y-game.quadrant.y
718 idelta.y = game.quadrant.x-game.state.kscmdr.x
720 # compute distances to starbases
721 if game.state.rembase <= 0:
725 sc = game.state.kscmdr
726 for i in range(1, game.state.rembase+1):
727 basetbl.append((i, distance(game.state.baseq[i], sc)))
728 if game.state.rembase > 1:
729 basetbl.sort(lambda x, y: cmp(x[1]. y[1]))
730 # look for nearest base without a commander, no Enterprise, and
731 # without too many Klingons, and not already under attack.
732 ifindit = iwhichb = 0
733 for i2 in range(1, game.state.rembase+1):
734 i = basetbl[i2][0]; # bug in original had it not finding nearest
735 ibq = game.state.baseq[i]
736 if same(ibq, game.quadrant) or same(ibq, game.battle) or \
737 game.state.galaxy[ibq.x][ibq.y].supernova or \
738 game.state.galaxy[ibq.x][ibq.y].klingons > MAXKLQUAD-1:
740 # if there is a commander, and no other base is appropriate,
741 # we will take the one with the commander
742 for j in range(1, game.state.remcom+1):
743 if same(ibq, game.state.kcmdr[j]) and ifindit!= 2:
747 if j > game.state.remcom: # no commander -- use this one
752 return; # Nothing suitable -- wait until next time
753 ibq = game.state.baseq[iwhichb]
754 # decide how to move toward base
755 idelta = ibq - game.state.kscmdr
756 # Maximum movement is 1 quadrant in either or both axes
757 idelta = idelta.sgn()
758 # try moving in both x and y directions
759 # there was what looked like a bug in the Almy C code here,
760 # but it might be this translation is just wrong.
761 iq = game.state.kscmdr + idelta
762 if movescom(iq, avoid):
763 # failed -- try some other maneuvers
764 if idelta.x==0 or idelta.y==0:
767 iq.y = game.state.kscmdr.y + 1
768 if movescom(iq, avoid):
769 iq.y = game.state.kscmdr.y - 1
772 iq.x = game.state.kscmdr.x + 1
773 if movescom(iq, avoid):
774 iq.x = game.state.kscmdr.x - 1
777 # try moving just in x or y
778 iq.y = game.state.kscmdr.y
779 if movescom(iq, avoid):
780 iq.y = game.state.kscmdr.y + idelta.y
781 iq.x = game.state.kscmdr.x
784 if game.state.rembase == 0:
787 for i in range(1, game.state.rembase+1):
788 ibq = game.state.baseq[i]
789 if same(ibq, game.state.kscmdr) and same(game.state.kscmdr, game.battle):
792 return; # no, don't attack base!
795 schedule(FSCDBAS, 1.0 +2.0*Rand())
796 if is_scheduled(FCDBAS):
797 postpone(FSCDBAS, scheduled(FCDBAS)-game.state.date)
798 if damaged(DRADIO) and game.condition != docked:
802 prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
804 prout(_(" reports that it is under attack from the Klingon Super-commander."))
805 proutn(_(" It can survive until stardate %d.\"") \
806 % int(scheduled(FSCDBAS)))
809 prout(_("Mr. Spock- \"Captain, shall we cancel the rest period?\""))
813 game.optime = 0.0; # actually finished
815 # Check for intelligence report
818 (damaged(DRADIO) and game.condition != docked) or \
819 not game.state.galaxy[game.state.kscmdr.x][game.state.kscmdr.y].charted):
822 prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
823 proutn(_(" the Super-commander is in Quadrant %s,") % game.state.kscmdr)
828 if not game.ithere or game.justin:
831 if game.tholian.x == 1 and game.tholian.y == 1:
832 idx = 1; idy = QUADSIZE
833 elif game.tholian.x == 1 and game.tholian.y == QUADSIZE:
834 idx = QUADSIZE; idy = QUADSIZE
835 elif game.tholian.x == QUADSIZE and game.tholian.y == QUADSIZE:
836 idx = QUADSIZE; idy = 1
837 elif game.tholian.x == QUADSIZE and game.tholian.y == 1:
840 # something is wrong!
844 # do nothing if we are blocked
845 if game.quad[idx][idy]!= IHDOT and game.quad[idx][idy]!= IHWEB:
847 game.quad[game.tholian.x][game.tholian.y] = IHWEB
849 if game.tholian.x != idx:
851 im = math.fabs(idx - game.tholian.x)*1.0/(idx - game.tholian.x)
852 while game.tholian.x != idx:
854 if game.quad[game.tholian.x][game.tholian.y]==IHDOT:
855 game.quad[game.tholian.x][game.tholian.y] = IHWEB
856 elif game.tholian.y != idy:
858 im = math.fabs(idy - game.tholian.y)*1.0/(idy - game.tholian.y)
859 while game.tholian.y != idy:
861 if game.quad[game.tholian.x][game.tholian.y]==IHDOT:
862 game.quad[game.tholian.x][game.tholian.y] = IHWEB
863 game.quad[game.tholian.x][game.tholian.y] = IHT
864 game.ks[game.nenhere] = game.tholian
866 # check to see if all holes plugged
867 for i in range(1, QUADSIZE+1):
868 if game.quad[1][i]!=IHWEB and game.quad[1][i]!=IHT:
870 if game.quad[QUADSIZE][i]!=IHWEB and game.quad[QUADSIZE][i]!=IHT:
872 if game.quad[i][1]!=IHWEB and game.quad[i][1]!=IHT:
874 if game.quad[i][QUADSIZE]!=IHWEB and game.quad[i][QUADSIZE]!=IHT:
876 # All plugged up -- Tholian splits
877 game.quad[game.tholian.x][game.tholian.y]=IHWEB
879 crmena(True, IHT, "sector", game.tholian)
880 prout(_(" completes web."))