Reset the translation, we're going to redo it with ctopy.
[super-star-trek.git] / src / sst.py
index 5d69d911dcf3d514ad98dbeb79ea859940ca1689..c082b3b4df7ed83bf73ba3980cb509ffdcbb4161 100644 (file)
@@ -7,7 +7,7 @@ radically different -- the Python code makes heavy use of objects.
 
 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
 
 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 exual to the hash of a literal tuple containing its
+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.
 
 """
 coordinate data, we ensure these can be indexed both ways.
 
 """
@@ -61,13 +61,14 @@ class coord:
         return "%d - %d" % (self.x, self.y)
 
 class feature:
         return "%d - %d" % (self.x, self.y)
 
 class feature:
-    "A feature in the current quadrant (ship, star, black hole, etc)." 
+    "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):
     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." 
         return self.name[0]
     def sectormove(self, dest):
         "Move this feature within the current quadrant." 
@@ -76,15 +77,14 @@ class feature:
         game.quad[dest] = self
         self.sector = dest
 
         game.quad[dest] = self
         self.sector = dest
 
-empty = None   # Value of empty space in game.quad
-
 class ship(feature):
 class ship(feature):
-    "An enemy ship in the current quadrant." 
-    def __init__(self):
+    "A starship, frindly or enemy." 
+    def __init__(self, type, power):
         feature.__init__(self)
         feature.__init__(self)
-        self.type = None       # klingon, romulan, commander,
-                               # supercommander, tholian
-        self.power = None      # power
+        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":
         if self.type in ("Klingon", "Commander", "Super-Commander"):
             game.remkl += 1
         elif self.type == "Romulan":
@@ -95,6 +95,16 @@ class ship(feature):
         elif self.type == "Romulan":
             game.romrem -= 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."
     def __init(self):
 class planet(feature):
     "A planet.  May be inhabited or not, may hold dilithium crystals or not."
     def __init(self):
@@ -103,32 +113,24 @@ class planet(feature):
         self.crystals = None   # "absent", "present", or "mined"
         self.inhabited = False
         self.known = "unknown" # Other values: "known" and "shuttle down"
         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'
 
     def __str__(self):
         if self.inhabited:
             return '@'
         else:
             return 'P'
 
-class star(feature):
-    "A star.  Has no state, just knows how to identify iself."
-    def __init(self):
-        feature.__init__(self)
-    def __str__(self):
-        return '*'
-
 class web(feature):
     "A bit of Tholian web.  Has no state, just knows how to identify iself."
 class web(feature):
     "A bit of Tholian web.  Has no state, just knows how to identify iself."
-    def __init(self):
-        feature.__init__(self)
     def __str__(self):
         return '*'
 
 class blackhole(feature):
     "A black hole.  Has no hair, 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 __init(self):
-        feature.__init__(self)
     def __str__(self):
     def __str__(self):
-        return '*'
+        return ' '
 
 class starbase(feature):
     "Starbases also have no features, just a location."
 
 class starbase(feature):
     "Starbases also have no features, just a location."
@@ -140,8 +142,6 @@ class starbase(feature):
         game.state.bases.remove(self)
     def __str__(self):
         return 'B'
         game.state.bases.remove(self)
     def __str__(self):
         return 'B'
-    def __del__(self):
-        feature.__del__(self)
 
 class quadrant:
     def __init__(self):
 
 class quadrant:
     def __init__(self):
@@ -180,9 +180,8 @@ class snapshot:
        self.starkl = None      # destroyed stars
        self.basekl = None      # destroyed bases
        self.nromrem = None     # Romulans remaining
        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.plnets = [];      # List of planets known
+       self.nplankl = None     # destroyed uninhabited planets self.nworldkl = None    # destroyed inhabited planets
+        self.planets = [];     # List of planets known
         self.date = None       # stardate
        self.remres = None      # remaining resources
        self. remtime = None    # remaining time
         self.date = None       # stardate
        self.remres = None      # remaining resources
        self. remtime = None    # remaining time
@@ -249,7 +248,7 @@ class game:
         self.skill = None              # levels: none, novice, fair, good,
                                        # expert, emeritus
         # Integer nembers sart here
         self.skill = None              # levels: none, novice, fair, good,
                                        # expert, emeritus
         # Integer nembers sart here
-       self.inkling = None             # initial number of klingons
+x      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.inbase = None              # initial number of bases
        self.incom = None               # initial number of commanders
        self.inscom = None              # initial number of commanders
@@ -296,463 +295,4 @@ class game:
        self.probeiny = None            #
        self.height = None              # height of orbit around planet
 
        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 movcom(): 
-    "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
-    global ipage
-    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.plnets:
-       if planet.location == game.state.kscmdr and planet.crystals=="present":
-           # destroy the planet
-           game.state.plnets.remove(planet)
-            if communicating():
-                if not ipage:
-                    pause_game(True)
-               ipage = 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:
-       # compute move away from Enterprise
-       idelta = game.state.kscmdr - game.quadrant
-        if distance(game.state.kscmdr) > 2.0:
-           # circulate in space
-           idelta,x = game.state.kscmdr.y-game.quadrant.y
-           idelta,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
-       idelta = 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 + idelta
-    if movescom(iq, passive):
-       # failed -- try some other maneuvers
-        if ideltax==0 or ideltay==0:
-           # attempt angle move
-            if ideltax != 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 + ideltay
-               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
-                if not ipage:
-                    pause_game(true)
-                ipage = 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
-    if ipage:
-        pause_game(true)
-        ipage = 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 game.quad[next] != empty and not 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 game.quad[game.tholian.location] == empty:
-                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 game.quad[game.tholian.location] == empty:
-                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