/Learning Lua/ Civ5 API

bane_

Howardianism High-Priest
Joined
Nov 27, 2013
Messages
1,559
Ok, I'm trying to figure out how to make my own codes, I'm doing ok so far, I can read and understand most codes most of the time, but actually starting one from scratch is way harder.

I have no idea how to actually now what these different API do, other than guessing and testing... but how would I test? I don't have any idea what should be put in the code.

Could some one explain me the difference between these, please?

City.ChangeBaseGreatPeopleRate (Civ5 API)
City.ChangeGreatPeopleProgress (Civ5 API)
City.ChangeGreatPeopleUnitProgress (Civ5 API)
City.GetBaseGreatPeopleRate (Civ5 API)
City.GetGreatPeopleRate (Civ5 API)
City.SetGreatPeopleUnitProgress (Civ5 API)
Player.ChangeNumFreeGreatPeople (Civ5 API)
Player.SetNumFreeGreatPeople (Civ5 API)


My goal is to increase the generation rate of some specific GP in all cities across the Empire. All of the above have one or other thing that seem to relate to that, hence my confusion.
 
Your best source of information are the .lua files that are included in the game/dlcs. Get yourself a good search tool that will enable you to search for API methods in all the files at the same time.

The ultimate answer to "what does this API method do" is to look at the C++ source code.
 
The C++ game source can be found in:
C:\Program Files\Steam\steamapps\common\Sid Meier's Civilization V SDK\CvGameCoreSource

Of course, you'll need some knowledge of C++ to have any idea of what in the world the code is saying...
 
I'm doing something similar in my own mod; wherein I use different methods to generic GPPs for the titular Sovereign units of my Sovereignty Revised mod, so I can provide some basic info.

City.ChangeBaseGreatPeopleRate (Civ5 API) -- this simply changes the rate of all Great People generation in a city; akin to the effect of the Leaning Tower wonder.
City.GetBaseGreatPeopleRate (Civ5 API) -- this will, I presume, retrieve the rate at which Great People are generated in a city, precluding any modifications done by Wonders, Policies, etc.
City.GetGreatPeopleRate (Civ5 API) -- this will, I presume, retrieve the rate at which Great People are generated in a city, including any modifications done by Wonders, Policies, etc.

City.ChangeGreatPeopleProgress (Civ5 API) -- this and
City.SetGreatPeopleUnitProgress (Civ5 API) -- this and
City.ChangeGreatPeopleUnitProgress (Civ5 API) -- this have not worked for some, so I can't say assuredly it's specific purpose, if any.

Player.SetNumFreeGreatPeople (Civ5 API) -- this will give the player a free Great Person to choose; just like with the Leaning Tower. Unlike the below, however, it will override any other free Great People that you have to choose on that turn (so say you call this on the same turn the player builds the Leaning Tower; you would only receive 1 free Great Person in this case).
Player.ChangeNumFreeGreatPeople (Civ5 API) -- this will give the player a free Great Person to choose; just like with the Leaning Tower. Unlike the above, however, it should be additive to any existing free Great People you get at the same time (so say you call this on the same turn the player builds the Leaning Tower; you would receive 2 free Great People in this case).

You'd probably also be interested in this:

City:ChangeSpecialistGreatPersonProgressTimes100(SpecialistTypes, iChange) -- this is what I use to add Great People points just as a wonder does. Here is an example of how I've used it. I've added some comments to it for your benefit:

Code:
function GreatPresidentPoints(playerID)
[COLOR="Red"]--this function is called every turn, but only progresses if the following conditions are met: the player is Alive, the player is not a City-State or Barbarian, and the player has adopted the Republic policy branch.[/COLOR]
	local player = Players[playerID]
	if (player:IsEverAlive()) then
		if (not player:IsMinorCiv() and not player:IsBarbarian()) then
			if (player:HasPolicy(GameInfoTypes["POLICY_LIBERTY"]) and not player:IsPolicyBlocked(GameInfoTypes["POLICY_LIBERTY"])) then
			local capital = player:GetCapitalCity() [COLOR="Red"]-- find the player's capital city[/COLOR]
			local greatPresidentPoints [COLOR="Red"]-- store the value of the end rate of great president points as a local variable; because there are other factors involved in determining what this value is, the variable is left empty for now.[/COLOR]
				if (player:HasPolicy(GameInfoTypes["POLICY_CITIZENSHIP"]) and not player:IsPolicyBlocked(GameInfoTypes["POLICY_CITIZENSHIP"])) then
					local numPopulation = math.floor(player:GetTotalPopulation() / 2) [COLOR="Red"]-- get the player's total population and divide that by 2.[/COLOR]
					greatPresidentPoints = math.floor((1 + numPopulation) * 100) [COLOR="Red"]-- fill the variable we made earlier with the following calculation: the default rate of Great President points (which, for the sake of explanation, is 1) plus the population amount as defined above, and times that by 100 (because that is what ChangeSpecialistGreatPersonProgressTimes100 requires). We'll use this variable to tell our function below how many Great President points a player should be receiving per turn.[/COLOR]
					capital:ChangeSpecialistGreatPersonProgressTimes100(GameInfoTypes["SPECIALIST_SR_PRESIDENT"], greatPresidentPoints)
				elseif (player:HasPolicy(GameInfoTypes["POLICY_REPRESENTATION"]) and not player:IsPolicyBlocked(GameInfoTypes["POLICY_REPRESENTATION"])) then
					local numCities = player:GetNumCities() [COLOR="Red"]-- get the player's total number of cities.[/COLOR]
					greatPresidentPoints = math.floor((1 + numCities) * 100)[COLOR="Red"] -- fill the variable we made earlier with the following calculation: the default rate of Great President points, plus the number of cities we found above, and times that by 100. [/COLOR]
					capital:ChangeSpecialistGreatPersonProgressTimes100(GameInfoTypes["SPECIALIST_SR_PRESIDENT"], greatPresidentPoints)
				else
                                [COLOR="Red"]--the player has not chosen a voting system, so stick to the default rate of Great People points.[/COLOR]
					greatPresidentPoints = math.floor(1 * 100)
					capital:ChangeSpecialistGreatPersonProgressTimes100(GameInfoTypes["SPECIALIST_SR_PRESIDENT"], greatPresidentPoints)
				end
			end
		end
	end
end
GameEvents.PlayerDoTurn.Add(GreatPresidentPoints)

It takes time to understand the different functions; the wiki is poorly documented in this regard. But like whoward69 states: the best way to learn is by investigating how functions are currently used. I prefer to search the mods of others - as they are often full of comments about the modder's actions, or generally less daunting. And I would recommend grepWin (http://stefanstools.sourceforge.net/grepWin.html) to search for things.

Hope this helps.
 
Yes it helps a lot!
Thank you very much, specially for the code. :D


EDIT: Just a quick question on Lua coding: What is called and what are for those 'things' after you start a function? There is one on your code (playerID), but take this one as an example:
"function FunctionWhatever(iOldOwner, bIsCapital, iX, iY, iNewOwner, iPop, bConquest)"

Are these something like variables you'll set during the code? Do they serve any purpouse before you set them (if they ARE variables)?
What happens if you put them there, but do not place those 'words' anywhere else in the code, does it works or the code doesn't load?
 
They're called parameters; they're the objects (an object such as a player, a city, a tile, a unit, etc.) that an event already has defined - or something like that. And you use an event to call a Function (or Function to call other Functions, but that's probably not relevant to you at the moment).

What you call these parameters doesn't matter - except for easy reference. You can call iPlayer, for instance, "afdadajbdsdb", but it will always refer to a particular object. In this case, a player object - or one of the civs on the map.

You can tell what the object is by checking the wiki and looking at the events. For instance, GameEvents.CityCaptureComplete(PlayerID player, int capital, ResourceType x, ResourceType y, PlayerID newPlayer, int conquest, int conquest) tells us that the parameter in the first place (named player) is a player object. You'll notice a second playerID further down. Investigating the use of this event in game files can show that this playerID is the player that just conquered the city, but you can probably infer that by what it's called: newPlayer. Capital is a boolean - a true or false check - to see if the captured city was a capital (this sort of thing isn't quite as inferable, but the wiki indicates what it is for if you're every stumped), and x and y are the map co-ordinates of the city.

With this information, you fill the function with these parameters, like so:

Code:
function FunctionWhatever(player, capital, x, y, newPlayer, conquest, conquest)

So we have a playerID for the player that just had their city conquered, a check for if the city was a capital, the x and y co-ordinates of the city, another playerID for the player that just conquered the city, and I'm not certain what the last two parameters are for... You must fill in all parameters, yes, but you don't need to define them all as variables (more on that a bit below). However, the above is functionally the same as what you had - but written in a clearer way*:

Code:
function FunctionWhatever(iOldOwner, bIsCapital, iX, iY, iNewOwner, iPop, bConquest)

Then you just tell the event to fire this function whenever the event occurs:

Code:
GameEvents.CityCaptureComplete.Add(FunctionWhatever)

With regard to variables, you'll use these to define objects and you'll always want to define any parameters that you're going to use as a variable. If you're not going to use it, though, you don't need to define it - such as the conquest parameter above. This is useful as you might need specific objects that aren't already defined. For instance, you might want to find out how much gold a player currently has. You would do this by defining a variable for the player object (there's almost always a player object parameter in an event), like so:

Code:
local player = Players[playerID] [COLOR="Red"]-- playerID is the name of the parameter, and it is contained within the player index ([B]Players[][/B]); although I don't understand this part well enough to explain further. Nonetheless, you'll need to do this, as many methods of retrieving other data will not work with just ID of the player.[/COLOR]

With that, you may define another variable in order to find the amount of gold the player has:

Code:
local playerGold = player:GetGold() [COLOR="Red"]-- player is the variable we've just defined, and GetGold() is a method (a function that belongs to a specific object, such as the player object).[/COLOR]

Of course, you don't necessarily need to define playerGold if that's all you're looking for, but if you intend to use that data in a more complex method (such as player:ChangeGold(playerGold), which would double the amount of gold a player has, as it would add to a player's current treasury what we defined as playerGold), it's best to localise it for performance reasons and praticality.

Hopefully I've explained it clearly enough; and hopefully I'm not too off the mark when it comes to what I've explained. It's taken a long time for me to wrap my head around a lot of the basic stuff for Lua and for the most part it's through trial and error; so don't let the task of learning to code in it get too daunting - you'll get there with enough perserverance. But it's highly satisfying when something comes to your understanding. So good luck and feel free to leave any more questions behind and I'll try to answer them.

*the letters in front of each parameter is called Hungarian Notification and it is used to indicate what a parameter is. i = an integer, b = a boolean, etc. You can find more info here: http://modiki.civfanatics.com/index.php/Civ5_API_FAQ. But of course it's only used as a label - this is something that confused me a lot before I learnt this
 
Incredible. Your explanation was clear as water.
You should make a post explaining this kind of stuff, this Forum already has a lot of good guides for almost everything, but most of them are directed to people with good grasp of the language. Of course it's just a suggestion.

Thank you very much. :)
 
What you call these parameters doesn't matter - except for easy reference. You can call iPlayer, for instance, "afdadajbdsdb", but it will always refer to a particular object. In this case, a player object - or one of the civs on the map.
I used to love doing that, until I realized now stupidly hard it was to try and copy "afdadajbdsdb" or whatever spelled exactly right. :lol: (That is, when you can't use your friends Copy and Paste)

Also, it makes a lot less sense for anyone trying to debug my code. So that doesn't help either.

You should make a post explaining this kind of stuff, this Forum already has a lot of good guides for almost everything, but most of them are directed to people with good grasp of the language. Of course it's just a suggestion.
Well as long as he's doing that, JFD should also make a complete guide to xml for the n00bs and C++ for the more experienced modders. Even Kael didn't get around to that! ;)
Or at least I don't think he did... :think: Which is why I will now go and check if he did!
 
Back
Top Bottom