1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

Bug Reports and Discussion

Discussion in 'More Naval AI Modmod' started by Tholal, Jan 3, 2013.

  1. platyping

    platyping Sleeping Dragon

    Joined:
    Oct 22, 2010
    Messages:
    4,626
    Location:
    Emerald Dreams
    I am more curious about that chunk of terrain if statements lol.
    Regardless of whether it is snow, desert, plains etc, you will always end up with grass, so why so troublesome.
     
  2. omegaflames

    omegaflames Warlord

    Joined:
    Sep 21, 2012
    Messages:
    163
    Ya when i went throu and made my own genesis code i removed that huge list of variables since only 2 of them is actually needed more than once and added marsh and shallows to the list as well since the current code doesn't change them for the regular genesis or the illian version of it. There are actually quite a few places that make me wonder why they were written a certain way unless someone knows if there are commands that are slightly faster than others in the code:confused:

    edit: also the current code completely ignores floodplains and oasis and would end up upgrading those plots as well
     
  3. Tholal

    Tholal Emperor

    Joined:
    May 19, 2009
    Messages:
    1,676
    Thanks for the report! I'll check the fix into the repository tonight.

    Interesting. I have no idea really. It does look pretty useless.

    Think those succeeding if statements should be elif instead.

    Good catch! Marsh is the bastard stepchild of the terrains and often is missed in the various python calls. I'll add in some code for Marsh.

    Feel free to point them out!

    Oases are not a big deal. Regular terraforming spells can change their terrain. I think the Floodplains part was intentional. I'll have to see if I can dig up any old posts on the matter.
     
  4. omegaflames

    omegaflames Warlord

    Joined:
    Sep 21, 2012
    Messages:
    163
    I'm still trying to work out how but a Baalseraphs cultist cast Inquistition on an Infernals plot, a plot that wasn't even a city there. Then I think moved a couple plots somehow and after casting (which failed and gave me an error) moved again reeeeally far away best I can tell. It's late so I'll finish hunting this all down after some sleep and update here. When I got the error popup I got a really weird audio get played that sounded like a woman's voice shouting at someone (I swear I'm not making this up).
     
  5. Tholal

    Tholal Emperor

    Joined:
    May 19, 2009
    Messages:
    1,676
    From your description, it sounds like the Cultist started inquisitioning an Infernal city, then lost the Open Borders agreement which booted the Cultist out of Infernal territory but since he was in the middle of a multi-turn casting process he ended up finishing outside the city which then ends up throwing a python error.
     
  6. omegaflames

    omegaflames Warlord

    Joined:
    Sep 21, 2012
    Messages:
    163
    nope he started it about 2 tiles away from a city to begin with, I happened to conquering the Infernals at the time and saw him but I just didn't really pay attention to what he was doing at the time. Just checked and those 2 still have an open borders agreement. i uploaded a copy of the PythonErr and BBAILog files at the time of the error.

    edit: found the sound file for the Inquisition spell and it was the correct one being played, such an odd sound to be hearing thou in a FFH2 game lol. The requirement code for Inquisition also to me shouldn't allow him to cast that spell in any city that isn't owned by the caster's player.
    Spoiler :
    Code:
    def reqInquisition(caster):
    	pPlot = caster.plot()
    	pCity = pPlot.getPlotCity()
    	pPlayer = gc.getPlayer(caster.getOwner())
    	StateBelief = pPlayer.getStateReligion()
    	
    	if pPlayer.canInquisition():
    		if StateBelief == -1:
    			if caster.getOwner() != pCity.getOwner():
    				return False
    		if (StateBelief != gc.getPlayer(pCity.getOwner()).getStateReligion()):
    			return False
    		for iTarget in range(gc.getNumReligionInfos()):
    			if (StateBelief != iTarget and pCity.isHasReligion(iTarget) and pCity.isHolyCityByType(iTarget) == False):
    				return True
    	return False
    also what exactly does "if pPlayer.canInquisition():" actually check because there is no def in any python file named "Inquisition" and since the xml tags for the spell include the very python code this is in wouldn't that end up being a circular dependancy? (unless maybe it ignores the PyRequirement tag when checking canInquisition?) Also now that I think about it the code that restricts the spell to only the caster's cities doesn't apply unless the caster doesn't have a state religion...
     

    Attached Files:

  7. omegaflames

    omegaflames Warlord

    Joined:
    Sep 21, 2012
    Messages:
    163
    In order to prevent division by zero errors in autologEventManager.py the "def onTechSelected(self, argsList):" needs to be changed to
    Spoiler :
    Code:
    	def onTechSelected(self, argsList):
    		if (AutologOpt.isLogTechnology()):
    			iTechType, iPlayer = argsList
    			if iPlayer == CyGame().getActivePlayer():
    				researchProgress = gc.getTeam(gc.getPlayer(iPlayer).getTeam()).getResearchProgress(gc.getPlayer(iPlayer).getCurrentResearch())
    				overflowResearch = (gc.getPlayer(iPlayer).getOverflowResearch() * gc.getPlayer(iPlayer).calculateResearchModifier(gc.getPlayer(iPlayer).getCurrentResearch()))/100
    				researchCost = gc.getTeam(gc.getPlayer(iPlayer).getTeam()).getResearchCost(gc.getPlayer(iPlayer).getCurrentResearch())
    				researchRate = gc.getPlayer(iPlayer).calculateResearchRate(-1)
    				if researchRate < 1:
    					researchRate = 1
    				zTurns = (researchCost - researchProgress - overflowResearch) / researchRate + 1
    				message = BugUtil.getText("TXT_KEY_AUTOLOG_RESEARCH_BEGUN", (PyInfo.TechnologyInfo(iTechType).getDescription(), zTurns))
    				Logger.writeLog(message, vColor="Green")
     
  8. MagisterCultuum

    MagisterCultuum Great Sage

    Joined:
    Feb 14, 2007
    Messages:
    16,350
    Location:
    Kael's head
    In my current game with my modmod I am getting a crash to desktop whenever I capture Meresin's last city.

    It seems that the problem was caused by the Meresin unit (which is Immortal) being loaded into a Galley which was stationed in the capital city.

    The game did not let him (or the Longbowman who was also in the galley) defend the city from conquest, but automatically destroyed him with his ship when the city was captured. When he died without personally engaging in combat, I think the game tried to resurrect him even though he had no place to go.

    I get the same bug when the city contains a regular Immortal on a Galley in the city when I capture it.

    I have not tested in base MNAI yet, but imagine that there would be an identical problem.

    ----

    This issue wouldn't matter in MNAI as there are no bAlwaysHostile units, but I really think you ought to do something about how units with that tag are treated.

    As things currently stand, they are treated as enemies when they attack units outside of cities, but can enter rival cities peacefully. They cannot however leave those cities peacefully. That is considered an act of war.

    The units can capture superforts without war, but again cannot leave them to enter rival plots without declaring war.

    Normal units trying to enter cities owned by the same player cannot do so if a rival player has a bAlwaysHostile unit stationed there. The bAlways hostile unit is being treated as hostile and yet not hostile at the same time. It is like other units have to attack them in order to enter the tile, but are not permitted to attack them while in the city.

    Those issues are extremely annoying for humans, and are almost guaranteed to cause an AI to get stuck in loops.

    I currently used some rather inefficient code under def unitCannotMoveInto(self,argsList): in my modmod to stop bAlwaysHostile units from entering rival cities or forts without war, but it is an imperfect fix. It wouldn't handle situations where cities change hands, as through Basium's, Rantine's, or Loki's abilities, or cultural flipping.


    I would really like it if you could make it so that bAlwaysHostile units are treated as if they had the bNoCapture tag when it comes to cities and superforts belonging to neutral players. They should be allowed to attack units there, but not capture any territory without a declaration of war. They should be vulnerable to attack while there, and should not have to declare war to leave.

    (I'd also really like it if promotions could grant bAlwaysHostile status too, but that is clearly a feature request and not even arguably a bug fix.)
     
  9. Tholal

    Tholal Emperor

    Joined:
    May 19, 2009
    Messages:
    1,676
    A saved game from a few turns back would be helpful, except that it looks like you are playing one of the alternate versions and not MNAI itself.

    Right. Which means the unit was moved after it started casting. This can happen sometimes with multi-turn spells. Should probably just cancel the spell casting if a unit is moved.

    Spoiler :
    Code:
    def reqInquisition(caster):
    	pPlot = caster.plot()
    	pCity = pPlot.getPlotCity()
    	pPlayer = gc.getPlayer(caster.getOwner())
    	StateBelief = pPlayer.getStateReligion()
    	
    	if pPlayer.canInquisition():
    		if StateBelief == -1:
    			if caster.getOwner() != pCity.getOwner():
    				return False
    		if (StateBelief != gc.getPlayer(pCity.getOwner()).getStateReligion()):
    			return False
    		for iTarget in range(gc.getNumReligionInfos()):
    			if (StateBelief != iTarget and pCity.isHasReligion(iTarget) and pCity.isHolyCityByType(iTarget) == False):
    				return True
    	return False


    It's a DLL call (pretty much anything referencing units, cities, players and teams will be accessing the DLL). There is an option in CivicInfos for a Civic to block the player from Inquisitioning. That tag is unused in MNAI but is there in case any modders want to use it.

    Right. That's for Agnostic civs to clear religions from their cities if they have units who can do so.

    For religious civs, they can Inquisition cities of other players as long as those players are following the same State Religion.


    Thanks!

    OK. I'll look into this. Sounds easy enough to replicate.

    Fair enough. Sounds like the implementation of Always Hostile units was not fully fleshed out or it was intended just for a specific scenario. I'll add it to the list!

    To the list as well!
     
  10. omegaflames

    omegaflames Warlord

    Joined:
    Sep 21, 2012
    Messages:
    163
    I'm playing with my personal mod of MNAI (added in a few things and tweak a few others to my personal taste) so I'm fairly certain a save game wouldn't be playable by you unless I gave you the files I changed as well. I'd like to suggest the following small changes to the inquisition req and cast, not big changes just imho a bit more seamless for the req part and adds in a call to double check the canInquisition part for the cast too.
    Spoiler :
    Code:
    def reqInquisition(caster):
    	pPlot = caster.plot()
    	pCity = pPlot.getPlotCity()
    	pPlayer = gc.getPlayer(caster.getOwner())
    	StateBelief = pPlayer.getStateReligion()
    	if pPlayer.canInquisition():
    		if StateBelief == -1:
    			if caster.getOwner() == pCity.getOwner():
    				return True
    		if (StateBelief == gc.getPlayer(pCity.getOwner()).getStateReligion()):
    			for iTarget in range(gc.getNumReligionInfos()):
    				if (StateBelief != iTarget and pCity.isHasReligion(iTarget) and pCity.isHolyCityByType(iTarget) == False):
    					return True
    	return False
    
    def spellInquisition(caster):
    	pPlot = caster.plot()
    	pCity = pPlot.getPlotCity()
    	pPlayer = gc.getPlayer(caster.getOwner())
    	StateBelief = gc.getPlayer(pCity.getOwner()).getStateReligion()
    	iRnd = CyGame().getSorenRandNum(4, "Bob")
    	if pPlayer.canInquisition():
    		if StateBelief == gc.getInfoTypeForString('RELIGION_THE_ORDER'):
    			iRnd = iRnd - 1
    		for iTarget in range(gc.getNumReligionInfos()):
    			if (StateBelief != iTarget and pCity.isHasReligion(iTarget) and pCity.isHolyCityByType(iTarget) == False):
    				pCity.setHasReligion(iTarget, False, True, True)
    				iRnd = iRnd + 1
    				for i in range(gc.getNumBuildingInfos()):
    					if gc.getBuildingInfo(i).getPrereqReligion() == iTarget:
    						pCity.setNumRealBuilding(i, 0)
    		if iRnd >= 1:
    			pCity.changeHurryAngerTimer(iRnd)
     
  11. omegaflames

    omegaflames Warlord

    Joined:
    Sep 21, 2012
    Messages:
    163
    in CvSpellInterface.py for spellMarchOfTheTrees, spellMotherLode, spellSanctuary, spellWorldbreak the checks for "if pPlot.isOwned():" seem a bit redundant since the code also does a check to see if the plot is owned by the caster and most of any map is going to be owned by someone so most plots would pass the isOwned check anyhow.
     
  12. Tholal

    Tholal Emperor

    Joined:
    May 19, 2009
    Messages:
    1,676
    If you try to call if pPlot.getOwner() on a plot with no Owner, the game will throw an error. Thus, we check beforehand to make sure its owned. There's lots of code in Civ4 that works this way.
     
  13. Terkhen

    Terkhen King

    Joined:
    Aug 1, 2011
    Messages:
    912
    Gender:
    Male
    Location:
    Granada
    In ExtraModMod I have gotten many reports about Loki being too efficient in taking cities over. The biggest problem probably is that he seems to disregard distance (although I checked and the Loki AI code certainly includes a way to penalize distance). In my test games I have also seen him cross Large pangaea maps and steal two or three cities even if they are so far. I think that distance should penalize a lot more how Loki values city targets for Disrupt, or that the * 20 to their value should be reduced.
     
  14. lfgr

    lfgr King

    Joined:
    Feb 6, 2010
    Messages:
    910
    I'm not able to build the dll at revision 1800 or 1806. 1799 works.
    Code:
    1>CvCityAI.cpp(8087): error C2664: 'CvPlot::calculateNatureYield' : cannot convert parameter 2 from 'PlayerTypes' to 'TeamTypes'
    1>          Conversion to enumeration type requires an explicit cast (static_cast, C-style cast or function-style cast)
    
     
  15. Tholal

    Tholal Emperor

    Joined:
    May 19, 2009
    Messages:
    1,676
    Apologies. That line shouldn't have been included yet. That's an upcoming change that I wasn't quite ready to add to the repository (though I will probably expedite things now that I have some out of sync code). Just change the reference to Team ID from Payer ID in the offending line and the build should work.
     
  16. MagisterCultuum

    MagisterCultuum Great Sage

    Joined:
    Feb 14, 2007
    Messages:
    16,350
    Location:
    Kael's head
    I just noticed that GAMEOPTION_START_AS_MINORS is never defined in either CvEnums.h or CIV4GameOptionInfos.xml but is still referenced in python and other DLL source files.

    In the DLL it is line 5016 of CvPlayerAI.cpp and lines 3519 and 3581 of CvTeam.cpp.

    In python it is in lines 52 and 103 of Assets\python\Revolution\Gameready\StartAsMinors.py.

    (It is also found commented out in line 143 of the same file and in lines 1207 and 1766 of Assets\python\Revolution\Gameready\BarbarianCiv.py and lines 165 and 228 of Assets\python\Revolution\RevolutionInit.py)

    This code could probably use cleaning up a bit.
     
  17. lfgr

    lfgr King

    Joined:
    Feb 6, 2010
    Messages:
    910
    Gekko reported that Scorpion clan goblin archers wander off instead of guarding the lair in EMM, because they have UNITAI_CITY_DEFENSE. I confirmed that this happens also in MNAI. In both cases, the problem lies in the initUnit() function. It is passed UNITAI_LAIRGUARDIAN, but that parameter is in the end ignored by AI_reset(), if it is not defined in the XML:
    Code:
    if (eUnitAI != NO_UNITAI)
    {
    	if (!GC.getUnitInfo(getUnitType()).getUnitAIType(eUnitAI))
    	{
    		eUnitAI = (UnitAITypes)GC.getUnitInfo(getUnitType()).getDefaultUnitAIType();
    	}
    }
    
    Lizardman f.e. are later assigned UNTAI_LAIRGUARDIAN (AI_setUnitAIType() has no such restriction), but goblin archers are not.

    Either the restriction should be removed or all units that could spawn as lair guardians should get UNTAI_LAIRGUARDIAN as a possible UnitAI. If you do the latter, I think ignoring the given UnitAI should at least trigger an assert, as it would be obviously a bug.
     
  18. Terkhen

    Terkhen King

    Joined:
    Aug 1, 2011
    Messages:
    912
    Gender:
    Male
    Location:
    Granada
    On line 734 of CustomFunctions (in doHellTerrain), pPlayer is referenced before assignment. This was added as part as the new volcano on hell terrain feature.
     
  19. Terkhen

    Terkhen King

    Joined:
    Aug 1, 2011
    Messages:
    912
    Gender:
    Male
    Location:
    Granada
    CvPlayerAI::AI_getPuppetAttitude is being called at CvGameTextMgr::getAttitudeString, but it is not being called at CvPlayerAI::AI_getAttitudeVal. Therefore, I believe that the attitude change for puppet states is not being taken into account.
     
  20. Tholal

    Tholal Emperor

    Joined:
    May 19, 2009
    Messages:
    1,676
    Fair enough. I'll try some tweaks in that regard.

    All of the references are commented out, so it doesn't hurt anything to have them there (aside from making the code a little messier). I believe I left that code there because I thought it was an interesting idea but needed some changes to make it fit better with FFH. I'll make a note to take a look at it and either remove the code or put in a tracking issue for implementing it as an option.

    I have a fix for this that I just haven't gotten around to uploading. The initial unit created on the plot will always be set to UNITAI_LAIRGUARDIAN (not just Lizardmen). The real issue is that subsequent units keep their city defense AI and try and head for the nearest barbarian city. My fix was to allow Scorpion Clan Goblin Archers to use UNITAI_ATTACK so that they will move off to harass players instead. Edit: I see now. It's the initial spawn that is not being set correctly. Goblin Forts are a special case in python. I'll add UNITAI_LAIRGUARDIAN to their XML.


    Note: I also saw your Puppet States fix/patch. Will try to merge that this week. Thanks!


    Thanks! I will fix both of these issues.
     

Share This Page