1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

Mapscripting: problems with isValid method for findStartingPlots

Discussion in 'Civ4 - Creation & Customization' started by Shizanu, Feb 6, 2010.

  1. Shizanu

    Shizanu Chieftain

    Feb 6, 2010

    not 100% sure I am right here, but the mapscripting forum looked more like being for finished maps.

    I am currently trying to do a fix on the starting positions of LD_Mirror_Inland_Sea_3a in Teamgames.

    What I am trying to achieve: LD_Mirror_Inland_Sea_3a uses the findStartingPlot methods from Mirror mapscript - meaning the default ones. This leads to very crazy player distribution when you play with more then two people (1v1) on the map.
    I want to have the player distribution done like on Inland Sea, by a given template with a certain variance.

    To do so, I reduced the part where one of the teams is chosen randomly to be assigned to the left side, to always the same team being taken (dont see much evil here on a mirrored map and makes coding this easier) and then changed the isValid method that is used for checking if the found starting plots are used, to one I am now trying to write myself.
    This part of the code looks like this: (changed method marked bold)

    Spoiler :
    teamOneIndex = 0
    for thisPlayer in playersOnTeamTwo:
    player = gc.getPlayer(thisPlayer)
    startPlot = CvMapGeneratorUtil.findStartingPlot(thisPlayer, isValidForMirrorInland)
    sPlot = map.plotByIndex(startPlot)
    player.setStartingPlot(sPlot, true)
    iX = sPlot.getX()
    iY = sPlot.getY()
    mirror_x = reflect_x(iX)
    mirror_y = reflect_y(iY)
    opposite_player = gc.getPlayer(playersOnTeamOne[teamOneIndex])
    oppositePlot = map.plot(mirror_x, mirror_y)
    opposite_player.setStartingPlot(oppositePlot, true)
    teamOneIndex += 1

    The findStartingPlot method that is called here from CvMapGeneratorUtil looks like this:

    Spoiler :
    def findStartingPlot(playerID, validFn = None):
    gc = CyGlobalContext()
    map = CyMap()
    player = gc.getPlayer(playerID)


    iRange = player.startingPlotRange()
    iPass = 0

    while (true):
    iBestValue = 0
    pBestPlot = None

    for iX in range(map.getGridWidth()):
    for iY in range(map.getGridHeight()):
    if validFn != None and not validFn(playerID, iX, iY):
    pLoopPlot = map.plot(iX, iY)

    val = pLoopPlot.getFoundValue(playerID)

    if val > iBestValue:

    valid = True

    for iI in range(gc.getMAX_CIV_PLAYERS()):
    if (gc.getPlayer(iI).isAlive()):
    if (iI != playerID):
    if gc.getPlayer(iI).startingPlotWithinRange(pLoopPlot, playerID, iRange, iPass):
    valid = False

    if valid:
    iBestValue = val
    pBestPlot = pLoopPlot

    if pBestPlot != None:
    return map.plotNum(pBestPlot.getX(), pBestPlot.getY())

    print "player", playerID, "pass", iPass, "failed"

    iPass += 1

    return -1

    My isValidForMirrorInland method currently looks like this:
    Spoiler :
    def isValidForMirrorInland(playerID, x, y):
    global playersOnTeamTwo

    i = 0
    while i<len(playersOnTeamTwo):
    i = i+1
    if (playerID == playersOnTeamTwo):
    teamnum = i

    mirrorTemplates = {0: [0.1, 0.5, 3, 3],
    1: [0.3, 0.167, 3, 3],
    2: [0.3, 0.833, 3, 3]}

    gc = CyGlobalContext()
    map = CyMap()
    pPlot = map.plot(x, y)
    mapsizeX = map.getGridWidth()
    mapsizeY = map.getGridHeight()

    [fLat, fLon, varX, varY] = mirrorTemplates[teamNum]

    # Check to ensure the plot is on the main landmass.
    if (pPlot.getArea() != map.findBiggestArea(False).getID()):
    return false

    # Now check for eligibility according to the defintions found in the template.
    expectedXvalue = int(mapsizeX * fLat)
    expectedYvalue = int(mapsizeY * fLon)
    westX = max(2, expectedXvalue - varX)
    eastX = min(mapsizeX - 3, expectedXvalue + varX)
    southY = max(2, expectedYvalue - varY)
    northY = min(mapsizeY - 3, expectedYvalue + varY)
    if x < westX:
    return false
    elif x > eastX:
    return false
    elif y < southY:
    return false
    elif y > northY:
    return false
    return true

    Obviously I kind of copied some stuff from Inland Sea skript and modified it. The template list obviously needs to be completed, but I only ran tests with 6 players so far, so this cant be the problem.

    Now what is the problem? Well plainly nothing is happening. I dont see any effect of my method. The map is launching without problems, but player start as random as ever.
    Now the first thing I did, was testing if my code was actually used. So I just put in some test stuff, limiting the position to certain x values. It definately IS used.
    I did some more testing etc, but I am severely at a loss of ideas why the method is plainly doing nothing.

    What is the code supposed to be doing. Well first compare the playerID with the playersOnTeamTwo list, to find out on what position that player is on that list. The position in the playersOnTeamTwo list decides, which template is used.
    And then I copied the code from Inland Sea is valid method (with some changed variable names to unconfuse myself), to check if the position is within a certain distance (values 3 and 4 in the template being the allowed distance) of the expected starting position. If it isn´t return false, else true.
    The only thing I am a little unsure about is that playerID variable. That one is dragged through several methods and I spend quite some time tracing it. But I am pretty sure it should be found within playerOnTeamTwo, because as you can see in the spoilered code, it is a value taken from that list, passed to findStartingPlot as PlayerID and then used to call upon isValidForMirrorInland in that method.
    Otherwise I am just at a loss of ideas :(

    Would be great if anyone could give me some help.

    I attached the script to the post and also LDeska´s original script.



    Attached Files:

  2. General Tso

    General Tso Panzer General

    Oct 12, 2007
    U. S. of A.
    I'm not familiar with map scripting, but I don't see any obvious problems with the code. I'd recommend printing - playerID, x, y, westX, eastX, northY, and southY to PythonDbg.log and see if any of the values are incorrect, then trace the problem from there.
  3. The_J

    The_J Say No 2 Net Validations Retired Moderator Supporter

    Oct 22, 2008
    Welcome to CFC Shizanu :D.

    First: Are the python exceptions enabled?
    Maybe there is something going wrong.

    And could you please post the code in php tags, and not in spoiler tags? That would make it easier to read it.
  4. Shizanu

    Shizanu Chieftain

    Feb 6, 2010
    thx for the answers, though...

    ...öhm, you are pretty much talking chinese here :)

    I just started on this yesterday with no preliminary knowledge of python or civ code :D

    However Its working now. One mistake was, that I defined the team number in teamnum and then tried to call on teamNum -.-

    Dont know if that was everything. I "debugged" by taking out all the code and then step by step adding it from the end and always testing by starting civ - horrible work and I always added new mistakes when defining variables myself for testing etc...
    Anyway its working now :)

    What do you mean with python exceptions enabled? Is there a way to get decent exceptions if there is some error? because if my method throws an exception the mapscript acts, as if it returned true. That confused me a lot till I found out about it, because I ecpected it to crash.

    And how do I do that printing? and where do I find it then?

    anyway going to attack the method, that makes starting positions bearable now - Sirian already lost that on creating the original Mirror script.



    PS: Code now looking like this:
            def isValidForMirrorInland(playerIDxy):
    #playersOnTeamTwo contains the playerIDs of the team that is assiged to the left side of the map
                #this array is greated in assignStartingPlots
                #the players position in that array is used to assign his individual template
    global playersOnTeamTwo

    #checks with position on the list playerOnTeamTwo this specific player holds
            #in order to assign the template by that number
    while i<(len(playersOnTeamTwo)):
                    if (
    playerID == playersOnTeamTwo[i]):
    teamnum i

    #templates for positioning in teamer games with 2 evenly numbered teams
                #structure: Number of players per team: {teamnumber of player: [Xvalue,Yvalue,Xvariance,Yvariance]}
    mirrorTemplates =  {2:{0: [0.2,0.167,2,2],
    1: [0.2,0.833,2,2]},

    3:{0: [0.10.522],
    1: [0.30.16722],
    2: [0.30.83322]}
    gc CyGlobalContext()
    map CyMap()
    pPlot map.plot(xy)

    # get mapsize in plots
    mapsizeX map.getGridWidth()
    mapsizeY map.getGridHeight()

    #assign values from template, by number of players in game and teamnumber of this specific player
    relativeXvalue mirrorTemplates[len(playersOnTeamTwo)][teamnum][0]
    relativeYvalue mirrorTemplates[len(playersOnTeamTwo)][teamnum][1]
    varX mirrorTemplates[len(playersOnTeamTwo)][teamnum][2]
    varY mirrorTemplates[len(playersOnTeamTwo)][teamnum][3]

    # Check to ensure the plot is on the main landmass.
    if (pPlot.getArea() != map.findBiggestArea(False).getID()):

    # Now check for eligibility according to the defintions found in the template.
            # First math out the expected value in Plot
    expectedXvalue int(mapsizeX relativeXvalue)
    expectedYvalue int(mapsizeY relativeYvalue)
    # Now assign border values, making sure that you dont try putting players out of the map
    westX max(2expectedXvalue varX)
    eastX min(mapsizeX 3expectedXvalue varX)
    southY max(2expectedYvalue varY)
    northY min(mapsizeY 3expectedYvalue varY)

    #check if the x/y coordinates passed to this method, are within those boundaries
            #if they are not return false, else true
    if westX:
            elif x 
            elif y 
            elif y 
  5. The_J

    The_J Say No 2 Net Validations Retired Moderator Supporter

    Oct 22, 2008
    Then your work is pretty good :).

    In the civilization4.ini (Eigene Dateien\My Games\BtS\Civilization4.ini) you can turn on some logging mechanisms and python exceptions.
    The exceptions will show up in the game, when something's wrong with the code technically (so not your mistake, but mistakes in grammar, etc).
    The logging will print out several things to files in Eigene Dateien\My Games\BtS\Logs, also the python exceptions. You can just add in the python code print SomeVariable, and this will be written in the PythonDbg.log (this is what General Tso has meant).
  6. Shizanu

    Shizanu Chieftain

    Feb 6, 2010
    thx, sounds useful :)

    btw I got the upgrade problem fixed as well and some other small changes. Only now the land is pretty imba - guess I am gonna remove some of the improve starting position methods again O.o.

    Anyway version should be ready for release within a few days :)

Share This Page