FramedArchitect
Reluctant Modder
See Post #6
<GameData>
<!-- Yagem -->
<YagemCityMap>
<!-- FRANCE -->
<Row>
<civilization>CIVILIZATION_FRANCE</civilization>
<X></X>
<Y></Y>
<ERA_ANCIENT>Parisi</ERA_ANCIENT>
<ERA_CLASSICAL>Lutece</ERA_CLASSICAL>
<ERA_MEDIEVAL>Paris</ERA_MEDIEVAL>
<ERA_RENAISSANCE>Paris</ERA_RENAISSANCE>
<ERA_INDUSTRIAL>Paris</ERA_INDUSTRIAL>
<ERA_MODERN>Paris</ERA_MODERN>
<ERA_FUTURE>Paris</ERA_FUTURE>
</Row>
</YagemCityMap>
<!-- europe Standard -->
<EuroLargeCityMap>
<!-- FRANCE -->
<Row>
<civilization>CIVILIZATION_FRANCE</civilization>
<X></X>
<Y></Y>
<ERA_ANCIENT>Lutece</ERA_ANCIENT>
<ERA_CLASSICAL>Lutece</ERA_CLASSICAL>
<ERA_MEDIEVAL>Paris</ERA_MEDIEVAL>
<ERA_RENAISSANCE>Paris</ERA_RENAISSANCE>
<ERA_INDUSTRIAL>Paris</ERA_INDUSTRIAL>
<ERA_MODERN>Paris</ERA_MODERN>
<ERA_FUTURE>Paris</ERA_FUTURE>
</Row>
</EuroLargeCityMap>
</GameData>
I hadn't ever really thought about adding era name changes, mostly because I never had a need for that kind of mechanic! But it seems a great idea for longer running scenarios, and probably easy to implement with SerialEventEraChanged?And yes, there is a small suggestion in that spoiler
> pCity:GetNameKey()
TXT_KEY_CITY_NAME_CARTHAGE
> pCity:GetName()
Carthage
> pCity:GetNameKey()
Carthage
> pCity:GetName()
Carthage
function IsValidCityName([COLOR="Red"][B]nameKey[/B][/COLOR])
[COLOR="red"][B]local nameStr = Locale.ConvertTextKey(nameKey)[/B][/COLOR]
for iPlayerLoop = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
local player = Players[iPlayerLoop];
if player:IsAlive() then
for city in player:Cities() do
if city ~= nil then
local cityName = [COLOR="red"][B]city:GetName()[/B][/COLOR];
if nameStr == cityName then
return false;
end
end
end
end
end
return true;
end
--only add valid names to array - You don't say!
if bValid then
--loop through scenario city names - Well I would never have guessed that!
for row in GameInfo.Civilization_ScenarioCityNames() do
--sort names by distance from new city plot - That makes more sense now :)
table.sort(CityNames, function(x,y) return x.dist < y.dist end)
local plot = Map.GetPlot(iX, iY)
local city = plot:GetPlotCity()
local city = Map.GetPlot(iX, iY):GetPlotCity()
function OnScenarioCityCreated( iPlayer, iX, iY )
if not IsScenarioWBMap() then return end
local city = [COLOR="Red"]Map.GetPlot(iX, iY)[/COLOR]:GetPlotCity()
if city == nil then return end
local nameKey = GetScenarioCityTxtKey(iPlayer, iX, iY)
if nameKey ~= nil then
city:SetName(Locale.ConvertTextKey(nameKey))
end
end
GameEvents.PlayerCityFounded.Add( OnScenarioCityCreated )
function OnScenarioCityCaptured (iOldOwner, bIsCapital, iX, iY, iNewOwner, iPop, bConquest)
if not IsScenarioWBMap() then return end
local city = [COLOR="Red"]Map.GetPlot(iX, iY)[/COLOR]:GetPlotCity()
if city == nil then return end
local nameKey = GetScenarioCityTxtKey(iNewOwner, iX, iY)
if nameKey ~= nil then
city:SetName(Locale.ConvertTextKey(nameKey))
end
end
GameEvents.CityCaptureComplete.Add( OnScenarioCityCaptured )
function GetScenarioCityTxtKey(iPlayer, iX, iY)
local cityNameKey = nil
local CityNames = {}
for row in GameInfo.Civilization_ScenarioCityNames() do
local civType = GameInfoTypes[ row.CivilizationType ]
local pCivType = Players[iPlayer]:GetCivilizationType()
if ( pCivType == civType ) then
local plotDistance = Map.PlotDistance(iX, iY, [COLOR="Red"]row.CityX[/COLOR], [COLOR="Red"]row.CityY[/COLOR])
if ( plotDistance <= row.CityRadius ) then
local cNameKey = row.CityName
if [COLOR="Red"]IsValidCityName(cNameKey)[/COLOR] then
[COLOR="Red"]table.insert(CityNames, {dist = plotDistance, name = cNameKey})[/COLOR]
end
end
end
end
local cityChoices = #CityNames
if cityChoices > 0 then
-- sort names by distance from new city plot
table.sort(CityNames, function(x,y) return x.dist < y.dist end)
local randName = {}
local minDist = CityNames[1].dist
for i,v in ipairs(CityNames) do
if cityChoices == 1 then
cityNameKey = [COLOR="Red"]CityNames[i].name[/COLOR]
else
if [COLOR="Red"]CityNames[i].dist[/COLOR] == minDist then
table.insert(randName, [COLOR="Red"]CityNames[i].name[/COLOR])
end
end
end
if #randName > 0 then
cityNameKey = randName[ math.random( #randName ) ]
end
end
return cityNameKey
end
function IsValidCityName(nameKey)
local nameKey = Locale.ConvertTextKey(nameKey)
for iPlayerLoop = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
local player = Players[iPlayerLoop]
if player:IsAlive() then
for city in player:Cities() do
if city ~= nil then
if nameKey == [COLOR="Red"]city:GetName()[/COLOR] then
return false
end
end
end
end
end
return true
end
function IsScenarioWBMap()
return Path.UsesExtension(PreGame.GetMapScript(),".Civ5Map")
end
-- We never use v so don't name it
for i,[COLOR="Red"]_[/COLOR] in ipairs(CityNames) do
if cityChoices == 1 then
cityNameKey = CityNames[i].name
else
if CityNames[i].dist == minDist then
table.insert(randName, CityNames[i].name)
end
end
end
if var == nil then return end
-- Do something positive
if var then
-- Do something positive
end
function OnScenarioCityCreated( iPlayer, iX, iY )
if not IsScenarioWBMap() then return end
local city = Map.GetPlot(iX, iY):GetPlotCity()
[COLOR="Red"]if city then[/COLOR]
local nameKey = GetScenarioCityTxtKey(iPlayer, iX, iY)
if [COLOR="Red"]nameKey[/COLOR] then
city:SetName(Locale.ConvertTextKey(nameKey))
end
[COLOR="Red"]end[/COLOR]
end
GameEvents.PlayerCityFounded.Add( OnScenarioCityCreated )
function OnScenarioCityCaptured (iOldOwner, bIsCapital, iX, iY, iNewOwner, iPop, bConquest)
if not IsScenarioWBMap() then return end
local city = Map.GetPlot(iX, iY):GetPlotCity()
[COLOR="Red"]if city then[/COLOR]
local nameKey = GetScenarioCityTxtKey(iNewOwner, iX, iY)
if [COLOR="Red"]nameKey[/COLOR] then
city:SetName(Locale.ConvertTextKey(nameKey))
end
[COLOR="Red"]end[/COLOR]
end
GameEvents.CityCaptureComplete.Add( OnScenarioCityCaptured )
function GetScenarioCityTxtKey(iPlayer, iX, iY)
local cityNameKey = nil
local CityNames = {}
for row in GameInfo.Civilization_ScenarioCityNames() do
local civType = GameInfoTypes[ row.CivilizationType ]
local pCivType = Players[iPlayer]:GetCivilizationType()
if ( pCivType == civType ) then
local plotDistance = Map.PlotDistance(iX, iY, row.CityX, row.CityY)
if ( plotDistance <= row.CityRadius ) then
local cNameKey = row.CityName
if IsValidCityName(cNameKey) then
table.insert(CityNames, {dist = plotDistance, name = cNameKey})
end
end
end
end
local cityChoices = #CityNames
if cityChoices > 0 then
-- sort names by distance from new city plot
table.sort(CityNames, function(x,y) return x.dist < y.dist end)
local randName = {}
local minDist = CityNames[1].dist
for i,_ in ipairs(CityNames) do
if cityChoices == 1 then
cityNameKey = CityNames[i].name
else
if CityNames[i].dist == minDist then
table.insert(randName, CityNames[i].name)
end
end
end
if #randName > 0 then
cityNameKey = randName[ math.random( #randName ) ]
end
end
return cityNameKey
end
function IsValidCityName(nameKey)
local nameKey = Locale.ConvertTextKey(nameKey)
for iPlayerLoop = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
local player = Players[iPlayerLoop]
if player:IsAlive() then
for city in player:Cities() do
if [COLOR="Red"]city[/COLOR] then
if nameKey == city:GetName() then
return false
end
end
end
end
end
return true
end
function IsScenarioWBMap()
return Path.UsesExtension(PreGame.GetMapScript(),".Civ5Map")
end
for iLoopPlayer = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
local pLoopPlayer = Players[iLoopPlayer]
local pPlayer = Players[Game.GetActivePlayer()]
-- do something with pLoopPlayer and pPlayer
end
local pPlayer = Players[Game.GetActivePlayer()]
for iLoopPlayer = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
local pLoopPlayer = Players[iLoopPlayer]
-- do something with pLoopPlayer and pPlayer
end
function GetScenarioCityTxtKey(iPlayer, iX, iY)
local cityNameKey = nil
local CityNames = {}
[COLOR="Red"]local pCivType = Players[iPlayer]:GetCivilizationType()[/COLOR]
for row in GameInfo.Civilization_ScenarioCityNames() do
local civType = GameInfoTypes[ row.CivilizationType ]
if ( pCivType == civType ) then
local plotDistance = Map.PlotDistance(iX, iY, row.CityX, row.CityY)
if ( plotDistance <= row.CityRadius ) then
local cNameKey = row.CityName
if IsValidCityName(cNameKey) then
table.insert(CityNames, {dist = plotDistance, name = cNameKey})
end
end
end
end
[COLOR="Red"]if (#CityNames == 1) then
cityNameKey = CityNames[1].name
elseif (#CityNames > 1) then[/COLOR]
-- sort names by distance from new city plot
table.sort(CityNames, function(x,y) return x.dist < y.dist end)
local randName = {}
local minDist = CityNames[1].dist
for i,_ in ipairs(CityNames) do
[COLOR="Red"]if CityNames[i].dist == minDist then
table.insert(randName, CityNames[i].name)
end[/COLOR]
end
if #randName > 0 then
cityNameKey = randName[ math.random( #randName ) ]
end
end
return cityNameKey
end
function OnScenarioCityCreated( iPlayer, iX, iY )
if not IsScenarioWBMap() then return end
local city = Map.GetPlot(iX, iY):GetPlotCity()
local nameKey = GetScenarioCityTxtKey(iPlayer, iX, iY)
if nameKey then
city:SetName(Locale.ConvertTextKey(nameKey))
end
end
GameEvents.PlayerCityFounded.Add( OnScenarioCityCreated )
function OnScenarioCityCaptured (iOldOwner, bIsCapital, iX, iY, iNewOwner, iPop, bConquest)
if not IsScenarioWBMap() then return end
local city = Map.GetPlot(iX, iY):GetPlotCity()
local nameKey = GetScenarioCityTxtKey(iNewOwner, iX, iY)
if nameKey then
city:SetName(Locale.ConvertTextKey(nameKey))
end
end
GameEvents.CityCaptureComplete.Add( OnScenarioCityCaptured )
function GetScenarioCityTxtKey(iPlayer, iX, iY)
local cityNameKey = nil
local CityNames = {}
[COLOR="Red"]-- row.CivilizationType below is a Type (eg CIVILIZATION_ENGLAND) so let's get the same thing here to simplify the code in the loop
local pCivType = GameInfo.Civilizations[Players[iPlayer]:GetCivilizationType()].Type[/COLOR]
for row in GameInfo.Civilization_ScenarioCityNames() do
[COLOR="Red"]if ( pCivType == row.CivilizationType ) then[/COLOR]
local plotDistance = Map.PlotDistance(iX, iY, row.CityX, row.CityY)
if ( plotDistance <= row.CityRadius ) then
local cNameKey = row.CityName
if IsValidCityName(cNameKey) then
table.insert(CityNames, {dist = plotDistance, name = cNameKey})
end
end
end
end
if (#CityNames == 1) then
cityNameKey = CityNames[1].name
elseif (#CityNames > 1) then
-- sort names by distance from new city plot
table.sort(CityNames, function(x,y) return x.dist < y.dist end)
local randName = {}
local minDist = CityNames[1].dist
[COLOR="Red"]-- cn is CityNames[i] so use it!
for _,cn in ipairs(CityNames) do
if cn.dist == minDist then
table.insert(randName, cn.name)
end
end[/COLOR]
[COLOR="Red"]-- There will always be at least one entry in randName
cityNameKey = randName[math.random(#randName)][/COLOR]
end
return cityNameKey
end
function IsValidCityName(nameKey)
local nameKey = Locale.ConvertTextKey(nameKey)
for iPlayerLoop = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
local player = Players[iPlayerLoop]
if player:IsAlive() then
for city in player:Cities() do
[COLOR="Red"]if nameKey == city:GetName() then
return false
end[/COLOR]
end
end
end
return true
end
for _,cn in ipairs(CityNames) do
if cn.dist == minDist then
table.insert(randName, cn.name)
else
[COLOR="Red"]-- As the list is sorted by distance, every other city will also be further away, so stop looking
break[/COLOR]
end
end
if (#CityNames == 1) then
cityNameKey = CityNames[1].name
elseif (#CityNames > 1) then
-- sort names by distance from new city plot
table.sort(CityNames, function(x,y) return x.dist < y.dist end)
[COLOR="Red"]local possibleCities = 0[/COLOR]
local minDist = CityNames[1].dist
for _,cn in ipairs(CityNames) do
if cn.dist == minDist then
[COLOR="Red"]possibleCities = possibleCities + 1[/COLOR]
else
-- As the list is sorted by distance, every other city will also be further away, so stop looking
break
end
end
[COLOR="Red"]cityNameKey = CityNames[math.random(possibleCities)] [/COLOR]
end
-- sort names by distance from new city plot, sort alphabetically when both are the same distance from the plot
table.sort(CityNames, function(x,y) if (x.dist == y.dist) then return (x.name < y.name) else return (x.dist < y.dist) end end)
-- SELECT * FROM Civilization_ScenarioCityNames
GameInfo.Civilization_ScenarioCityNames()
-- SELECT * FROM Civilization_ScenarioCityNames WHERE CivilizationType='CIVILIZATION_ENGLAND'
GameInfo.Civilization_ScenarioCityNames("CivilizationType='CIVILIZATION_ENGLAND'")
[COLOR="Red"]for row in GameInfo.Civilization_ScenarioCityNames("CivilizationType='" .. pCivType .. "'") do[/COLOR]
local plotDistance = Map.PlotDistance(iX, iY, row.CityX, row.CityY)
if ( plotDistance <= row.CityRadius ) then
local cNameKey = row.CityName
if IsValidCityName(cNameKey) then
table.insert(CityNames, {dist = plotDistance, name = cNameKey})
end
end
end
local pCivType = GameInfo.Civilizations[Players[iPlayer]:GetCivilizationType()].Type
for row in GameInfo.Civilization_ScenarioCityNames("CivilizationType='" .. pCivType .. "'") do
for row in GameInfo.Civilization_ScenarioCityNames("CivilizationType='" .. GameInfo.Civilizations[Players[iPlayer]:GetCivilizationType()].Type .. "'") do
function OnScenarioCityCreated( iPlayer, iX, iY )
if not IsScenarioWBMap() then return end
local city = Map.GetPlot(iX, iY):GetPlotCity()
local nameKey = GetScenarioCityTxtKey(iPlayer, iX, iY)
if nameKey then
city:SetName(Locale.ConvertTextKey(nameKey))
end
end
GameEvents.PlayerCityFounded.Add( OnScenarioCityCreated )
function OnScenarioCityCaptured (iOldOwner, bIsCapital, iX, iY, iNewOwner, iPop, bConquest)
if not IsScenarioWBMap() then return end
local city = Map.GetPlot(iX, iY):GetPlotCity()
local nameKey = GetScenarioCityTxtKey(iNewOwner, iX, iY)
if nameKey then
city:SetName(Locale.ConvertTextKey(nameKey))
end
end
GameEvents.CityCaptureComplete.Add( OnScenarioCityCaptured )
function GetScenarioCityTxtKey(iPlayer, iX, iY)
local cityNameKey = nil
local CityNames = {}
local pCivType = GameInfo.Civilizations[Players[iPlayer]:GetCivilizationType()].Type
for row in GameInfo.Civilization_ScenarioCityNames("CivilizationType='" .. pCivType .. "'") do
local plotDistance = Map.PlotDistance(iX, iY, row.CityX, row.CityY)
if ( plotDistance <= row.CityRadius ) then
local cNameKey = row.CityName
if IsValidCityName(cNameKey) then
table.insert(CityNames, {dist = plotDistance, name = cNameKey})
end
end
end
if (#CityNames == 1) then
cityNameKey = CityNames[1].name
elseif (#CityNames > 1) then
-- sort names by distance from new city plot, use the city names when both the same distance from the plot
table.sort(CityNames, function(x,y) if (x.dist == y.dist) then return (x.name < y.name) else return (x.dist < y.dist) end end)
local possibleCities = 0
local minDist = CityNames[1].dist
for _,cn in ipairs(CityNames) do
if cn.dist == minDist then
possibleCities = possibleCities + 1
else
-- As the list is sorted by distance, every other city will also be further away, so stop looking
break
end
end
cityNameKey = CityNames[math.random(possibleCities)]
end
return cityNameKey
end
function IsValidCityName(nameKey)
local nameKey = Locale.ConvertTextKey(nameKey)
for iPlayerLoop = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
local player = Players[iPlayerLoop]
if player:IsAlive() then
for city in player:Cities() do
if nameKey == city:GetName() then
return false
end
end
end
end
return true
end
function IsScenarioWBMap()
return Path.UsesExtension(PreGame.GetMapScript(),".Civ5Map")
end
Firstly, there is nothing wrong with the code, it does what it says so is, by definition, correct. However, it contains a number of aspects that could be better, and are quite common beginner scripting mistakes, so are probably worth pointing out.
What does this mod do exactly? There wasn't much info on that in post 6(except for programmers).
How do you use this? How do you assign city names to plots? I'd like some more documentation, as I would love to use this on some giant TSL maps.
CREATE TABLE Civilization_ScenarioCityNames
(
CivilizationType TEXT DEFAULT NULL,
CityX INTEGER DEFAULT 0,
CityY INTEGER DEFAULT 0,
CityRadius INTEGER DEFAULT 0,
CityName TEXT DEFAULT NULL
);
INSERT INTO Civilization_ScenarioCityNames (CivilizationType, CityX, CityY, CityRadius, CityName)
SELECT 'CIVILIZATION_SPAIN', 18, 12, 2, 'TXT_KEY_SCENARIO_CITY_TUMBES' UNION ALL
SELECT 'CIVILIZATION_SPAIN', 21, 8, 2, 'TXT_KEY_SCENARIO_CITY_TALARA' UNION ALL
SELECT 'CIVILIZATION_SPAIN', 28, 5, 2, 'TXT_KEY_SCENARIO_CITY_CHICLAYO' UNION ALL
SELECT 'CIVILIZATION_SPAIN', 38, 7, 2, 'TXT_KEY_SCENARIO_CITY_TRUJILLO' UNION ALL
SELECT 'CIVILIZATION_SPAIN', 71, 8, 2, 'TXT_KEY_SCENARIO_CITY_LIMA';
Excellent! Probably should include information like this in the first post, but thank you for answering!