Can construct building if you have a resource without consuming it

If you've never done programming before than the difficulty of learning to do Lua modding will depend on how difficult learning the basics of programming is for you. Once you have the basics it becomes much easier to learn more.
-----------------------
I'll break down the EmpireResourceAnds_Check as an example. Since you already know what this code does, you only need to learn how it does it.
Code:
function [COLOR="Sienna"]Building_EmpireReourceAnds_Check[/COLOR]([COLOR="Blue"]playerID, buildingID[/COLOR])
  ...stuff...
end
[COLOR="Purple"]GameEvents.PlayerCanConstruct[/COLOR].Add([COLOR="Sienna"]Building_EmpireReourceAnds_Check[/COLOR]);
Event name: In Civ 95% of the Lua you write will be connected to an event. Most events "fire" at certain times (such as when a city is captured, when a technology is finished). GameEvents.PlayerCanConstruct is the name of the event that this function hooks into. It works slightly differently. It lets mod makers put additional restrictions on when a building can be built (outside of the standard XML/SQL restrictions).

Inputs: In addition to a name, events provide arguments as inputs. These arguments contain information that we may need. The PlayerCanConstruct event provides us with playerID (the player trying to build) and buildingID (the building that player is trying to build).

function name: The line "function Building_EmpireReourceAnds_Check" defines what "Building_EmpireReourceAnds_Check" refers to. The second line is connecting 'Building_EmpireReourceAnds_Check" to the event. It doesn't really matter what the name of the function is (you could even use anonymous functions if you wished but for simplicity ignore anonymous functions for now), it would work the exact same if it was called "heojdkflejin". The reason I picked the name "Building_EmpireReourceAnds_Check" was to help communicate its purpose to people reading the code. Many practices in programming are done not because they are required for the code to function correctly but because they make it easier to read and understand.
-------------------
Code:
function Building_EmpireReourceAnds_Check(playerID, buildingID)
	[COLOR="Purple"]local player = Players[playerID];[/COLOR]
...
			[COLOR="Blue"]return false[/COLOR]; -- Found a required resource 
...
	[COLOR="Blue"]return true[/COLOR];
end
Return values: The way "GameEvents.PlayerCanConstruct" works is that if the connected function returns true, everything can proceed. But if the connected function returns false than the building does not show up on the list of things that can be built. Everything within this function is structured around returning true or false depending on what resources the player has and what the Building_EmpireResources XML table says.

Variables: This line is creating a variable (that is what "local" does) with a name of "player" and a value of "Players[playerID]". In Civ "Players" is something you can put anywhere in your Lua code. It is how you get a "player object" which has a bunch of information on that player. We'll need it here to know what resources the player has.
-------------------
Code:
function Building_EmpireReourceAnds_Check(playerID, buildingID)
	local player = Players[playerID];

	local [COLOR="Sienna"]condition [/COLOR]= "BuildingType = '" .. [COLOR="Blue"]GameInfo.Buildings[buildingID].Type[/COLOR] .. "'";
	[COLOR="Purple"]for row in GameInfo.Building_EmpireResourceAnds[/COLOR]([COLOR="Sienna"]condition[/COLOR]) do
[COLOR="DeepSkyBlue"]		if(player:GetNumResourceAvailable(GameInfoTypes[row.ResourceType], row.AllowsImport) <= 0) then
			return false; -- Found a required resource the player doesn't have
		end[/COLOR]
	end

	return true;
end
Using GameInfo: In Civ you can use "GameInfo" anywhere. This lets you get the contents of the various XML/SQL tables. GameInfo.Buildings means we are looking at the Buildings table. GameInfo.Buildings[0] would get us the 0th row of the table (which is the floating gardens). Once we have a row of a table we can get the values of the columns for that row. For example:
Code:
GameInfo.Buildings[0].Type     would get: BUILDING_FLOATING_GARDENS
GameInfo.Buildings[0].BuildingClass     would get: BUILDINGCLASS_WATERMILL
GameInfo.Buildings[0].Cost     would get: 75
In this case we're getting the "Type" of whatever building the player is trying to build, so if the player was trying to build a forge it would give us: "BUILDING_FORGE".

Iterating over a table: This is the line where most of the work happens. "GameInfo.Building_EmpireResourceAnds" means we are looking at the new XML table that was created. "for row in" means that everything this color will happen multiple times (once for each row). "row" in this case is just a variable name. It could be something else. But "for" and "in" are not.

The condition: If the player was trying to build a forge than this would come out as a string that read: "BuildingType = BUILDING_FORGE". This plus the for loop is similar to the following SQL:
SELECT * FROM Building_EmpireResourceAnds WHERE BuildingType = BUILDING_FORGE;

The condition is a WHERE clause that limits what rows in the Building_EmpireResourceAnds table we see. Specifically it limits the rows to those that match the building the player is trying to build.

The last chunk is the if statement.
 
Good luck! :)

Thank You bane_ for your advices, you're very kind.
I noticed that some modders make comments on their lua files using "--" (used also in SQL with the same purpose) and as soon I have more time I'll surely check the LUA website (although the benefit here is that I can make questions :) ).

I'll surely try to learn everything I can, I'm really enjoying Modding.
Thanks again!
 
For Machiavelli:

Thank you very much, you're very kind, this is far more clear!

I've some questions:

1: .. GameInfo.Table[ID].Column .. is always surrounded by ".. .."?

2: about: local condition = "BuildingType = '" .. GameInfo.Buildings[buildingID].Type .. "'";
So, as general rule, when stating a condition, we first write nameofthetable-column (buildingType) specifing if we are referring to all or a specific one (= '" or = BUILDING_FORGE").
Than we write "GameInfo.Table[ID].Column"
(in this case [buildingID] means all building IDs) in order to specify in which part of the database the data are.
Am I correct ?

3: The event "GameEvents.PlayerCanConstruct" has only those two inputs ? can you choose which imput write or you have to write them all?

4: Where I can find a list of all events and their respective inputs ?

5: The inputs of an event must always be written after the name of the function?

6: You said that "row" could be something else: like "column" for example? I don't think you mean "dfbklsadf"

7: as general rule, when ending the line with " ; " ?
 
7: as general rule, when ending the line with " ; " ?
You want to put ; at the end of statements. In LUA they are optional but in other languages they are not.
--------------------
Questions related to arguments (aka inputs):
4: Where I can find a list of all events and their respective inputs ?
The general Lua reference. More specifically, the GameEvents reference. (Note: things that are listed in the "Event"/"SerialEvents" page (which I did not link to) are generally tied to UI and animation related activity are by default should not be used for game play behaviors).

5: The inputs of an event must always be written after the name of the function?
Those are arguments and their value is provided by the event. "playerID" is just the name of the argument, it could be called "ubnkejo" and everything would work the same.

3: The event "GameEvents.PlayerCanConstruct" has only those two inputs ? can you choose which imput write or you have to write them all?
If you don't provide a variable name when declaring the function (functions are declared with the "function funcName(Arguments)" line) you won't be able to access the value that the event provides.
-----------------------
Questions related to the for loop:
Code:
	local condition = "BuildingType = '" .. GameInfo.Buildings[buildingID].Type .. "'";
	for row in GameInfo.Building_EmpireResourceAnds(condition) do
		if(player:GetNumResourceAvailable(GameInfoTypes[row.ResourceType], row.AllowsImport) <= 0) then
			return false; -- Found a required resource the player doesn't have
		end
	end

1: .. GameInfo.Table[ID].Column .. is always surrounded by ".. .."?
In general no. What is happening on the line that starts with "local condition = ..." is that a variable (called "condition" but it could also be called "xxx") is being assigned a value. That value is a string that will be used by the for loop to form the "WHERE clause" of the SQL statement. The (..) are string concatenation (appending one string to another string).

If that is unclear, focus on the for loop first.
Code:
For row in GameInfo.Buildings_EmpireResourcesAnds() do
  if(row.BuildingType = "BUILDING_MARKET") then
    ...do stuff...
  end
end
Is the same as:
Code:
For row in GameInfo.Buildings_EmpireResourcesAnds("BuildingType = 'BUILDING_MARKET'") do
  ...do stuff...
end
In the first example, we look at every row in the table, but only do stuff if the if-statement is true. In the second example, the optional WHERE clause provided between the parenthesis will ensure we only look at the Market rows of the table. But we do stuff for every Market row.

6: You said that "row" could be something else: like "column" for example? I don't think you mean "dfbklsadf"
Code:
For xxx in GameInfo.Table() do
  xxx.Column
end
Is the same as:
Code:
For row in GameInfo.Table() do
  row.Column
end
 
Thank you for your efforts, I really appreciated it. I will make good use of it.
Keep up the good work!
 
Back
Top Bottom