Python errors in mapscript, help needed

civcivv

Warlord
Joined
Dec 1, 2009
Messages
126
Location
London
Hello there,

I've been re-working the Earth3 mapscript conceived by jkp1187 - the file for which is no longer available.
I've followed the instructions provided in the thread (merging Earth2 with LDiCesare's Tectonics) and have had Sto give me some helpful advice on achieving my goals within the script.

Still, I've run into a couple of issues due to my lack of knowledge of python.

I've attached the script along with the errors with this post in hopes someone may be able to help me and thus re-publish Earth3 for the community.

Thanks in advance!

View attachment Earth3mod.zip
 
Can you post the errors you're getting in a spoiler/code block so I can help? I'm using a machine that is limited and can only access what's in the actual post. Otherwise, I'll try to remember to check out this thread over the weekend.
 
Errors:
Code:
Traceback (most recent call last):

File "string", line 1, in ?

File "string", line 35, in load_module

File "string, line 13, in _get_code

IndentationError: unindent does not match any outer indentation levvel (Earth3, line 1201)

I have tried selecting all and untabifying in python but when checking the script it always told me of the Indentation Error that I'm unable to get rid off (it looks fine to me that is to say...).

Thanks.

Earth3 as txt file:
View attachment Earth3.txt
 
I think the problem is in line 1137, it should have the same indentation as line 1138
 
Use a program like Notepad++ and turn on "View Whitespace" or whatever allows you to distinguish between spaces and tabs. In Python, whitespace is significant and part of the syntax.

Can you post in a [code]...[/code] block the first 30 or so lines or your file? It says the error is on line 13, and hopefully that's the line where the problem actually lies.
 
Here you go, first 35 lines :)

Code:
#
#   FILE:    earth3.py
#   PURPOSE: Global map script - Simulates Randomized Earth
#-----------------------------------------------------------------------------
#   Copyright (c) 2008 Firaxis Games, Inc. All rights reserved.
#-----------------------------------------------------------------------------
#

from CvPythonExtensions import *
import CvUtil
import CvMapGeneratorUtil
from CvMapGeneratorUtil import MultilayeredFractal
from CvMapGeneratorUtil import TerrainGenerator
from CvMapGeneratorUtil import FeatureGenerator

def getDescription():
    return "TXT_KEY_MAP_SCRIPT_earth2_DESCR"

def isAdvancedMap():
    "This map should show up in simple mode"
    return 0

def getGridSize(argsList):
    "Enlarge the grids! According to Soren, Earth-type maps are usually huge anyway."
    grid_sizes = {
        WorldSizeTypes.WORLDSIZE_DUEL:      (10,6),
        WorldSizeTypes.WORLDSIZE_TINY:      (15,9),
        WorldSizeTypes.WORLDSIZE_SMALL:     (20,12),
        WorldSizeTypes.WORLDSIZE_STANDARD:  (25,15),
        WorldSizeTypes.WORLDSIZE_LARGE:     (30,18),
        WorldSizeTypes.WORLDSIZE_HUGE:      (40,24)
    }

I'll have a look at whitespaces in the meantime, thanks!

[edit]

OK got myself Notepad++ and selected show whitespaces and tabs (and make it more visible with another color) but I can't find any issues at or near those error points... it looks fine to me, but then again I know quite little...
 
Well, that makes no sense. Line 13 has no indentation--let alone unindentation. I would recommend removing the "from CvMapGeneratorUtil import ..." lines only because you import the module itself just above them. Instead, reference all functions/classes in CvMapGeneratorUtil using "CvMapGeneratorUtil.<thing>" directly. The "from X import Y" construct is handy but unnecessary.

The first step in the face of unfathomable errors is to remove all uncertainty.
 
Hi EmperorFool,

The earliest error from the log refers to line 1201 having the error rather than 13 I believe? I'll go ahead and see whether I can do what you asked for though in the meantime.

I've posted 1131-1238 for you here
Code:
class earth2TerrainGenerator(CvMapGeneratorUtil.TerrainGenerator):
        def __init__(self, iDesertPercent=40, iPlainsPercent=26,
                 fSnowLatitude=0.82, fTundraLatitude=0.75,
                 fGrassLatitude=0.1, fDesertBottomLatitude=0.1,
                 fDesertTopLatitude=0.3, fracXExp=-1,
                 fracYExp=-1, grain_amount=3):
                self.gc = CyGlobalContext()
        self.map = CyMap()

        grain_amount += self.gc.getWorldInfo(self.map.getWorldSize()).getTerrainGrainChange()
        
        self.grain_amount = grain_amount

        self.iWidth = self.map.getGridWidth()
        self.iHeight = self.map.getGridHeight()

        self.mapRand = self.gc.getGame().getMapRand()
        
        self.iFlags = 0  # Disallow FRAC_POLAR flag, to prevent "zero row" problems.
        if self.map.isWrapX(): self.iFlags += CyFractal.FracVals.FRAC_WRAP_X
        if self.map.isWrapY(): self.iFlags += CyFractal.FracVals.FRAC_WRAP_Y

        self.deserts=CyFractal()
        self.plains=CyFractal()
        self.variation=CyFractal()

        iDesertPercent += self.gc.getClimateInfo(self.map.getClimate()).getDesertPercentChange()
        iDesertPercent = min(iDesertPercent, 100)
        iDesertPercent = max(iDesertPercent, 0)

        self.iDesertPercent = iDesertPercent
        self.iPlainsPercent = iPlainsPercent

        self.iDesertTopPercent = 100
        self.iDesertBottomPercent = max(0,int(100-iDesertPercent))
        self.iPlainsTopPercent = 100
        self.iPlainsBottomPercent = max(0,int(100-iDesertPercent-iPlainsPercent))
        self.iMountainTopPercent = 75
        self.iMountainBottomPercent = 60

        fSnowLatitude += self.gc.getClimateInfo(self.map.getClimate()).getSnowLatitudeChange()
        fSnowLatitude = min(fSnowLatitude, 1.0)
        fSnowLatitude = max(fSnowLatitude, 0.0)
        self.fSnowLatitude = fSnowLatitude

        fTundraLatitude += self.gc.getClimateInfo(self.map.getClimate()).getTundraLatitudeChange()
        fTundraLatitude = min(fTundraLatitude, 1.0)
        fTundraLatitude = max(fTundraLatitude, 0.0)
        self.fTundraLatitude = fTundraLatitude

        fGrassLatitude += self.gc.getClimateInfo(self.map.getClimate()).getGrassLatitudeChange()
        fGrassLatitude = min(fGrassLatitude, 1.0)
        fGrassLatitude = max(fGrassLatitude, 0.0)
        self.fGrassLatitude = fGrassLatitude

        fDesertBottomLatitude += self.gc.getClimateInfo(self.map.getClimate()).getDesertBottomLatitudeChange()
        fDesertBottomLatitude = min(fDesertBottomLatitude, 1.0)
        fDesertBottomLatitude = max(fDesertBottomLatitude, 0.0)
        self.fDesertBottomLatitude = fDesertBottomLatitude

        fDesertTopLatitude += self.gc.getClimateInfo(self.map.getClimate()).getDesertTopLatitudeChange()
        fDesertTopLatitude = min(fDesertTopLatitude, 1.0)
        fDesertTopLatitude = max(fDesertTopLatitude, 0.0)
        self.fDesertTopLatitude = fDesertTopLatitude
        
        self.fracXExp = fracXExp
        self.fracYExp = fracYExp

        self.initFractals()
        
[B]    def initFractals(self):[/B]
        self.deserts.fracInit(self.iWidth, self.iHeight, self.grain_amount, self.mapRand, self.iFlags, self.fracXExp, self.fracYExp)
        self.iDesertTop = self.deserts.getHeightFromPercent(self.iDesertTopPercent)
        self.iDesertBottom = self.deserts.getHeightFromPercent(self.iDesertBottomPercent)

        self.plains.fracInit(self.iWidth, self.iHeight, self.grain_amount+1, self.mapRand, self.iFlags, self.fracXExp, self.fracYExp)
        self.iPlainsTop = self.plains.getHeightFromPercent(self.iPlainsTopPercent)
        self.iPlainsBottom = self.plains.getHeightFromPercent(self.iPlainsBottomPercent)

        self.variation.fracInit(self.iWidth, self.iHeight, self.grain_amount, self.mapRand, self.iFlags, self.fracXExp, self.fracYExp)

        self.terrainDesert = self.gc.getInfoTypeForString("TERRAIN_DESERT")
        self.terrainPlains = self.gc.getInfoTypeForString("TERRAIN_PLAINS")
        self.terrainIce = self.gc.getInfoTypeForString("TERRAIN_SNOW")
        self.terrainTundra = self.gc.getInfoTypeForString("TERRAIN_TUNDRA")
        self.terrainGrass = self.gc.getInfoTypeForString("TERRAIN_GRASS")

    def getLatitudeAtPlot(self, iX, iY):
        """given a point (iX,iY) such that (0,0) is in the NW,
        returns a value between 0.0 (tropical) and 1.0 (polar).
        This function can be overridden to change the latitudes; for example,
        to make an entire map have temperate terrain, or to make terrain change from east to west
        instead of from north to south"""
        lat = abs((self.iHeight / 2) - iY)/float(self.iHeight/2) # 0.0 = equator, 1.0 = pole

        # Adjust latitude using self.variation fractal, to mix things up:
        lat += (128 - self.variation.getHeight(iX, iY))/(255.0 * 5.0)

        # Limit to the range [0, 1]:
        if lat < 0:
            lat = 0.0
        if lat > 1:
            lat = 1.0

        return lat

    def generateTerrain(self):      
        terrainData = [0]*(self.iWidth*self.iHeight)
        for x in range(self.iWidth):
            for y in range(self.iHeight):
                iI = y*self.iWidth + x
                terrain = self.generateTerrainAtPlot(x, y)
                terrainData[iI] = terrain
        return terrainData

    def generateTerrainAtPlot(self,iX,iY):
        lat = self.getLatitudeAtPlot(iX,iY)

        if (self.map.plot(iX, iY).isWater()):
            return self.map.plot(iX, iY).getTerrainType()

        terrainVal = self.terrainGrass

        if lat >= self.fSnowLatitude:
            terrainVal = self.terrainIce
        elif lat >= self.fTundraLatitude:
            terrainVal = self.terrainTundra
        elif lat < self.fGrassLatitude:
            terrainVal = self.terrainGrass
        else:
            desertVal = self.deserts.getHeight(iX, iY)
            plainsVal = self.plains.getHeight(iX, iY)
            if ((desertVal >= self.iDesertBottom) and (desertVal <= self.iDesertTop) and (lat >= self.fDesertBottomLatitude) and (lat < self.fDesertTopLatitude)):
                terrainVal = self.terrainDesert
            elif ((plainsVal >= self.iPlainsBottom) and (plainsVal <= self.iPlainsTop)):
                terrainVal = self.terrainPlains

        if (terrainVal == TerrainTypes.NO_TERRAIN):
            return self.map.plot(iX, iY).getTerrainType()

        return terrainVal

def generateTerrainTypes():
    NiTextOut("Generating Terrain (Python Terra) ...")
    terraingen = earth2TerrainGenerator()
    terrainTypes = terraingen.generateTerrain()
    return terrainTypes

def addFeatures():
    NiTextOut("Adding Features (Python earth2) ...")
    featuregen = FeatureGenerator()
    featuregen.addFeatures()
    return 0
 
Can you bold and colorize line 1201 so I don't have to count 70 lines to try to help you? I'm going to bed now, so no rush, but maybe others can help in the meantime. I will be back in about 24 hours.
 
The indentation on that line looks fine. Most all files in BTS use tabs instead of spaces for indentation, but it seems that code you posted uses all spaces--so that should be fine. And the bolded line is indented exactly what I'd expect given the line before it. I don't think that line is the problem.
 
Hmmm what struck me as odd about that error was that its found in a section that I have not even touched really - its base code from Earth2.

The only way that part of the code was even touched was during my "Select All + Detabify" using IDLE... but it threw that error at me before I did that even - right after I fixed the tab errors in the section I was actually working on:

Code:
# Starting position generation.
def findStartingPlot(argsList):
    gc = CyGlobalContext()
    map = CyMap()
    map.recalculateAreas()
    dice = gc.getGame().getMapRand()
    iPlayers = gc.getGame().countCivPlayersEverAlive()
    areas = CvMapGeneratorUtil.getAreas()
    areaValue = {}
    [playerID] = argsList

    if iPlayers < 2 or iPlayers > 18:
        bSuccessFlag = False
        CyPythonMgr().allowDefaultImpl()
        return

        bestAreaValue = 0
        global bestArea
        bestArea = -1
        for area in areas:
                    if area.isWater(): continue
                    if area.getNumTiles() < 12: continue
        areaValue[area.getID()] = area.calculateTotalBestNatureYield() + area.getNumRiverEdges() + 2 * area.countCoastalLand() + 3 * area.countNumUniqueBonusTypes()
        players = 2*area.getNumStartingPlots()

        #Avoid single players on landmasses:
        value = areaValue[area.getID()] / (1 + 2*players )
        if (value > bestAreaValue):
            bestAreaValue = value;
            bestArea = area.getID()

        def isValid(playerID, x, y):
            global bestArea
            plot = CyMap().plot(x,y)
            if (plot.getArea() != bestArea):
                return false
            if (plot.getLatitude() >= 75):
                return false
            return true
        findstart = CvMapGeneratorUtil.findStartingPlot(playerID,isValid)
        sPlot = map.plotByIndex(findstart)
        player.setStartingPlot(sPlot,true)

    return None
#

From my experience with other game scripting, I imagine it may be possible that an error somewhere in here would only be recognized by the game way further down the code (usually happens with an excessive bracket).

Could that be the case here?
 
Code:
class earth2TerrainGenerator(CvMapGeneratorUtil.TerrainGenerator):
        def __init__(self, iDesertPercent=40, iPlainsPercent=26,
def __init___ has 8 spaces indent
the next method:
Code:
    def initFractals(self):
def initFractals has only 4 spaces (like all other methods).

Hope that helps.
 
Thanks Temudjin,

I have now reduced the indent by 4 spaces for earth2TerrainGenerator and that part hasn't thrown an error, but the error for line 1201 seems to remain sadly :cry:


Another thing I found weird was that if I run Earth2.py (the basic script supplied with BtS) through IDLE's checker, it also returns an error, but the one regarding inconsistent tabbing and spacing. Oddly enough, the game has no problems running earth2 and doesn't seem to throw errors when I try to load that as a map :confused:


Newest Earth3 script in txt format:
View attachment Earth3.txt
 
Huh, guess what I did now...

I just ended up using the base Earth2 script for the parts following my own modifications. IDLE complained that tabs and spaces are now not used consistently, but the game doesn't throw any errors when loading the python script and the map generates just fine! :confused: :confused:

So yeah...it seems that this issue is solved...kind of. But in a weird way huh?


Putting the IDLE error aside for the moment, I did want to ask you experts though whether my modified section as per post #12 would work fine or whether there would be any issues with it?
What its supposed to do is:
- Ensure players can start anywhere on the map if its land and not an island smaller than 12 tiles
- Players cannot start alone on any landmass (though I imagine that would also apply to islands... might need to look into working around that)
- Otherwise players start as per default difficulty

In particular, is this part even needed? I cannot find it in the default earth2 script which ends before that line
Code:
        sPlot = map.plotByIndex(findstart)
        player.setStartingPlot(sPlot,true)

I didn't get any python exceptions but I don't know how I could possibly check if that part ran as intended?

Thanks in advance!
 
Code:
    def __init__(self, iDesertPercent=40, iPlainsPercent=26,
                 fSnowLatitude=0.82, fTundraLatitude=0.75,
                 fGrassLatitude=0.1, fDesertBottomLatitude=0.1,
                 fDesertTopLatitude=0.3, fracXExp=-1,
                 fracYExp=-1, grain_amount=3):
        self.gc = CyGlobalContext()
        self.map = CyMap()

Note that self.gc ... and self.map ... need the same indent.

@post #15
The first line converts the index of the newly found starting-plot into a plot and the other line sets this plot as the starting-plot for the appropriate player. You have to do that somewhere.

Incidentally now there are a few mods for more than 18 players. So in line 48 you might want to check against CyGlobalContext().getMAX_PLAYERS()-1 instead of 18.
 
Thanks Temudjin,

I take it you mean:
Code:
if iPlayers > CyGlobalContext().getMAX_PLAYERS()-1:

Is the code fine otherwise in the starting location section? Any conflicts or superfluous items?
 
That's what I meant.
I didn't look for potential trouble though, it's just that several scripts have this 1ß-player problem.
 
What are news of the remake Earth3.py ?
Quelles sont les nouvelles du remake de Earth3.py

It has a few rough things...
Il y a quelques trucs un peu rugueux...
 
Top Bottom