issue preventing the AI from clearing lairs

omegaflames

Warlord
Joined
Sep 21, 2012
Messages
181
I'm trying to change the spell for exploring a lair (specifically the SPELL_EXPLORE_LAIR_RUINS one in this case, but since all of them have the same PyRequirement then really all of them) so that it can't be explored if it's on a plot that is owned by someone else. For the life of me I can't get the below code to prevent Cardith from clearing the ruin in my territory with his scout. Any help would be greatly appreciated.
Spoiler :
Code:
def reqExploreLair(caster):
	if caster.isOnlyDefensive():
		return False
	if caster.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
		return False
	if caster.isBarbarian():
		return False
	if caster.getDuration() > 0:
		return False
	if caster.getSpecialUnitType() == gc.getInfoTypeForString('SPECIALUNIT_SPELL'):
		return False
	if caster.getSpecialUnitType() == gc.getInfoTypeForString('SPECIALUNIT_BIRD'):
		return False
	pPlayer = gc.getPlayer(caster.getOwner())
	iTeam = pPlayer.getTeam()
	eTeam = gc.getTeam(iTeam)
	bPlayer = gc.getPlayer(gc.getBARBARIAN_PLAYER())
	if not eTeam.isAtWar(bPlayer.getTeam()):
		return False
	[COLOR="Red"]pPlot = caster.plot()
	if pPlot.isOwned():
		iImprovement = pPlot.getImprovementType()
		if gc.getImprovementInfo(iImprovement).isUnique():
			if not gc.getImprovementInfo(iImprovement).getBonusConvert() == BonusTypes.NO_BONUS:
				return False
		if pPlot.getOwner() != caster.getOwner():
			return False[/COLOR]
	if pPlayer.isHuman() == False:
		if pPlayer.getNumCities() < 1:
			return False
	return True
 
To try and debug this I changed the code I marked red above to
Spoiler :
Code:
	pPlot = caster.plot()
	if pPlot.isOwned():
		BugUtil.trace("if pPlot.isOwned(): passed", )
		iImprovement = pPlot.getImprovementType()
		if gc.getImprovementInfo(iImprovement).isUnique():
			if not gc.getImprovementInfo(iImprovement).getBonusConvert() == BonusTypes.NO_BONUS:
				return False
		if pPlot.getOwner() != caster.getOwner():
			BugUtil.trace("if pPlot.getOwner() != caster.getOwner() passed", )
			return False
The first trace sends me a message but the second is never sending it's message so there is something wrong with the ".getOwner" command. Only thing I can think of is that because the ruin is right beside a city I recently created and since that city hasn't made any culture yet then maybe that's why? I used the worldbuilder to change the city to fledgling and gave it a monument but that didn't help either.
 
got the bright idea to check what values are being returned for pPlot.getOwner() and caster.getOwner() so I changed the code to the below and now it's telling me that iOwner and iCaster are both returning 0 for my unit AND for Cardith's unit when he explores it :confused::confused::confused:
Spoiler :
Code:
	pPlot = caster.plot()
	if pPlot.isOwned():
		BugUtil.trace("if pPlot.isOwned(): passed", )
		iImprovement = pPlot.getImprovementType()
		if gc.getImprovementInfo(iImprovement).isUnique():
			if not gc.getImprovementInfo(iImprovement).getBonusConvert() == BonusTypes.NO_BONUS:
				return False
		iOwner = pPlot.getOwner()
		iCaster = caster.getOwner()
		BugUtil.trace("iOwner is %s and iCaster is %s", iOwner, iCaster)
		if pPlot.getOwner() != caster.getOwner():
			BugUtil.trace("if pPlot.getOwner() != caster.getOwner() passed", )
			return False
 
just fyi when I run the code
Code:
		iOwner = gc.getPlayer(pPlot.getOwner())
		iCaster = gc.getPlayer(caster.getOwner())
		BugUtil.trace("iOwner is %s and iCaster is %s", iOwner, iCaster)
on my adept on this same ruin it is returning the results
Code:
20:43:54 TRACE: iOwner is <CvPythonExtensions.CyPlayer object at 0x3C4C7E68> and iCaster is <CvPythonExtensions.CyPlayer object at 0x3C4C7F80>
you will note that 0x3C4C7E68 =/= 0x3C4C7F80. This being my unit and a plot I own, aren't they supposed to have the same results?
 
just fyi when I run the code
Code:
		iOwner = gc.getPlayer(pPlot.getOwner())
		iCaster = gc.getPlayer(caster.getOwner())
		BugUtil.trace("iOwner is %s and iCaster is %s", iOwner, iCaster)
on my adept on this same ruin it is returning the results
Code:
20:43:54 TRACE: iOwner is <CvPythonExtensions.CyPlayer object at 0x3C4C7E68> and iCaster is <CvPythonExtensions.CyPlayer object at 0x3C4C7F80>
you will note that 0x3C4C7E68 =/= 0x3C4C7F80. This being my unit and a plot I own, aren't they supposed to have the same results?

No. The Python/C++ interface code is setup such that the Python functions return a newly constructed object each time.

You should compare IDs like so:
Code:
	iPlotOwner = pPlot.getOwner()
	iCasterOwner = caster.getOwner()
	BugUtil.trace("Plot owner ID is %i and caster owner ID is %i", iPlotOwner, iCasterOwner)

Alternatively, you could try something like this (untested):
Code:
	pPlotOwner = gc.getPlayer(pPlot.getOwner())
	pCasterOwner = gc.getPlayer(caster.getOwner())
	BugUtil.trace("Plot owner is %s and caster owner is %s", pPlotOwner.getName(), pCasterOwner.getName())


Regarding why your other code is not working, it would really help to have a save file from the turn just before the lair gets explored.
 
ummm your first suggestion is the same code as in my first 3 posts and the alternative you gave is exactly the same as the post above it as all you did was rename the variables which code wise does nothing new. A save file probably won't work for you as I've made changes to the xml but you are welcome to give it a try.
 

Attachments

  • EricFFH2-1.CivBeyondSwordSave
    332.1 KB · Views: 149
ummm your first suggestion is the same code as in my first 3 posts

Because that is how ownership is usually compared in Civ4.


the alternative you gave is exactly the same as the post above it

No, it is not. Look closer.

Each call to gc.getPlayer returns a unique object; comparing their addresses is meaningless.


A save file probably won't work for you as I've made changes to the xml

If you have made such alterations, then yeah, we would also need all the files that you have changed.

Indeed, given that the code you initially posted looks at least superficially OK, it would be pointless to delve any further without knowing what else you have changed.
 
Because that is how ownership is usually compared in Civ4.
Which is why this thread was created, because it's not working correctly.
No, it is not. Look closer.
Yes I see now that you added in .getName commands to the Trace code instead of the variables where it would have made a hell of alot more sense to put commands like that since those variables literally exist only for that Trace command.
Each call to gc.getPlayer returns a unique object; comparing their addresses is meaningless.
Thank you for that info, but if there is ALWAYS a newly constructed object each time then you could NEVER compare anything and we clearly do alot of comparing all the time.
If you have made such alterations, then yeah, we would also need all the files that you have changed.

Indeed, given that the code you initially posted looks at least superficially OK, it would be pointless to delve any further without knowing what else you have changed.
I've changed nothing in the dll and 99% of everything is exactly the same as MNAI but since doing things like making Priests of Winter a buildable unit and adding in 6-7 new spells breaks saves such is life. Also I don't know of any method of any xml or python changes could stop .getOwner from working. Anyhow the attached rar is every file I've made any change to (the Omegas FFH2 change log.txt lists most changes I've made but not all of them).
 

Attachments

  • changed files.rar
    1.3 MB · Views: 155
Which is why this thread was created, because it's not working correctly.

The code in question is working correctly. Now that I have had a chance to test it, I know why things are behaving as they are.


Thank you for that info, but if there is ALWAYS a newly constructed object each time then you could NEVER compare anything and we clearly do alot of comparing all the time.

It is meaningless to compare the addresses of the objects returned by the Civ4 Python API. You can compare simple values - like the integers returned by getOwner() - just fine.


For the life of me I can't get the below code to prevent Cardith from clearing the ruin in my territory with his scout.

The restrictions in reqExploreLair only apply to human players. If you want to similarly restrict AI players, you would need to change CvUnitAI::AI_exploreLair in the DLL.
 
The restrictions in reqExploreLair only apply to human players. If you want to similarly restrict AI players, you would need to change CvUnitAI::AI_exploreLair in the DLL.

Python spell restrictions affect all players. They are checked in CvUnit::canCast()
 
Python spell restrictions affect all players. They are checked in CvUnit::canCast()

In the - admittedly quick - tests I did, reqExploreLair did not seem to get called except for human-controlled units. I guess more investigation is needed.
 
looking throu the BBAILog I think fe79 might be right that for w/e reason the AI is able to bypass reqExploreLair somehow. I think that instead of what I thought was carth being identified as me
iOwner and iCaster are both returning 0 for my unit AND for Cardith's unit when he explores it
back when I was comparing pPlot.getOwner() and caster.getOwner() in post number 3, was infact my unit getting checked at the end of my turn (hence the 2nd entry in the logs) but carth not actually getting checked himself.
 
OK, so I found out what is really going on:
Cardith's scout is not casting Explore Lair, nor any other spell for that matter. It turns out that AI units always clear unit-spawning improvements when moving into a tile unless at peace with the barbarians. Human players do the same for temporary unit spawners (like bear dens), but AI players clear permanent ones as well.

Is this really desired behavior? After all, it means that AI players will never explore lairs unless the leader has the Barbarian trait.

Anyway, the relevant code is in CVUnit.cpp, in the function CvUnit::setXY, specifically around line 12292.
 
OK, so I found out what is really going on:
Cardith's scout is not casting Explore Lair, nor any other spell for that matter. It turns out that AI units always clear unit-spawning improvements when moving into a tile unless at peace with the barbarians. Human players do the same for temporary unit spawners (like bear dens), but AI players clear permanent ones as well.

Is this really desired behavior? After all, it means that AI players will never explore lairs unless the leader has the Barbarian trait.

Good catch and interesting find! I never really noticed since the AI will still explore dungeons and such. This only affects unit spawning improvements. This is original code from Kael, but I have no idea why he did it this way. I would guess it was due to AI limitations at the time on implementation for the lairs. But since the AI can now explore lairs on its own, I'll go ahead and remove that special case for the AI players.

Thanks for hunting this down!
 
Yes ty fe79 for finding the problem. Also good to know it wasn't because I screwed something up :)
 
Top Bottom