X-Git-Url: https://jxself.org/git/?p=super-star-trek.git;a=blobdiff_plain;f=src%2Fsst.py;h=1cf20dc175ed24dd115673f7863754b23f6cc703;hp=ace9641c7da650a38076089c0f05ba4c97016f96;hb=b40eba51deeb13f362e95416c005156be4104067;hpb=9aef5f5aae5fde0ed2b462945750c7aee59b3c1e diff --git a/src/sst.py b/src/sst.py index ace9641..1cf20dc 100644 --- a/src/sst.py +++ b/src/sst.py @@ -1,41 +1,34 @@ """ sst.py =-- Super Star Trek in Python -Control flow of this translation is pretty much identical to the C version -(and thus like the ancestral FORTRAN) but the data structures are -radically different -- the Python code makes heavy use of objects. +""" +import os, sys, math, curses -Note that the game.quad, game.snap.galaxy and game.snap.chart members -are not actually arrays but dictioaries indixed by coord tuples. Be setting -the hash of a coord equal to the hash of a literal tuple containing its -coordinate data, we ensure these can be indexed both ways. +SSTDOC = "/usr/share/doc/sst/sst.doc" -""" -import math +# Stub to be replaced +def _(str): return str PHASEFAC = 2.0 GALSIZE = 8 -NINHAB = GALSIZE * GALSIZE / 2 +NINHAB = (GALSIZE * GALSIZE / 2) MAXUNINHAB = 10 -PLNETMAB = NINHAB + MAXUNINHAB +PLNETMAX = (NINHAB + MAXUNINHAB) QUADSIZE = 10 -BASEMAX = 5 -FULLCREW = 428 # BSD Trek was 387, that's wrong +BASEMAX = (GALSIZE * GALSIZE / 12) MAXKLGAME = 127 MAXKLQUAD = 9 +FULLCREW = 428 # BSD Trek was 387, that's wrong FOREVER = 1e30 -# These macros hide the difference between 0-origin and 1-origin addressing. -# They're a step towards de-FORTRANizing the code. -def VALID_QUADRANT(x,y): ((x)>=1 and (x)<=GALSIZE and (y)>=1 and (y)<=GALSIZE) -def VALID_SECTOR(x, y): ((x)>=1 and (x)<=QUADSIZE and (y)>=1 and (y)<=QUADSIZE) +# These functions hide the difference between 0-origin and 1-origin addressing. +def VALID_QUADRANT(x, y): return ((x)>=1 and (x)<=GALSIZE and (y)>=1 and (y)<=GALSIZE) +def VALID_SECTOR(x, y): return ((x)>=1 and (x)<=QUADSIZE and (y)>=1 and (y)<=QUADSIZE) -# These types have not been dealt with yet -IHQUEST = '?', -IHWEB = '#', -IHMATER0 = '-', -IHMATER1 = 'o', -IHMATER2 = '0', +def square(i): return ((i)*(i)) +def distance(c1, c2): return math.sqrt(square(c1.x - c2.x) + square(c1.y - c2.y)) +def invalidate(w): w.x = w.y = 0 +def is_valid(w): return (w.x != 0 and w.y != 0) class coord: def __init(self, x=None, y=None): @@ -60,691 +53,246 @@ class coord: def __str__(self): return "%d - %d" % (self.x, self.y) -class feature: - "A feature in the current quadrant (ship, star, black hole, base, etc)." - def __init__(self): - self.type = None # name of feature type - self.sector = None # sector location - def distance(self): - return self.sector.distance(game.sector) - def __str__(self): - "This will be overridden by subclasses." - return self.name[0] - def sectormove(self, dest): - "Move this feature within the current quadrant." - if self.sector: - game.quad[self.sector] = None - game.quad[dest] = self - self.sector = dest - -class ship(feature): - "A starship, frindly or enemy." - def __init__(self, type, power): - feature.__init__(self) - self.type = type # klingon, romulan, commander, - # supercommander, tholian, - # enterprise, faerie queene. - self.power = power # power - if self.type in ("Klingon", "Commander", "Super-Commander"): - game.remkl += 1 - elif self.type == "Romulan": - game.romrem += 1 - def __del__(self): - if self.type in ("Klingon", "Commander", "Super-Commander"): - game.remkl -= 1 - elif self.type == "Romulan": - game.romrem -= 1 - -class space(feature): - "Empty space. Has no state, just knows how to identify iself." - def __str__(self): - return '*' - -class star(feature): - "A star. Has no state, just knows how to identify iself." - def __str__(self): - return '*' - -class planet(feature): - "A planet. May be inhabited or not, may hold dilithium crystals or not." +class planet: def __init(self): - feature.__init__(self) - self.name = None - self.crystals = None # "absent", "present", or "mined" - self.inhabited = False - self.known = "unknown" # Other values: "known" and "shuttle down" - game.state.planets.append(self) - def __del__(self): - game.state.planets.remove(self) - def __str__(self): - if self.inhabited: - return '@' - else: - return 'P' - -class web(feature): - "A bit of Tholian web. Has no state, just knows how to identify iself." - def __str__(self): - return '*' - -class blackhole(feature): - "A black hole. Has no hair, just knows how to identify iself." - def __str__(self): - return ' ' - -class starbase(feature): - "Starbases also have no features, just a location." - def __init(self, quadrant): - feature.__init__(self) - self.quadrant = quadrant - game.state.bases.append(self) - def __del__(self): - game.state.bases.remove(self) - def __str__(self): - return 'B' + self.name = None # string-valued if inhabited + self.w = coord() # quadrant located + self.pclass = None # could be ""M", "N", "O", or "destroyed" + self.crystals = None # could be "mined", "present", "absent" + self.known = None # could be "unknown", "known", "shuttle_down" + +# How to represent features +IHR = 'R', +IHK = 'K', +IHC = 'C', +IHS = 'S', +IHSTAR = '*', +IHP = 'P', +IHW = '@', +IHB = 'B', +IHBLANK = ' ', +IHDOT = '.', +IHQUEST = '?', +IHE = 'E', +IHF = 'F', +IHT = 'T', +IHWEB = '#', +IHMATER0 = '-', +IHMATER1 = 'o', +IHMATER2 = '0' +NOPLANET = None class quadrant: - def __init__(self): + def __init(self): self.stars = None self.planet = None - self.starbase = None - self.klingons = None - self.romulans = None - self.supernova = None - self.charted = None - self.status = "secure" # Other valuues: "distressed", "enslaved" - def enemies(self): - "List enemies in this quadrant." - lst = [] - for feature in self.quad.values: - if not isinstance(feature, ship): - continue - if feature.name not in ("Enterprise", "Faerie Queene"): - lst.append(feature) - return lst + self.starbase = None + self.klingons = None + self.romulans = None + self.supernova = None + self.charted = None + self.status = None # Could be "secure", "distressed", "enslaved" class page: - "A chart page. The starchart is a 2D array of these." - def __init__(self): - self.stars = None # Will hold a number - self.starbase = None # Will hold a bool - self.klingons = None # Will hold a number + def __init(self): + self.stars = None + self.starbase = None + self.klingons = None class snapshot: - "State of the universe. The galaxy is a 2D array of these." - def __init__(self): + def __init(self): + self.snap = False # snapshot taken self.crew = None # crew complement self.remkl = None # remaining klingons self.remcom = None # remaining commanders self.nscrem = None # remaining super commanders + self.rembase = None # remaining bases self.starkl = None # destroyed stars self.basekl = None # destroyed bases self.nromrem = None # Romulans remaining - self.nplankl = None # destroyed uninhabited planets self.nworldkl = None # destroyed inhabited planets - self.planets = []; # List of planets known + self.nplankl = None # destroyed uninhabited planets + self.nworldkl = None # destroyed inhabited planets + self.planets = [] # Planet information + for i in range(PLNETMAX): + self.planets.append(planet()) self.date = None # stardate self.remres = None # remaining resources - self. remtime = None # remaining time - self.bases = [] # Base quadrant coordinates + self.remtime = None # remaining time + self.baseq = [] # Base quadrant coordinates + for i in range(BASEMAX+1): + self.baseq.append(coord()) self.kcmdr = [] # Commander quadrant coordinates - self.kscmdr = None # Supercommander quadrant coordinates - self.galaxy = {} # Dictionary of quadrant objects - self.chart = {} # Dictionary of page objects - -def damaged(dev): - return game.damage[dev] != 0.0 + for i in range(QUADSIZE+1): + self.kcmdr.append(coord()) + self.kscmdr = coord() # Supercommander quadrant coordinates + self.galaxy = [] # The Galaxy (subscript 0 not used) + for i in range(GALSIZE+1): + self.chart.append([]) + for j in range(GALSIZE+1): + self.galaxy[i].append(quadrant()) + self.chart = [] # the starchart (subscript 0 not used) + for i in range(GALSIZE+1): + self.chart.append([]) + for j in range(GALSIZE+1): + self.chart[i].append(page()) class event: def __init__(self): - self.date = None # The only mandatory attribute - -class game: + self.date = None # A real number + self.quadrant = None # A coord structure + +# game options +OPTION_ALL = 0xffffffff +OPTION_TTY = 0x00000001 # old interface +OPTION_CURSES = 0x00000002 # new interface +OPTION_IOMODES = 0x00000003 # cover both interfaces +OPTION_PLANETS = 0x00000004 # planets and mining +OPTION_THOLIAN = 0x00000008 # Tholians and their webs +OPTION_THINGY = 0x00000010 # Space Thingy can shoot back +OPTION_PROBE = 0x00000020 # deep-space probes +OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart +OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise +OPTION_MVBADDY = 0x00000100 # more enemies can move +OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you +OPTION_BASE = 0x00000400 # bases have good shields +OPTION_WORLDS = 0x00000800 # logic for inhabited worlds +OPTION_PLAIN = 0x01000000 # user chose plain game +OPTION_ALMY = 0x02000000 # user chose Almy variant + +# Define devices +DSRSENS = 0 +DLRSENS = 1 +DPHASER = 2 +DPHOTON = 3 +DLIFSUP = 4 +DWARPEN = 5 +DIMPULS = 6 +DSHIELD = 7 +DRADIO = 0 +DSHUTTL = 9 +DCOMPTR = 10 +DNAVSYS = 11 +DTRANSP = 12 +DSHCTRL = 13 +DDRAY = 14 +DDSP = 15 +NDEVICES= 16 # Number of devices + +def damaged(dev): return (game.damage[dev] != 0.0) + +# Define future events +FSPY = 0 # Spy event happens always (no future[] entry) + # can cause SC to tractor beam Enterprise +FSNOVA = 1 # Supernova +FTBEAM = 2 # Commander tractor beams Enterprise +FSNAP = 3 # Snapshot for time warp +FBATTAK = 4 # Commander attacks base +FCDBAS = 5 # Commander destroys base +FSCMOVE = 6 # Supercommander moves (might attack base) +FSCDBAS = 7 # Supercommander destroys base +FDSPROB = 8 # Move deep space probe +FDISTR = 9 # Emit distress call from an inhabited world +FENSLV = 10 # Inhabited word is enslaved */ +FREPRO = 11 # Klingons build a ship in an enslaved system +NEVENTS = 12 + +# +# abstract out the event handling -- underlying data structures will change +# when we implement stateful events +# +def findevent(evtype): return game.future[evtype] + +class gamestate: def __init__(self): - self.options = [] # List of option strings - self.state = snapshot() # State of the universe - self.snapsht = snapshot() # For backwards timetravel - self.quad = {} # contents of our quadrant - self.kpower = {} # enemy energy levels - self.kdist = {} # enemy distances - self.kavgd = {} # average distances - self.damage = {} # damage encountered - self.future = [] # future events - self.passwd = None # Self Destruct password - # Coordinate members start here - self.enemies = {} # enemy sector locations - self.quadrant = None # where we are - self.sector = None - self.tholian = None # coordinates of Tholian - self.base = None # position of base in current quadrant - self.battle = None # base coordinates being attacked - self.plnet = None # location of planet in quadrant - self.probec = None # current probe quadrant - # Flag members start here - self.gamewon = None # Finished! - self.ididit = None # action taken -- allows enemy to attack - self.alive = None # we are alive (not killed) - self.justin = None # just entered quadrant - self.shldup = None # shields are up - self.shldchg = None # shield changing (affects efficiency) - self.comhere = None # commander here - self.ishere = None # super-commander in quadrant - self.iscate = None # super commander is here - self.ientesc = None # attempted escape from supercommander - self.ithere = None # Tholian is here - self.resting = None # rest time - self.icraft = None # Kirk in Galileo - self.landed = None # party on planet or on ship - self.alldone = None # game is now finished - self.neutz = None # Romulan Neutral Zone - self.isarmed = None # probe is armed - self.inorbit = None # orbiting a planet - self.imine = None # mining - self.icrystl = None # dilithium crystals aboard - self.iseenit = None # seen base attack report - self.thawed = None # thawed game - # String members start here - self.condition = None # green, yellow, red, docked, dead, - self.iscraft = None # onship, offship, removed - self.skill = None # levels: none, novice, fair, good, - # expert, emeritus - # Integer nembers sart here - self.inkling = None # initial number of klingons - self.inbase = None # initial number of bases - self.incom = None # initial number of commanders - self.inscom = None # initial number of commanders - self.inrom = None # initial number of commanders - self.instar = None # initial stars - self.intorps = None # initial/max torpedoes - self.torps = None # number of torpedoes - self.ship = None # ship type -- 'E' is Enterprise - self.abandoned = None # count of crew abandoned in space - self.length = None # length of game - self.klhere = None # klingons here - self.casual = None # causalties - self.nhelp = None # calls for help - self.nkinks = None # count of energy-barrier crossings - self.iplnet = None # planet # in quadrant - self.inplan = None # initial planets - self.irhere = None # Romulans in quadrant - self.isatb = None # =1 if super commander is attacking base - self.tourn = None # tournament number - self.proben = None # number of moves for probe - self.nprobes = None # number of probes available - # Float members start here - self.inresor = None # initial resources - self.intime = None # initial time - self.inenrg = None # initial/max energy - self.inshld = None # initial/max shield - self.inlsr = None # initial life support resources - self.indate = None # initial date - self.energy = None # energy level - self.shield = None # shield level - self.warpfac = None # warp speed - self.wfacsq = None # squared warp factor - self.lsupres = None # life support reserves - self.dist = None # movement distance - self.direc = None # movement direction - self.optime = None # time taken by current operation - self.docfac = None # repair factor when docking (constant?) - self.damfac = None # damage factor - self.lastchart = None # time star chart was last updated - self.cryprob = None # probability that crystal will work - self.probex = None # location of probe - self.probey = None # - self.probeinx = None # probe x,y increment - self.probeiny = None # - self.height = None # height of orbit around planet - -def communicating(): - "Are we in communication with Starfleet Command?" - return (not damaged("DRADIO")) or game.condition == "docked" - -# Code corresponding to ai.c begins here - -def tryexit(look, ship, irun): - # a bad guy attempts to bug out of the quadrant - iq = coord() - iq.x = game.quadrant.x+(look.x+(QUADSIZE-1))/QUADSIZE - 1 - iq.y = game.quadrant.y+(look.y+(QUADSIZE-1))/QUADSIZE - 1 - if not valid_quadrant(iq) or \ - game.state.galaxy[iq].supernova or \ - game.state.galaxy[iq].klingons > MAXKLQUAD-1: - return False; # no can do -- neg energy, supernovae, or >MAXKLQUAD-1 Klingons - if ship.type == "Romulan": - return False # Romulans cannot escape - if not irun: - # avoid intruding on another commander's territory - if ship.type == "Commander": - if iq in gamestate.kcmdr: - return False - # refuse to leave if currently attacking starbase: - if game.battle == game.quadrant: - return False; - # don't leave if over 1000 units of energy - if ship.power > 1000.0: - return false; - # Print escape message and move out of quadrant. - # We know this if either short or long range sensors are working - if not damaged("DSRSENS") or not damaged("DLRSENS") or game.condition=="docked": - crmena(True, "sector", ship) - prout(" escapes to quadrant %s (and regains strength)." % iq) - # handle local matters related to escape - game.quad[ship.location] = None; - if game.condition != "docked": - newcnd() - # Handle global matters related to escape - game.state.galaxy[game.quadrant].klingons -= 1 - game.state.galaxy[iq].klingons += 1 - if ship.type == "Super-Commander": - game.ishere = False - game.iscate = False - game.ientesc = False - game.isatb = 0 - schedule("FSCMOVE", 0.2777) - unschedule("FSCDBAS") - game.state.kscmdr = iq - else: - for (n, cmdr) in enumerate(game.state.kcmdr): - if cmdr == game.quadrant: - game.state.kcmdr[n] = iq - break - game.comhere = False - return True # successful exit - -def sgn(n): n / abs(n) - -''' -Algorithm for moving bad guys: - - * Enterprise has "force" based on condition of phaser and photon torpedoes. - If both are operating full strength, force is 1000. If both are damaged, - force is -1000. Having shields down subtracts an additional 1000. - - * Enemy has forces equal to the energy of the attacker plus - 100*(K+R) + 500*(C+S) - 400 for novice through good levels OR - 346*K + 400*R + 500*(C+S) - 400 for expert and emeritus. - - Attacker Initial energy levels (nominal): - Klingon Romulan Commander Super-Commander - Novice 400 700 1200 - Fair 425 750 1250 - Good 450 800 1300 1750 - Expert 475 850 1350 1875 - Emeritus 500 900 1400 2000 - VARIANCE 75 200 200 200 - - Enemy vessels only move prior to their attack. In Novice - Good games - only commanders move. In Expert games, all enemy vessels move if there - is a commander present. In Emeritus games all enemy vessels move. - - * If Enterprise is not docked, an agressive action is taken if enemy - forces are 1000 greater than Enterprise. - - Agressive action on average cuts the distance between the ship and - the enemy to 1/4 the original. - - * At lower energy advantage, movement units are proportional to the - advantage with a 650 advantage being to hold ground, 800 to move forward - 1, 950 for two, 150 for back 4, etc. Variance of 100. - - If docked, is reduced by roughly 1.75*game.skill, generally forcing a - retreat, especially at high skill levels. - - * Motion is limited to skill level, except for SC hi-tailing it out. -''' - -def movebaddy(ship): - # tactical movement for the bad guys - bugout = False - # This should probably be just game.comhere + game.ishere - if game.skill >= SKILL_EXPERT: - nbaddys = int((game.comhere*2 + game.ishere*2+game.klhere*1.23+game.irhere*1.5)/2.0) - else: - nbaddys = game.comhere + game.ishere - dist1 = ship.distance() - mdist = round(dist1 + 0.5) # Nearest integer distance - # If SC, check with spy to see if should high-tail it - if ship.type == "Super-Commander" and \ - (ship.power <= 500.0 or (game.condition==docked and not damaged("DPHOTON"))): - bugout = True; - motion = -QUADSIZE; - else: - # decide whether to advance, retreat, or hold position - forces = ship.power + 100.0*len(game.quad.enemies()) + 400*(nbaddys-1) - if not game.shldup: - forces += 1000.0 # Good for enemy if shield is down! - if not damaged("DPHASER") or not damaged("DPHOTON"): - if damaged(DPHASER): - forces += 300.0 - else: - forces -= 0.2*(game.energy - 2500.0); - if damaged("DPHOTON"): - forces += 300.0 - else: - forces -= 50.0*game.torps - else: - # phasers and photon tubes both out! - forces += 1000.0 - motion = 0; - if forces <= 1000.0 and game.condition != "docked": # Typical case - motion = ((forces+200.0*Rand())/150.0) - 5.0 - else: - if forces > 1000.0: # Very strong -- move in for kill - motion = (1.0-square(Rand()))*dist1 + 1.0 - if game.condition == "docked" and "base" in game.options: - # protected by base -- back off ! - motion -= game.skill * (2.0-Rand()**2) - if idebug: - proutn("=== MOTION = %1.2f, FORCES = %1.2f, ", motion, forces) - # don't move if no motion - if motion == 0: - return - # Limit motion according to skill - if abs(motion) > game.skill: - if motion < 0: - motion = -game.kill - else: - motion = game.skill - # calculate preferred number of steps - nsteps = abs(motion) - if motion > 0 and nsteps > mdist: # don't overshoot - nsteps = mdist - if nsteps > QUADSIZE: # This shouldn't be necessary - nsteps = QUADSIZE - if nsteps < 1: # This shouldn't be necessary - nsteps = 1 - if idebug: - proutn("NSTEPS = %d:", nsteps) - # Compute preferred values of delta X and Y - me = game.sector - com; - if 2.0 * abs(me.x) < abs(me.y): - me.x = 0; - if 2.0 * abs(me.y) < abs(game.sector.x-com.x): - me.y = 0; - if me.x != 0: me.x = sgn(me.x*motion) - if me.y != 0: me.y = sgn(me.y*motion) - next = com; - # main move loop - for ll in range(nsteps): - if idebug: - proutn(" %d", ll+1) - # Check if preferred position available - look = next + me - krawl = me.sgn() - success = False - attempts = 0 # Settle meysterious hang problem - while attempts < 20 and not success: - attempts += 1 - if look.x < 1 or look.x > QUADSIZE: - if motion < 0 and tryexit(look, ship, bugout): - return - if krawl.x == me.x or me.y == 0: - break - look.x = next.x + krawl.x - krawl.x = -krawl.x - elif look.y < 1 or look.y > QUADSIZE: - if motion < 0 and tryexit(look, ship, bugout): - return - if krawl.y == me.y or me.x == 0: - break - look.y = next.y + krawl.y - krawl.y = -krawl.y - elif "ramming" in game.options and game.quad[look] != IHDOT: - # See if we should ram ship - if game.quad[look] == game.ship and ienm in (IHC, IHS): - ram(true, ienm, com) - return - if krawl.x != me.x and me.y != 0: - look.x = next.x + krawlx - krawl.x = -krawl.x - elif krawly != me.y and me.x != 0: - look.y = next.y + krawly - krawl.y = -krawl.y - else: - break # we have failed - else: - success = True - if success: - next = look - if idebug: - proutn(str(next)) - else: - break # done early - if idebug: - prout("") - # Put ship in place within same quadrant - if next != ship.location: - # it moved - if not damaged("DSRSENS") or game.condition == "docked": - proutn("*** %s from sector %s" % (ship, ship.location)) - if ship.distance() < dist1: - prout(" advances to sector %s" % ship.location) - else: - prout(" retreats to sector %s" % ship.location) - ship.sectormove(next) - -def moveklings(): - "Allow enemies to move." - for enemy in self.quad.enemies(): - if enemy.type == "Commander": - movebaddy(enemy) - break - for enemy in self.quad.enemies(): - if enemy.type == "Super-Commander": - movebaddy(enemy) - break - # Ff skill level is high, move other Klingons and Romulans too! - # Move these last so they can base their actions on what the - # commander(s) do. - if game.skill >= SKILL_EXPERT and "movebaddy" in game.options: - for enemy in self.quad.enemies(): - if enemy.type in ("Klingon", "Romulan"): - movebaddy(enemy) - break - -def movescom(ship, avoid): - # commander movement helper - if game.state.kscmdr == game.quadrant or \ - game.state.galaxy[iq].supernova or \ - game.state.galaxy[iq].klingons > MAXKLQUAD-1: - return True - if avoid: - # Avoid quadrants with bases if we want to avoid Enterprise - for base in game.state.starbases: - if base.location == ship.location: - return True - if game.justin and not game.iscate: - return True - # Super-Commander has scooted, Remove him from current quadrant. - if game.state.kscmdr == game.quadrant: - game.iscate = False - game.isatb = 0 - game.ientesc = False - unschedule("FSCDBAS") - if game.condition != "docked": - newcnd() - ship.sectormove(None) - # do the actual move - game.state.galaxy[game.state.kscmdr].klingons -= 1 - game.state.kscmdr = iq - game.state.galaxy[game.state.kscmdr].klingons += 1 - # check for a helpful planet in the destination quadrant - for planet in game.state.planets: - if planet.location == game.state.kscmdr and planet.crystals=="present": - # destroy the planet - del planet - if communicating(): - pause_game(True) - prout("Lt. Uhura- \"Captain, Starfleet Intelligence reports") - proutn(_(" a planet in ")) - proutn(cramlc(quadrant, game.state.kscmdr)) - prout(" has been destroyed") - prout(" by the Super-commander.\"") - break - return False # looks good! - -def scom(): - # move the Super Commander - if (idebug): - prout("== SCOM") - - # Decide on being active or passive - passive = ((NKILLC+NKILLK)/(game.state.date+0.01-game.indate) < 0.1*game.skill*(game.skill+1.0) \ - or (game.state.date-game.indate) < 3.0) - if not game.iscate and passive: - # coxmpute move away from Enterprise - delta = game.state.kscmdr - game.quadrant - if distance(game.state.kscmdr) > 2.0: - # circulate in space - delta.x = game.state.kscmdr.y-game.quadrant.y - delta.y = game.quadrant.x-game.state.kscmdr.x - else: - if len(game.state.bases): - unschedule("FSCMOVE") - return - sc = game.state.kscmdr - # compute distances to starbases - game.starbases.sort(lambda x, y: cmp(distance(x, game.quadrant), distance(y, game.quadrant))) - # look for nearest base without a commander, no Enterprise, and - # without too many Klingons, and not already under attack. - nearest = filter(game.starbases, - lambda x: game.state.galaxy[x].supernova \ - and game.state.galaxy[x].klingons <= MAXKLQUAD-1) - if game.quadrant in nearest: - nearest.remove(game.quadrant) - if game.battle in nearest: - nearest.remove(game.battle) - # if there is a commander, and no other base is appropriate, - # we will take the one with the commander - nocmd = filter(lambda x: x.location not in game.state.kcmdr, nearest) - if len(nocmd): - nearest = nocmd - ibq = nearest[0] - if len(nearest) == 0: - return # Nothing suitable -- wait until next time - # decide how to move toward base - delta = ibq - game.state.kscmdr - # maximum movement is 1 quadrant in either or both axis - delta = delta.sgn() - # try moving in both x and y directions - iq = game.state.kscmdr + delta - if movescom(iq, passive): - # failed -- try some other maneuvers - if delta.x==0 or delta.y==0: - # attempt angle move - if delta.x != 0: - iq.y = game.state.kscmdr.y + 1 - if movescom(iq, passive): - iq.y = game.state.kscmdr.y - 1 - movescom(iq, passive) - else: - iq.x = game.state.kscmdr.x + 1 - if movescom(iq, passive): - iq.x = game.state.kscmdr.x - 1 - movescom(iq, passive) - else: - # try moving just in x or y - iq.y = game.state.kscmdr.y - if movescom(iq, passive): - iq.y = game.state.kscmdr.y + delta.y - iq.x = game.state.kscmdr.x - movescom(iq, passive) - # check for a base - if len(game.state.bases) == 0: - unschedule("FSCMOVE") - else: - for ibq in game.bases: - if ibq == game.state.kscmdr and game.state.kscmdr == game.battle: - # attack the base - if passive: - return # no, don't attack base! - game.iseenit = false - game.isatb = 1 - schedule("FSCDBAS", 1.0 +2.0*Rand()) - if is_scheduled("FCDBAS"): - postpone("FSCDBAS", scheduled("FCDBAS")-game.state.date) - if not communicating(): - return # no warning - game.iseenit = True - pause_game(true) - proutn(_("Lt. Uhura- \"Captain, the starbase in ")) - proutn(cramlc(quadrant, game.state.kscmdr)) - skip(1) - prout(" reports that it is under attack from the Klingon Super-commander.") - proutn(" It can survive until stardate %d.\"", - int(scheduled(FSCDBAS))) - if not game.resting: - return - prout("Mr. Spock- \"Captain, shall we cancel the rest period?\"") - if ja() == false: - return - game.resting = False - game.optime = 0.0 # actually finished - return - # Check for intelligence report - if (Rand() > 0.2 or not communicating() or - not game.state.galaxy[game.state.kscmdr].charted): - return - pause_game(true) - prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports")) - proutn(_(" the Super-commander is in ")) - proutn(cramlc(quadrant, game.state.kscmdr)) - prout(".\"") - return - -def movetho(void): - "Move the Tholian (an instance of ship type pointed at by game.tholian)." - if not game.tholian or game.justin: - return - next = coord() - if game.tholian.location.x == 1 and game.tholian.location.y == 1: - next.x = 1 - next.y = QUADSIZE - elif game.tholian.location.x == 1 and game.tholian.location.y == QUADSIZE: - next.x = next.y = QUADSIZE - elif game.tholian.location.x == QUADSIZE and game.tholian.location.y == QUADSIZE: - next.x = QUADSIZE - next.y = 1 - elif game.tholian.location.x == QUADSIZE and game.tholian.location.y == 1: - next.x = next.y = 1 - else: - # something is wrong! - game.tholian = None - return - # Do nothing if we are blocked - if not (isinstance(game.quad[next], space) or isinstance(game.quad[next], web)): - return - # Now place some web - im = (next - game.tholian.location).sgn() - if game.tholian.x != next.x: - # move in x axis - while game.tholian.location.x != next.x: - game.tholian.location.x += im.x - if isinstance(game.quad[game.tholian.location], space): - game.quad[game.tholian.location] = web() - elif game.tholian.y != next.y: - # move in y axis - while game.tholian.y != next.y: - game.tholian.y += im.y - if isinstance(game.quad[game.tholian.location], space): - game.quad[game.tholian.location] = web() - # web is done, move ship - game.tholian.movesector(next) - # check to see if all holes plugged - for i in range(1, QUADSIZE+1): - if (not isinstance(game.quad[(1,i)],web)) and game.quad[(1,i)]!=game.tholian: - return - if (not isinstance(game.quad[(QUADSIZE,i)],web)) and game.quad[(QUADSIZE,i)]!=game.tholian: - return - if (not isinstance(game.quad[(i,1)],web)) and game.quad[(i,1)]!=game.tholian: - return - if (not isinstance(game.quad[(i.QUADSIZE)],web)) and game.quad[(i,QUADSIZE)]!=game.tholian: - return - # All plugged up -- Tholian splits - game.quad[game.tholian] = web() - ship.movesector(None) - crmena(True, IHT, sector, game.tholian) - prout(" completes web.") - game.tholian = None - return + self.options = None # Game options + self.state = None # A snapshot structure + self.snapsht = None # Last snapshot taken for time-travel purposes + self.quad = [[IHDOT * (QUADSIZE+1)] * (QUADSIZE+1)] # contents of our quadrant + self.kpower = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)] # enemy energy levels + self.kdist = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)] # enemy distances + self.kavgd = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)] # average distances + self.damage = [0] * NDEVICES # damage encountered + self.future = [0.0] * NEVENTS # future events + for i in range(NEVENTS): + self.future.append(event()) + self.passwd = None; # Self Destruct password + self.ks = [[None * (QUADSIZE+1)] * (QUADSIZE+1)] # enemy sector locations + self.quadrant = None # where we are in the large + self.sector = None # where we are in the small + self.tholian = None # coordinates of Tholian + self.base = None # position of base in current quadrant + self.battle = None # base coordinates being attacked + self.plnet = None # location of planet in quadrant + self.probec = None # current probe quadrant + self.gamewon = False # Finished! + self.ididit = False # action taken -- allows enemy to attack + self.alive = False # we are alive (not killed) + self.justin = False # just entered quadrant + self.shldup = False # shields are up + self.shldchg = False # shield is changing (affects efficiency) + self.comhere = False # commander here + self.ishere = False # super-commander in quadrant + self.iscate = False # super commander is here + self.ientesc = False # attempted escape from supercommander + self.ithere = False # Tholian is here + self.resting = False # rest time + self.icraft = False # Kirk in Galileo + self.landed = False # party on planet (true), on ship (false) + self.alldone = False # game is now finished + self.neutz = False # Romulan Neutral Zone + self.isarmed = False # probe is armed + self.inorbit = False # orbiting a planet + self.imine = False # mining + self.icrystl = False # dilithium crystals aboard + self.iseenit = False # seen base attack report + self.thawed = False # thawed game + self.condition = None # "green", "yellow", "red", "docked", "dead" + self.iscraft = None # "onship", "offship", "removed" + self.skill = None # Player skill level + self.inkling = 0 # initial number of klingons + self.inbase = 0 # initial number of bases + self.incom = 0 # initial number of commanders + self.inscom = 0 # initial number of commanders + self.inrom = 0 # initial number of commanders + self.instar = 0 # initial stars + self.intorps = 0 # initial/max torpedoes + self.torps = 0 # number of torpedoes + self.ship = 0 # ship type -- 'E' is Enterprise + self.abandoned = 0 # count of crew abandoned in space + self.length = 0 # length of game + self.klhere = 0 # klingons here + self.casual = 0 # causalties + self.nhelp = 0 # calls for help + self.nkinks = 0 # count of energy-barrier crossings + self.iplnet = 0 # planet # in quadrant + self.inplan = 0 # initial planets + self.nenhere = 0 # number of enemies in quadrant + self.irhere = 0 # Romulans in quadrant + self.isatb = 0 # =1 if super commander is attacking base + self.tourn = 0 # tournament number + self.proben = 0 # number of moves for probe + self.nprobes = 0 # number of probes available + self.inresor = 0.0 # initial resources + self.intime = 0.0 # initial time + self.inenrg = 0.0 # initial/max energy + self.inshld = 0.0 # initial/max shield + self.inlsr = 0.0 # initial life support resources + self.indate = 0.0 # initial date + self.energy = 0.0 # energy level + self.shield = 0.0 # shield level + self.warpfac = 0.0 # warp speed + self.wfacsq = 0.0 # squared warp factor + self.lsupres = 0.0 # life support reserves + self.dist = 0.0 # movement distance + self.direc = 0.0 # movement direction + self.optime = 0.0 # time taken by current operation + self.docfac = 0.0 # repair factor when docking (constant?) + self.damfac = 0.0 # damage factor + self.lastchart = 0.0 # time star chart was last updated + self.cryprob = 0.0 # probability that crystal will work + self.probex = 0.0 # location of probe + self.probey = 0.0 # + self.probeinx = 0.0 # probe x,y increment + self.probeiny = 0.0 # + self.height = 0.0 # height of orbit around planet