Double-checking Diplomacy function logic

Craig_Sutter

Deity
Joined
Aug 13, 2002
Messages
2,773
Location
Calgary, Canada
Hello... I am finding it incredibly difficult to test whether the logic of this function is working as expected. It is supposed to give negative diplomacy in a couple of situations from the perspective of ePlayer1 to ePlayer2.

- ePlayer1 has three Earldoms while ePlayer2 has London (ePlayer2 should see a negative diplomatic modifier (red message) from ePlayer1.
- ePlayer1 has no Archdiocese while ePlayer2 has at least 1.
- a combination of the above 2.

In all cases, from ePlayer 2 perspective he should get a negative modifier in his relationship to ePlayer1... ePlayer1 should not get any such negative modifiers.

Question... is the code working as expected?

Code:
function VictoryCityB (ePlayer1, ePlayer2)

-- check diplomacy for ePlayer2 and ePlayer1

	local pPlayer1 = Players[ePlayer1]
	local pPlayer2 = Players[ePlayer2]	
	local isLondon = false
	local iEarldom = GameInfoTypes.BUILDING_EARLDOM
	local iArchdiocese = GameInfoTypes.BUILDING_ARCHDIOCESE

	if pPlayer1:IsAlive () and pPlayer2:IsAlive () then

		-- check cities owned for London

		for pCity in pPlayer2:Cities() do 

			if pCity:GetName() == "London" then

			isLondon = true

			end

		end

		--vary diplomacy based on duchies owned and owning London

		if (pPlayer1:CountNumBuildings(iEarldom) > 2) and isLondon == true then
		
			return 90;	
		
		elseif (pPlayer1:CountNumBuildings(iArchdiocese) == 0 ) and (pPlayer2:CountNumBuildings(iArchdiocese) > 0 ) then

			return 90;		
	
		elseif (pPlayer1:CountNumBuildings(iEarldom) > 2) and (pPlayer1:CountNumBuildings(iArchdiocese) == 0 ) and isLondon == true and (pPlayer2:CountNumBuildings(iArchdiocese) > 0 ) then

			return 120;

		else
			return 0;		
		end
	end
end

GameEvents.GetScenarioDiploModifier3.Add(VictoryCityB)

I also have a similar code that is far easier to test.

Code:
function VictoryCityA (ePlayer1, ePlayer2)

-- check diplomacy for ePlayer2

	local pPlayer2 = Players[ePlayer2]	
	local isLondon = false
	local iBuilding = GameInfoTypes.BUILDING_EARLDOM

	if (pPlayer2:IsAlive ()) then

		-- check cities owned for London
		for pCity in pPlayer2:Cities() do 

			if pCity:GetName() == "London" then

			isLondon = true

			end

		end

		--vary diplomacy based on duchies owned and owning London
		if (pPlayer2:CountNumBuildings(iBuilding) == 2) then
		
			return 15;	
		
		elseif (pPlayer2:CountNumBuildings(iBuilding) == 1 ) and (isLondon == true) then

			return 15;		
	
		elseif (pPlayer2:CountNumBuildings(iBuilding) == 2 ) and (isLondon == true) then

			return 45;

		elseif (pPlayer2:CountNumBuildings(iBuilding) == 3) then
		
			return 45;

		elseif (pPlayer2:CountNumBuildings(iBuilding) == 3 ) and (isLondon == true)  then
		
			return 75;

		else
			return 0;		
		end
	end
end

GameEvents.GetScenarioDiploModifier2.Add(VictoryCityA)

My question is, to save GetScenarioDiploModifier functions (as there are only three such), is there a way to amalgamate this and the first code? The text message for each is very similar so it would be nice to have them together. Somehow, I feel that the diplomatic modifier from the 2nd code could be easily brought as a value to be added to the 1st through some kind of subroutine, but I am uncertain how to do this.

Thank-you.

Regards, Craig :)
 
The if ... elseif logic is flawed, it will never return 120
Code:
if (pPlayer1:CountNumBuildings(iEarldom) > 2) and isLondon == true then
	return 90;	
elseif (pPlayer1:CountNumBuildings(iArchdiocese) == 0 ) and (pPlayer2:CountNumBuildings(iArchdiocese) > 0 ) then
	return 90;		
elseif (pPlayer1:CountNumBuildings(iEarldom) > 2) and (pPlayer1:CountNumBuildings(iArchdiocese) == 0 ) and isLondon == true and (pPlayer2:CountNumBuildings(iArchdiocese) > 0 ) then
	return 120;
else
	return 0;		
end

The above can be rewritten as (by pulling out all the Boolean evaluations into temporary variables)
Code:
local a = pPlayer1:CountNumBuildings(iEarldom)
local b = pPlayer1:CountNumBuildings(iArchdiocese)
local c = pPlayer2:CountNumBuildings(iArchdiocese)

local x = ((a > 2) and isLondon)
local y = ((b == 0) and (c > 0))

if x then
	return 90;	
elseif y then
	return 90;		
elseif x and y then
	return 120;
else
	return 0;		
end
which should illustrate the problem. To solve it you need
Code:
if x and y then
	return 120;	
elseif x then
	return 90;		
elseif y then
	return 90;
else
	return 0;		
end
which you could also write as
Code:
if x and y then
	return 120;	
elseif x or y then
	return 90;		
end

And move the "return 0;" bit to the very end of the function, as you should always return a value from an "accumulator" event handler (also a TestAll/TestAny event handler)
 
I have reworked the second function in my OP by trying to follow the same logic pattern as was shown to me...

Here it goes:

Code:
function VictoryCityA (ePlayer1, ePlayer2)

-- check diplomacy for ePlayer2

	local pPlayer2 = Players[ePlayer2]	
	local isLondon = false
	local iBuilding = GameInfoTypes.BUILDING_EARLDOM

	if (pPlayer2:IsAlive ()) then

		-- check cities owned for London
		for pCity in pPlayer2:Cities() do 

			if pCity:GetName() == "London" then

			isLondon = true

			end

		end

		--vary diplomacy based on earldoms owned and owning London

		local a = pPlayer1:CountNumBuildings(iBuilding)
		local x = (a == 1)

		if (x+2) and isLondon then
		
			return 75;
			
		elseif (x+2) or (x+1 and isLondon) then
		
			return 45;		
		
		elseif (x+1) or (x and isLondon) then

			return 15;	

		end
			return 0;
	end
end

GameEvents.GetScenarioDiploModifier2.Add(VictoryCityA)

It was a little more difficult as the progression is not as regular as the other function.

Are there any holes in this logic?

Thank-you

PS as I mentioned, both of the original functions have basically the same type of message... is it possible to link these functions by adding the returned value of one into the returned value of the second? That way, I might be able to get away with using just one of the GetScenarioDiploModifier events and save the other for a different use.
 
Code:
	local a = pPlayer1:CountNumBuildings(iBuilding)
	local x = (a == 1)

	if (x+2) and isLondon then

a is a number, in this case an integer from 0 to some small positive number
x is a Boolean (true or false), if a is 1, x is true, otherwise x is false ... let's assume a is 1, so x is true

what does (x + 2), ie "true + 2" mean :crazyeye:
 
Just realized it upon rethinking... was reducing the functions mathematically. Was a silly thing to do...

Code:
local a = pPlayer1:CountNumBuildings(iBuilding)
local x = (a == 1)
local y = (a == 2)
local z = (a == 3)

	if (z) and isLondon then

			return 75;
			
		elseif (z) or (y and isLondon) then
		
			return 45;		
		
		elseif (y) or (x and isLondon) then

			return 15;	

		end
			return 0;
	end
end

Sorry for the foolishness...
 
Back
Top Bottom