AI Civ Research Gets Stuck After Using SetCivic

isau

Deity
Joined
Jan 15, 2007
Messages
3,071
Hey guys, weird problem showing up in my mod related to the code below. Wondering if anyone can suggest a workaround.

The code below properly gives the Code of Laws civic to Gilgamesh on turn 1. It's borrowed more or less directly from code from scenario files that award free techs on turn 1.


Code:
    -- on turn 1 give gilgamesh code of laws civic for free
    if (currentTurn == 1) then  
        if (sLeaderName == "LEADER_GILGAMESH") then
            local pCulture:table = pPlayer:GetCulture();
            pCulture:SetCivic(GameInfo.Civics["CIVIC_CODE_OF_LAWS"].Index, true);
            pCulture:SetCivicCompletedThisTurn(true);
           
            pCulture:UnlockGovernment(GameInfo.Governments["GOVERNMENT_CHIEFDOM"].Index);
            pCulture:SetCurrentGovernment(GameInfo.Governments["GOVERNMENT_CHIEFDOM"].Index);
        end
    end

It works fine for human players and also appears to award the tech to the AI. But then the AI never advances past Code of Laws. It just sits there the whole game without researching anything else.

The unlock government bit at the bottom isn't actually needed--I just added it in there in case that was getting the AI stuck. But it doesn't fix the issue. Nor does the SetCivicCompletedThisTurn setting. Is there something obvious I'm missing?

TBH I'd really rather do this with Modifiers anyway, so if there's an Effect for just outright awarding a specific civic someone knows of, I'd be delighted if you could point me to it. I try to avoid Lua wherever possible. :)
 
I have not used those functions, so will speculate a little.
Are you sure which function actually completes the civic?
Seems for me that SetCivicCompletedThisTurn works for the currently progressing civic. So, if you use SetCivic then there's none. Maybe that's the problem.

Edit. Another idea. Try to use SetCulturalProgress to achieve 100%. That would simulate actual completion I think.
 
I have not used those functions, so will speculate a little.
Are you sure which function actually completes the civic?
Seems for me that SetCivicCompletedThisTurn works for the currently progressing civic. So, if you use SetCivic then there's none. Maybe that's the problem.

Edit. Another idea. Try to use SetCulturalProgress to achieve 100%. That would simulate actual completion I think.


Thanks I'll try that.

The function that completes the civic is:

Code:
pCulture:SetCivic(GameInfo.Civics["CIVIC_CODE_OF_LAWS"].Index, true);


I copied the function from one of the scenario scripts. Makes me wonder if in the scenario packs the AIs are also getting stuck, or if there is some other magic in there that unsticks the AI. I put the other lines of code in there in hopes of unsticking them, but it didn't work. I'll try your workaround idea.
 
I use this function where:
  1. sCivic is the civic typename like "CIVIC_CODE_OF_LAWS"
  2. pPlayer is the player object as in
    Code:
    local pPlayer = Players[iPlayer]
  3. iPlayer is the player # for the current game for the player being processed
Code:
function FinishCivic(sCivic, pPlayer, iPlayer)
	local iCivic = DB.MakeHash(sCivic)
	if iCivic ~= nil then
		local pCulture = pPlayer:GetCulture()
		if pCulture ~= nil then
			local iCivicCost = pCulture:GetCultureCost(iCivic)
			pCulture:SetCulturalProgress(iCivic, iCivicCost)
			return true
		else
			print("FinishCivic: invalid player civics table for player # " .. iPlayer .. ", returning nil")
		end
	else
		print("FinishCivic: invalid civic hash")
	end
	return nil
end
  • This might actually cause the same issue since I never thought to run a 'listener" to see what an Ai player is "researching" civics-wise after giving a civic via this method.
  • I've slowly been going back through my code and removing any instances of DB.MakeHash(Item) because when I did this for Technologies I got wildly bizarre results at one time and I'd rather use the known reliable method of
    Code:
    local tCivic, iCivic = GameInfo.Civics[sCivic], -1
    if tCivic ~= nil then
    	iCivic = tCivic.Index
    	...etc....
To simplify needed arguments and adapt to the usage of using row index # instead of DB.Hash:
Code:
function FinishCivic(sCivic, iPlayer)
	local tCivic = GameInfo.Civics[sCivic]
	if tCivic ~= nil then
		local iCivic = tCivic.Index
		local pPlayer = Players[iPlayer]
		if (pPlayer ~= nil) and pPlayer:IsAlive() and not pPlayer:IsBarbarian() then
			local pCulture = pPlayer:GetCulture()
			if pCulture ~= nil then
				local iCivicCost = pCulture:GetCultureCost(iCivic)
				pCulture:SetCulturalProgress(iCivic, iCivicCost)
				return true
			else
				print("FinishCivic: invalid player civics table for player # " .. iPlayer .. ": returning nil")
			end
		else
			print("FinishCivic: invalid player data for player # " .. iPlayer .. " Player is nil or dead or is a Barb: returning nil")
		end
	else
		print("FinishCivic: invalid civic designation")
	end
	return nil
end
The 1st example assumed the additional checks against nil player or barbs etc had been done in the code before activation of the routine.
 
Last edited:
Thanks guys. Because the Civic was Code of Laws (first in the tree) I was able to use a fairly simple workaround: just toss 20 Culture at the player on Turn 1 using a Modifier. That accomplishes the same end, even if I never solved the original problem.
 
Thanks guys. Because the Civic was Code of Laws (first in the tree) I was able to use a fairly simple workaround: just toss 20 Culture at the player on Turn 1 using a Modifier. That accomplishes the same end, even if I never solved the original problem.
A good solution to the problem, but is it possible that 20 points of culture will suffice for those conditions when you are playing at a marathon or, for example, in modifying the increase in the cost of research?
 
A good solution to the problem, but is it possible that 20 points of culture will suffice for those conditions when you are playing at a marathon or, for example, in modifying the increase in the cost of research?

Good question. I've set it to flex by gamespeed and tested at each speed, so yes it does account for that. :)

The implementation in SQL is very straightforward:

Code:
-- Give Sumeria a burst of Culture
INSERT INTO Modifiers
    (ModifierId, ModifierType, RunOnce, Permanent, OwnerRequirementSetId, SubjectRequirementSetId)
VALUES    ('QUO_SUMERIA_FREE_STARTING_CULTURE', 'MODIFIER_PLAYER_GRANT_YIELD', 1, 1, NULL, NULL) ;


INSERT INTO ModifierArguments
    (ModifierId,             Name,             Type,             Value,         Extra,     SecondExtra)
VALUES    ('QUO_SUMERIA_FREE_STARTING_CULTURE',     'Amount',     'ScaleByGameSpeed',     '20',        NULL,     NULL),
    ('QUO_SUMERIA_FREE_STARTING_CULTURE',     'YieldType',     'ARGTYPE_IDENTITY',     'YIELD_CULTURE',    NULL,     NULL)  ;


INSERT INTO TraitModifiers
    (TraitType,             ModifierID)
VALUES    ('TRAIT_CIVILIZATION_FIRST_CIVILIZATION',    'QUO_SUMERIA_FREE_STARTING_CULTURE')  ;



EDIT: Although you're correct that if someone were to change the tech costs it would be too much/too little. That's just something they'll have to deal with. :) I figure if they've increased the tech costs that a free tech at start would be overpowered anyway, and instead they just get a 20 point bonus instead of the actual tech.
 
EDIT: Although you're correct that if someone were to change the tech costs it would be too much/too little. That's just something they'll have to deal with. :) I figure if they've increased the tech costs that a free tech at start would be overpowered anyway, and instead they just get a 20 point bonus instead of the actual tech.

Look at the solution of the problem in the modification "Really Advanced Setup Lite".
I gave the code for the original modification, and the code that might solve your problem.

Spoiler Really :
1. Original
<RASL_CivicsStatus>
<Row CivicType="CIVIC_CRAFTSMANSHIP" Value="100" AIMajPlayer="false" EraType="ERA_ANCIENT" />
<Row CivicType="CIVIC_MILITARY_TRADITION" Value="50" AIMajPlayer="false" EraType="ERA_ANCIENT" /
<Row CivicType="CIVIC_FOREIGN_TRADE" Finish="true" CivilizationType="CIVILIZATION_ROME" AIMajPlayer="false" EraType="ERA_ANCIENT" />
</RASL_CivicsStatus>

2. For Mod
<RASL_CivicsStatus>
<Row CivicType="CIVIC_CODE_OF_LAWS" Finish="true" CivilizationType="CIVILIZATION_SUMERIA"/>
</RASL_CivicsStatus>
 
I'm implementing everything in that mod via lua.

You enter your desired effects into the xml-tables I am adding to the game, and then the lua code (which you as the user never touch) implements the commanded effects via the code quoted in post #4
 
I've verified that using the pPlayer:GetCulture():SetCulturalProgress(iCivic, iProgress) method in lua does not cause the AI's to cease researching civics. Nor does the method pPlayer:GetTechs():SetResearchProgress(iTech, iProgress) cause them to stop researching technologies.
 
I've verified that using the pPlayer:GetCulture():SetCulturalProgress(iCivic, iProgress) method in lua does not cause the AI's to cease researching civics. Nor does the method pPlayer:GetTechs():SetResearchProgress(iTech, iProgress) cause them to stop researching technologies.


I wonder if its something specific to just the Code of Laws civic then? I removed the code that added the civic from the mod and changed nothing else, and it fixed it.


EDIT: Nevermind, I'm an idiot. Your method is different than what I was using. :)
 
Back
Top Bottom