Missionary conversion code not working out as expected.

Craig_Sutter

Deity
Joined
Aug 13, 2002
Messages
2,773
Location
Calgary, Canada
Here is a bit of code I have in my mod... The first portion converts missionary units to a UU Irish missionary. It is supposed to convert units if the missionary is run by a human, and otherwise, to do so 40% or the time (2/5).

The second portion calls a building to generate missionaries and forcibly deducts faith to pay for them. The intent is that the first code will operate upon the second to convert the building spawned missionaries to Irish missionaries.

The only problem is that the conversion seems to be happening 100% of the time as opposed to 40%.

I cannot figure out why.

Here is the code:

Code:
-- Exchanges missionary purchased with Unique unit
-- MissionaryReplacer
-- Author: LastSword
-- DateCreated: 8/24/2013 2:56:18 PM
--------------------------------------------------------------
local sUnitType = "UNIT_MISSIONARY"
local iMissionaryID = GameInfo.Units.UNIT_MISSIONARY.ID
local iMissionaryOverride = GameInfo.Units.UNIT_IRISH_MISSIONARY.ID
local iCivType = GameInfo.Civilizations["CIVILIZATION_OTTOMAN"].ID

function MissionaryOverride(iPlayer, iUnit)
    local pPlayer = Players[iPlayer];
    if (pPlayer:IsEverAlive()) then
        if (pPlayer:GetCivilizationType() == iCivType) then
       	    if pPlayer:GetUnitByID(iUnit) ~= nil then
				pUnit = pPlayer:GetUnitByID(iUnit);
                if (pUnit:GetUnitType() == iMissionaryID) then

					if pPlayer:IsHuman() or (math.random (5) > 2) then

                    local newUnit = pPlayer:InitUnit(iMissionaryOverride, pUnit:GetX(), pUnit:GetY())
                    newUnit:Convert(pUnit);

					end
                end
            end
        end
    end
end
LuaEvents.SerialEventUnitCreatedGood.Add( MissionaryOverride )


-- To spawn a Missionary in AI player city and deduct faith purchase price.

function ForceMissionaryPurchase (iPlayer)

	local player = Players[iPlayer]
	if player and player:IsAlive() and (GameInfo.Civilizations.CIVILIZATION_OTTOMAN.ID == player:GetCivilizationType()) and not player:IsHuman() then
		
		for city in player:Cities() do
			if (city:GetReligiousMajority() == GameInfoTypes["RELIGION_CHRISTIANITY"]) or (city:GetReligiousMajority() == GameInfoTypes["RELIGION_HINDUISM"]) 
			or (city:GetReligiousMajority() == GameInfoTypes["RELIGION_CONFUCIANISM"]) or (city:GetReligiousMajority() == GameInfoTypes["RELIGION_BUDDHISM"]) then

				local iMissionary = GameInfoTypes.UNIT_MISSIONARY
				local iUnitCost = city:GetUnitFaithPurchaseCost(iMissionary)
				if player:GetFaith() >= iUnitCost then
				city:SetNumRealBuilding(GameInfoTypes["BUILDING_CLOISTER"], 1);					
				player:ChangeFaith ( -iUnitCost )
				else
				city:SetNumRealBuilding(GameInfoTypes["BUILDING_CLOISTER"], 0);
				end

			end				
		end
	end
end

Can fresh eyes figure out why this is so?

Thank-you.
 
  1. This equals 60%, not 40%:
    Code:
    (math.random (5) > 2)
    Your possible outcomes are: 1, 2, 3, 4, 5. Since blue outcomes match the conditions of the code, and you have 3 'blues" and only 2 'red', you get 60%. You need
    Code:
    (math.random(5) <= 2)

    Otherwise I don't see an issue with the 1st chunk of code, so stymied why it would give conversions all the time. I usually shove a bunch of print statements into my code if I cannot figure out why it is not behaving the way I expected as oppposed to the way I actually programmed.
  2. For test purposes I would probably re-arrange as
    Code:
    local sUnitType = "UNIT_MISSIONARY"
    local iMissionaryID = GameInfo.Units.UNIT_MISSIONARY.ID
    local iMissionaryOverride = GameInfo.Units.UNIT_IRISH_MISSIONARY.ID
    local iCivType = GameInfo.Civilizations["CIVILIZATION_OTTOMAN"].ID
    
    function MissionaryOverride(iPlayer, iUnit)
    	local pPlayer = Players[iPlayer];
    	if (pPlayer:IsEverAlive()) then
    		if (pPlayer:GetCivilizationType() == iCivType) then
    			if pPlayer:GetUnitByID(iUnit) ~= nil then
    				local pUnit = pPlayer:GetUnitByID(iUnit);
    				if (pUnit:GetUnitType() == iMissionaryID) then
    					local bConvert = pPlayer:IsHuman()
    					if bConvert == false then
    						print("bConvert was false, so the player for CIVILIZATION_OTTOMAN should not have been human")
    						if (math.random(5) <= 2) then
    							print("the random value when the player is not human was less than or equal to 2, so conversion should occur")
    							bConvert = true
    						else
    							print("the random value when the player is not human was 3 or greater, so conversion should NOT occur")
    						end
    					end
    					if bConvert then
    						print("Conversion from Missionary to Irish Missionary is being conducted")
    						local newUnit = pPlayer:InitUnit(iMissionaryOverride, pUnit:GetX(), pUnit:GetY())
    						newUnit:Convert(pUnit)
    					else
    						print("Conversion from Missionary to Irish Missionary was not conducted")
    					end
    				end
    			end
    		end
    	end
    end
    LuaEvents.SerialEventUnitCreatedGood.Add( MissionaryOverride )
    • This should get rid of any possible variable localization scoping issues
    • also I got rid of the space you had here
      Code:
      math.random (5)
      in case lua in this instance wants to give significance to the space between "random" and "(5)" and wants to operate differently than expected. Not that I ever remember this occuring, but I always try to eliminate all possibles when faced with such a conundrum. (This is carry-over from a couple of now-long-obsolete machine-tool programming-languages where in some cases the space would have been significant, and in other cases not, even with the same machine's language).
 
Eureka moment...

The method I am using to force purchase the unit is via a building that spawns it. I assume that the building is spawning based upon the unit class and not the unit.... and so it is calling for the unique version of the missionary (Irish Missionary) for the owning civilization.

Hence, I am always getting the Irish Missionary... the conversion code is not even being called.

I guess I will either have to live with it... or use UnitInit.

Thanks... your code helped in that despite none of the print statements being called, I got the converted unit.

Thank-you.
 
Eureka moment...

The method I am using to force purchase the unit is via a building that spawns it. I assume that the building is spawning based upon the unit class and not the unit.... and so it is calling for the unique version of the missionary (Irish Missionary) for the owning civilization.

Hence, I am always getting the Irish Missionary... the conversion code is not even being called.

I guess I will either have to live with it... or use UnitInit.

Thanks... your code helped in that despite none of the print statements being called, I got the converted unit.

Thank-you.
Yes. <Building_FreeUnits> always gives the correct unit based on settings of DefaultUnit within the class and any overrides that are active from within that Unit-Class for that civilization. It really ought to be called <Building_FreeUnitClasses>. So yeah, even if you put UNIT_MISSIONARY in <Building_FreeUnits>, if the correct unit from within the class for CIV_X is UNIT_IRISH_MISSIONARY they'll get UNIT_IRISH_MISSIONARY.
 
Back
Top Bottom