FfH2 0.23 Bug Thread

Discussion in 'Civ4 - Fall from Heaven' started by Kael, Jul 13, 2007.

  1. Sureshot

    Sureshot Goddess

    Joined:
    Feb 2, 2006
    Messages:
    3,771
    the weirdest part is seeing things like:

    4.00 str versus 4.00 str, both full health with odds like 60%
     
  2. Gabriel21

    Gabriel21 Warlord

    Joined:
    Jun 5, 2007
    Messages:
    207
    With Tears of Sucellus one usually can heal (30%) a unit per turn. But it needs life mana. As Malakim you have life mana from the beginning, but you cannot heal units until you have a life mana node extra. Should not be, isn't it?
    Editing: It seems to be only an "incorrect" translation in the German version. It's the Shrine of Sucellus, of course.
     
  3. Gabriel21

    Gabriel21 Warlord

    Joined:
    Jun 5, 2007
    Messages:
    207
    I fully agree with you, it is ununderstandable loosing regulary a fight with 99,7% or similar, even when you reload several times to try it out. It seems to me the AI plays uncorrectly for it is far from a probability calculation. And winning a fight with a 1,2% quote is crazy.
     
  4. DarthCycle

    DarthCycle WWII Freako

    Joined:
    Jul 25, 2005
    Messages:
    290
    In version .23c

    When using a unit with the fear promotion; when the unit attacks and wins combat, all defending units will retreat from the defending location and the attacking unit will move in the location; this do not occur in cities though.

    I thought that fear was effective during defense: an attacking unit would break its attack against the unit with the fear promotion.
     
  5. vorshlumpf

    vorshlumpf Emperor

    Joined:
    Dec 5, 2003
    Messages:
    1,096
    Location:
    Victoria, BC, Canada
    This is as designed. I'm not sure where I read it - perhaps in the 'Pedia under the Fear promotion.
     
  6. Annex

    Annex Tyranny and Mutation

    Joined:
    Jul 20, 2007
    Messages:
    2,230
    Location:
    New York State
    This may be intentional, but when i use an adept to construct wall of stone i still need to build city walls in order to build a castle.
     
  7. vorshlumpf

    vorshlumpf Emperor

    Joined:
    Dec 5, 2003
    Messages:
    1,096
    Location:
    Victoria, BC, Canada
    Yeah, the stone wall from the spell is temporary. If you move your adept out of the city, the wall is gone.
     
  8. xanaqui42

    xanaqui42 King

    Joined:
    Sep 5, 2006
    Messages:
    780
    RE:Comments from my last two posts: I'd be happy to discuss those issues on another thread.

    Suggested fix; let me know if you want more detail.
    Spoiler :
    Code:
    CvUnit::updateCombat
    ...
    			iAttackerStrength = currCombatStr(NULL, NULL, &cdAttackerDetails, true, pDefender); // Smarter Orcs
    			iAttackerFirepower = currFirepower(NULL, NULL, true, pDefender); // Smarter Orcs
    
    
    //FfH: Added by Kael 03/06/2007
    int CvUnit::maxCombatStr(const CvPlot* pPlot, const CvUnit* pAttacker, CombatDetails* pCombatDetails) const
    {
        return maxCombatStr(pPlot, pAttacker, pCombatDetails, true, NULL);//Smarter Orcs
    }
    //FfH: End Add
    
    //FfH: Modified by Kael 12/22/2006
    //int CvUnit::maxCombatStr(const CvPlot* pPlot, const CvUnit* pAttacker, CombatDetails* pCombatDetails) const
    // BetterAI start
    // maxCombatStr can be called in four different configurations
    //		pPlot == NULL, pAttacker == NULL for combat when this is the attacker
    //		pPlot valid, pAttacker valid for combat when this is the defender
    //		pPlot valid, pAttacker == NULL (new case), when this is the defender, attacker unknown
    //		pPlot valid, pAttacker == this (new case), when the defender is unknown, but we want to calc approx str
    //			note, in this last case, it is expected pCombatDetails == NULL, it does not have to be, but some
    //			values may be unexpectedly reversed in this case (iModifierTotal will be the negative sum)
    // BetterAI end
    //Smarter Orcs start
    // In:	pDefender - the defending unit.
    int CvUnit::maxCombatStr(const CvPlot* pPlot, const CvUnit* pAttacker, CombatDetails* pCombatDetails, bool bAttacking, const CvUnit* pDefender) const
    // Smarter Orcs end
    //FfH: End Modify
    
    {
    	 // CvCity* pCity; // BetterAI removal
    	int iModifier;
    	int iCombat;
    
    	FAssertMsg((pPlot == NULL) || (pPlot->getTerrainType() != NO_TERRAIN), "(pPlot == NULL) || (pPlot->getTerrainType() is not expected to be equal with NO_TERRAIN)");
    	FAssertMsg((pAttacker == NULL) || (pDefender == NULL),"Improper call!"); // Smarter Orcs
    ...
    
    // Following replaces the resistance code:
    	// Smarter Orcs start
    	int iResistCold = 0;
    	int iResistDeath = 0;
    	int iResistFire = 0;
    	int iResistHoly = 0;
    	int iResistLightning = 0;
    	int iResistPoison = 0;
    	int iResistUnholy = 0;
    	const CvUnit *pOtherUnit;
    
    	
    	if (pAttacker != NULL)
        {
    		pOtherUnit = pAttacker;
    	}
    	else if (pDefender != NULL)
        {
    		pOtherUnit = pDefender;
    	}
    	else
    	{
    		pOtherUnit = NULL;
    	}
    	if (pOtherUnit != NULL)
    	{
    		iResistCold = pOtherUnit->getResistCold();
    		iResistDeath = pOtherUnit->getResistDeath();
    		iResistFire = pOtherUnit->getResistFire();
    		iResistHoly = pOtherUnit->getResistHoly();
    		iResistLightning = pOtherUnit->getResistLightning();
    		iResistPoison = pOtherUnit->getResistPoison();
    		iResistUnholy = pOtherUnit->getResistUnholy();
    	}
        if (getCombatCold() != 0)
        {
            iCombat += getCombatCold() * (100 - iResistCold);
        }
        if (getCombatDeath() != 0)
        {
            iCombat += getCombatDeath() * (100 - iResistDeath);
        }
        if (getCombatFire() != 0)
        {
            iCombat += getCombatFire() * (100 - iResistFire);
        }
        if (getCombatHoly() != 0)
        {
            iCombat += getCombatHoly() * (100 - iResistHoly);
        }
        if (getCombatLightning() != 0)
        {
            iCombat += getCombatLightning() * (100 - iResistLightning);
        }
        if (getCombatPoison() != 0)
        {
            iCombat += getCombatPoison() * (100 - iResistPoison);
        }
        if (getCombatUnholy() != 0)
        {
            iCombat += getCombatUnholy() * (100 - iResistUnholy);
        }
    	// Smarter Orcs end
    
    //FfH: Added by Kael 03/06/2007
    int CvUnit::currCombatStr(const CvPlot* pPlot, const CvUnit* pAttacker, CombatDetails* pCombatDetails) const
    {
        return currCombatStr(pPlot, pAttacker, pCombatDetails, true, NULL); // Smarter Orcs
    }
    //FfH: End Add
    
    //FfH: Modified by Kael 12/22/2006
    //int CvUnit::currCombatStr(const CvPlot* pPlot, const CvUnit* pAttacker, CombatDetails* pCombatDetails) const
    //{
    //	return ((maxCombatStr(pPlot, pAttacker, pCombatDetails) * currHitPoints()) / maxHitPoints());
    //}
    // Smarter Orcs start
    int CvUnit::currCombatStr(const CvPlot* pPlot, const CvUnit* pAttacker, CombatDetails* pCombatDetails, bool bAttacking, const CvUnit* pDefender) const
    {
    	return ((maxCombatStr(pPlot, pAttacker, pCombatDetails, bAttacking, pDefender) * currHitPoints()) / maxHitPoints());
    	// Smarter Orcs end
    }
    //FfH: End Modify
    
    //FfH: Added by Kael 03/06/2007
    int CvUnit::currFirepower(const CvPlot* pPlot, const CvUnit* pAttacker) const
    {
        return currFirepower(pPlot, pAttacker, true, NULL); // Smarter Orcs
    }
    //FfH: End Add
    
    //FfH: Modified by Kael 12/22/2006
    //int CvUnit::currFirepower(const CvPlot* pPlot, const CvUnit* pAttacker) const
    //{
    //	return ((maxCombatStr(pPlot, pAttacker) + currCombatStr(pPlot, pAttacker) + 1) / 2);
    // Smarter Orcs start
    int CvUnit::currFirepower(const CvPlot* pPlot, const CvUnit* pAttacker, bool bAttacking, const CvUnit* pDefender) const
    {
    	return ((maxCombatStr(pPlot, pAttacker, NULL, bAttacking, pDefender) + currCombatStr(pPlot, pAttacker, NULL, bAttacking, pDefender) + 1) / 2);
    	// Smarter Orcs end
    //FfH: End Modify
    }
    
    //BetterAI start
    // this nomalizes str by firepower, useful for quick odds calcs
    // the effect is that a damaged unit will have an effective str lowered by firepower/maxFirepower
    // doing the algebra, this means we mulitply by 1/2(1 + currHP)/maxHP = (maxHP + currHP) / (2 * maxHP)
    int CvUnit::currEffectiveStr(const CvPlot* pPlot, const CvUnit* pAttacker, CombatDetails* pCombatDetails) const
    {
    	return currEffectiveStr(pPlot, pAttacker, pCombatDetails, true);
    }
    //Smarter Orcs start
    int CvUnit::currEffectiveStr(const CvPlot* pPlot, const CvUnit* pAttacker, CombatDetails* pCombatDetails, bool bAttacking, const CvUnit* pDefender) const // Smarter Orcs
    {
    	int currStr = currCombatStr(pPlot, pAttacker, pCombatDetails, bAttacking, pDefender); // Smarter Orcs
    
    	currStr *= (maxHitPoints() + currHitPoints());
    	currStr /= (2 * maxHitPoints());
    
    	return currStr;
    }
    //Smarter Orcs end
    //BetterAI end
    //FfH: Added by Kael 03/06/2007
    float CvUnit::maxCombatStrFloat(const CvPlot* pPlot, const CvUnit* pAttacker) const
    {
        return maxCombatStrFloat(pPlot, pAttacker, true, NULL);// Smarter Orcs
    }
    //FfH: End Add
    
    //FfH: Modified by Kael 12/22/2006
    //float CvUnit::maxCombatStrFloat(const CvPlot* pPlot, const CvUnit* pAttacker) const
    //{
    //	return (((float)(maxCombatStr(pPlot, pAttacker))) / 100.0f);
    //Smarter Orcs start
    float CvUnit::maxCombatStrFloat(const CvPlot* pPlot, const CvUnit* pAttacker, bool bAttacking, const CvUnit* pDefender) const
    {
    	return (((float)(maxCombatStr(pPlot, pAttacker, NULL, bAttacking, pDefender))) / 100.0f);
    	// Smarter Orcs end
    //FfH: End Modify
    }
    
    //FfH: Added by Kael 03/06/2007
    float CvUnit::currCombatStrFloat(const CvPlot* pPlot, const CvUnit* pAttacker) const
    {
        return currCombatStrFloat(pPlot, pAttacker, true, NULL);//Smarter Orcs
    }
    //FfH: End Add
    
    //FfH: Modified by Kael 12/22/2006
    //float CvUnit::currCombatStrFloat(const CvPlot* pPlot, const CvUnit* pAttacker) const
    //{
    //	return (((float)(currCombatStr(pPlot, pAttacker))) / 100.0f);
    //Smarter Orcs start
    float CvUnit::currCombatStrFloat(const CvPlot* pPlot, const CvUnit* pAttacker, bool bAttacking, const CvUnit* pDefender) const
    {
    	return (((float)(currCombatStr(pPlot, pAttacker, NULL, bAttacking, pDefender))) / 100.0f);
    	// Smarter Orcs end
    //FfH: End Modify
    }
    ...
    bool CvGameTextMgr::setCombatPlotHelp(CvWString &szString, CvPlot* pPlot)
    {
    ...
    			szOffenseOdds.Format(L"%.2f", ((pAttacker->getDomainType() == DOMAIN_AIR) ? pAttacker->airCurrCombatStrFloat() : pAttacker->currCombatStrFloat(NULL, NULL, true, pDefender))); // Smarter Orcs
    ...
    int CvUnitAI::AI_attackOdds(const CvPlot* pPlot, bool bPotentialEnemy) const
    {
    ...
    	iOurStrength = ((getDomainType() == DOMAIN_AIR) ? airCurrCombatStr() : currCombatStr(NULL, NULL, NULL, true, pDefender)); // Smarter Orcs
    	iOurFirepower = ((getDomainType() == DOMAIN_AIR) ? iOurStrength : currFirepower(NULL, NULL, true, pDefender)); // Smarter Orcs
    ...
    int getCombatOdds(CvUnit* pAttacker, CvUnit* pDefender)
    {
    ...
    	iAttackerStrength = pAttacker->currCombatStr(NULL, NULL, NULL, true, pDefender); // Smarter Orcs
    	iAttackerFirepower = pAttacker->currFirepower(NULL, NULL, true, pDefender); // Smarter Orcs
    ...
    // CvUnit.h:
    
    	int currEffectiveStr(const CvPlot* pPlot, const CvUnit* pAttacker, CombatDetails* pCombatDetails = NULL, bool bAttacker = true, const CvUnit* pDefender = NULL) const; // BetterAI // Smarter Orcs
    	DllExport float maxCombatStrFloat(const CvPlot* pPlot, const CvUnit* pAttacker) const;																	// Exposed to Python
    	DllExport float currCombatStrFloat(const CvPlot* pPlot, const CvUnit* pAttacker) const;																	// Exposed to Python
    
    //FfH: Added by Kael 12/22/2006
    	DllExport int maxCombatStr(const CvPlot* pPlot, const CvUnit* pAttacker, CombatDetails* pCombatDetails = NULL, bool bAttacking = true, const CvUnit* pDefender = NULL) const; // Smarter Orcs
    	DllExport int currCombatStr(const CvPlot* pPlot, const CvUnit* pAttacker, CombatDetails* pCombatDetails = NULL, bool bAttacking = true, const CvUnit* pDefender = NULL) const; // Smarter Orcs
    	DllExport int baseCombatStr(bool bAttacking = true) const;
    	DllExport int currFirepower(const CvPlot* pPlot, const CvUnit* pAttacker, bool bAttacking = true, const CvUnit* pDefender = NULL) const; // Smarter Orcs
    	DllExport float maxCombatStrFloat(const CvPlot* pPlot, const CvUnit* pAttacker, bool bAttacking = true, const CvUnit* pDefender = NULL) const; // Smarter Orcs
    	DllExport float currCombatStrFloat(const CvPlot* pPlot, const CvUnit* pAttacker, bool bAttacking = true, const CvUnit* pDefender = NULL) const; // Smarter Orcs
    //FfH: End Add
    
    


    I should note that the main known issue with this code is that if a defender is immune to all the attacker's damage, the attack is still valid, but the attacker's strength is treated as 0.01. I am not certain that this is desired (or undesired) behavior; I merely consider it far better than ignoring the defender's resistances.
     
  9. xanaqui42

    xanaqui42 King

    Joined:
    Sep 5, 2006
    Messages:
    780
    It is possible for a unit to gain over 100% resistance. With the current math (or the math I suggest above), any resistance above 100% is treated as a negative toward the rest of the other creature's strength (in other words, a creature with 100% fire resistance attacking a Fire Elemental would not do as well as one with 120% resistance, but is otherwise the same). I'm not certain if that is desired.
     
  10. Grillick

    Grillick Prince

    Joined:
    Jul 19, 2006
    Messages:
    311
    Location:
    Albuquerque, NM
    I'm experiencing a crash while playing Hyborem. It occurs when I research Divine Essence, but I don't know if that is the cause.

    I can't upload the save here, because it is too large.

    How can I sent it, and to whom?
     
  11. HammerU89

    HammerU89 Chieftain

    Joined:
    Aug 8, 2007
    Messages:
    4
    Come across another error after it continues to crash from time to time. This one is found over and over in my xml.log file.

    Code:
    [3093.546] info type UNITCLASS_HIGH_PRIEST not found, Current XML file is: Misc/Civ4TutorialInfos.xml
    [3093.546] info type UNITCLASS_MONK not found, Current XML file is: Misc/Civ4TutorialInfos.xml
    [3093.546] info type UNITCLASS_CAMEL_ARCHER not found, Current XML file is: Misc/Civ4TutorialInfos.xml
    [3093.546] info type BUILDING_DWARVEN_FORGE not found, Current XML file is: Misc/Civ4TutorialInfos.xml
    Not quite sure why it's looking in that file, there's only a this in that file.

    Code:
    <?xml version="1.0" ?> 
    - <!--  edited with XMLSPY v2004 rel. 2 U (http://www.xmlspy.com) by Ed Piper (Firaxis Games) 
      --> 
    - <!--  Sid Meier's Civilization 4 
      --> 
    - <!--  Copyright Firaxis Games 2005 
      --> 
    - <!--  
      --> 
    - <!--  Tutorial Infos 
      --> 
    - <Civ4TutorialInfos xmlns="x-schema:CIV4TutorialSchema.xml">
    - <TutorialInfo>
      <Type>TUTORIAL_INTRODUCTION</Type> 
    - <TutorialMessages>
    - <TutorialMessage>
      <TutorialMessageText>Welcome to Sid Meiers Civilization 4.</TutorialMessageText> 
      <TutorialMessageImage>ART_DEF_TUTORIAL_CIV4LOGO</TutorialMessageImage> 
      <TutorialMessageSound>AS2D_TUTORIAL_INTRODUCTION_1</TutorialMessageSound> 
      </TutorialMessage>
      </TutorialMessages>
      </TutorialInfo>
      </Civ4TutorialInfos>
    I doubt this will fix my current problem with the constent crashing from time to time, but it sure can't harm it by trying to correct the problem.
     
  12. xanaqui42

    xanaqui42 King

    Joined:
    Sep 5, 2006
    Messages:
    780
    The problem (if there is one) is in other XML files. The information above suggests that CVI4UnitClassInfos.xml and CIV4BuildingInfos.xml are missing/corrupt/not loading successfully, or possibly just loading after the tutorial file.
     
  13. xanaqui42

    xanaqui42 King

    Joined:
    Sep 5, 2006
    Messages:
    780
    I'd zip it or rar it, then post it here.
     
  14. The Tyrant

    The Tyrant Prince

    Joined:
    Mar 1, 2006
    Messages:
    445
    On a wrap-around map, which most maps are, the spread of hell terrain does not wrap around. It goes to the "edge" of the map (what you see in the minimap) and then stops. This is significant when Hyborem spawns near the edge of the map.

    EDIT: (a month later...) Okay, I just had a game where the spread of hell terrain did wrap around. Now I wish I had kept a savegame from the time it didn't wrap. In the game where it didn't wrap, Hyborem spawned very near the western edge of the map. Hell terrain spread far to the east, but never crossed the short water expanse to enter my lands to the west. There was no alignment or AC counter reason for it not to spread. I have no idea what caused the initial result, but I just had a game where hell terrain did wrap around the edge of the map. 'Just thought I would update this post with that information.
     
  15. vorshlumpf

    vorshlumpf Emperor

    Joined:
    Dec 5, 2003
    Messages:
    1,096
    Location:
    Victoria, BC, Canada
    Interesting. That is one more issue at the map edge, then - I wonder why the edge causes so much trouble.
     
  16. clut

    clut Warlord

    Joined:
    Jul 27, 2005
    Messages:
    140
    I've captured a wolf, and have sent it back to my capital.

    Just as my wolf is entering my capital, it turns out that Garrim Gyr (with whom I have open borders) has a scout in my capital. Instead of just entering the tile, my wolf attacks Garrim Gyr's scout and dies.

    I understand that my wolf had HN, and therefore could attack without fear of causing a war, but I really didn't want it to attack. Is there anyway of stopping this?... and no, I don't want to hand-hold my wolf all the way back to the capital 1 tile at a time making sure he doesn't attack anyone.
     
  17. jwin

    jwin Warlord

    Joined:
    Jan 30, 2007
    Messages:
    254
    Location:
    NY
    You can declare nationality. If you want to put him in a pen, it doesn't matter if you do or not. Otherwise, no you have to hold his paw all the way to a city.
    Keep in mind, once in the city HN is off, so they are safe from attacks from others.
     
  18. jonottawa

    jonottawa Chieftain

    Joined:
    Dec 11, 2006
    Messages:
    33
    To what jwin said I'd add that Garrim Gyr's scout would have attacked your wolf anyway, so 'handholding' really isn't the issue.

    If you want to add an animal to a carnival or create a dancing bear with it or whatever, declare nationality.

    If you want to use it as a HN mercenary, treat it like any other HN mercenary. (Stack it with other HN units and keep an eye on it lest it be removed from the ecosystem by a more powerful AI unit or stack.)
     
  19. xanaqui42

    xanaqui42 King

    Joined:
    Sep 5, 2006
    Messages:
    780
    Here's the fixed code:

    Spoiler :
    Code:
    // Smarter Orcs start- defect fix.
    //
    // creates a derived artItem class which automatically registers itself with the ARTFILEMGR upon contruction.
    // creates a static var of that artItem type which constructs (and registers) at startup.
    // creates a getFooArtInfo() function that searches the map based on the id provided and returns the artInfo struct or null.
    //
    #define ART_INFO_DEFN(name) \
    \
    class Cv##name##ArtInfoItem : public CvArtFileMgr::ArtInfoItem \
    { \
    	void init() { ARTFILEMGR.m_map##name##ArtInfos = new CvArtFileMgr::ArtInfo##name##MapType; } \
    	void deInit() { SAFE_DELETE(ARTFILEMGR.m_map##name##ArtInfos); SAFE_DELETE_ARRAY(ARTFILEMGR.m_pa##name##ArtInfo); } \
    	void buildMap() { BUILD_INFO_MAP(*ARTFILEMGR.m_map##name##ArtInfos, ARTFILEMGR.get##name##ArtInfo, ARTFILEMGR.getNum##name##ArtInfos()); } \
    }; \
    \
    static Cv##name##ArtInfoItem g##name##ArtInfoItem; \
    \
    CvArtInfo##name##* CvArtFileMgr::get##name##ArtInfo( const char *szArtDefineTag ) const \
    { \
    	FAssertMsg(szArtDefineTag, "NULL string on art info lookup?"); \
    	ArtInfo##name##MapType::const_iterator it = m_map##name##ArtInfos->find( szArtDefineTag );\
    	if ( it == m_map##name##ArtInfos->end() ) \
    	{\
    		char szErrorMsg[256]; \
    		sprintf(szErrorMsg, "get##name##ArtInfo: %s was not found", szArtDefineTag); \
    		FAssertMsg(false, szErrorMsg ); \
    		int iCompare = strncmp( szArtDefineTag, "ERROR", strlen(szArtDefineTag) ); \
    		if ( iCompare == 0 ) \
    		{ \
    			return NULL; \
    		} \
    		else \
    		{ \
    			return get##name##ArtInfo( "ERROR" ); \
    		} \
    	} \
    	return it->second; \
    } \
    CvArtInfo##name##& CvArtFileMgr::get##name##ArtInfo(int i) { return m_pa##name##ArtInfo[i]; }
    // Smarter Orcs end
    


    The changed lines are:
    Code:
    		int iCompare = strncmp( szArtDefineTag, "ERROR", strlen(szArtDefineTag) ); \
    		if ( iCompare == 0 ) \
    The original code was attempting to compare szArtDefineTag directly with "ERROR", which (while valid in most cases in python) will always return false in C++ (save in a single contrived edge case). This would cause it to go down the error branch, which causes an infinite recursive loop, and a crash at the stack overflow.

    This appears to be a vanilla defect as well.
     
  20. Gabriel21

    Gabriel21 Warlord

    Joined:
    Jun 5, 2007
    Messages:
    207
    Thank you, Sureshot :) , for this valuable advice, now I know, why the odds are always the same.
     

Share This Page