Detecting Peace Treaty to use in Trait

Craig_Sutter

Deity
Joined
Aug 13, 2002
Messages
2,773
Location
Calgary, Canada
I have cludged together some code to give Golden Age points or extended Golden Ages to a civilization if they are in a Peace Treaty.

The Golden Age code I use in other function and it is working... I am a bit uncertain of the Peace Treaty detection and operation. I borrowed it from another's mod and changed it considerably. The original code installed or took away a building based on the code... mine engages a function. As well, the original function triggered on both PlayerDoTurn and WarStateChanged events... I saw this as unnecessary so removed the latter.

There are also items that I deem unneeded but have left in the code such as the tracking of IsTreaty = 0 or IsTreaty >= 1. I think that could be tightened up.

The code is quite hard to test... so first, I would ask if someone could kindly check the logic to see if I haven't screwed it up when I adjusted the original code. Also, does the code actually do as it is supposed to, or do I need to have kept the double trigger of PlayerDoTurn and WarStateChanged.

Finally, I am not certain if the above code will be additive if more than one treaty exists... I would like it to be, but am not certain how the saving of the GoldenAge items with the text key will react to multiple treaties. Perhaps there being any treaty in place would be better... but I'm not certain what the code will actually do in the end.

Here it is:

Code:
-- check to see if Normans have a peace treaty and give Golden Age points if so.

function NormanPeaceBuilding (iPlayer)

	local IsNorman = false;
	local pPlayer = Players[iPlayer] 
	local isTreaty = 0

	--determine if Player is Norman

	if (GameInfo.Civilizations.CIVILIZATION_GREECE.ID == pPlayer:GetCivilizationType()) and pPlayer:IsAlive () and pPlayer:GetNumCities() >= 1 then
					
		IsNorman = true;

	end	

	if (IsNorman == true ) then	
	
		for mPlayer=0, GameDefines.MAX_MAJOR_CIVS-1 do

			local mPlayer = Players[mPlayer];
			if mPlayer ~= pPlayer then

				if (mPlayer:IsAlive()) then
					local pTeam = pPlayer:GetTeam();
					local mTeam = mPlayer:GetTeam();

					if Teams[pTeam]:IsForcePeace(mTeam) then
					print ("Is Treaty!!!!");
					isTreaty = isTreaty + 1
					end
				end
			end
		end

		if isTreaty >= 1 then
			
			NormanGoldenAges(iPlayer)

		end

	else
	end		
end

GameEvents.PlayerDoTurn.Add(NormanPeaceBuilding);



local modData = Modding.OpenSaveData()
local modNormanGoldenAgeKey = "NormanGoldenAge"
local haveNormanGoldenAge = (modData.GetValue(modNormanGoldenAgeKey) == 1)

-- Sets up Norman trait
-- Determine bonus level based on number of puppeted cities
-- no Golden Age adds bonus to progress and sets mod data to false
-- if Golden Age sets mod data to true and increases Golden Age length

function NormanGoldenAges(iPlayer)	
	
	-- Set up bonus		
	local pPlayer = Players[iPlayer] 
	local Bonus = pPlayer:GetNumCities()	
	local NormanGoldenAgeProgressBonus = Bonus + (pPlayer:GetCurrentEra() * Bonus )
	local IsNormanGoldenAge = pPlayer:IsNormanGoldenAge()

	if not IsNormanGoldenAge then

	pPlayer:ChangeNormanGoldenAgeProgressMeter( NormanGoldenAgeProgressBonus )
	haveNormanGoldenAge = false
	modData.SetValue(modNormanGoldenAgeKey, 1)
	print (pPlayer:GetName() ,"is getting",NormanGoldenAgeProgressBonus, "points towards a Golden Age from Peace Treaties");

		elseif IsNormanGoldenAge then

			if (haveNormanGoldenAge == false) then

			pPlayer:ChangeNormanGoldenAgeTurns( Bonus )
			haveNormanGoldenAge = true
			modData.SetValue(modNormanGoldenAgeKey, 1)
			print (pPlayer:GetName() ,"has increased Golden Age by ",Bonus, "turns from Peace Treaties");

			end
		end
	
	return
		
end

Thank-you for your help.

Craig
 
I have cludged together some code to give Golden Age points or extended Golden Ages to a civilization if they are in a Peace Treaty.

The Golden Age code I use in other function and it is working... I am a bit uncertain of the Peace Treaty detection and operation. I borrowed it from another's mod and changed it considerably. The original code installed or took away a building based on the code... mine engages a function. As well, the original function triggered on both PlayerDoTurn and WarStateChanged events... I saw this as unnecessary so removed the latter.

There are also items that I deem unneeded but have left in the code such as the tracking of IsTreaty = 0 or IsTreaty >= 1. I think that could be tightened up.

The code is quite hard to test... so first, I would ask if someone could kindly check the logic to see if I haven't screwed it up when I adjusted the original code. Also, does the code actually do as it is supposed to, or do I need to have kept the double trigger of PlayerDoTurn and WarStateChanged.

Finally, I am not certain if the above code will be additive if more than one treaty exists... I would like it to be, but am not certain how the saving of the GoldenAge items with the text key will react to multiple treaties. Perhaps there being any treaty in place would be better... but I'm not certain what the code will actually do in the end.

Here it is:

Spoiler :
Code:
-- check to see if Normans have a peace treaty and give Golden Age points if so.

function NormanPeaceBuilding (iPlayer)

	local IsNorman = false;
	local pPlayer = Players[iPlayer] 
	local isTreaty = 0

	--determine if Player is Norman

	if (GameInfo.Civilizations.CIVILIZATION_GREECE.ID == pPlayer:GetCivilizationType()) and pPlayer:IsAlive () and pPlayer:GetNumCities() >= 1 then
					
		IsNorman = true;

	end	

	if (IsNorman == true ) then	
	
		for mPlayer=0, GameDefines.MAX_MAJOR_CIVS-1 do

			local mPlayer = Players[mPlayer];
			if mPlayer ~= pPlayer then

				if (mPlayer:IsAlive()) then
					local pTeam = pPlayer:GetTeam();
					local mTeam = mPlayer:GetTeam();

					if Teams[pTeam]:IsForcePeace(mTeam) then
					print ("Is Treaty!!!!");
					isTreaty = isTreaty + 1
					end
				end
			end
		end

		if isTreaty >= 1 then
			
			NormanGoldenAges(iPlayer)

		end

	else
	end		
end

GameEvents.PlayerDoTurn.Add(NormanPeaceBuilding);



local modData = Modding.OpenSaveData()
local modNormanGoldenAgeKey = "NormanGoldenAge"
local haveNormanGoldenAge = (modData.GetValue(modNormanGoldenAgeKey) == 1)

-- Sets up Norman trait
-- Determine bonus level based on number of puppeted cities
-- no Golden Age adds bonus to progress and sets mod data to false
-- if Golden Age sets mod data to true and increases Golden Age length

function NormanGoldenAges(iPlayer)	
	
	-- Set up bonus		
	local pPlayer = Players[iPlayer] 
	local Bonus = pPlayer:GetNumCities()	
	local NormanGoldenAgeProgressBonus = Bonus + (pPlayer:GetCurrentEra() * Bonus )
	local IsNormanGoldenAge = pPlayer:[color="red"]IsNormanGoldenAge[/color]()

	if not IsNormanGoldenAge then

		pPlayer:[color="red"]ChangeNormanGoldenAgeProgressMeter[/color]( NormanGoldenAgeProgressBonus )
		haveNormanGoldenAge = false
		modData.SetValue(modNormanGoldenAgeKey, 1)
		print (pPlayer:GetName() ,"is getting",NormanGoldenAgeProgressBonus, "points towards a Golden Age from Peace Treaties");

	elseif IsNormanGoldenAge then

		if (haveNormanGoldenAge == false) then

			pPlayer:[color="red"]ChangeNormanGoldenAgeTurns[/color]( Bonus )
			haveNormanGoldenAge = true
			modData.SetValue(modNormanGoldenAgeKey, 1)
			print (pPlayer:GetName() ,"has increased Golden Age by ",Bonus, "turns from Peace Treaties");

		end
	end
	
	return
		
end

Thank-you for your help.

Craig
Well, you have a couple problems that are always going to cause run-time errors, as highlighted in red in your original code. Probably stemming from using global "Find">"Replace" methods in your editor.

I'm not familiar enough with using Modding.OpenSaveData() for data-persisting to know if anything is wrong in the usage there.

This is really not necessary (not wrong in the sense of "won't work", just really not needed) in the blue highlights:
Code:
	[color="blue"]local IsNorman = false;[/color]
	local pPlayer = Players[iPlayer] 
	local isTreaty = 0

	--determine if Player is Norman

	if (GameInfo.Civilizations.CIVILIZATION_GREECE.ID == pPlayer:GetCivilizationType()) [color="blue"]and pPlayer:IsAlive ()[/color] and pPlayer:GetNumCities() >= 1 then
					
		[color="blue"]IsNorman = true;[/color]

	end	

	[color="blue"]if (IsNorman == true ) then[/color]
I realise this all stems from code used as a template.
  1. the code creates a variable called "IsNorman"
  2. the code checks if the player is the correct civ, is alive, and has at least one city, and if so sets variable "IsNorman" to "true"
    • the check for whether the player is alive is not needed because PlayerDoTurn does not fire for players that have been eliminated
    • only when your function will be executed from more 'Events' than just PlayerDoTurn do you really need to check for whether the player currently being processed as "iPlayer" is still alive.
    • do not confuse this with the 100% needed check inside the for mPlayer=0, GameDefines.MAX_MAJOR_CIVS-1 do loop, because then you are scanning through all major players of the game, both dead and alive or not used in the current game.
  3. the code then checks to see if variable "IsNorman" is set to "true". In other words, repeating the exact same evaluation that was just conducted.
I would simplify and streamline the PlayerDoTurn function a bit to as follows, although a few of the changes made are just my own personal bugaboos:
Code:
local iRequiredCiv = GameInfoTypes.CIVILIZATION_GREECE
function NormanPeaceBuilding (iPlayer)
	local pPlayer = Players[iPlayer] 

	--determine if Player is Norman

	if (iRequiredCiv == pPlayer:GetCivilizationType()) and pPlayer:GetNumCities() >= 1 then
		local pTeam = Teams[pPlayer:GetTeam()];
		local isTreaty = 0
		for iOtherPlayer=0, GameDefines.MAX_MAJOR_CIVS-1 do
			if iOtherPlayer ~= iPlayer then
				local mPlayer = Players[iOtherPlayer];
				if (mPlayer:IsAlive()) then
					local mTeam = mPlayer:GetTeam();
					if pTeam:IsForcePeace(mTeam) then
						print ("Is Treaty!!!!");
						isTreaty = isTreaty + 1
					end
				end
			end
		end
		if isTreaty >= 1 then
			NormanGoldenAges(iPlayer)
		end
	end		
end
GameEvents.PlayerDoTurn.Add(NormanPeaceBuilding);
The reason I introduced "iOtherPlayer" into the mix is to ensure no confusion between the methods the original code was using for variable "mPlayer"
 
Thank you.... I am going to have to go through the golden age code to see what happened in find/replace. As I said, it is a working code for another civ in my mod. I had changed some of the modsave data keys to not conflict with the naming for the saved data for the other civ in my mod... I will go through it again to be certain to correct errors.

Thank you once more for the advice.
 
The first of your original code where I red highlighted you had "IsNormanGoldenAge" as a player method. This probably was originally "pPlayer:IsGoldenAge()". So if you accidently changed all occurances of "Golden" to "NormanGolden" you would get the items I red highlighted.
 
In testing thus far, the code seems to be working with no errors printed out... but my test hasn't shown a peace treaty as yet. I have a game on autoplay, so we should see a treaty at some point, I assume.

Here's the whole code for completeness. Only thing I am uncertain of is how the trait will run in the instance of more than one treaty. My instinct is that it will fire multiple times a turn, once for each treaty. If so, that's okay... otherwise the trait is pretty weak.

Code:
-- check to see if Normans have a peace treaty and give Golden Age points if so.

local iRequiredCiv = GameInfoTypes.CIVILIZATION_GREECE
function NormanPeaceBuilding (iPlayer)
	local pPlayer = Players[iPlayer] 

	--determine if Player is Norman

	if (iRequiredCiv == pPlayer:GetCivilizationType()) and pPlayer:GetNumCities() >= 1 then
		local pTeam = Teams[pPlayer:GetTeam()];
		local isTreaty = 0
		for iOtherPlayer=0, GameDefines.MAX_MAJOR_CIVS-1 do
			if iOtherPlayer ~= iPlayer then
				local mPlayer = Players[iOtherPlayer];
				if (mPlayer:IsAlive()) then
					local mTeam = mPlayer:GetTeam();
					if pTeam:IsForcePeace(mTeam) then
						print ("Is Treaty!!!!");
						isTreaty = isTreaty + 1
					end
				end
			end
		end
		if isTreaty >= 1 then
			NormanGoldenAges(iPlayer)
		end
	end		
end
GameEvents.PlayerDoTurn.Add(NormanPeaceBuilding);


local modData = Modding.OpenSaveData()
local modNormanGoldenAgeKey = "NormanGoldenAge"
local haveNormanGoldenAge = (modData.GetValue(modNormanGoldenAgeKey) == 1)

-- Sets up Norman trait
-- no Golden Age adds bonus to progress and sets mod data to false
-- if Golden Age sets mod data to true and increases Golden Age length

function NormanGoldenAges(iPlayer)	
	
	-- Set up bonus		
	local pPlayer = Players[iPlayer] 
	local Bonus = pPlayer:GetNumCities()	
	local NormanGoldenAgeProgressBonus = Bonus + (pPlayer:GetCurrentEra() * Bonus )
	local IsNormanGoldenAge = pPlayer:IsGoldenAge()

	if not IsNormanGoldenAge then

	pPlayer:ChangeGoldenAgeProgressMeter( NormanGoldenAgeProgressBonus )
	haveNormanGoldenAge = false
	modData.SetValue(modNormanGoldenAgeKey, 1)
	print (pPlayer:GetName() ,"is getting",NormanGoldenAgeProgressBonus, "points towards a Golden Age from Peace Treaties");

		elseif IsNormanGoldenAge then

			if (haveNormanGoldenAge == false) then

			pPlayer:ChangeGoldenAgeTurns( Bonus )
			haveNormanGoldenAge = true
			modData.SetValue(modNormanGoldenAgeKey, 1)
			print (pPlayer:GetName() ,"has increased Golden Age by ",Bonus, "turns from Peace Treaties");

			end
		end
	
	return
		
end
 
Since the hook event is PlayerDoTurn the entire code will only execute once per turn. The bulk of your code within the PlayerDoTurn-subscribed function 'NormanPeaceBuilding' only runs for the correct civ. 'NormanGoldenAges' only ever executes when called from within 'NormanPeaceBuilding' and because of the way 'NormanPeaceBuilding' is coded will only be called when 'isTreaty' (ie, number of peace treaties) is >= 1.


The stuff that is outside of any function runs once when the game loads from a save or from 'start new game'.
 
Thank-you.

In my tests, I found that the values per turn of the peace treaty were very high... + 105 golden age points per turn and +21 golden age length when that kicked in. This one tested in a quick game.

I think that these are high for Quick speed... not as bad for a longer game.

I am thinking of introducing scaling according to game length... reducing the bonus while making game speed a multiplier.

My follow up question is... is this merited or am I missing some factor that is already scaling the golden age points and length? I think not, but I could be missing something.

Thanks.
 
If the player has 6 cities:
  1. And they are not in a Golden Age, then the Golden Age progress meter will be adjusted by (6 + (6 * EraID#)). Which means:
    Era EraID# ExtraBonus Total Bonus
    ERA_ANCIENT 0 0 6
    ERA_CLASSICAL 1 6 12
    ERA_MEDIEVAL 2 12 18
    ERA_RENAISSANCE 3 18 24
    ERA_INDUSTRIAL 4 24 30
    ERA_MODERN 5 30 36
    ERA_POSTMODERN 6 36 42
    ERA_FUTURE 7 42 48
    And this will all be in addition to any normal progress added by excess empire happiness every turn. And the Bonus of course will only be applied when the main code determines that there is at least one "forced peace" active.
  2. If they are in a Golden Age, then on the 1st turn after the start of the Golden Age, the length of the Golden Age will be increased by +6 turns. So far as I know pPlayer:ChangeGoldenAgeTurns( Bonus ) does not take player gamespeed into account.
So you also have to sort out what else is adding to Golden Age Progress Meter and Golden Age Duration before you can really say whether the code is giving too high a number. The first thing I would do, though, is to add print statements right where the code is adding the Golden Age turns and the Golden Age Progress Meter to see what the code is actually generating. Never mind, it is already in there.
 
The way I see it... since treaty length varies with game speed, the points accrued as progress will naturally, in total, vary indirectly with game speed.

However, Golden Age length increase is an absolute value... so I should adjust it in accordance to the game speed.

I think I need to go to game speed XML to see how the Golden Age length and bonuses are adjusted by Firaxis code... that will perhaps indicate how I should likewise adjust my trait bonuses.

At least it will give me a direction as to how I should scale things.

As always, thanks for the advice.
 
There is a GoldenAgePercent in Gamespeeds. It varies inversely with Gamespeed... highest for Marathon, lowest for Quick. Now I need to determine if this is just for the length or also for the points accrued.

For Quick, my GoldenAgePercent is 45...

so...

pPlayer:ChangeGoldenAgeTurns( Bonus*iGoldenAgePercent ) might be the way to go.

Using lua, I could detect the current game speed and find the Row value of iGoldenAgePercent and use it as my variable above...

PS

This might work...

By the way, LeeS, it was from some 2014 code of yours in another thread :). I have adjusted it somewhat.

iGoldenAgePercent = GameInfo.GameSpeeds[Game.GetGameSpeedType()].GoldenAgePercent/ 100
 
Back
Top Bottom