Barathor
Emperor
- Joined
- May 7, 2011
- Messages
- 1,202
EDIT: See post #4 for the working function.
- - - - - - - -
I'm not very familiar with Lua at all and only to a certain extent can I logically figure out what the heck it's doing by staring at it, highlighting things, following the steps of the code, and Googling
. I'd greatly appreciate any help on this from someone more knowledgeable! Okay, where to start...
It's not really a big issue. Within a modded map script of mine, I simply wanted to prevent city start locations on tiles not only two tiles from water, but also three tiles as well. Again, yeah, it's not the end of the world if your city starts in a spot like this since it's the outer most ring and there are more than enough other tiles to work -- it's a bit like getting mountains within your workable radius. But, if all it takes are some simple adjustments, then I think it could be worth it.
A quick (and hopefully somewhat accurate) description:
As far as I can tell, the game currently disqualifies land tiles that are two tiles from water. Within AssignStartingPlots:FindStart(), it searches for and designates tiles throughout the map as candidates. One of its tables is called two_plots_from_ocean, which it labels as disqualified and does nothing with (I think). The function that is called to figure out if the current plot index should be inserted into that table is GenerateNextToCoastalLandDataTables() within MapmakerUtilities.lua (so, I guess that would be MapmakerUtilities:GenerateNextToCoastalLandDataTables()?). So, once the plotDataIsCoastal table is created and updated, The "NextToCoastal" function above searches for tiles that are neither water or labeled as coastal in the plotDataIsCoastal table, then it searches all adjacent tiles for "coastal" land tiles. If it picks anything up, then the current index is labeled as a "next to coast" land tile.
So, I created a new function called GenerateNearCoastalLandDataTables() by copying GenerateNextToCoastalLandDataTables() and changing variables around. This functions just like the existing function except that it uses the complete "is coastal" (adjacent to water) and "is next to coastal" (2 tiles from water) tables to create another table of plot indexes which lists which tiles are "near to coastal" (3 tiles from water).
My new function, GenerateNearCoastalLandDataTables(), copied from an existing, similar function:
Here is the original GenerateNextToCoastalLandDataTables() I copied off of:
This is my modified AssignStartingPlots:FindStart() with modifications highlighted in red:
I must have missed something or did something incorrectly because once a game begins, it immediately ends as a loss because the map isn't generated correctly.
I have the two functions in a new Small Continents Deluxe script I'm working on. It worked perfectly until I added these two functions.
I believe these are the Lua errors within the log, if it helps:
Also, attached are the two functions in a Lua file if one prefers to view it there (probably easier).
- - - - - - - -
I'm not very familiar with Lua at all and only to a certain extent can I logically figure out what the heck it's doing by staring at it, highlighting things, following the steps of the code, and Googling

It's not really a big issue. Within a modded map script of mine, I simply wanted to prevent city start locations on tiles not only two tiles from water, but also three tiles as well. Again, yeah, it's not the end of the world if your city starts in a spot like this since it's the outer most ring and there are more than enough other tiles to work -- it's a bit like getting mountains within your workable radius. But, if all it takes are some simple adjustments, then I think it could be worth it.
A quick (and hopefully somewhat accurate) description:
As far as I can tell, the game currently disqualifies land tiles that are two tiles from water. Within AssignStartingPlots:FindStart(), it searches for and designates tiles throughout the map as candidates. One of its tables is called two_plots_from_ocean, which it labels as disqualified and does nothing with (I think). The function that is called to figure out if the current plot index should be inserted into that table is GenerateNextToCoastalLandDataTables() within MapmakerUtilities.lua (so, I guess that would be MapmakerUtilities:GenerateNextToCoastalLandDataTables()?). So, once the plotDataIsCoastal table is created and updated, The "NextToCoastal" function above searches for tiles that are neither water or labeled as coastal in the plotDataIsCoastal table, then it searches all adjacent tiles for "coastal" land tiles. If it picks anything up, then the current index is labeled as a "next to coast" land tile.
So, I created a new function called GenerateNearCoastalLandDataTables() by copying GenerateNextToCoastalLandDataTables() and changing variables around. This functions just like the existing function except that it uses the complete "is coastal" (adjacent to water) and "is next to coastal" (2 tiles from water) tables to create another table of plot indexes which lists which tiles are "near to coastal" (3 tiles from water).
My new function, GenerateNearCoastalLandDataTables(), copied from an existing, similar function:
Spoiler :
Code:
-- New function to construct a table of tiles that are 3 tiles from water.
function GenerateNearCoastalLandDataTables()
-- Set up data table for IsCoastal and IsNextToCoast
local plotDataIsCoastal = GenerateCoastalLandDataTable()
local plotDataIsNextToCoast = GenerateNextToCoastalLandDataTables()
-- Set up data table for NearCoast
local iW, iH = Map.GetGridSize();
local plotDataIsNearCoast = {};
table.fill(plotDataIsNearCoast, false, iW * iH);
-- When generating a plot data table incrementally, process Y first so that plots go row by row.
-- Keeping plot data table indices consistent with the main plot database could save you enormous grief.
-- In this case, accessing an existing table by plot index, it doesn't matter.
for x = 0, iW - 1 do
for y = 0, iH - 1 do
local i = iW * y + x + 1;
local plot = Map.GetPlot(x, y);
if plotDataIsCoastal[i] == false and plotDataIsNextToCoast[i] == false and not plot:IsWater() then -- plot is not itself on the coast, or next to coast, or in the water.
-- So we will check all adjacent plots to see if any of those are next to the coast.
local NEPlot = Map.PlotDirection(x, y, DirectionTypes.DIRECTION_NORTHEAST);
local EPlot = Map.PlotDirection(x, y, DirectionTypes.DIRECTION_EAST);
local SEPlot = Map.PlotDirection(x, y, DirectionTypes.DIRECTION_SOUTHEAST);
local SWPlot = Map.PlotDirection(x, y, DirectionTypes.DIRECTION_SOUTHWEST);
local WPlot = Map.PlotDirection(x, y, DirectionTypes.DIRECTION_WEST);
local NWPlot = Map.PlotDirection(x, y, DirectionTypes.DIRECTION_NORTHWEST);
--
-- Check plot to northeast of current plot. This operation accounts for map edge and world wrap.
if NEPlot ~= nil then
local adjX = NEPlot:GetX();
local adjY = NEPlot:GetY();
local adjI = iW * adjY + adjX + 1;
if plotDataIsNextToCoast[adjI] == true then
-- The current loop plot is not itself on the coast or next to coast but is "near" the coast (within 3 tiles).
plotDataIsNearCoast[i] = true;
end
end
-- Check plot to east of current plot.
if EPlot ~= nil then
local adjX = EPlot:GetX();
local adjY = EPlot:GetY();
local adjI = iW * adjY + adjX + 1;
if plotDataIsNextToCoast[adjI] == true then
plotDataIsNearCoast[i] = true;
end
end
-- Check plot to southeast of current plot.
if SEPlot ~= nil then
local adjX = SEPlot:GetX();
local adjY = SEPlot:GetY();
local adjI = iW * adjY + adjX + 1;
if plotDataIsNextToCoast[adjI] == true then
plotDataIsNearCoast[i] = true;
end
end
-- Check plot to southwest of current plot.
if SWPlot ~= nil then
local adjX = SWPlot:GetX();
local adjY = SWPlot:GetY();
local adjI = iW * adjY + adjX + 1;
if plotDataIsNextToCoast[adjI] == true then
plotDataIsNearCoast[i] = true;
end
end
-- Check plot to west of current plot.
if WPlot ~= nil then
local adjX = WPlot:GetX();
local adjY = WPlot:GetY();
local adjI = iW * adjY + adjX + 1;
if plotDataIsNextToCoast[adjI] == true then
plotDataIsNearCoast[i] = true;
end
end
-- Check plot to northwest of current plot.
if NWPlot ~= nil then
local adjX = NWPlot:GetX();
local adjY = NWPlot:GetY();
local adjI = iW * adjY + adjX + 1;
if plotDataIsNextToCoast[adjI] == true then
plotDataIsNearCoast[i] = true;
end
end
end
end
end
-- returns tables
return plotDataIsCoastal, plotDataIsNextToCoast, plotDataIsNearCoast
end
Here is the original GenerateNextToCoastalLandDataTables() I copied off of:
Spoiler :
Code:
function GenerateNextToCoastalLandDataTables()
-- Set up data table for IsCoastal
local plotDataIsCoastal = GenerateCoastalLandDataTable()
-- Set up data table for IsNextToCoast
local iW, iH = Map.GetGridSize();
local plotDataIsNextToCoast = {};
table.fill(plotDataIsNextToCoast, false, iW * iH);
-- When generating a plot data table incrementally, process Y first so that plots go row by row.
-- Keeping plot data table indices consistent with the main plot database could save you enormous grief.
-- In this case, accessing an existing table by plot index, it doesn't matter.
for x = 0, iW - 1 do
for y = 0, iH - 1 do
local i = iW * y + x + 1;
local plot = Map.GetPlot(x, y);
if plotDataIsCoastal[i] == false and not plot:IsWater() then -- plot is not itself on the coast or in the water.
-- So we will check all adjacent plots to see if any of those are on the coast.
local NEPlot = Map.PlotDirection(x, y, DirectionTypes.DIRECTION_NORTHEAST);
local EPlot = Map.PlotDirection(x, y, DirectionTypes.DIRECTION_EAST);
local SEPlot = Map.PlotDirection(x, y, DirectionTypes.DIRECTION_SOUTHEAST);
local SWPlot = Map.PlotDirection(x, y, DirectionTypes.DIRECTION_SOUTHWEST);
local WPlot = Map.PlotDirection(x, y, DirectionTypes.DIRECTION_WEST);
local NWPlot = Map.PlotDirection(x, y, DirectionTypes.DIRECTION_NORTHWEST);
--
-- Check plot to northeast of current plot. This operation accounts for map edge and world wrap.
if NEPlot ~= nil then
local adjX = NEPlot:GetX();
local adjY = NEPlot:GetY();
local adjI = iW * adjY + adjX + 1;
if plotDataIsCoastal[adjI] == true then
-- The current loop plot is not itself on the coast but is next to a plot that is on the coast.
plotDataIsNextToCoast[i] = true;
end
end
-- Check plot to east of current plot.
if EPlot ~= nil then
local adjX = EPlot:GetX();
local adjY = EPlot:GetY();
local adjI = iW * adjY + adjX + 1;
if plotDataIsCoastal[adjI] == true then
plotDataIsNextToCoast[i] = true;
end
end
-- Check plot to southeast of current plot.
if SEPlot ~= nil then
local adjX = SEPlot:GetX();
local adjY = SEPlot:GetY();
local adjI = iW * adjY + adjX + 1;
if plotDataIsCoastal[adjI] == true then
plotDataIsNextToCoast[i] = true;
end
end
-- Check plot to southwest of current plot.
if SWPlot ~= nil then
local adjX = SWPlot:GetX();
local adjY = SWPlot:GetY();
local adjI = iW * adjY + adjX + 1;
if plotDataIsCoastal[adjI] == true then
plotDataIsNextToCoast[i] = true;
end
end
-- Check plot to west of current plot.
if WPlot ~= nil then
local adjX = WPlot:GetX();
local adjY = WPlot:GetY();
local adjI = iW * adjY + adjX + 1;
if plotDataIsCoastal[adjI] == true then
plotDataIsNextToCoast[i] = true;
end
end
-- Check plot to northwest of current plot.
if NWPlot ~= nil then
local adjX = NWPlot:GetX();
local adjY = NWPlot:GetY();
local adjI = iW * adjY + adjX + 1;
if plotDataIsCoastal[adjI] == true then
plotDataIsNextToCoast[i] = true;
end
end
end
end
end
-- returns table, table
return plotDataIsCoastal, plotDataIsNextToCoast
end
This is my modified AssignStartingPlots:FindStart() with modifications highlighted in red:
Spoiler :
Code:
-- Modified to also disqualify land tiles that are 3 tiles from water for potential starting city locations.
function AssignStartingPlots:FindStart(region_number)
-- This function attempts to choose a start position for a single region.
-- This function returns two boolean flags, indicating the success level of the operation.
local bSuccessFlag = false; -- Returns true when a start is placed, false when process fails.
local bForcedPlacementFlag = false; -- Returns true if this region had no eligible starts and one was forced to occur.
-- Obtain data needed to process this region.
local iW, iH = Map.GetGridSize();
local region_data_table = self.regionData[region_number];
local iWestX = region_data_table[1];
local iSouthY = region_data_table[2];
local iWidth = region_data_table[3];
local iHeight = region_data_table[4];
local iAreaID = region_data_table[5];
local iMembershipEastX = iWestX + iWidth - 1;
local iMembershipNorthY = iSouthY + iHeight - 1;
--
local terrainCounts = self.regionTerrainCounts[region_number];
--
local region_type = self.regionTypes[region_number];
-- Done setting up region data.
-- Set up contingency.
local fallback_plots = {};
-- Establish scope of center bias.
local fCenterWidth = (self.centerBias / 100) * iWidth;
local iNonCenterWidth = math.floor((iWidth - fCenterWidth) / 2)
local iCenterWidth = iWidth - (iNonCenterWidth * 2);
local iCenterWestX = (iWestX + iNonCenterWidth) % iW; -- Modulo math to synch coordinate to actual map in case of world wrap.
local iCenterTestWestX = (iWestX + iNonCenterWidth); -- "Test" values ignore world wrap for easier membership testing.
local iCenterTestEastX = (iCenterWestX + iCenterWidth - 1);
local fCenterHeight = (self.centerBias / 100) * iHeight;
local iNonCenterHeight = math.floor((iHeight - fCenterHeight) / 2)
local iCenterHeight = iHeight - (iNonCenterHeight * 2);
local iCenterSouthY = (iSouthY + iNonCenterHeight) % iH;
local iCenterTestSouthY = (iSouthY + iNonCenterHeight);
local iCenterTestNorthY = (iCenterTestSouthY + iCenterHeight - 1);
-- Establish scope of "middle donut", outside the center but inside the outer.
local fMiddleWidth = (self.middleBias / 100) * iWidth;
local iOuterWidth = math.floor((iWidth - fMiddleWidth) / 2)
local iMiddleWidth = iWidth - (iOuterWidth * 2);
local iMiddleWestX = (iWestX + iOuterWidth) % iW;
local iMiddleTestWestX = (iWestX + iOuterWidth);
local iMiddleTestEastX = (iMiddleTestWestX + iMiddleWidth - 1);
local fMiddleHeight = (self.middleBias / 100) * iHeight;
local iOuterHeight = math.floor((iHeight - fMiddleHeight) / 2)
local iMiddleHeight = iHeight - (iOuterHeight * 2);
local iMiddleSouthY = (iSouthY + iOuterHeight) % iH;
local iMiddleTestSouthY = (iSouthY + iOuterHeight);
local iMiddleTestNorthY = (iMiddleTestSouthY + iMiddleHeight - 1);
-- Assemble candidates lists.
[COLOR="Red"]local three_plots_from_ocean = {}; -- MOD[/COLOR]
local two_plots_from_ocean = {};
local center_candidates = {};
local center_river = {};
local center_coastal = {};
local center_inland_dry = {};
local middle_candidates = {};
local middle_river = {};
local middle_coastal = {};
local middle_inland_dry = {};
local outer_plots = {};
-- Identify candidate plots.
for region_y = 0, iHeight - 1 do -- When handling global plot indices, process Y first.
for region_x = 0, iWidth - 1 do
local x = (region_x + iWestX) % iW; -- Actual coords, adjusted for world wrap, if any.
local y = (region_y + iSouthY) % iH; --
local plotIndex = y * iW + x + 1;
local plot = Map.GetPlot(x, y);
local plotType = plot:GetPlotType()
if plotType == PlotTypes.PLOT_HILLS or plotType == PlotTypes.PLOT_LAND then -- Could host a city.
-- Check if plot is two away from salt water.
if self.plotDataIsNextToCoast[plotIndex] == true then
table.insert(two_plots_from_ocean, plotIndex);
[COLOR="Red"]elseif self.plotDataIsNearCoast[plotIndex] == true then -- MOD
table.insert(three_plots_from_ocean, plotIndex); -- MOD[/COLOR]
else
local area_of_plot = plot:GetArea();
if area_of_plot == iAreaID or iAreaID == -1 then -- This plot is a member, so it goes on at least one candidate list.
--
-- Test whether plot is in center bias, middle donut, or outer donut.
--
local test_x = region_x + iWestX; -- "Test" coords, ignoring any world wrap and
local test_y = region_y + iSouthY; -- reaching in to virtual space if necessary.
if (test_x >= iCenterTestWestX and test_x <= iCenterTestEastX) and
(test_y >= iCenterTestSouthY and test_y <= iCenterTestNorthY) then -- Center Bias.
table.insert(center_candidates, plotIndex);
if plot:IsRiverSide() then
table.insert(center_river, plotIndex);
elseif plot:IsFreshWater() or self.plotDataIsCoastal[plotIndex] == true then
table.insert(center_coastal, plotIndex);
else
table.insert(center_inland_dry, plotIndex);
end
elseif (test_x >= iMiddleTestWestX and test_x <= iMiddleTestEastX) and
(test_y >= iMiddleTestSouthY and test_y <= iMiddleTestNorthY) then
table.insert(middle_candidates, plotIndex);
if plot:IsRiverSide() then
table.insert(middle_river, plotIndex);
elseif plot:IsFreshWater() or self.plotDataIsCoastal[plotIndex] == true then
table.insert(middle_coastal, plotIndex);
else
table.insert(middle_inland_dry, plotIndex);
end
else
table.insert(outer_plots, plotIndex);
end
end
end
end
end
end
-- Check how many plots landed on each list.
[COLOR="Red"]local iNumDisqualified = table.maxn(two_plots_from_ocean) + table.maxn(three_plots_from_ocean); -- MOD[/COLOR]
local iNumCenter = table.maxn(center_candidates);
local iNumCenterRiver = table.maxn(center_river);
local iNumCenterCoastLake = table.maxn(center_coastal);
local iNumCenterInlandDry = table.maxn(center_inland_dry);
local iNumMiddle = table.maxn(middle_candidates);
local iNumMiddleRiver = table.maxn(middle_river);
local iNumMiddleCoastLake = table.maxn(middle_coastal);
local iNumMiddleInlandDry = table.maxn(middle_inland_dry);
local iNumOuter = table.maxn(outer_plots);
--[[ Debug printout.
print("-");
print("--- Number of Candidate Plots in Region #", region_number, " - Region Type:", region_type, " ---");
print("-");
print("Candidates in Center Bias area: ", iNumCenter);
print("Which are next to river: ", iNumCenterRiver);
print("Which are next to lake or sea: ", iNumCenterCoastLake);
print("Which are inland and dry: ", iNumCenterInlandDry);
print("-");
print("Candidates in Middle Donut area: ", iNumMiddle);
print("Which are next to river: ", iNumMiddleRiver);
print("Which are next to lake or sea: ", iNumMiddleCoastLake);
print("Which are inland and dry: ", iNumMiddleInlandDry);
print("-");
print("Candidate Plots in Outer area: ", iNumOuter);
print("-");
print("Disqualified, two plots away from salt water: ", iNumDisqualified);
print("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
]]--
-- Process lists of candidate plots.
if iNumCenter + iNumMiddle > 0 then
local candidate_lists = {};
if iNumCenterRiver > 0 then -- Process center bias river plots.
table.insert(candidate_lists, center_river);
end
if iNumCenterCoastLake > 0 then -- Process center bias lake or coastal plots.
table.insert(candidate_lists, center_coastal);
end
if iNumCenterInlandDry > 0 then -- Process center bias inland dry plots.
table.insert(candidate_lists, center_inland_dry);
end
if iNumMiddleRiver > 0 then -- Process middle donut river plots.
table.insert(candidate_lists, middle_river);
end
if iNumMiddleCoastLake > 0 then -- Process middle donut lake or coastal plots.
table.insert(candidate_lists, middle_coastal);
end
if iNumMiddleInlandDry > 0 then -- Process middle donut inland dry plots.
table.insert(candidate_lists, middle_inland_dry);
end
--
for loop, plot_list in ipairs(candidate_lists) do -- Up to six plot lists, processed by priority.
local election_returns = self:IterateThroughCandidatePlotList(plot_list, region_type)
-- If any candidates are eligible, choose one.
local found_eligible = election_returns[1];
if found_eligible then
local bestPlotScore = election_returns[2];
local bestPlotIndex = election_returns[3];
local x = (bestPlotIndex - 1) % iW;
local y = (bestPlotIndex - x - 1) / iW;
self.startingPlots[region_number] = {x, y, bestPlotScore};
self:PlaceImpactAndRipples(x, y)
return true, false
end
-- If none eligible, check for fallback plot.
local found_fallback = election_returns[4];
if found_fallback then
local bestFallbackScore = election_returns[5];
local bestFallbackIndex = election_returns[6];
local x = (bestFallbackIndex - 1) % iW;
local y = (bestFallbackIndex - x - 1) / iW;
table.insert(fallback_plots, {x, y, bestFallbackScore});
end
end
end
-- Reaching this point means no eligible sites in center bias or middle donut subregions!
-- Process candidates from Outer subregion, if any.
if iNumOuter > 0 then
local outer_eligible_list = {};
local found_eligible = false;
local found_fallback = false;
local bestFallbackScore = -50;
local bestFallbackIndex;
-- Process list of candidate plots.
for loop, plotIndex in ipairs(outer_plots) do
local score, meets_minimums = self:EvaluateCandidatePlot(plotIndex, region_type)
-- Test current plot against best known plot.
if meets_minimums == true then
found_eligible = true;
table.insert(outer_eligible_list, plotIndex);
else
found_fallback = true;
if score > bestFallbackScore then
bestFallbackScore = score;
bestFallbackIndex = plotIndex;
end
end
end
if found_eligible then -- Iterate through eligible plots and choose the one closest to the center of the region.
local closestPlot;
local closestDistance = math.max(iW, iH);
local bullseyeX = iWestX + (iWidth / 2);
if bullseyeX < iWestX then -- wrapped around: un-wrap it for test purposes.
bullseyeX = bullseyeX + iW;
end
local bullseyeY = iSouthY + (iHeight / 2);
if bullseyeY < iSouthY then -- wrapped around: un-wrap it for test purposes.
bullseyeY = bullseyeY + iH;
end
if bullseyeY / 2 ~= math.floor(bullseyeY / 2) then -- Y coord is odd, add .5 to X coord for hex-shift.
bullseyeX = bullseyeX + 0.5;
end
for loop, plotIndex in ipairs(outer_eligible_list) do
local x = (plotIndex - 1) % iW;
local y = (plotIndex - x - 1) / iW;
local adjusted_x = x;
local adjusted_y = y;
if y / 2 ~= math.floor(y / 2) then -- Y coord is odd, add .5 to X coord for hex-shift.
adjusted_x = x + 0.5;
end
if x < iWestX then -- wrapped around: un-wrap it for test purposes.
adjusted_x = adjusted_x + iW;
end
if y < iSouthY then -- wrapped around: un-wrap it for test purposes.
adjusted_y = y + iH;
end
local fDistance = math.sqrt( (adjusted_x - bullseyeX)^2 + (adjusted_y - bullseyeY)^2 );
if fDistance < closestDistance then -- Found new "closer" plot.
closestPlot = plotIndex;
closestDistance = fDistance;
end
end
-- Assign the closest eligible plot as the start point.
local x = (closestPlot - 1) % iW;
local y = (closestPlot - x - 1) / iW;
-- Re-get plot score for inclusion in start plot data.
local score, meets_minimums = self:EvaluateCandidatePlot(closestPlot, region_type)
-- Assign this plot as the start for this region.
self.startingPlots[region_number] = {x, y, score};
self:PlaceImpactAndRipples(x, y)
return true, false
end
-- Add the fallback plot (best scored plot) from the Outer region to the fallback list.
if found_fallback then
local x = (bestFallbackIndex - 1) % iW;
local y = (bestFallbackIndex - x - 1) / iW;
table.insert(fallback_plots, {x, y, bestFallbackScore});
end
end
-- Reaching here means no plot in the entire region met the minimum standards for selection.
-- The fallback plot contains the best-scored plots from each test area in this region.
-- We will compare all the fallback plots and choose the best to be the start plot.
local iNumFallbacks = table.maxn(fallback_plots);
if iNumFallbacks > 0 then
local best_fallback_score = 0
local best_fallback_x;
local best_fallback_y;
for loop, plotData in ipairs(fallback_plots) do
local score = plotData[3];
if score > best_fallback_score then
best_fallback_score = score;
best_fallback_x = plotData[1];
best_fallback_y = plotData[2];
end
end
-- Assign the start for this region.
self.startingPlots[region_number] = {best_fallback_x, best_fallback_y, best_fallback_score};
self:PlaceImpactAndRipples(best_fallback_x, best_fallback_y)
bSuccessFlag = true;
else
-- This region cannot have a start and something has gone way wrong.
-- We'll force a one tile grass island in the SW corner of the region and put the start there.
local forcePlot = Map.GetPlot(iWestX, iSouthY);
bSuccessFlag = true;
bForcedPlacementFlag = true;
forcePlot:SetPlotType(PlotTypes.PLOT_LAND, false, true);
forcePlot:SetTerrainType(TerrainTypes.TERRAIN_GRASS, false, true);
forcePlot:SetFeatureType(FeatureTypes.NO_FEATURE, -1);
self.startingPlots[region_number] = {iWestX, iSouthY, 0};
self:PlaceImpactAndRipples(iWestX, iSouthY)
end
return bSuccessFlag, bForcedPlacementFlag
end
I must have missed something or did something incorrectly because once a game begins, it immediately ends as a loss because the map isn't generated correctly.

I believe these are the Lua errors within the log, if it helps:
Code:
[16921.631] Runtime Error: [string "Small_Continents_Deluxe.lua"]:370: attempt to index field 'plotDataIsNearCoast' (a nil value)
stack traceback:
[string "Small_Continents_Deluxe.lua"]:370: in function 'FindStart'
[string "Assets\DLC\Expansion\Gameplay\Lua\AssignSta..."]:3437: in function 'ChooseLocations'
[string "Small_Continents_Deluxe.lua"]:913: in function 'StartPlotSystem'
[string "Assets\DLC\Expansion\Gameplay\Lua\MapGenera..."]:815: in function <[string "Assets\DLC\Expansion\Gameplay\Lua\MapGenera..."]:779>
[C]: ?