Machiavelli24
Mod creator
- Joined
- May 9, 2012
- Messages
- 818
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.
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.
-------------------
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.
-------------------
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:
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.
-----------------------
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]);
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
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
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
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.