Help making a map script

Joined
Apr 11, 2015
Messages
438
Anyone know code for preventing map scripts from generating land area that is too big or too small?

So something like this:
Code:
- Calculate land area

- If total land area is:

    more than 55% of total map area

    Or

    less than 45% of total map area

- Then regenerate the map
 
The code for rejecting the map if the largest landmass is not at the specified size looks like it might be reconfigurable. I'm not sure what the definition for total number of map tiles is, though - "g_iNumTotalLandTiles" is the total number of land tiles, but I want total number of all tiles.
Code:
    -- Generate continental fractal layer and examine the largest landmass. Reject
    -- the result until the largest landmass occupies 84% or more of the total land.

...

        AreaBuilder.Recalculate();

        local biggest_area = Areas.FindBiggestArea(false);
        iNumBiggestAreaTiles = biggest_area:GetPlotCount();
       
        -- Now test the biggest landmass to see if it is large enough.
        if iNumBiggestAreaTiles >= g_iNumTotalLandTiles * 0.84 then
            done = true;
            iBiggestID = biggest_area:GetID();
        end
        iAttempts = iAttempts + 1;
 
Code:
Map.GetPlotCount()
will return the total number of map plots.

Snippet from NaturalWonderGenerator.lua
Code:
function NaturalWonderGenerator:__FindValidLocs()

	local iW, iH;
	iW, iH = Map.GetGridSize();

	local iBaseScore = 1;

	local iPlotCount = Map.GetPlotCount();
	for i = 0, iPlotCount - 1 do
		local pPlot = Map.GetPlotByIndex(i);
 
Code:
Map.GetPlotCount()
will return the total number of map plots.

Snippet from NaturalWonderGenerator.lua
Code:
function NaturalWonderGenerator:__FindValidLocs()

    local iW, iH;
    iW, iH = Map.GetGridSize();

    local iBaseScore = 1;

    local iPlotCount = Map.GetPlotCount();
    for i = 0, iPlotCount - 1 do
        local pPlot = Map.GetPlotByIndex(i);
Thanks.

I extrapolate and reconfigure to make this:
Code:
        local iPlotCount = Map.GetPlotCount();
        if g_iNumTotalLandTiles <= iPlotCount * 0.55
        and       
        if g_iNumTotalLandTiles >= iPlotCount  * 0.45
        then
            done = true;
 
your syntax is incorrect.
Code:
local iPlotCount = Map.GetPlotCount();
if (g_iNumTotalLandTiles <= iPlotCount * 0.55) and (g_iNumTotalLandTiles >= iPlotCount  * 0.45) then
     done = true
end
You can't have "and" followed by another "if". "and" requires another conditional evaluation to follow it. Before another "if" can be stated there has also to be a "then"

You can also do it like this
Code:
local iPlotCount = Map.GetPlotCount();
if (g_iNumTotalLandTiles <= iPlotCount * 0.55) then
     if (g_iNumTotalLandTiles >= iPlotCount  * 0.45) then
          done = true
     end
end
None of the parenthesis are really needed -- they just help in most cases to lend clarity as to what is part of what conditional evaluation or math calculation. Lua does follow the rules of mathematical calculation, though, so whenever a formula can be calculated not as you intend by the rule that multiplication comes before addition you should use parenthesis to force the math to be done in the order you actually want it done. So generally I will tend to code more like this
Code:
if (g_iNumTotalLandTiles <= (iPlotCount * 0.55) ) then
 
your syntax is incorrect.
Code:
local iPlotCount = Map.GetPlotCount();
if (g_iNumTotalLandTiles <= iPlotCount * 0.55) and (g_iNumTotalLandTiles >= iPlotCount  * 0.45) then
     done = true
end
You can't have "and" followed by another "if". "and" requires another conditional evaluation to follow it. Before another "if" can be stated there has also to be a "then"

You can also do it like this
Code:
local iPlotCount = Map.GetPlotCount();
if (g_iNumTotalLandTiles <= iPlotCount * 0.55) then
     if (g_iNumTotalLandTiles >= iPlotCount  * 0.45) then
          done = true
     end
end
None of the parenthesis are really needed -- they just help in most cases to lend clarity as to what is part of what conditional evaluation or math calculation. Lua does follow the rules of mathematical calculation, though, so whenever a formula can be calculated not as you intend by the rule that multiplication comes before addition you should use parenthesis to force the math to be done in the order you actually want it done. So generally I will tend to code more like this
Code:
if (g_iNumTotalLandTiles <= (iPlotCount * 0.55) ) then
Thanks. That looks good.

Do you know what this line is?
Code:
       iAttempts = iAttempts + 1;
And whether it needs to go between end and end, as it does with the Pangaea code? So like this:
Code:
    AreaBuilder.Recalculate();

    local iPlotCount = Map.GetPlotCount();
    if (g_iNumTotalLandTiles <= (iPlotCount * 0.55)) then
        if (g_iNumTotalLandTiles >= (iPlotCount  * 0.45)) then
            done = true
    end
    iAttempts = iAttempts + 1;
end
 
It looks like the "iAttempts" bit of code only appears when there's code to reject map generations that don't fit specified landmass size requirements. So it looks like it might be needed.

It may be that the following code also needs to be inserted a bit earlier in the map script, before the fractal generation:
Code:
    local done = false;
    local iAttempts = 0;
    while done == false do
 
Without looking at the code used by Firaxis (which I have not done), I would surmise there is a larger loop that is tracking the number of attempts made to create an "acceptable" result, by using and incrementing this counter every time the generation loop is conducted
Code:
 iAttempts = iAttempts + 1;
And then if the value of "iAttempts" gets larger than some preset value the code will abandon any further attempts to get a better result and just accept the latest result. My guess is this is acting as a safety valve to keep the code from endlessly repeating and never getting an "acceptable" result -- anyway that's the sort of thing I would add into such a loop because otherwise you would be guaranteed by the laws of chance to get conditions where map generation never completes and just keeps constantly re-running through the process.
 
Without looking at the code used by Firaxis (which I have not done), I would surmise there is a larger loop that is tracking the number of attempts made to create an "acceptable" result, by using and incrementing this counter every time the generation loop is conducted
Code:
 iAttempts = iAttempts + 1;
And then if the value of "iAttempts" gets larger than some preset value the code will abandon any further attempts to get a better result and just accept the latest result. My guess is this is acting as a safety valve to keep the code from endlessly repeating and never getting an "acceptable" result -- anyway that's the sort of thing I would add into such a loop because otherwise you would be guaranteed by the laws of chance to get conditions where map generation never completes and just keeps constantly re-running through the process.
Thanks.

I tried it without the iAttempts line, but it didn't work - error message while generating map.

From Lua.log:
Code:
Runtime Error: C: ... .lua:293: operator < is not supported for nil < number
stack traceback:
    C: ... .lua:293: in function 'GeneratePlotTypes'
    C: ... .lua:61: in function 'GenerateMap'
    [C]: in function '(anonymous)'
Lua callstack:
Runtime Error: Call to GenerateMap() had errors
stack traceback:
    [C]: in function '(anonymous)'
Line 293 is the code line:
Code:
    if (g_iNumTotalLandTiles <= (iPlotCount * 0.55)) then
 
where is g_iNumTotalLandTiles defined in your code ?
 
where is g_iNumTotalLandTiles defined in your code ?
It's from the Pangaea map script. Looking at that script, there's mention of g_iNumTotalLandTiles near the start:
Code:
local g_iW, g_iH;
local g_iFlags = {};
local g_continentsFrac = nil;
local g_iNumTotalLandTiles = 0;
local featureGen = nil;
local world_age_new = 5;
local world_age_normal = 3;
local world_age_old = 2;
Maybe I need to insert this line in my script:
Code:
local g_iNumTotalLandTiles = 0;
 
Yep, that worked. The map has generated now and game started.

I'll try and test whether it's actually taking effect by setting the percentages so that maps will generate small, or that the game will hang on loading since it can't fulfil the requirements.
 
I've been adjusting the settings and generating maps to try and test it, and I don't think the changes have taken effect. I even tried setting the land requirement range to 10-20%, which should be impossible, and a normal-sized map was generated, rather than it hanging in an endless loop at map generation.
 
Are you directly-editing the game's original files, and if so are you sure you are editing the correct version of the file for the expansion you are using ?
It's its own mod in the mod folder, based upon an Expansion2 map script.
 
It's from the Pangaea map script. Looking at that script, there's mention of g_iNumTotalLandTiles near the start:
Code:
local g_iW, g_iH;
local g_iFlags = {};
local g_continentsFrac = nil;
local g_iNumTotalLandTiles = 0;
local featureGen = nil;
local world_age_new = 5;
local world_age_normal = 3;
local world_age_old = 2;
Maybe I need to insert this line in my script:
Code:
local g_iNumTotalLandTiles = 0;
That won't be enough, now you have to assign the number of total land tiles to g_iNumTotalLandTiles before it's compared in your function. You should check where and how it's done in the Pangaea map script.
 
As in
Code:
local g_iNumTotalLandTiles = 0
Then after the map is actually generated
Code:
g_iNumTotalLandTiles = ??
Where '??" is a stand-in for the code needed to grab the number of land tiles. As Firaxis does here within function GeneratePlotTypes() in file Pangea.lua
Code:
		g_iNumTotalLandTiles = 0;
		for x = 0, g_iW - 1 do
			for y = 0, g_iH - 1 do
				local i = y * g_iW + x;
				local val = g_continentsFrac:GetHeight(x, y);
				local pPlot = Map.GetPlotByIndex(i);
				if(val <= iWaterThreshold) then
					plotTypes[i] = g_PLOT_TYPE_OCEAN;
					TerrainBuilder.SetTerrainType(pPlot, g_TERRAIN_TYPE_OCEAN);  -- temporary setting so can calculate areas
				else
					plotTypes[i] = g_PLOT_TYPE_LAND;
					TerrainBuilder.SetTerrainType(pPlot, g_TERRAIN_TYPE_DESERT);  -- temporary setting so can calculate areas
					g_iNumTotalLandTiles = g_iNumTotalLandTiles + 1;
				end
			end
		end
The reason they originally set the variable to 0 at the top of the file is so that the variable is "scoped" to the root level of the lua script and can therefore be used and updated by any function within the rest of the file. Note that here they are not declaring "local" again
Code:
g_iNumTotalLandTiles = 0
They are resetting the value to 0 to erase any previous data that may have been placed in the variable, and they are then recalculating the new value of "g_iNumTotalLandTiles" during the loop through all the tiles of the newly generated map:
Code:
g_iNumTotalLandTiles = g_iNumTotalLandTiles + 1;
 
Last edited:
Thanks for the replies.

I inserted the block of code from the Pangaea script into where I think it should go:
Code:
        g_iNumTotalLandTiles = 0;
        for x = 0, g_iW - 1 do
            for y = 0, g_iH - 1 do
                local i = y * g_iW + x;
                local val = g_continentsFrac:GetHeight(x, y);
                local pPlot = Map.GetPlotByIndex(i);
                if(val <= iWaterThreshold) then
                    plotTypes[i] = g_PLOT_TYPE_OCEAN;
                    TerrainBuilder.SetTerrainType(pPlot, g_TERRAIN_TYPE_OCEAN);  -- temporary setting so can calculate areas
                else
                    plotTypes[i] = g_PLOT_TYPE_LAND;
                    TerrainBuilder.SetTerrainType(pPlot, g_TERRAIN_TYPE_DESERT);  -- temporary setting so can calculate areas
                    g_iNumTotalLandTiles = g_iNumTotalLandTiles + 1;
                end
            end
        end
The map generated, but the changes still did not appear to have taken effect.

I also tried inserting the code lines that immediately precede that block of text:
Code:
        g_continentsFrac = nil;
        InitFractal{continent_grain = grain_dice, rift_grain = rift_dice};
        iWaterThreshold = g_continentsFrac:GetHeight(water_percent);
That caused an error message.

Here's the modified script:
Spoiler :
Code:
------------------------------------------------------------------------------
--    A modification of...
------------------------------------------------------------------------------
--    FILE:     Splintered_Fractal.lua
--    AUTHOR: 
--    PURPOSE: Base game script - Produces widely varied continents.
------------------------------------------------------------------------------
--    Copyright (c) 2014 Firaxis Games, Inc. All rights reserved.
------------------------------------------------------------------------------

include "MapEnums"
include "MapUtilities"
include "MountainsCliffs"
include "RiversLakes"
include "FeatureGenerator"
include "TerrainGenerator"
include "NaturalWonderGenerator"
include "ResourceGenerator"
include "CoastalLowlands"
include "AssignStartingPlots"

local g_iW, g_iH;
local g_iFlags = {};
local g_continentsFrac = nil;
local g_iNumTotalLandTiles = 0;
local featureGen = nil;
local world_age_new = 5;
local world_age_normal = 3;
local world_age_old = 2;
local islands = {};

-------------------------------------------------------------------------------
function GenerateMap()
    print("Generating Splintered Fractal Map");
    local pPlot;

    -- Set globals
    g_iW, g_iH = Map.GetGridSize();
    g_iFlags = TerrainBuilder.GetFractalFlags();

    local temperature = MapConfiguration.GetValue("temperature"); -- Default setting is Temperate.
    if temperature == 4 then
        temperature  =  1 + TerrainBuilder.GetRandomNumber(3, "Random Temperature- Lua");
    end
   
    --    local world_age
    local world_age = MapConfiguration.GetValue("world_age");
    if (world_age == 1) then
        world_age = world_age_new;
    elseif (world_age == 2) then
        world_age = world_age_normal;
    elseif (world_age == 3) then
        world_age = world_age_old;
    else
        world_age = 2 + TerrainBuilder.GetRandomNumber(4, "Random World Age - Lua");
    end

    plotTypes = GeneratePlotTypes(world_age);
    terrainTypes = GenerateTerrainTypes(plotTypes, g_iW, g_iH, g_iFlags, false, temperature);
    ApplyBaseTerrain(plotTypes, terrainTypes, g_iW, g_iH);
   
    AreaBuilder.Recalculate();
    TerrainBuilder.AnalyzeChokepoints();
    TerrainBuilder.StampContinents();

    local iContinentBoundaryPlots = GetContinentBoundaryPlotCount(g_iW, g_iH);
    local biggest_area = Areas.FindBiggestArea(false);
    print("After Adding Hills: ", biggest_area:GetPlotCount());
    AddTerrainFromContinents(plotTypes, terrainTypes, world_age, g_iW, g_iH, iContinentBoundaryPlots);

    AreaBuilder.Recalculate();

    -- River generation is affected by plot types, originating from highlands and preferring to traverse lowlands.
    AddRivers();
   
    -- Lakes would interfere with rivers, causing them to stop and not reach the ocean, if placed any sooner.
    local numLargeLakes = GameInfo.Maps[Map.GetMapSize()].Continents
    AddLakes(numLargeLakes);

    AddFeatures();
    TerrainBuilder.AnalyzeChokepoints();
   
    print("Adding cliffs");
    AddCliffs(plotTypes, terrainTypes);

    local args = {
        numberToPlace = GameInfo.Maps[Map.GetMapSize()].NumNaturalWonders,
    };
    local nwGen = NaturalWonderGenerator.Create(args);
   
    AddFeaturesFromContinents();
    MarkCoastalLowlands();
   
    --for i = 0, (g_iW * g_iH) - 1, 1 do
        --pPlot = Map.GetPlotByIndex(i);
        --print ("i: plotType, terrainType, featureType: " .. tostring(i) .. ": " .. tostring(plotTypes[i]) .. ", " .. tostring(terrainTypes[i]) .. ", " .. tostring(pPlot:GetFeatureType(i)));
    --end
    local resourcesConfig = MapConfiguration.GetValue("resources");
    local startconfig = MapConfiguration.GetValue("start"); -- Get the start config
    local args = {
        resources = resourcesConfig,
        START_CONFIG = startConfig,
    };
    local resGen = ResourceGenerator.Create(args);

    print("Creating start plot database.");
   
    -- START_MIN_Y and START_MAX_Y is the percent of the map ignored for major civs' starting positions.
    local args = {
        MIN_MAJOR_CIV_FERTILITY = 175,
        MIN_MINOR_CIV_FERTILITY = 50,
        MIN_BARBARIAN_FERTILITY = 1,
        START_MIN_Y = 15,
        START_MAX_Y = 15,
        START_CONFIG = startconfig,
    };
    local start_plot_database = AssignStartingPlots.Create(args)

    local GoodyGen = AddGoodies(g_iW, g_iH);
end


-------------------------------------------------------------------------------
function GeneratePlotTypes(world_age)
    print("Generating Plot Types");
    local plotTypes = {};
   
    local sea_level_low = 67;
    local sea_level_normal = 74;
    local sea_level_high = 80;
    local extra_mountains = 0;
    local adjust_plates = 1.0;
    local shift_plot_types = true;
    local hills_ridge_flags = g_iFlags;
    local peaks_ridge_flags = g_iFlags;
    local has_center_rift = false;

    --    local sea_level
    local sea_level = MapConfiguration.GetValue("sea_level");
    local water_percent;
    local water_percent_modifier = 0;
    if sea_level == 1 then -- Low Sea Level
        water_percent = sea_level_low
        water_percent_modifier = -4
    elseif sea_level == 2 then -- Normal Sea Level
        water_percent =sea_level_normal
        water_percent_modifier = 4;
    elseif sea_level == 3 then -- High Sea Level
        water_percent = sea_level_high
    else
        water_percent = TerrainBuilder.GetRandomNumber(sea_level_high- sea_level_low, "Random Sea Level - Lua") + sea_level_low  + 1 ;
        water_percent_modifier = TerrainBuilder.GetRandomNumber(9, "Random Sea Level - Lua") - 4;
    end

    -- Set values for hills and mountains according to World Age chosen by user.
    local adjustment = world_age;
    if world_age <= world_age_old  then -- 5 Billion Years
        adjust_plates = adjust_plates * 0.75;
    elseif world_age >= world_age_new then -- 3 Billion Years
        adjust_plates = adjust_plates * 1.5;
    else -- 4 Billion Years
    end

    local hillsBottom1 = 28 - adjustment;
    local hillsTop1 = 28 + adjustment;
    local hillsBottom2 = 72 - adjustment;
    local hillsTop2 = 72 + adjustment;
    local hillsClumps = 1 + adjustment;
    local hillsNearMountains = 91 - (adjustment * 2) - extra_mountains;
    local mountains = 97 - adjustment - extra_mountains;

    local polar =  true;

    local fracFlags = {};

    fracFlags.FRAC_POLAR = true;
    local MapSizeTypes = {};
    for row in GameInfo.Maps() do
        MapSizeTypes[row.MapSizeType] = row.PlateValue;
    end
    local sizekey = Map.GetMapSize();
    local numPlates = MapSizeTypes[sizekey] or 4;

    local continent_grain = 2;
    local rift_grain = -1;

    local riftsFrac = Fractal.Create(g_iW, g_iH, rift_grain, {}, 6, 5);
    g_continentsFrac = Fractal.CreateRifts(g_iW, g_iH, continent_grain, fracFlags, riftsFrac, 6, 5);
    g_continentsFrac:BuildRidges(numPlates, {}, 1, 2);
   
    hillsFrac = Fractal.Create(g_iW, g_iH, continent_grain, {}, 6, 5);
    mountainsFrac = Fractal.Create(g_iW, g_iH, continent_grain, {}, 6, 5);
    hillsFrac:BuildRidges(numPlates, g_iFlags, 1, 2);
    mountainsFrac:BuildRidges(numPlates * 2/3, g_iFlags, 6, 1);
    local iWaterThreshold = g_continentsFrac:GetHeight(water_percent);   
    local iHillsBottom1 = hillsFrac:GetHeight(hillsBottom1);
    local iHillsTop1 = hillsFrac:GetHeight(hillsTop1);
    local iHillsBottom2 = hillsFrac:GetHeight(hillsBottom2);
    local iHillsTop2 = hillsFrac:GetHeight(hillsTop2);
    local iHillsClumps = mountainsFrac:GetHeight(hillsClumps);
    local iHillsNearMountains = mountainsFrac:GetHeight(hillsNearMountains);
    local iMountainThreshold = mountainsFrac:GetHeight(mountains);
    local iPassThreshold = hillsFrac:GetHeight(hillsNearMountains);
    local iMountain100 = mountainsFrac:GetHeight(100);
    local iMountain99 = mountainsFrac:GetHeight(99);
    local iMountain97 = mountainsFrac:GetHeight(97);
    local iMountain95 = mountainsFrac:GetHeight(95);

    for x = 0, g_iW - 1 do
        for y = 0, g_iH - 1 do
            local i = y * g_iW + x + 1;
            local val = g_continentsFrac:GetHeight(x, y);
            local mountainVal = mountainsFrac:GetHeight(x, y);
            local hillVal = hillsFrac:GetHeight(x, y);
            local pPlot = Map.GetPlotByIndex(i);
   
            if(val <= iWaterThreshold) then
                plotTypes[i] = g_PLOT_TYPE_OCEAN;
                TerrainBuilder.SetTerrainType(pPlot, g_TERRAIN_TYPE_OCEAN);  -- temporary setting so can calculate areas

                if (mountainVal == iMountain100) then -- Isolated peak in the ocean
                    plotTypes[i] = g_PLOT_TYPE_MOUNTAIN;
                    TerrainBuilder.SetTerrainType(pPlot, g_TERRAIN_TYPE_DESERT);  -- temporary setting so can calculate areas
                elseif (mountainVal == iMountain99) then
                    plotTypes[i] = g_PLOT_TYPE_HILLS;
                    TerrainBuilder.SetTerrainType(pPlot, g_TERRAIN_TYPE_DESERT);  -- temporary setting so can calculate areas
                elseif (mountainVal == iMountain97) or (mountainVal == iMountain95) then
                    plotTypes[i] = g_PLOT_TYPE_LAND;
                    TerrainBuilder.SetTerrainType(pPlot, g_TERRAIN_TYPE_DESERT);  -- temporary setting so can calculate areas
                end
            else
                if (mountainVal >= iMountainThreshold) then
                    if (hillVal >= iPassThreshold) then -- Mountain Pass though the ridgeline - Brian
                        plotTypes[i] = g_PLOT_TYPE_HILLS;
                        TerrainBuilder.SetTerrainType(pPlot, g_TERRAIN_TYPE_DESERT);  -- temporary setting so can calculate areas
                    else -- Mountain
                        plotTypes[i] = g_PLOT_TYPE_MOUNTAIN;
                        TerrainBuilder.SetTerrainType(pPlot, g_TERRAIN_TYPE_DESERT);  -- temporary setting so can calculate areas
                    end
                elseif (mountainVal >= iHillsNearMountains) then
                    plotTypes[i] = g_PLOT_TYPE_HILLS;
                    TerrainBuilder.SetTerrainType(pPlot, g_TERRAIN_TYPE_DESERT);  -- temporary setting so can calculate areas
                else
                    if ((hillVal >= iHillsBottom1 and hillVal <= iHillsTop1) or (hillVal >= iHillsBottom2 and hillVal <= iHillsTop2)) then
                        plotTypes[i] = g_PLOT_TYPE_HILLS;
                        TerrainBuilder.SetTerrainType(pPlot, g_TERRAIN_TYPE_DESERT);  -- temporary setting so can calculate areas
                    else
                        plotTypes[i] = g_PLOT_TYPE_LAND;
                        TerrainBuilder.SetTerrainType(pPlot, g_TERRAIN_TYPE_DESERT);  -- temporary setting so can calculate areas
                    end
                end
            end
        end
    end
   
    ShiftPlotTypes(plotTypes);
    AreaBuilder.Recalculate();

    -- Generate Large Islands   
    local args = {};   
    islands = plotTypes;
    args.iWaterPercent = 75 + water_percent_modifier;
    args.iRegionWidth = math.ceil(g_iW);
    args.iRegionHeight = math.ceil(g_iH);
    args.iRegionWestX = math.floor(0);
    args.iRegionSouthY = math.floor(0);
    args.iRegionGrain = 2;
    args.iRegionHillsGrain = 4;
    args.iRegionPlotFlags = g_iFlags;
    args.iRegionPlotFlags = {FRAC_POLAR = true};
    args.iRegionFracXExp = 6;
    args.iRegionFracYExp = 5;
    plotTypes = GenerateFractalLayerWithoutHills(args, plotTypes);

    ShiftPlotTypes(plotTypes);
    AreaBuilder.Recalculate();








        g_iNumTotalLandTiles = 0;
        for x = 0, g_iW - 1 do
            for y = 0, g_iH - 1 do
                local i = y * g_iW + x;
                local val = g_continentsFrac:GetHeight(x, y);
                local pPlot = Map.GetPlotByIndex(i);
                if(val <= iWaterThreshold) then
                    plotTypes[i] = g_PLOT_TYPE_OCEAN;
                    TerrainBuilder.SetTerrainType(pPlot, g_TERRAIN_TYPE_OCEAN);  -- temporary setting so can calculate areas
                else
                    plotTypes[i] = g_PLOT_TYPE_LAND;
                    TerrainBuilder.SetTerrainType(pPlot, g_TERRAIN_TYPE_DESERT);  -- temporary setting so can calculate areas
                    g_iNumTotalLandTiles = g_iNumTotalLandTiles + 1;
                end
            end
        end








    local iPlotCount = Map.GetPlotCount();
    if (g_iNumTotalLandTiles <= (iPlotCount * 0.10)) then
        if (g_iNumTotalLandTiles >= (iPlotCount  * 0.05)) then
            done = true
    end
end







    local args = {};
    world_age = world_age;
    args.world_age = world_age;
    args.iW = g_iW;
    args.iH = g_iH
    args.iFlags = g_iFlags;
    args.tectonic_islands = false;
    args.blendRidge = 10;
    args.blendFract = 1;
    args.extra_mountains = 10;
    mountainRatio = 11 + world_age * 2;
    plotTypes = ApplyTectonics(args, plotTypes);
    plotTypes = AddLonelyMountains(plotTypes, mountainRatio);

    return plotTypes;
end

----------------------------------------------------------------------------------
function AddFeatures()
    print("Adding Features");

    -- Get Rainfall setting input by user.
    local rainfall = MapConfiguration.GetValue("rainfall");
    if rainfall == 4 then
        rainfall = 1 + TerrainBuilder.GetRandomNumber(3, "Random Rainfall - Lua");
    end
   
    local args = {rainfall = rainfall}
    featuregen = FeatureGenerator.Create(args);
    featuregen:AddFeatures(true, true);  --second parameter is whether or not rivers start inland);
end

function AddFeaturesFromContinents()
    print("Adding Features from Continents");

    featuregen:AddFeaturesFromContinents();
end

-------------------------------------------------------------------------------
function GenerateFractalLayerWithoutHills (args, plotTypes)
    local args = args or {};
    local plotTypes2 = {};

    -- Handle args or assign defaults.
    local iWaterPercent = args.iWaterPercent or 55;
    local iRegionWidth = args.iRegionWidth; -- Mandatory Parameter, no default
    local iRegionHeight = args.iRegionHeight; -- Mandatory Parameter, no default
    local iRegionWestX = args.iRegionWestX; -- Mandatory Parameter, no default
    local iRegionSouthY = args.iRegionSouthY; -- Mandatory Parameter, no default
    local iRegionGrain = args.iRegionGrain or 1;
    local iRegionPlotFlags = args.iRegionPlotFlags or g_iFlags;
    local iRegionTerrainFlags = g_iFlags; -- Removed from args list.
    local iRegionFracXExp = args.iRegionFracXExp or 6;
    local iRegionFracYExp = args.iRegionFracYExp or 5;
    local iRiftGrain = args.iRiftGrain or -1;
    local bShift = args.bShift or true;
   
    --print("Received Region Data");
    --print(iRegionWidth, iRegionHeight, iRegionWestX, iRegionSouthY, iRegionGrain);
    --print("- - -");
   
    --print("Filled regional table.");
    -- Loop through the region's plots
    for x = 0, iRegionWidth - 1, 1 do
        for y = 0, iRegionHeight - 1, 1 do
            local i = y * iRegionWidth + x + 1; -- Lua arrays start at 1.
            plotTypes2[i] =g_PLOT_TYPE_OCEAN;
        end
    end

    -- Init the land/water fractal
    local regionContinentsFrac;
    if(iRiftGrain > 0 and iRiftGrain < 4) then
        local riftsFrac = Fractal.Create(g_iW, g_iH, rift_grain, {}, iRegionFracXExp, iRegionFracYExp);
        regionContinentsFrac = Fractal.CreateRifts(g_iW, g_iH, iRegionGrain, iRegionPlotFlags, riftsFrac, iRegionFracXExp, iRegionFracYExp);
    else
        regionContinentsFrac = Fractal.Create(g_iW, g_iH, iRegionGrain, iRegionPlotFlags, iRegionFracXExp, iRegionFracYExp);   
    end
    --print("Initialized main fractal");
    local iWaterThreshold = regionContinentsFrac:GetHeight(iWaterPercent);

    -- Loop through the region's plots
    for x = 0, iRegionWidth - 1, 1 do
        for y = 0, iRegionHeight - 1, 1 do
            local i = y * iRegionWidth + x + 1;
            local val = regionContinentsFrac:GetHeight(x,y);
            if val <= iWaterThreshold or Adjacent(i) == true then
                --do nothing
            else
                plotTypes2[i] = g_PLOT_TYPE_LAND;
            end
        end
    end

    if bShift then
        ShiftPlotTypes(plotTypes);
    end

    print("Shifted Plots - Width: ", iRegionWidth, "Height: ", iRegionHeight);

    -- Apply the region's plots to the global plot array.
    for x = 0, iRegionWidth - 1, 1 do
        local wholeworldX = x + iRegionWestX;
        for y = 0, iRegionHeight - 1, 1 do
            local index = y * iRegionWidth + x + 1
            if plotTypes2[index] ~= g_PLOT_TYPE_OCEAN then
                local wholeworldY = y + iRegionSouthY;
                local i = wholeworldY * g_iW + wholeworldX + 1
                plotTypes[i] = plotTypes2[index];
            end
        end
    end
    --print("Generated Plot Types");

    return plotTypes;
end

-------------------------------------------------------------------------------------------
function Adjacent(index)
    aIslands = islands;
    index = index -1;

    if(aIslands == nil) then
        return false;
    end
   
    if(index < 0) then
        return false
    end

    local plot = Map.GetPlotByIndex(index);
    if(aIslands[index] ~= nil and aIslands[index] == g_PLOT_TYPE_LAND) then
        return true;
    end

    for direction = 0, DirectionTypes.NUM_DIRECTION_TYPES - 1, 1 do
        local adjacentPlot = Map.GetAdjacentPlot(plot:GetX(), plot:GetY(), direction);
        if(adjacentPlot ~= nil) then
            local newIndex = adjacentPlot:GetIndex();
            if(aIslands  ~= nil and aIslands[newIndex] == g_PLOT_TYPE_LAND) then
                return true;
            end
        end
    end

    return false;
end
I use diffchecker.com to compare text.
 
g_iW and g_iW might be 0 at the time you are referencing them, which would cause the loop to do nothing. You need to make sure these two variables for gird X width and grid Y height have been given correct values before you can execute the loop.

The snippet I posted earlier was meant as an example of the method Firaxis uses to give a valid value to g_iNumTotalLandTiles. You need to use a customized version of that counting method rather than a complete copy/paste because that loop temporarily sets all land plots to Desert and all water plots to Ocean and then apparently other parts of the code located elsewhere in the file are probably setting them back to their original TerrainType or else completely regenerate the land and water TerrainTypes.

----------------------------------------------------------

This topic seems to be getting pretty detailed and complex for the intent of a quick modding questions thread. Perhaps the discussion on this topic ought to be moved to its own thread @Gedemon ? Although I guess it might be a bit of a PITA to move quite a few comments as we seem to have accumulated on this one SubjectRequirementSetId subject.

erm.. not sure how that auto-fill happened.
 
Last edited:
Moderator Action: yes, posts moved to a separate thread.
 
Top Bottom