Hey all,
this is a cut & paste of a lua script I have used in learning how to script lua for Civ5 maps. I have it set up for WorldBuilder to explore what various fractal options do.
This post prompted me share it, so I thought it would be appropriate to put up here as well. I threw some quick comments in my code, some of which may be incorrect or need better explanation from someone with more experience as to my understanding of how things work. Once I am confident that this is an informative tool, ill package it up and make available for download in game, and here at Civ fanatics.
Hope it helps someone. Feedback encouraged and appreciated.
EDIT1: fixed small bug! oops
EDIT2: Caught another one (if anyone cares, this version is the same as edit 3 in the other thread. I should have just made sure that one was right before posting this one. sorry for confusion!
this is a cut & paste of a lua script I have used in learning how to script lua for Civ5 maps. I have it set up for WorldBuilder to explore what various fractal options do.
This post prompted me share it, so I thought it would be appropriate to put up here as well. I threw some quick comments in my code, some of which may be incorrect or need better explanation from someone with more experience as to my understanding of how things work. Once I am confident that this is an informative tool, ill package it up and make available for download in game, and here at Civ fanatics.
Hope it helps someone. Feedback encouraged and appreciated.
Code:
------------------------------------------------------------------------------
-- FILE: FractalMapOptionsPlayground.lua
-- AUTHOR: Jamie McQueen (Skweetis)
-- PURPOSE: Map script for exploring Fractal options and their effects during
-- Map Generation. By a mapscript virgin for mapscript virgins.
-- Some options will hang worldbuilder
-- in certain cases (I.E low continent_grain value and extra_mountains
-- value above 6 for example. Generator log printstatements allow
-- debugging of values. Best when used with UNOFFICIAL patched
-- WorldBuilder version 4 or better (available at www.civfanatics.com)
-- which keeps the log window open during map generation among other
-- improvements.
-- I have included what comments I can, and have laid it out in a way
-- that I find easiest to follow. By no means is this reflective of how
-- things should be laid out. I have only hobby
-- level programming experience and am not a coding expert by any stretch.
-- It has helped me immensly though, in figuring out what things do,
-- And learning to create mapscripts. As this was created as a personal
-- reference tool, it has not been tested in-game, though I see no
-- reason why it should not work. Hopefully other budding mapscripters
-- will find it useful. I suggest looking through this while also
-- refering to FractalWorlds.lua in ../GamePlay/Lua/. which is really
-- the blood and guts of fractal world building, and includes numerous
-- helpfull comments left by Bob and Brian (some referenced in here)
-- Enjoy and good luck exploring! -jm
-- Special thanks to ColBashar for his input on my map script, his
-- advice helped align me in the direction I needed to go. Turned
-- into a public tool because of cassembler's request for a blank
-- map.
------------------------------------------------------------------------------
-- Copyright (c) 2010 Firaxis Games, Inc. All rights reserved.
------------------------------------------------------------------------------
--what other lua files have code in them we will call in our map script are listed here.
include("MapGenerator");
include("FractalWorld");
include("FeatureGenerator");
include("TerrainGenerator");
------------------------------------------------------------------------------
function GetMapScriptInfo() --somebody else would be better to describe it, I'm sure my explaination would cause more confusion than knowledge.
local world_age, temperature, rainfall, sea_level, resources = GetCoreMapOptions() -- 'local' statements are where how declare a variable.
return { -- somebody else can explain returns better.
Name = "FractalMapOptionsPlayground",
Description = "A very customisable fractal based world generator.",
IsAdvancedMap = false, -- setting to True will make this map only appear when Advanced button is clicked
IconIndex = 16,
SortIndex = 1,
CustomOptions = {
world_age, temperature, rainfall, sea_level, resources, --CustomOption index +5 (5 core map options, which are defaulted to -99 to -95 so as to always come first)
{
Name = "Continent Grain", -- Map.GetCustomOption(6) <<I do this only for reference to help remember what Option Pulldown information I am getting when putting in a variable (see next function)
Values = { -- play and see! basically smaller values make larger continents or a pangaea, larger will result in scattered islands.
"1", -- DefaultValue means this will be the first option displayed. Index (count) starts at 1 and counts up for each entry. Text is only used in pull down. Script takes index only.
"2", -- index value 2
"3",
"4",
"5",
"6",
"TXT_KEY_MAP_OPTION_RANDOM"
},
DefaultValue = 1, -- which index position will be displayed by default in pulldown.
SortPriority = 1, -- which order this option pulldown will be displayed.
},
{
Name = "Center Rift?", -- Map.GetCustomOption(7)
Values = { -- puts an ocean rift on the map to difinitively split continents apart. Essentially creates at least two separate land masses.
"No", -- Default
"Yes",
"TXT_KEY_MAP_OPTION_RANDOM"
},
DefaultValue = 1,
SortPriority = 2,
},
{
Name = "Rift Grain", -- Map.GetCustomOption(8)
Values = {-- -1 is Default no rifts. Set grain to between 1 and 3 to add rifts. - Bob(FractalWorld.lua)
"-1", -- Default
"1",
"2",
"TXT_KEY_MAP_OPTION_RANDOM"-- Default
},
DefaultValue = 1,
SortPriority = 3,
},
{
Name = "Has Tectonic Islands?", -- Map.GetCustomOption(9)
Values = {-- Build islands in oceans along tectonic ridge lines - Brian(FractalWorlds.lua)
"No", -- Default
"Yes",
"TXT_KEY_MAP_OPTION_RANDOM"
},
DefaultValue = 1,
SortPriority = 4,
},
{
Name = "Polar?", -- Map.GetCustomOption(10)
Values = { -- I'm not clear exactly on what this does yet -jm
"No", -- Default
"Yes",
"TXT_KEY_MAP_OPTION_RANDOM"
},
DefaultValue = 1,
SortPriority = 5,
},
{
Name = "Extra Mountains", -- Map.GetCustomOption(11)
Values = {
"0", -- Default
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"TXT_KEY_MAP_OPTION_RANDOM"
},
DefaultValue = 1,
SortPriority = 6,
},
{
Name = "Adjust Plates", -- Map.GetCustomOption(12)
Values = {
"0", -- Default
"1",
"1.5",
"3",
"TXT_KEY_MAP_OPTION_RANDOM"
},
DefaultValue = 1,
SortPriority = 7,
},
{
Name = "Player Distribution",-- Map.GetCustomOption(13)
Values = {
"Old World",
"Continental",
"Map Rectangle",
"TXT_KEY_MAP_OPTION_RANDOM"-- DefaultValue = 4,
},
DefaultValue = 4,
SortPriority = 8
},
};
};
end
------------------------------------------------------------------------------
------------------------------------------------------------------------------
function GeneratePlotTypes()
print("Generating Plot Types (Lua Worlds Unlimited) ..."); -- these statements only printout in the log. Useful for debugging, gives you a reference point when (and it will) your script blows up in the builder. Last print you see, gives you an idea where to look in your script.
-- collect user options and put them in a variable. I do it this way, there are many other methods, likely better coding practice, but
-- I found this way easier to follow while learning. The index of the option selected above is what we pass to the variable so we can do
-- stuff with it.
local sea_level = Map.GetCustomOption(4) -- my translation: "make me a container called sea_level and put the value the Map Option
local world_age = Map.GetCustomOption(1)
local continent_grain = Map.GetCustomOption(6) --this is the first custom option in the above function.
local rift_bool = Map.GetCustomOption(7) -- bool is short for boolean (true or false) Im in the habit of getting the numerical value, and turn it in to actual true or false after.
local rift_grain = Map.GetCustomOption(8)
local islands_bool = Map.GetCustomOption(9)
local polar_bool = Map.GetCustomOption(10)
local extra_mountains = Map.GetCustomOption(11)
local adjust_plates = Map.GetCustomOption(12)
--default to false, I find it good practice to always 'initialise' your variables (ie, make sure they = something). I can't remember why though I'm sure there is a good reason! The pros always seem to do it!
local has_center_rift = false;
local tectonic_islands = false;
local polar = false;
-- calculate random selections, and modify any values
if sea_level == 4 then -- user selected random, so we are going to select from one of the other options in the list. Remember, we use the pulldown option index value, the text in quotes means nothing to the script.
sea_level = 1 + Map.Rand(3, "Random Sea Level - Lua"); -- this one is a bit longer to explain. try and take a good look at it and see if you can figure out and understand what is happening here (a good habit and skill to practice, imo) if not, make sure you take a peak at one of the tutorial's for Civ5 Map scripting out there.
end
print("DEBUG - Sea Level: ", sea_level); -- we want to see what was picked, this desplays it in the log. notice how it is written, recognise anything familiar?
if world_age == 4 then -- always always always try to remember to make sure you use two == when doing an 'if' evaluation. pain in the ass to find when you have a big script and cant find out why it isn't working!
world_age = 1 + Map.Rand(3, "Random World Age - Lua");
end
print("DEBUG - World Age: ", world_age);
if continent_grain == 7 then
continent_grain = 1 + Map.Rand(6, "Random Continent Grain - Lua");
end
print("DEBUG - Continent Grain: ", continent_grain);
if rift_bool == 3 then
rift_bool = 1 + Map.Rand(2, "Random Has Rift - Lua"); -- don't add 1, this is boolean.
end
if rift_bool == 2 then
has_center_rift = true; -- remember we initialised this to false above? well if it isn't random, and they didn't pick the first option (which would be false, and this variable is already set to false) the only option they have left is 2, which translates to true.
end
print("DEBUG - Has Center Rift: ", has_center_rift);
if rift_grain == 4 then
rift_grain = Map.Rand(3, "Random Continent Grain - Lua"); -- no need to add 1, because randomising resets the index start count to 0, and the value we need from this option is 0.
else
rift_grain = rift_grain - 1-- we still need that value to be 0, so if random was not selected, the index count would be 1 if the user selected the first value, and we need 0 for this option, so lets take one away from that value.
end
if rift_grain < 1 then -- only do this if the value is 0 or less
rift_grain = -1; -- we needed the 0, but it is not a valid option, and the first for this list is -1, so this here turns that 0 we can't use into a zero we can.
end
print("DEBUG - Rift Grain: ", rift_grain);
if polar == 3 then
polar = 1 + Map.Rand(2, "Random Polar - Lua");
end
if polar_bool == 2 then
polar = true;
end
print("DEBUG - Polar: ", polar);
if islands_bool == 3 then
islands_bool = 1 + Map.Rand(2, "Random Tectonic Islands - Lua");
end
if islands_bool == 2 then
tectonic_islands = true;
end
print("DEBUG - Tectonic Islands: ", tectonic_islands);
if extra_mountains == 12 then
extra_mountains = Map.Rand(11, "Random Extra Mountains - Lua"); -- no need to add 1, starts at 0
else
extra_mountains = extra_mountains -1;
end
print("DEBUG - Extra Mountains: ", extra_mountains);
if adjust_plates == 5 then
adjust_plates = 1 + Map.Rand(4, "Random Adjust Plates - Lua");
end
if adjust_plates == 1 then
adjust_plates = 0;
elseif adjust_plates == 2 then
adjust_plates = 1;
elseif adjust_plates == 3 then
adjust_plates = 1.5;
elseif adjust_plates == 4 then
adjust_plates = 3;
end
print("DEBUG - Adjust Plates: ", adjust_plates);
local fractal_world = FractalWorld.Create(); -- the way I undertand it, this gets the code from the Create() function in the file FractalWorld, the . is the separator, and it gets stored in our variable called fractal_world which we will use below. It may just be that its easier to type fractal_world than FractalWorld.Create() repeatedly... either way we are calling a function from another file we included at the top of our script.
fractal_world:InitFractal{ -- passing all the values between the braces, each variable separated by commas. the duplicate names may be redundant, but it makes it quicker to play change the value of any of those variables.
continent_grain = continent_grain,
rift_grain = rift_grain,
has_center_rift = has_center_rift,
polar = polar,
};
local args = {
sea_level = sea_level,
world_age = world_age,
sea_level_low = 69,
sea_level_normal = 75,
sea_level_high = 80,
extra_mountains = extra_mountains,
adjust_plates = adjust_plates,
has_center_rift = has_center_rift,
tectonic_islands = tectonic_islands,
};
local plotTypes = fractal_world:GeneratePlotTypes(args);
SetPlotTypes(plotTypes);
GenerateCoasts();
end
------------------------------------------------------------------------------
function GenerateTerrain()
print("Generating Terrain (Lua Worlds Unlimited) ...");
-- Get Temperature setting input by user.
local temp = Map.GetCustomOption(2)
if temp == 4 then
temp = 1 + Map.Rand(3, "Random Temperature");
end
local args = {temperature = temp};
local terraingen = TerrainGenerator.Create(args);
terrainTypes = terraingen:GenerateTerrain();
SetTerrainTypes(terrainTypes);
end
------------------------------------------------------------------------------
function AddFeatures()
print("Adding Features (Lua Worlds Unlimited) ...");
-- Get Rainfall setting input by user.
local rain = Map.GetCustomOption(3)
if rain == 4 then
rain = 1 + Map.Rand(3, "Random Rainfall - Lua");
end
local args = {rainfall = rain}
local featuregen = FeatureGenerator.Create(args);
-- False parameter removes mountains from coastlines.
featuregen:AddFeatures();
end
------------------------------------------------------------------------------
function StartPlotSystem()
-- Get Resources setting input by user.
local res = Map.GetCustomOption(5)
local start_method = Map.GetCustomOption(13)
if res == 6 then
res = 1 + Map.Rand(3, "Random Resources Option");
end
if start_method == 4 then
start_method = 1 + Map.Rand(3, "Random Player Distribution");
end
print("Creating start plot database.");
local start_plot_database = AssignStartingPlots.Create()
print("Dividing the map in to Regions.");
local args = {
method = start_method,
resources = res,
};
start_plot_database:GenerateRegions(args)
print("Choosing start locations for civilizations.");
start_plot_database:ChooseLocations()
print("Normalizing start locations and assigning them to Players.");
start_plot_database:BalanceAndAssign()
print("Placing Natural Wonders.");
start_plot_database:PlaceNaturalWonders()
print("Placing Resources and City States.");
start_plot_database:PlaceResourcesAndCityStates()
end
------------------------------------------------------------------------------
EDIT1: fixed small bug! oops
EDIT2: Caught another one (if anyone cares, this version is the same as edit 3 in the other thread. I should have just made sure that one was right before posting this one. sorry for confusion!