Some assistance with Civilization Traits in Lua

In this section you have the highlighted line stated twice:
Code:
    [color="blue"]local attPlayer	= Players[attPlayerID];[/color]
	local defPlayer	= Players[defPlayerID];
	local defUnit	= defPlayer:GetUnitByID(defUnitID);
   [color="blue"] local attPlayer	= Players[attPlayerID];[/color]
This does not actually hurt anything but you don't need the second one, so just change it to read:
Code:
	local attPlayer	= Players[attPlayerID];
	local defPlayer	= Players[defPlayerID];
	local defUnit	= defPlayer:GetUnitByID(defUnitID);
	if attPlayer:GetCivilizationType() ~= GameInfoTypes.CIVILIZATION_AMERICA then return end
This should work to only make America get the benefit because everything else is written to only apply the Great Writer Points bonus to "attPlayer".
 
Thanks for catching that. I wouldn't have since it was pretty much a copy/paste on my part. Works flawlessly now. Thanks!
 
Way back when I posted about a problem where I was having issues with a Worker's animations due to redefining actions for it for a particular Civ.

Example:
Code:
	<BuildFeatures>
		<Row>
			<BuildType>BUILD_AMERICA_FARM</BuildType>
			<FeatureType>FEATURE_JUNGLE</FeatureType>
			<PrereqTech>TECH_BRONZE_WORKING</PrereqTech>
			<Time>700</Time>
			<Production>20</Production>
			<Remove>true</Remove>
		</Row>
		<Row>
			<BuildType>BUILD_AMERICA_FARM</BuildType>
			<FeatureType>FEATURE_FOREST</FeatureType>
			<PrereqTech>TECH_MINING</PrereqTech>
			<Time>400</Time>
			<Production>60</Production>
			<Remove>true</Remove>
		</Row>
	</BuildFeatures>
This was to enable said Civ to receive extra Production when clearing Forests and to receive Production when clearing Jungles. My question is: Is there a way to program this effect in Lua so that only a particular Civ would receive increased Production yields when clearing Forests and Jungles? And could it be set to scale said yields for game speed?

Although I pretty much have the desired effect programmed in XML, I'd think having it in Lua would reduce the mod's size a nice chunk, fix the Worker animation errors, and improve the overall presentation.
 
without the whole mod to look at in its current state it is impossible to say, but I've never had any problem with odd animations (or anything for that matter) with adding a custom improvement for a civ. But that having been said, the game does not seem to like to have you try to replace a 'standard' improvement such as the Farm with a custom version of one. I remember various people have run into difficulties doing so. There was also at one time some real bugginess with the farm especially where it was a 'touch it and watch your mod die' sort of a deal :)
 
I recently implemented the code found in this thread: http://forums.civfanatics.com/showthread.php?t=535701 So that I could force one of my unique Civilizations to adopt an Ideology immediately when they enter into the Industrial Era. It does work, but I keep running into an anomaly, which may cause other civilizations to benefit from it as well (such as when I tested it while playing a team game).

I get this error in the .lua log when testing it:
Code:
[10449.929] Runtime Error: C:\...\Sid Meier's Civilization 5\MODS\Harkodos' The Equalists (BNW)\Lua/Amon_Buildings.lua:19: attempt to index local 'pCapitalCity' (a nil value)

Here's the actual code I have for reference:
Code:
-- Amon_Buildings
-- Author: Lee
-- Edited by: Harkodos
--------------------------------------------------------------
gBuildingEarlyIdeology = GameInfoTypes.BUILDING_AMERICA_IDEOLOGY_DUMMYBUILDING
gRequiredCivilization = GameInfoTypes.CIVILIZATION_AMERICA

--------------------------------------------------------------
-- check for a change in era during PlayerDoTurn
--------------------------------------------------------------
function PlayerEraChanged(iPlayer)
	local pPlayer = Players[iPlayer]
	if not pPlayer:GetCivilizationType() == gRequiredCivilization then return end
	if not pPlayer:IsAlive() then return end
	local iNewPlayerEra = pPlayer:GetCurrentEra()
	--print("The value for player era was " .. tostring(iNewPlayerEra))
	local iNumBuildingEarlyIdeology = 0
	local pCapitalCity = pPlayer:GetCapitalCity()
	if pCapitalCity:IsHasBuilding(gBuildingEarlyIdeology) then
		iNumBuildingEarlyIdeology = pCapitalCity:GetNumRealBuilding(gBuildingEarlyIdeology)
		--print("The number of gBuildingEarlyIdeology buildings was " .. tostring(iNumBuildingEarlyIdeology))
	end
	if iNewPlayerEra > iNumBuildingEarlyIdeology then
		--print("The era value was found to be greater than the number of Early Ideology buildings")
		pCapitalCity:SetNumRealBuilding(gBuildingEarlyIdeology, iNewPlayerEra)
		--print("The number of gBuildingEarlyIdeology buildings was changed from " .. tostring(iNumBuildingEarlyIdeology) .. " to " .. tostring(iNewPlayerEra))
	end
end
GameEvents.PlayerDoTurn.Add(PlayerEraChanged);
 
I recently implemented the code found in this thread: http://forums.civfanatics.com/showthread.php?t=535701 So that I could force one of my unique Civilizations to adopt an Ideology immediately when they enter into the Industrial Era. It does work, but I keep running into an anomaly, which may cause other civilizations to benefit from it as well (such as when I tested it while playing a team game).

I get this error in the .lua log when testing it:
Code:
[10449.929] Runtime Error: C:\...\Sid Meier's Civilization 5\MODS\Harkodos' The Equalists (BNW)\Lua/Amon_Buildings.lua:19: attempt to index local 'pCapitalCity' (a nil value)

Here's the actual code I have for reference:
Code:
-- Amon_Buildings
-- Author: Lee
-- Edited by: Harkodos
--------------------------------------------------------------
gBuildingEarlyIdeology = GameInfoTypes.BUILDING_AMERICA_IDEOLOGY_DUMMYBUILDING
gRequiredCivilization = GameInfoTypes.CIVILIZATION_AMERICA

--------------------------------------------------------------
-- check for a change in era during PlayerDoTurn
--------------------------------------------------------------
function PlayerEraChanged(iPlayer)
	local pPlayer = Players[iPlayer]
	if not pPlayer:GetCivilizationType() == gRequiredCivilization then return end
	if not pPlayer:IsAlive() then return end
	local iNewPlayerEra = pPlayer:GetCurrentEra()
	--print("The value for player era was " .. tostring(iNewPlayerEra))
	local iNumBuildingEarlyIdeology = 0
	local pCapitalCity = pPlayer:GetCapitalCity()
	if pCapitalCity:IsHasBuilding(gBuildingEarlyIdeology) then
		iNumBuildingEarlyIdeology = pCapitalCity:GetNumRealBuilding(gBuildingEarlyIdeology)
		--print("The number of gBuildingEarlyIdeology buildings was " .. tostring(iNumBuildingEarlyIdeology))
	end
	if iNewPlayerEra > iNumBuildingEarlyIdeology then
		--print("The era value was found to be greater than the number of Early Ideology buildings")
		pCapitalCity:SetNumRealBuilding(gBuildingEarlyIdeology, iNewPlayerEra)
		--print("The number of gBuildingEarlyIdeology buildings was changed from " .. tostring(iNumBuildingEarlyIdeology) .. " to " .. tostring(iNewPlayerEra))
	end
end
GameEvents.PlayerDoTurn.Add(PlayerEraChanged);

Wowser, it's been a while since I wrote that!

You'll get the runtime error if the player hasn't founded a capital city yet, or if for some other reason during turn processing there is no capital city for the player. I would change to this:
Code:
--------------------------------------------------------------
local iBuildingEarlyIdeology = GameInfoTypes.BUILDING_AMERICA_IDEOLOGY_DUMMYBUILDING
local iRequiredCivilization = GameInfoTypes.CIVILIZATION_AMERICA

--------------------------------------------------------------
-- check for a change in era during PlayerDoTurn
--------------------------------------------------------------
function PlayerEraChanged(iPlayer)
	local pPlayer = Players[iPlayer]
	if pPlayer:GetCivilizationType() ~= iRequiredCivilization then return end
	if not pPlayer:IsAlive() then return end
	local iNewPlayerEra = pPlayer:GetCurrentEra()
	--print("The value for player era was " .. iNewPlayerEra)
	local iNumBuildingEarlyIdeology = 0
	local pCapitalCity = pPlayer:GetCapitalCity()
	if pCapitalCity ~= nil then
		if pCapitalCity:IsHasBuilding(iBuildingEarlyIdeology) then
			iNumBuildingEarlyIdeology = pCapitalCity:GetNumRealBuilding(iBuildingEarlyIdeology)
			--print("The number of iBuildingEarlyIdeology buildings was " .. iNumBuildingEarlyIdeology)
		end
		if iNewPlayerEra > iNumBuildingEarlyIdeology then
			--print("The era value was found to be greater than the number of Early Ideology buildings")
			pCapitalCity:SetNumRealBuilding(iBuildingEarlyIdeology, iNewPlayerEra)
			--print("The number of iBuildingEarlyIdeology buildings was changed from " .. iNumBuildingEarlyIdeology .. " to " .. iNewPlayerEra)
		end
	end
end
GameEvents.PlayerDoTurn.Add(PlayerEraChanged);
That should keep the runtime error related to the player's capital city being nil from occuring.

If this building (BUILDING_AMERICA_IDEOLOGY_DUMMYBUILDING) isn't defined anywhere in your XML or SQL you'll get floating gardens being added to your capital city.

There's still the possible issue as mentioned in that other thread of the player's capital city getting captured and the dummy buildings are either destroyed in the process of the city capture or else they are now located in a city where they ought not to be. It really depends on the effects you are tyring to implement via the buildings whether this is a big deal or not.

Team games are just a pain to deal with because so many parts of the game's code is based on Teams owning things (like techs) and not individual players owning them.

------------------------------------------------------

But even though I just updated that code I would really want to know exactly what the effect is you are trying to implement before I'd really want to say any more, because the possibilities of bad advices are just too many.
 
Oh, well the effect is simple:

Each time the player advances into a new Era they receive a free copy of said unique dummybuilding. The building won't do anything until they player receives the 4th one due to the XBuiltTriggersIdeologyChoice trigger, in which case, once the player is in the Industrial era, it will trigger, giving them the ability to immediately choose an Ideology (most likely before anyone else). That's pretty much it.

During the team game, somehow my teammate received the buildings as well so I went and defined the default buildingclass as NONE to prevent this.
 
As a general rule you don't want to do this:
Code:
	<BuildingClasses>
		<Row>
			<Type>BUILDINGCLASS_AMERICA_IDEOLOGY_DUMMYBUILDING</Type>
			<DefaultBuilding>NONE</DefaultBuilding>
			<Description>TXT_KEY_BUILDING_AMERICA_IDEOLOGY_DUMMYBUILDING_DESC</Description>
		</Row>
	</BuildingClasses>
Because:
  • there are too many effects that can come from a building and which the game refuses to implement unless the building is either (a) the default within its class, or (b), the unique version within that class that has been assigned to the specific civilization.
  • Using "NONE" as the default building means that no building from within the class would ever meet the first of the two conditions stated for that Building-Class.
  • It will also make the game CTD (as I recall) if you get into this habit and then state such a Building-Class as a <FreeBuilding> or <FreeBuildingThisCity> within table <Buildings> and may cause CTD if the Building-Class is shown for <BuildingClassType> in any table that makes references to Building-Class-Type such as <Building_LockedBuildingClasses>, <Building_BuildingClassYieldChanges>, <Building_BuildingClassHappiness>, <Belief_BuildingClassYieldChanges>, <Belief_BuildingClassHappiness>, <Belief_BuildingClassTourism>, <Policy_BuildingClassYieldChanges>, <Policy_BuildingClassTourismModifiers>, <Policy_BuildingClassHappiness>, <Policy_BuildingClassYieldModifiers>, <Policy_BuildingClassCultureChanges>.
 
Well, alright then. Guess I better scour my other civs to make sure that's not the case in any more of them (I'm certain I did this in at least 1 other Civ I'm making).

Okay, so while going through my Civs, I found that one of my Civilizations sort of depends upon having NONE defined in the DefaultBuildingClass as it prevents other civilizations from using what are supposed to be that civilization's entirely unique buildings. How would I go about fixing this problem so that only my custom civ can use said buildings without doing what I've already done?

-EDIT-

Turns out I actually already had an ingenious solution to this programmed into one of my other Civilizations that added a new BuildingType into the game. All I have to do is define a default building that is similar to a DummyBuilding that can never appear in the tech tree, then I simply define that building as the default for my Civ's unique buildings and then program accordingly. It's a bit extra work (especially in a civ that took forever to program correctly) but the results will be worth it.
 

Attachments

Well, alright then. Guess I better scour my other civs to make sure that's not the case in any more of them (I'm certain I did this in at least 1 other Civ I'm making).

Okay, so while going through my Civs, I found that one of my Civilizations sort of depends upon having NONE defined in the DefaultBuildingClass as it prevents other civilizations from using what are supposed to be that civilization's entirely unique buildings. How would I go about fixing this problem so that only my custom civ can use said buildings without doing what I've already done?

-EDIT-

Turns out I actually already had an ingenious solution to this programmed into one of my other Civilizations that added a new BuildingType into the game. All I have to do is define a default building that is similar to a DummyBuilding that can never appear in the tech tree, then I simply define that building as the default for my Civ's unique buildings and then program accordingly. It's a bit extra work (especially in a civ that took forever to program correctly) but the results will be worth it.

You define the Building as the Default within its Class, and then you lock all other civs from being able to construct it via lua CityCanConstruct and/or PlayerCanConstruct events. Unless you specifically want this building to be used to fill the 2-uniques requirement: in that particular case your more difficult solution is the one desired.
 
Eh, I understand XML more so that's the method I went with.

On another topic: I'm currently trying to program a feature where a Civ receives Gold from World Wonders based on their age. It works as I have it, except when showing new Wonders to be built from an advanced era, I get a +-Gold, and any Wonder from the Ancient Era that can get Gold just displays +1 Gold forever.

I used the code from post #27 to accomplish this, but I think I need a different version that removes the building used upon entering a new era and replacing it with a different one, doing this of course a total of 6 times for 7 buildings. An easier solution would be that the Palace replacement forces them to have a static amount of Gold for the entire game, but that would be really powerful in the early game, so I'd like to accomplish it in the former way if possible.
 
Eh, I understand XML more so that's the method I went with.

On another topic: I'm currently trying to program a feature where a Civ receives Gold from World Wonders based on their age. It works as I have it, except when showing new Wonders to be built from an advanced era, I get a +-Gold, and any Wonder from the Ancient Era that can get Gold just displays +1 Gold forever.

I used the code from post #27 to accomplish this, but I think I need a different version that removes the building used upon entering a new era and replacing it with a different one, doing this of course a total of 6 times for 7 buildings. An easier solution would be that the Palace replacement forces them to have a static amount of Gold for the entire game, but that would be really powerful in the early game, so I'd like to accomplish it in the former way if possible.

I'm sorry but you just really lost me.
 
Okay, let me try and explain it again.

First, I have a unique palace replacement which applies negative Gold yields to all of the World Wonders in the game (barring the Ancient Era and Information Era Wonders). Each negative yield is based on when the Wonder is available in the game, so The Great Lighthouse has -1 Gold, while say The Pentagon has -6 Gold.

Then, using a dummybuilding and the method in post #27, Each Wonder starting with Ancient Era Wonders up to Atomic Era Wonders receives +1 Gold. By the Information Era this should apply +7 Gold to say Stonehenge, +6 to The Great Lighthouse, but only +1 Gold to the Pentagon.

This all works. The problem is that after applying the first Gold yield increase from the first copy of the dummybuilding, it will only display +1 Gold on Stonehenge, even if it is in the Information Era, where it should display that it has 7. Likewise, other Wonders may wind up displaying a +- Gold value after the first era transition.

So, I need the code in post #27 to be modified so that each time the player enters into a new era, the dummybuilding is replaced with a new one specific to that new era, rather than just stacking the same dummybuilding on top of one another, seeing as that does not cause the Gold yields of the Wonders to display properly.

I hope that was more clear.
 
In your dummy were you using <Building_BuildingClassYieldChanges> and something like:
Code:
<GameData>
	...snipped lines of code.....

	<Building_BuildingClassYieldChanges>
		<Row>
			<BuildingType>BUILDING_PALACE</BuildingType>
			<BuildingClassType>BUILDINGCLASS_STONEHENGE</BuildingClassType>
			<YieldType>YIELD_GOLD</YieldType>
			<YieldChange>-1</YieldChange>
		</Row>
		<Row>
			<BuildingType>BUILDING_DUMMYSOMETHING</BuildingType>
			<BuildingClassType>BUILDINGCLASS_STONEHENGE</BuildingClassType>
			<YieldType>YIELD_GOLD</YieldType>
			<YieldChange>1</YieldChange>
		</Row>
	</Building_BuildingClassYieldChanges>
</GameData>
And before you added a BUILDING_DUMMYSOMETHING somewhere you were seeing Stonehenge showing a Yield of +-1 Gold, and after the 1st BUILDING_DUMMYSOMETHING was added in your capital city you were seeing 0 gold (for example), and then it was never changing for Stonehenge even after you added a 2nd or 3rd copy of BUILDING_DUMMYSOMETHING in your capital?

Essentially what you were seeing ?

----------------------------------------------------------------

  • <Building_BuildingClassYieldChanges> affects won't stack for multiple copies of whatever is specified as <BuildingType> within the same city. So after the 1st copy of BUILDING_DUMMYSOMETHING added within the same city, you won't see any change
  • The +- for a yield where you have stated a negative yield is normal because the game designers did not consider the idea there might be a sneaky mod-maker who wanted a negative yield. Short of re-making the CityView.lua there's nothing you can do about that.
----------------------------------------------------------------

You would need multiple buildings or you would need to take a different approach, by using GameEvents.TeamSetEra which only fires when a Team enters a new era. But then, as you've discovered, there's the potential for odd behaviors when people are actually using Teams.

It's possible in this case to use City:SetBuildingYieldChange(BuildingClassType, YieldType, int) and City:GetBuildingYieldChange(BuildingClassType, YieldType) to determine what the current Yield Amount of Wonder-X is, and alter it as needed when the player enters a new era.
 
The -+ effect wasn't specifically being seen with Ancient Era Wonders because they never had to have a - value attached to them (Classical and onward would be more accurate).

But yes, that's the basic idea of what was happening.

These City:SetBuildingYieldChange(BuildingClassType, YieldType, int) and City:GetBuildingYieldChange(BuildingClassType, YieldType), are they XML or .lua? If this can be achieved in XML, how? I'm not familiar with changing things by era beyond the Building_TechEnhancedYieldChanges, and that only fires once, so that makes it very limiting.
 
I recently tried re-working the declaring friendship code that qqqbbb so kindly helped me with to allow it to work with Denouncements instead, but I do not believe I got it to work (it may even be working backwards with how I programmed it, as there were no errors in the .lua log).

Here is the code as is:
Code:
local iAmerica = GameInfoTypes.CIVILIZATION_AMERICA
local 	iWashington
local 	pWashington
local iDummyBuilding = GameInfoTypes.BUILDING_AMERICA_DENOUNCED_DUMMYBUILDING

local function OnPlayerDoTurn(iPlayer)
	local pPlayer = Players[iPlayer]
	if pPlayer:IsAlive() and pPlayer:[COLOR="Blue"]IsDenouncedPlayer[/COLOR](iWashington) == 1 then
		local pTheirCapital = pPlayer:GetCapitalCity()
		pTheirCapital :SetNumRealBuilding(iDummyBuilding , 1)
	end
end

for iPlayer = 0, GameDefines.MAX_MAJOR_CIVS - 1, 1 do
	local pPlayer = Players[iPlayer]
	if pPlayer:GetCivilizationType() == iAmerica then
		iWashington = iPlayer
		pWashington = pPlayer
		GameEvents.PlayerDoTurn.Add ( OnPlayerDoTurn )
		break
	end
end
The blue segment is pretty much all I changed.

Also, I need an .lua code where when the player discovers a specific technology (in this case: TECH_FLIGHT), they receive a dummybuilding in the Capital.
 
Back
Top Bottom