Resources Spawn Buildings

Ulixes

Prince
Joined
May 2, 2010
Messages
312
While I was working on another code, following (partially) an hint of Bobert13, I made a code that should spawn a building in your cities when you have access to a resource (owned or traded) and delete it when the resource is no more avalaible.

14. function ResourcesSpawnBuildings(playerID)
15. local player = Players[playerID];
16. local pCity = player:GetCityByID(cityID);
17.
18. if(player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true) > 0) then
19. pCity:SetNumRealBuilding(50, 1)
20. end
21. if(player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true) <= 0) then
22. pCity:SetNumRealBuilding(50, 0)
23. end
24. end
25. GameEvents.PlayerDoTurn.Add(ResourcesSpawnBuildings);


(I used, for testing, the Library. "50" is its ID)

The code works as intended, but has two problems:
1) it works only for the capital
(although this can be resolved using xml I would like to understand how to apply it to all cities)
2) Lua.log show this error more times:
Runtime Error: C:\Users\Windows 7\Desktop\Documents\My Games\Sid Meier's Civilization 5\MODS\My - Changes (v 1)\LUA/MyLuaChanges.lua:22: attempt to index local 'pCity' (a nil value)

Another strange thing is that this error disappear if I delete the second 'if' statement (21-23)
So, it give a value to the first 'pCity' but not to the second, why?

Any help would be really appreciated!

Thanks in advance for your time, Ulixes
 
While I was working on another code, following (partially) an hint of Bobert13, I made a code that should spawn a building in your cities when you have access to a resource (owned or traded) and delete it when the resource is no more avalaible.

14. function ResourcesSpawnBuildings(playerID)
15. local player = Players[playerID];
16. local pCity = player:GetCityByID(cityID);
17.
18. if(player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true) > 0) then
19. pCity:SetNumRealBuilding(50, 1)
20. end
21. if(player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true) <= 0) then
22. pCity:SetNumRealBuilding(50, 0)
23. end
24. end
25. GameEvents.PlayerDoTurn.Add(ResourcesSpawnBuildings);


(I used, for testing, the Library. "50" is its ID)

The code works as intended, but has two problems:
1) it works only for the capital
(although this can be resolved using xml I would like to understand how to aplly it to all cities)
2) Lua.log show this error more times:
Runtime Error: C:\Users\Windows 7\Desktop\Documents\My Games\Sid Meier's Civilization 5\MODS\My - Changes (v 1)\LUA/MyLuaChanges.lua:22: attempt to index local 'pCity' (a nil value)

Another strange thing is that this error disappear if I delete the second 'if' statement (21-23)
So, it give a value to the first 'pCity' but not to the second, why?

Any help would be really appreciated!

Thanks in advance for your time, Ulixes
  1. cityID is equal to "nil" since it is an undefined variable
  2. Because of #1, pCity will always be a "nil" value.
  3. Most likely, the conditional on line number 18 is probably not "true", therefore lines 19 and 20 never run
  4. If there is no Silk available, only lines 21-23 out of the group 18-23 will ever execute, and since pCity is "nil", you are getting your runtime error for a "nil" value when line number 22 tries to execute.

To run through all of a player's cities, use:
Code:
for [COLOR="Blue"]pCity[/COLOR] in player:Cities() do
	--do something for each city here, such as:
	[COLOR="blue"]pCity[/COLOR]:SetNumRealBuilding(50, 0)
end
This tells the game to run through all of a player's cities, and for each city one at a time create a variable called pCity to be used for each individual city in the list while running through the list of cities as commanded to do by the line:
Code:
for pCity in player:Cities() do

And git rid of this line:
Code:
local pCity = player:GetCityByID(cityID);
 
Thank you LeeS, it works perfectly! :woohoo:

If you (or someone else) have the time, I have 3 questions:

1) Why this code (made by Machiavelli24) doesn't need 'cityID' to be defined ?

Spoiler :
function WeaverMarketBonus(playerID)
local player = Players[playerID];
local numWeaverMarkets = 0;
local foodBonus = 0;
local city = player:GetCityByID(cityID);

-- Count how many Weaver Markets the player has
for indexCity in player:Cities() do
if(indexCity:IsHasBuilding(GameInfoTypes["BUILDING_WEAVER_MARKET"])) then
numWeaverMarkets = numWeaverMarkets + 1;
end
end

-- Calculate the bonus food to give
if(numWeaverMarkets > 0) then
if(player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true) > 0) then
foodBonus = foodBonus + 1;
end
if(player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_COTTON"], true) > 0) then
foodBonus = foodBonus + 1;
end

city:ChangeFood(numWeaverMarkets * foodBonus);
end
end
GameEvents.PlayerDoTurn.Add(WeaverMarketBonus);


I fear the answer to the next question, considering it might be far beyond my skills, but there is always the possibility that things are more simple than you thought :)

2) How can I give the building only to cities connected with the capital ?

EDIT: 3) How much this code could hit performances (if applied for all resources), in your opinion ?
 
#1) which Machiavelli mod? can't really answer #1 without knowing what the rest of the file looks like. Likely he has predefined cityID elsewhere than within that function as a global.
#2) player:IsCapitalConnectedToCity(pCity)
#3) Depends on how you structure, really. I have one mod that does a lot of processing looking through city production items and then all workable plots surrounding each city, and it does not seem to much effect turn processing time.
 
1) I can't find it defined as a global anywhere and I remember the code worked.
Machiavelli did for me some code a long time ago that allowed resources to give yields to buildings. Under his guidance, I replaced some lines.
I'm trying to obtain a similar effect in another way now because with his code the amount was not shown in the top panel, I didn't considered this a big problem back then, but, with time I discovered that it can be annoying, plus, maybe this system can have more uses.
You can find the thread here

2) Thank you (glad it is simple :) ), but, forgive my ignorance, do you mean in this way? EDIT: clearly wrong I'm trying to inesrt it in the "if" statement.

Spoiler :
function ResourcesSpawnBuildings(playerID)
local player = Players[playerID];

for pCity in player:Cities() do
for player:IsCapitalConnectedToCity(pCity) do
if(player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true) > 0) then
pCity:SetNumRealBuilding(50, 1)
end
if(player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true) <= 0) then
pCity:SetNumRealBuilding(50, 0)
end
end
end
end
GameEvents.PlayerDoTurn.Add(ResourcesSpawnBuildings);


3) What do you mean by "structure" ? I just insert the file with the code into the mod as shown here, add new buildings and resources in the usual SQL files. Is there something else I could do ?
 
1) I can't find it defined as a global anywhere and I remember the code worked.
Machiavelli did for me some code a long time ago that allowed resources to give yields to buildings. Under his guidance, I replaced some lines.
I'm trying to obtain a similar effect in another way now because with his code the amount was not shown in the top panel, I didn't considered this a big problem back then, but, with time I discovered that it can be annoying, plus, maybe this system can have more uses.
You can find the thread here

2) Thank you (glad it is simple :) ), but, forgive my ignorance, do you mean in this way? EDIT: clearly wrong I'm trying to inesrt it in the "if" statement.

Spoiler :
function ResourcesSpawnBuildings(playerID)
local player = Players[playerID];

for pCity in player:Cities() do
for player:IsCapitalConnectedToCity(pCity) do
if(player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true) > 0) then
pCity:SetNumRealBuilding(50, 1)
end
if(player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true) <= 0) then
pCity:SetNumRealBuilding(50, 0)
end
end
end
end
GameEvents.PlayerDoTurn.Add(ResourcesSpawnBuildings);


3) What do you mean by "structure" ? I just insert the file with the code into the mod as shown here, add new buildings and resources in the usual SQL files. Is there something else I could do ?
Something like this for the connected to capital thing, since that is a boolean (true/false) that will have a different true-false answer for every city within an empire:
Code:
function ResourcesSpawnBuildings(playerID)
	local player = Players[playerID];
	
	for pCity in player:Cities() do
		if player:IsCapitalConnectedToCity(pCity) then
			if(player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true) > 0) then
				pCity:SetNumRealBuilding(50, 1)
			end
			if(player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true) <= 0) then
				pCity:SetNumRealBuilding(50, 0)
			end
		end
	end
end
GameEvents.PlayerDoTurn.Add(ResourcesSpawnBuildings);

By "structure" I mean if it were me I would get all the "answers" to whether the player has Resouce A, B, C, D, ..... X, Y, Z before ever looking through all the player's cities, and I would stick these "answers" into variables of some kind:
Code:
local iNumberSilk = player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true)
This would mean that "question" would only ever have to be "asked" and "answered" once per run through the entirety of function ResourcesSpawnBuildings. I would put all similar commands just above the line
Code:
for pCity in player:Cities() do
like this:
Code:
function ResourcesSpawnBuildings(playerID)
	local player = Players[playerID];
	local iNumberSilk = player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true)	
	for pCity in player:Cities() do
		if player:IsCapitalConnectedToCity(pCity) then
			if iNumberSilk > 0 then
				pCity:SetNumRealBuilding(50, 1)
			end
			if iNumberSilk <= 0 then
				pCity:SetNumRealBuilding(50, 0)
			end
		end
	end
end
GameEvents.PlayerDoTurn.Add(ResourcesSpawnBuildings);

I'll have to look through that linked thread later since I've got some RL stuff I have to go do for a while.

Also, it's much easier to read someone's code if you use
Code:
 instead of [spoiler]. In the advanced view for forum replies the "code" wraps around a chunk of selected text can be done using the "#" button across the top of the forum-reply box where you type in your text.
 
Thank you!
I had posted my (wrong) code where I put the 'IsCapitalConnectedToCity(pCity)' in the first "if" statement but then I read your reply.
Thank you for the clarification about this.

As for the structure, clever!
Correct me if I'm wrong, but I could use this for multiple resources that spawn building in a single function instead of using many functions.

For example:

Code:
function ResourcesSpawnBuildings(playerID)
	local player = Players[playerID];
	local iNumberSilk = player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true)
	local iNumberCotton = player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_COTTON"], true)
	for pCity in player:Cities() do
		if player:IsCapitalConnectedToCity(pCity) then
			if iNumberSilk > 0 then
				pCity:SetNumRealBuilding(50, 1)
			end
			if iNumberSilk <= 0 then
				pCity:SetNumRealBuilding(50, 0)
			end
			if iNumberCotton > 0 then
				pCity:SetNumRealBuilding(50, 1)
			end
			if iNumberCotton <= 0 then
				pCity:SetNumRealBuilding(50, 0)
			end
		end
	end
end
GameEvents.PlayerDoTurn.Add(ResourcesSpawnBuildings);

Would this improve performances?
 
Correction (in case you didn't read it, I edited my previous post):

It worked also before, I just, for distraction, added an "end" at the bottom of the function that, obviously, made it not working.

For anyone interested it can be done in 3 ways:

1)

Code:
function ResourcesSpawnBuildings(playerID)
	local player = Players[playerID];
	
	for pCity in player:Cities() do
	if(player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true) > 0 and player:IsCapitalConnectedToCity(pCity)) then
		pCity:SetNumRealBuilding(50, 1)
    end
	if(player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true) <= 0) then
		pCity:SetNumRealBuilding(50, 0)
    end
	end
end
GameEvents.PlayerDoTurn.Add(ResourcesSpawnBuildings);

2)

Code:
function ResourcesSpawnBuildings(playerID)
	local player = Players[playerID];
	
	for pCity in player:Cities() do
		if player:IsCapitalConnectedToCity(pCity) then
			if(player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true) > 0) then
				pCity:SetNumRealBuilding(50, 1)
			end
			if(player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true) <= 0) then
				pCity:SetNumRealBuilding(50, 0)
			end
		end
	end
end
GameEvents.PlayerDoTurn.Add(ResourcesSpawnBuildings);

and 3)

Code:
function ResourcesSpawnBuildings(playerID)
	local player = Players[playerID];
	local iNumberSilk = player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true)	
	for pCity in player:Cities() do
		if player:IsCapitalConnectedToCity(pCity) then
			if iNumberSilk > 0 then
				pCity:SetNumRealBuilding(50, 1)
			end
			if iNumberSilk <= 0 then
				pCity:SetNumRealBuilding(50, 0)
			end
		end
	end
end
GameEvents.PlayerDoTurn.Add(ResourcesSpawnBuildings);

That said, in case you missed my edit on the previous post, can inserting multiple resources and related spawned building in the same function improve performances?

Example:

Code:
function ResourcesSpawnBuildings(playerID)
	local player = Players[playerID];
	local iNumberSilk = player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true)
	local iNumberCotton = player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_COTTON"], true)
	for pCity in player:Cities() do
		if player:IsCapitalConnectedToCity(pCity) then
			if iNumberSilk > 0 then
				pCity:SetNumRealBuilding(50, 1)
			end
			if iNumberSilk <= 0 then
				pCity:SetNumRealBuilding(50, 0)
			end
			if iNumberCotton > 0 then
				pCity:SetNumRealBuilding(50, 1)
			end
			if iNumberCotton <= 0 then
				pCity:SetNumRealBuilding(50, 0)
			end
		end
	end
end
GameEvents.PlayerDoTurn.Add(ResourcesSpawnBuildings);

There are limits (or advices against) on how many resources/buildings I can put in it?

P.S.: Thanks for the "
Code:
" suggestion, not being used to post codes, I didn't thought about it :)
 
Those can also be optimized with an else statement. If iVal > 0 is true or false then iVal <= 0 is false or true and is therefore redundant.

Code:
if iNumberSilk > 0 then
	pCity:SetNumRealBuilding(50, 1)
else
	pCity:SetNumRealBuilding(50, 0)
end
 
Irrefutable Logic.

Thank you, I'll follow your suggestion!

P.S.: on a second thought, I remember that, when I first started putting together the code, I've thought something like this, using "else" instead of another "if", but, being highly unsure of my skills, I wanted to keep it close to what I already saw in other codes.
I have to be more self-confident next time!
 
Those can also be optimized with an else statement. If iVal > 0 is true or false then iVal <= 0 is false or true and is therefore redundant.

Code:
if iNumberSilk > 0 then
	pCity:SetNumRealBuilding(50, 1)
else
	pCity:SetNumRealBuilding(50, 0)
end
This was going to be the next optimizing suggestion after I returned from Real Life interferences.

It will also be quicker for scanning through the list of a player's cities if it is possible based on the desired outcome to set the number of buildings as a variable and make the determination for what value should be set in cities before ever scanning through the list of a player's cities. So the code as shown here would set a cotton-linked and silk-linked building into cities that are connected to the capital if the player has silk or cotton, and would remove them from all cities that are not connected to the capital. It would also tend to process somewhat faster since the ID#s for cotton, silk, and the two buildings is being "researched" from the game's database when the mod loads into the game instead of looking up those values from the game's database every turn for every player.

Code:
iResourceSilk = GameInfoTypes["RESOURCE_SILK"]
iSilkBuildings = GameInfoTypes["BUILDING_SOME_BUILDING"]
iResourceCotton = GameInfoTypes["RESOURCE_COTTON"]
iCottonBuildings = GameInfoTypes["BUILDING_SOME_OTHER_BUILDING"]

function ResourcesSpawnBuildings(playerID)
	local player = Players[playerID];
	local iNumberSilkBuildings, iNumberCottonBuildings = 0, 0
	if player:GetNumResourceAvailable(iResourceSilk, true) > 0 then
		iNumberSilkBuildings = 1
	end
	if player:GetNumResourceAvailable(iResourceCotton, true) > 0 then
		iNumberCottonBuildings = 1
	end
	for pCity in player:Cities() do
		if player:IsCapitalConnectedToCity(pCity) then
			pCity:SetNumRealBuilding(iSilkBuildings, iNumberSilkBuildings)
			pCity:SetNumRealBuilding(iCottonBuildings, iNumberCottonBuildings)
		else
			pCity:SetNumRealBuilding(iSilkBuildings, 0)
			pCity:SetNumRealBuilding(iCottonBuildings, 0)
		end
	end
end
GameEvents.PlayerDoTurn.Add(ResourcesSpawnBuildings);
 
Wow... that's very interesting...
and not only for creating more "resource-buildings" (with the minimum performance hit), it could be a good starting example for many other ideas...

Thank you LeeS, I couldn't have hoped for a better help! :thanx:
 
How fast is too fast? :lol:

You should be setting those initial variables up as locals. And while you're at it, you could localize, well everything, on initialization. I've noticed noone who codes for Civ bothers with localizing. Probably, partially, because it convolutes the code but some of it is as simple as adding the word local to the front of a line.

Mostly local:
Code:
local iResourceSilk = GameInfoTypes["RESOURCE_SILK"]
local iSilkBuildings = GameInfoTypes["BUILDING_SOME_BUILDING"]
local iResourceCotton = GameInfoTypes["RESOURCE_COTTON"]
local iCottonBuildings = GameInfoTypes["BUILDING_SOME_OTHER_BUILDING"]

--local ResourcesSpawnBuildings = function(playerID) -- this is equivalent to the line below. The latter is syntactic sugar.
local function ResourcesSpawnBuildings(playerID)
	local player = Players[playerID];
	local iNumberSilkBuildings, iNumberCottonBuildings = 0, 0
	if player:GetNumResourceAvailable(iResourceSilk, true) > 0 then
		iNumberSilkBuildings = 1
	end
	if player:GetNumResourceAvailable(iResourceCotton, true) > 0 then
		iNumberCottonBuildings = 1
	end
	for pCity in player:Cities() do
		if player:IsCapitalConnectedToCity(pCity) then
			pCity:SetNumRealBuilding(iSilkBuildings, iNumberSilkBuildings)
			pCity:SetNumRealBuilding(iCottonBuildings, iNumberCottonBuildings)
		else
			pCity:SetNumRealBuilding(iSilkBuildings, 0)
			pCity:SetNumRealBuilding(iCottonBuildings, 0)
		end
	end
end

Really super local:
Code:
local iResourceSilk = GameInfoTypes["RESOURCE_SILK"]
local iSilkBuildings = GameInfoTypes["BUILDING_SOME_BUILDING"]
local iResourceCotton = GameInfoTypes["RESOURCE_COTTON"]
local iCottonBuildings = GameInfoTypes["BUILDING_SOME_OTHER_BUILDING"]

local myGetNumResourceAvailable(me, resource, bool) = me:GetNumResourceAvailable(resource, bool)
local mySetNumRealBuilding(city, building, val) = city:SetNumRealBuilding(building, val)
local myCities(me) = me:Cities()
local myIsCapitalConnectedToCity(me, city) = me:IsCapitalConnectedToCity(city)


--local ResourcesSpawnBuildings = function(playerID) -- this is equivalent to the line below. The latter is syntactic sugar.
local function ResourcesSpawnBuildings(playerID)
	local player = Players[playerID];
	local iNumberSilkBuildings, iNumberCottonBuildings = 0, 0
	if myGetNumResourceAvailable(player, iResourceSilk, true) > 0 then
		iNumberSilkBuildings = 1
	end
	if myGetNumResourceAvailable(player, iResourceCotton, true) > 0 then
		iNumberCottonBuildings = 1
	end
	for pCity in myCities(player) do
		if myIsCapitalConnectedToCity(player, pCity) then
			mySetNumRealBuilding(pCity, iSilkBuildings, iNumberSilkBuildings)
			mySetNumRealBuilding(pCity, iCottonBuildings, iNumberCottonBuildings)
		else
			mySetNumRealBuilding(pCity, iSilkBuildings, 0)
			mySetNumRealBuilding(pCity, iCottonBuildings, 0)
		end
	end
end

Global lookups are significantly slower than locals, hence why this is an optimization. (note: I'm not 100% sure that my redefinition of the pseudo-class functions in the "really super local" version would work as intended, the way I've coded them. I do know this sort of redefinition in local space is possible in Lua, though I simply may not be using the correct syntax; it's been a while.)

Code:
local myGetNumResourceAvailable = #player_object#.GetNumResourceAvailable(me, resource, bool)
If the first version doesn't work, this one definitely does. #player_object# obviously needs to be replaced with the actual class definition though I think it's simply "Player" though I can't recall at the moment.
 
Too fast is not fast enough :)

I have about 90 resources with related buildings so, as you can understand, I need the minimum performance hit possible.

That said, I have to report that the last 3 codes have problems.

Last LeeS code require both silk AND cotton and doesn't give a library but Floating Gardens (ID 0)

I already encountered this bug, the game gives you the building with ID 0 when it requires an ID in the Lua code and you didn't give any
(the first time I put together the code in the first post I inserted 'BUILDING_LIBRARY' instead of '50' and it gave the Floating Garden that, looking with SQLiteSpy in the database, was ID 0, there I understood that 'SetNumRealBuilding' requires the ID).
There isn't a second building appearing.
It gives no error in the Lua code.

Both Bobert13's codes don't work.

They give this generic error in the Lua.log:
Runtime Error: Error loading C:\Users\Windows 7\Desktop\Documents\My Games\Sid Meier's Civilization 5\MODS\My - Changes (v 1)\LUA/MyLuaChanges.lua.

My edit on the previous LeeS' code works like a charm:

Code:
function ResourcesSpawnBuildings(playerID)
	local player = Players[playerID];
	local iNumberSilk = player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_SILK"], true)
	local iNumberCotton = player:GetNumResourceAvailable(GameInfoTypes["RESOURCE_COTTON"], true)
	for pCity in player:Cities() do
		if player:IsCapitalConnectedToCity(pCity) then
			if iNumberSilk > 0 then
				pCity:SetNumRealBuilding(50, 1)
			end
			if iNumberSilk <= 0 then
				pCity:SetNumRealBuilding(50, 0)
			end
			if iNumberCotton > 0 then
				pCity:SetNumRealBuilding(40, 1)
			end
			if iNumberCotton <= 0 then
				pCity:SetNumRealBuilding(40, 0)
			end
		end
	end
end
GameEvents.PlayerDoTurn.Add(ResourcesSpawnBuildings);

Where "50": Library, "40": Granary

Maybe later I will do some other testing trying to editing the codes
 
You didn't replace BUILDING_SOME_BUILDING and BUILDING_SOME_OTHER_BUILDING with a valid designation of a <Buildings> <Type> field from the list of active buildings registered with the game.

BUILDING_SOME_BUILDING and BUILDING_SOME_OTHER_BUILDING are just example placeholders for use in demonstrating the code, and if actually run in-game without being changed to a valid building specification will cause the game to revert to Floating Gardens because it is the 'default' value, as it were.

Verify by using my code and replace BUILDING_SOME_BUILDING with BUILDING_LIBRARY and replace in my code BUILDING_SOME_OTHER_BUILDING with BUILDING_GRANARY.

The code as written does not require a player to have both silk and cotton in order to have one of the two buildings added to a city, though relooking at it, it might never give the buildings in the capital city itself.

It will, however, also require that the player have silk or cotton in order for the correct silk or cotton resource-linked building to be placed in any city. And the non-capital city must be connected to the capital.
 
You didn't replace BUILDING_SOME_BUILDING and BUILDING_SOME_OTHER_BUILDING with a valid designation of a <Buildings> <Type> field from the list of active buildings registered with the game.

BUILDING_SOME_BUILDING and BUILDING_SOME_OTHER_BUILDING are just example placeholders for use in demonstrating the code, and if actually run in-game without being changed to a valid building specification will cause the game to revert to Floating Gardens because it is the 'default' value, as it were.

Of course I did. I'm a newbie, not completely dumb. ;)

I replaced your placeholders with buildings from the database,
I thought there was non need to specify this.
When I tested it, I used BUILDING_LIBRARY and BUILDING_GRANARY (and, of course, so I did for Bobert13 versions).

I may be wrong, but my (newbie's) impression is that the code wants to give to 'mySetNumRealBuilding' a "building type" when it needs an "ID".
 
Pretty much everything in the lua API needs to be an integer corresponding to a Building's, Resource's, Improvement's, BuildingClasses' ID# from the game's corresponding <Buildings>, <Resources>, etc., tables.

Doing this
Code:
local iSilkBuildings = GameInfoTypes["BUILDING_LIBRARY"]
or this
Code:
local iSilkBuildings = GameInfoTypes.BUILDING_LIBRARY
instructs the game to create a local variable called iSilkBuildings and stick the ID# for BUILDING_LIBRARY from the game's <Buildings> table into that local variable called iSilkBuildings.

Attach your mod you are using at the moment to test one of these methods (mine or Bobert's). There has to be something else you are not quite doing correctly. A copy-paste typo, something.

This works just fine for me:
Code:
iResourceSilk = GameInfoTypes["RESOURCE_SILK"]
iSilkBuildings = GameInfoTypes["BUILDING_LIBRARY"]
iResourceCotton = GameInfoTypes["RESOURCE_COTTON"]
iCottonBuildings = GameInfoTypes["BUILDING_GRANARY"]

function ResourcesSpawnBuildings(playerID)
	local player = Players[playerID];
	local iNumberSilkBuildings, iNumberCottonBuildings = 0, 0
	if player:GetNumResourceAvailable(iResourceSilk, true) > 0 then
		iNumberSilkBuildings = 1
	end
	if player:GetNumResourceAvailable(iResourceCotton, true) > 0 then
		iNumberCottonBuildings = 1
	end
	for pCity in player:Cities() do
		if player:IsCapitalConnectedToCity(pCity) then
			pCity:SetNumRealBuilding(iSilkBuildings, iNumberSilkBuildings)
			pCity:SetNumRealBuilding(iCottonBuildings, iNumberCottonBuildings)
		else
			pCity:SetNumRealBuilding(iSilkBuildings, 0)
			pCity:SetNumRealBuilding(iCottonBuildings, 0)
		end
	end
end
GameEvents.PlayerDoTurn.Add(ResourcesSpawnBuildings);
  1. The Silk or Cotton must be improved with a Plantation before the game will count them in the number of available resources and you must have the Calendar tech in the case of Silk and Cotton resources.
  2. The city and the capital must be connected and you must have the Wheel tech in the case of road-connections or the cities must be connected by a network of roads+harbors, and you must also have the Compass (?) tech that enables Harbors and "sea connections" between cities
  3. The capital will always be considered as being connected to itself, but you must still have the correct improvements and the correct tech that allows the improvements (Calendar in the case of Plantations for Silk and Cotton).
  4. If, for example, you use IGE to give yourself a road-connection between a city and the capital, but do not also give yourself the Wheel tech, only the capital would get the buildings. I tested this exact scenario.
 
I'll be damned if I know what I did wrong last time I tested it, but now your code works:

Code:
iResourceSilk = GameInfoTypes["RESOURCE_SILK"]
iSilkBuildings = GameInfoTypes["BUILDING_LIBRARY"]
iResourceCotton = GameInfoTypes["RESOURCE_COTTON"]
iCottonBuildings = GameInfoTypes["BUILDING_GRANARY"]

function ResourcesSpawnBuildings(playerID)
	local player = Players[playerID];
	local iNumberSilkBuildings, iNumberCottonBuildings = 0, 0
	if player:GetNumResourceAvailable(iResourceSilk, true) > 0 then
		iNumberSilkBuildings = 1
	end
	if player:GetNumResourceAvailable(iResourceCotton, true) > 0 then
		iNumberCottonBuildings = 1
	end
	for pCity in player:Cities() do
		if player:IsCapitalConnectedToCity(pCity) then
			pCity:SetNumRealBuilding(iSilkBuildings, iNumberSilkBuildings)
			pCity:SetNumRealBuilding(iCottonBuildings, iNumberCottonBuildings)
		else
			pCity:SetNumRealBuilding(iSilkBuildings, 0)
			pCity:SetNumRealBuilding(iCottonBuildings, 0)
		end
	end
end
GameEvents.PlayerDoTurn.Add(ResourcesSpawnBuildings);

For the record, this is my testing schedule:
1) The mod is a blank mod (for testing, I use Whoward's "My Changes", quick and easy)
2) The file is properly inserted in the modinfo file, I didn't modified it so this isn't the issue
3) I use Notebook++
4) I delete any other previous function.
5) It has a feature (as you probably know) that let you know if a "if", "for", or "function" doesn't have a proper "end" statement.
6) If I have to insert database elements, I copy/paste directly from the XML civ files (to avoid typo errors)
7) I let the first turn pass without opening IGE.
8) I use IGE: I give myself the required tech then I place the improvement (and I let 1 turn pass between tech discovery and improvement placement).
9) I disconnect and re-connect resources to see if it works properly.

Of course I'm human so a mistake can happen but this time I really was sure to have done everthing correctly.

Anyway, sorry, my mistake. :blush:

Confirmed instead that Bobert13 codes have no effect and throw the already mentioned generic error:

Runtime Error: Error loading C:\Users\Windows 7\Desktop\Documents\My Games\Sid Meier's Civilization 5\MODS\My - Changes (v 1)\LUA/MyLuaChanges.lua.

Code:
local iResourceSilk = GameInfoTypes["RESOURCE_SILK"]
local iSilkBuildings = GameInfoTypes["BUILDING_LIBRARY"]
local iResourceCotton = GameInfoTypes["RESOURCE_COTTON"]
local iCottonBuildings = GameInfoTypes["BUILDING_GRANARY"]

--local ResourcesSpawnBuildings = function(playerID) -- this is equivalent to the line below. The latter is syntactic sugar.
local function ResourcesSpawnBuildings(playerID)
	local player = Players[playerID];
	local iNumberSilkBuildings, iNumberCottonBuildings = 0, 0
	if player:GetNumResourceAvailable(iResourceSilk, true) > 0 then
		iNumberSilkBuildings = 1
	end
	if player:GetNumResourceAvailable(iResourceCotton, true) > 0 then
		iNumberCottonBuildings = 1
	end
	for pCity in player:Cities() do
		if player:IsCapitalConnectedToCity(pCity) then
			pCity:SetNumRealBuilding(iSilkBuildings, iNumberSilkBuildings)
			pCity:SetNumRealBuilding(iCottonBuildings, iNumberCottonBuildings)
		else
			pCity:SetNumRealBuilding(iSilkBuildings, 0)
			pCity:SetNumRealBuilding(iCottonBuildings, 0)
		end
	end
end


Code:
local iResourceSilk = GameInfoTypes["RESOURCE_SILK"]
local iSilkBuildings = GameInfoTypes["BUILDING_LIBRARY"]
local iResourceCotton = GameInfoTypes["RESOURCE_COTTON"]
local iCottonBuildings = GameInfoTypes["BUILDING_GRANARY"]

local myGetNumResourceAvailable(me, resource, bool) = me:GetNumResourceAvailable(resource, bool)
local mySetNumRealBuilding(city, building, val) = city:SetNumRealBuilding(building, val)
local myCities(me) = me:Cities()
local myIsCapitalConnectedToCity(me, city) = me:IsCapitalConnectedToCity(city)


--local ResourcesSpawnBuildings = function(playerID) -- this is equivalent to the line below. The latter is syntactic sugar.
local function ResourcesSpawnBuildings(playerID)
	local player = Players[playerID];
	local iNumberSilkBuildings, iNumberCottonBuildings = 0, 0
	if myGetNumResourceAvailable(player, iResourceSilk, true) > 0 then
		iNumberSilkBuildings = 1
	end
	if myGetNumResourceAvailable(player, iResourceCotton, true) > 0 then
		iNumberCottonBuildings = 1
	end
	for pCity in myCities(player) do
		if myIsCapitalConnectedToCity(player, pCity) then
			mySetNumRealBuilding(pCity, iSilkBuildings, iNumberSilkBuildings)
			mySetNumRealBuilding(pCity, iCottonBuildings, iNumberCottonBuildings)
		else
			mySetNumRealBuilding(pCity, iSilkBuildings, 0)
			mySetNumRealBuilding(pCity, iCottonBuildings, 0)
		end
	end
end

tested also the vartiant with

Code:
local myGetNumResourceAvailable = #player_object#.GetNumResourceAvailable(me, resource, bool)

replacing "#player_object#" with "Player"
 
For the record:

I tested the code also with traded resources. It works as intended, same as owned resources.
 
The reason Bobert's code is not doing anything is that the code as you are showing it is missing a GameEvent activation such as the final line of my version has. Anyway, I can't see one. Not sure why his code is giving the refusal to load error, though. I may try his version later this afternoon or evening to see what I get in my quick-lua-test mod I use for this sort of thing.
 
Back
Top Bottom