Building requires gold code?

Damirith

Prince
Joined
Mar 11, 2015
Messages
379
I was wondering if there is a code in order to reduce the player's gold in any way?

I want to make a building that costs you 300 gold on completion as an "investment" since its going to give you a boost to gold later on.

I tried putting in <Gold>-300</Gold> but that didn't seem to do anything.

I dont want Gold Maintenance, just a one time payment.
 
I think you will have to do it via lua as a GameEvents.CityConstructed.Add(YourFunctionName)

It could possibly be done as a subtraction when you add the building to a city build qeue, but that is a bit more difficult (ie, I am not exactly sure how I would go about doing it that would both work and not be a code-nightmare) because you not only need to detect in that case when the building is placed in the city qeue but also if it is removed for some reason, and then a player's gold would have to be updated in both cases.
 
Again, pretty new to modding. There isn't someway I could use the pillage mechanic to subtract the gold?

Hmm I think I might have hit a wall I then, looking at changing the LUA seems to be a bit above my head. Even if I could figure out how to do it, doesn't changing the LUA mean that the building would really only work for me since give it to others wouldn't be as simple as all the other mods that just gives you new xml code to dump into the MODS folder?
 
Again, pretty new to modding. There isn't someway I could use the pillage mechanic to subtract the gold?

Hmm I think I might have hit a wall I then, looking at changing the LUA seems to be a bit above my head. Even if I could figure out how to do it, doesn't changing the LUA mean that the building would really only work for me since give it to others wouldn't be as simple as all the other mods that just gives you new xml code to dump into the MODS folder?
New lua 'programs' are added as part of mods all the time, so there is no constraint there. It is really just the problem of learning to work in the lua language when XML or SQL changes can't accomplish what you are looking for.
 
Anyone know if a newbs guide to working with ModsBuddy to make a LUA with a game event?

I seem to be finding ones that already assume you know the basics of LUA or are only on the topics of making new Civs or messing with the user interface.
 
Ok so I am new to Civ 5 modding and while I am getting a handle on using ModBuddy to make some wonders, working with LUA is a bit over my head. I do have little experience with C++ but that was back in high school.

I want to make a wonder that ends up costing the player 300 gold when its completed as an "investment" since its going to give you a nice bonus in the end. I know about gold maintenance, but I dont want gold lost each turn I just want a one time "payment" when the wonder is built. I have been told that there is no XML for this and that I would have to write a LUA to get this to work that uses the function " GameEvents.CityConstructed.Add(YourFunctionName). "

I am trying to read some guides but I am still lost since I dont know all the Civ5 functions, let alone which ones I should be using to check the player's current gold (making sure they have 300 gold or more and if not stopping them at "99.9% production" until they can afford it), check for if the wonder was built, then reduce the player's gold by 300. I pretty much learn best by cookie cutting, that is by seeing examples of similar code that works and working off of that. Once I have the understanding of each of the functions, then I can go off on my own but for now I am stuck in the mud.

Are there any examples I could pull from Civ 5 to help copy/guide me to write this LUA and if so where would I find the files? Anyone bored enough to write a template for me :D?

Any help would be appreciated.
 
There are two parts to what you are trying to do:

1) When a specific wonder is built, deduct 300 gold from the player who built it.
2) Don't let players with less than 300 gold build the wonder.

Around the time Beyond Earth came out I believe they released an update to Civ 5 that included support for an event that fired when a building finished. CityConstructed may be it but I don't remember off hand. You'll have to get the owning player object then use the "player:ChangeGold(-300);"

As for part 2, that can be achieved with a PlayerCanConstruct check. PlayerCanConstruct lets you put additional restrictions on when buildings are legal to be built. If any function you add to PlayerCanConstruct returns false than the building is blocked (it won't even show up on the UI). And if the player has started building it they are forced to change their production (but it still remembers the amount of production they have spent toward it).
 
So I wrote a LUA scrip. Not sure it works, however how do I get it to load with the mod?

Do I just need to import it into VFS?

Do I add it through Content? If so it only comes up if I select MapScript which I dont think is what I want.

bane_'s guide doesn't say anything on it nor does Kael's Modders Guide to Civ 5.
 
Ok so either 1 of 2 things isnt working or both...

1) When I go to Content and select InGameUIAddin, the lua doesn't come up under the File drop down arrow. However, it seems I can work around this by just selecting the File first, then going up to Type and selecting InGameUIAddin. Is that a sign that something is wrong?

2) I found a script that supposedly works and adds 10 people to your city when you have built a wonder. So I tired it with my Fort Knox just to see if I can get a LUA to work but nothing happened. Does this script work?

Code:
fmBoolean = true;

for i, player in pairs(Players) do
	if player:GetBuildingClassCount(GameInfoTypes.BUILDINGCLASS_FORT_KNOX) then
		fmBoolean = false;
	end
end

GameEvents.PlayerDoTurn.Add(function(iPlayer)
	if fmBoolean then
		if Players[iPlayer]:GetBuildingClassCount(GameInfoTypes.BUILDINGCLASS_FORT_KNOX) then
			fmBoolean = false;
			for iCity in Players[iPlayer]:Cities() do
				if iCity:GetNumBuilding(GameInfoTypes.BUILDING_FORT_KNOX) then
					iCity:ChangePopulation(10);
				end
			end
		end
	end
end)
Edit: I dont know why the forum is showing a space between the N and G in the first instance of " (GameInfoTypes.BUILDINGCLASS_FORT_KNOX)" or between the K and N in " (GameInfoTypes.BUILDING_FORT_KNOX) " those spaces are not in the actual script.

Edit2: Added code blocks :)
 
Would this part work so far for just checking to see if a person has built the wonder?

Code:
fmBoolean = true;

for i, player in pairs(Players) do
	if player:GetBuildingClassCount(GameInfoTypes.BUILDINGCLASS_THEWONDER) then
		fmBoolean = false;
	end
end

GameEvents.PlayerDoTurn.Add(function(iPlayer)
	if fmBoolean then
		if Players[iPlayer]:GetBuildingClassCount(GameInfoTypes.BUILDINGCLASS_THEWONDER) then
			fmBoolean = false;

-- code here to pull up players gold---

(I was trying to see if I can use the code LastSword posted here: http://forums.civfanatics.com/showthread.php?t=515252 )

Edit: Added the Code blocks :)
-------

For the gold part, would I need to use Player:GetGold() like " if Player:GetGold(>=300) do player:ChangeGold(-300) " ?

I know I am talking out of my ass atm, again I can only work off of working scripts to learn this stuff
 
Ugh.
Please, please, please, please wrap your code inside CODE blocks.

You really don't need to be talking out of your ass. Refer to the Modiki for a list of Lua methods you can use. It's slighty outdated, since it doesn't include anything new to BNW, but it's a start, and contains most of the stuff you will use.

Since you need to find information about a Player, you will refer to the Player Object Methods on the Modiki. Checking through that list will reveal to you that Player:GetGold() is a valid Player method although the way you're trying to use it is not quite correct.

It seems as if you don't quite understand the code you are copying in an attempt to use.

That code is largely separated into two main blocks, each doing a different thing.

Code:
fmBoolean = true;

for i, player in pairs(Players) do
	if player:GetBuildingClassCount(GameInfoTypes.BUILDINGCLASS_THEWONDER) then
		fmBoolean = false;
	end
end

This first section is not wrapped inside any function, and so it means it will run once when the script is loaded. Its purpose is to first set a boolean value that a later function will refer to. To do so, it loops through the Players table, which contains all the data of all the Players in the game, in order to figure out if anyone has a value returned for GetBuildingClassCount().

The way the condition is written, it doesn't care what the value is, only that it has a value other than false or nil. The problem is I'm not entirely sure if it returns 0 or not if the building doesn't exist; I have yet to test this method.

In any case, if any value is found, it is assumed that the Wonder has been constructed, and it toggles the boolean.

There are two issues I see with this:
  1. This loop does not check for the Player actually being in the game, so it will loop over all of the nonexistent players as well, needlessly expending CPU cycles.
  2. This appears to have been potentially written before the last BNW patch which gave us the CityConstructed Game Event, which can fire when the Wonder is built to toggle the boolean then. The only downside to this approach is that you need to persist the boolean across game saves, whereas the above method doesn't rely on it since it manually scans every time.

In any case, the next section does the legwork.

It is a function attached to the Game Event called PlayerDoTurn which fires at the start of every Player's turn, right before they gain control. This code adds a new user function into that part of the game code, allowing the game to run this additional logic while it processes its own stuff at that point.

This Game Event provides one value: the Player ID of whoever player's turn it is processing at that moment. This is captured in the custom function via the variable iPlayer. The function then begins its logic by checking the global boolean that was set beforehand, and if that boolean is true (or rather, any value besides nil or false) then it runs another check to see if the current player owns the Wonder.

If it passes, then it toggles the boolean to prevent this function from firing again. After that, you can insert your Gold modifying code. To that point, Player:GetGold() by itself returns a number. Placing something inside those parentheses means you are trying to pass into that method an argument, which I'm not sure if anything will happen since I don't think it expects any. To do a comparison, you have to compare against the returned value:

Code:
Player:GetGold() >= 300

Considering the nature of this function though, I'd imagine you could theoretically save a bit more on computing time by removing the function from the event hook altogether, but I don't believe you can do that as it's currently written, since it's an anonymous function.
 
Ok so either 1 of 2 things isnt working or both...

1) When I go to Content and select InGameUIAddin, the lua doesn't come up under the File drop down arrow. However, it seems I can work around this by just selecting the File first, then going up to Type and selecting InGameUIAddin. Is that a sign that something is wrong?
As shown in whoward's tutorial, this is the method to follow. What you are seeing is normal ModBuddy behavior.
2) I found a script that supposedly works and adds 10 people to your city when you have built a wonder. So I tired it with my Fort Knox just to see if I can get a LUA to work but nothing happened. Does this script work?

Code:
fmBoolean = true;

for i, player in pairs(Players) do
	if player:GetBuildingClassCount(GameInfoTypes.BUILDINGCLASS_FORT_KNOX) then
		fmBoolean = false;
	end
end

GameEvents.PlayerDoTurn.Add(function(iPlayer)
	if fmBoolean then
		if Players[iPlayer]:GetBuildingClassCount(GameInfoTypes.BUILDINGCLASS_FORT_KNOX) then
			fmBoolean = false;
			for iCity in Players[iPlayer]:Cities() do
				if iCity:GetNumBuilding(GameInfoTypes.BUILDING_FORT_KNOX) then
					iCity:ChangePopulation(10);
				end
			end
		end
	end
end)
It looks to me like that code came from before the most-recent game-patch. Methods for detecting wonders having been built were a PITA. Since the latest patch it is much easier because we now have a direct 'game event' for whenever any building is constructed, and we can therefore sort for whether that just-constructed-building is the wonder we are interested in.

Here is a bit of code I am using for when a player completes my Leonardo's workshop Wonder:
Code:
gLeonardoDummy = GameInfoTypes.BUILDING_LEONARDO_DUMMY
gLeonardoBuilding = GameInfoTypes.BUILDING_LEONOARDOS_WORKSHOP

function LeonardoCompleted(ownerId, cityId, buildingType, bGold, bFaithOrCulture)
	if buildingType ~= gLeonardoBuilding then return end
	local pPlayer = Players[ownerId]

	[color="blue"]LeonardoUpgradeUnits(ownerId, pPlayer, iNumUnitsToUpgrade)[/color]

	[color="green"]local pCity = pPlayer:GetCityByID(cityId);
	pCity:SetNumRealBuilding(gLeonardoDummy, 1)[/color]
end
GameEvents.CityConstructed.Add(LeonardoCompleted)
It runs a sub-function (the blue line) that looks to find upgradable units and upgrades for free a preset number of units.
It also adds a dummy building in the city where the wonder was constructed (the green lines).


Edit: I dont know why the forum is showing a space between the N and G in the first instance of " (GameInfoTypes.BUILDINGCLASS_FORT_KNOX)" or between the K and N in " (GameInfoTypes.BUILDING_FORT_KNOX) " those spaces are not in the actual script
The forum just does that. Don't worry aobut it. But if you use
Code:
 blocks around game-code, the forum will not do that. Hint: make like you are doing a direct "quote" of this post for a message-reply and then look at the formatting codes that are present in this post. In the advanced view of forum posting, you can use the '#' sign to wrap a selection of text with [code] blocks.
 
Ok, can you further explain your code to me? Again, I am only going to learn this by stealing someone else's and making it fit what I need :D

If I understand how you are using this code am I right in saying that you are
1) telling the function that the variable gLeonardoBuilding is equal to GameInfoTpyes.BUILDING_LEONARDOS_WORKSHOP
2) that GameInfoTypes is used like a switch? If the building doesn't exist then GameInfoTypes. BUILDING_LEONARDOS_WORKSHOP isn't "true", but when it is built it then becomes "true" which then
3) allows the part " if buildingType ~= gLenardoBuilding then return end " to be true and
4) then assigns the owner with " local pPlayer =Players[ownerId] "

Or am I getting this wrong?

Is your code GameInfoTpyes.BUILDING_LEONARDOS_WORKSHOP called that because it needs to point to the buildingclass back in the XML such as
Code:
 	<BuildingClasses>
		<Row>
			<Type>BUILDINGCLASS_LEONARDOS_WORKSHOP</Type>
			<DefaultBuilding>BUILDING_LEONARDOS_WORKSHOP</DefaultBuilding>
			<Description>TXT_KEY_BUILDING_LEONARDOS_WORKSHOP</Description>
			<MaxGlobalInstances>1</MaxGlobalInstances>
		</Row>
	</BuildingClasses>

Also what is the point of adding a dummy building to the city?

The code very end with " GameEvents.CityConstructed.Add(LeonardoCompleted) " works by taking the whole function you wrote and sticking it in as a event trigger?
 
You don't need to check each turn to see if the wonder exists if you have an event that fires when the wonder is built.
 
The following (untested) code is what you want.

This section makes is so that the player who completes the "goldHall" wonder loses 300 gold.
Code:
function GoldHallBuilt(playerId, cityId, buildingType, bGold, bFaithOrCulture)
	local player = Players[playerId];

	if(buildingType == GameInfoTypes["BUILDING_GOLDHALL"]) then
		player:ChangeGold(-300);
	end
end
GameEvents.CityConstructed.Add(GoldHallBuilt);

This section makes it so players with less than 300 gold can not contribute production toward the GoldHall wonder.
Code:
function GoldHallRestriction(playerID, buildingTypeID)
	local player = Players[playerID];

	-- If this isn't the wonder, allow it
	if(buildingTypeID~= GameInfoTypes["BUILDING_GOLDHALL"]) then
		return true;
	end
	
	if(player:GetGold() >= 300) then
		return true;
	else
		return false;
	end
end
GameEvents.PlayerCanConstruct.Add(GoldHallRestriction);
edit: Changed the restriction code a bit. It had the wrong arguments before.
 
Machiavelli24 - Thanks for the code, I will test it out soon and get back to you on it :)

Rob (R8XFT) - Sorry about that, thought my problem was with XML code and then it moved into LUA so I made the 2nd post
 
Hey Machiavelli24, so I copied your code into the LUA and replaced BUILDING_GOLDHALL with BUILDING_FORT_KNOX, along with a few other name changes. The subtracting the gold part seems to work fine, however when I dump all of my gold into other buildings to put me under 300 gold, I can still build the wonder.

Does the GameIntoTypes need to be pointing to " BUILDING_FORT_KNOX " or the class " BUILDINGCLASS_FORT_KNOX " ?

Here is the whole LUA I made with your temple, am I doing something wrong?

Code:
function FortKnoxBuilt(playerId, cityId, buildingType, bGold, bFaithOrCulture)
	local player = Players[playerId];

	if(buildingType == GameInfoTypes["BUILDING_FORT_KNOX"]) then
		player:ChangeGold(-300);
	end
end
GameEvents.CityConstructed.Add(FortKnoxBuilt);

function FortKnoxRestriction(playerId, cityId, buildingType, bGold, bFaithOrCulture)
	local player = Players[playerId];

	-- If this isn't the wonder, allow it
	if(buildingType ~= GameInfoTypes["BUILDING_FORT_KNOX"]) then
		return true;
	end
	
	if(player:GetGold() >= 300) then
		return true;
	else
		return false;
	end
end
GameEvents.PlayerCanConstruct.Add(FortKnoxRestriction);
 
Back
Top Bottom