FfH2 0.33 Bug Thread

In a no-settler game i had Tebryn was Ashen (suprise) and in his capital i spotted 30 ents. I was sailing down there and got killed by a stack of kraken.

WTH?

Ah, yes... the Chaos III spell, Wonder, has a chance of summoing permanent Treants (e.g. Ents) and Krakens. Tebryn starts with Chaos Mana. Some Archmage must have been having some fun.
 
Phyton error during AI turn.
 

Attachments

  • Civ4ScreenShot0008.JPG
    Civ4ScreenShot0008.JPG
    239.5 KB · Views: 98
AI_unitUpdate

In AI_unitUpdate, the return value 1 is supposed to be used to indicate that the move is handled in python, however, this python function doesn't actually handle the move on that layer. It should do the equivalent of:

getGroup()->pushMission(MISSION_SKIP);

To indicate that a particular group should skip its move.

Since it doesn't, bool CvSelectionGroupAI::AI_update() fails its infinite loop check (thus looping 100 times instead of 0 - this may be a time resource drain).

I have the following patch in the C++ code in my next version of Wiser Orcs, but I think it would be better to fix this in python, in case you'd like to actually handle non-skip moves in the future in AI_unitUpdate:

Code:
bool CvUnitAI::AI_update()
{
	PROFILE_FUNC();

	CvUnit* pTransportUnit;

	FAssertMsg(canMove(), "canMove is expected to be true");
	FAssertMsg(isGroupHead(), "isGroupHead is expected to be true"); // XXX is this a good idea???

	// allow python to handle it
	CyUnit* pyUnit = new CyUnit(this);
	CyArgsList argsList;
	argsList.add(gDLL->getPythonIFace()->makePythonObject(pyUnit));	// pass in unit class
	long lResult=0;
	gDLL->getPythonIFace()->callFunction(PYGameModule, "AI_unitUpdate", argsList.makeFunctionArgs(), &lResult);
	delete pyUnit;	// python fxn must not hold on to this pointer
	if (lResult == 1)
	{
[B]		// Wiser Orcs start - prevent infinite loop.
		if (getGroup()->getLengthMissionQueue() < 1)
		{
			getGroup()->pushMission(MISSION_SKIP);  //TODO: check if this prevents spellcasting.
		}
		// Wiser Orcs end
[/B]		return false;
	}

CvUnit::healRate

You added the following code:

Code:
//FfH Mana Effects: Added by Kael 08/21/2007
                iTotalHeal += GET_PLAYER(pPlot->getOwnerINLINE()).getHealChangeEnemy();
//FfH: End Add
This will not work correctly if pPlot->getOwnerINLINE() == NO_PLAYER.

Suggested fix:
Code:
//FfH Mana Effects: Added by Kael 08/21/2007
[B]				// Wiser Orce start - defect fix
				if (pPlot->getOwnerINLINE() != NO_PLAYER)
				{
[/B]					iTotalHeal += GET_PLAYER(pPlot->getOwnerINLINE()).getHealChangeEnemy();
[B]				}
				// Wiser Orcs end[/B]
//FfH: End Add

CvUnit::changeExtraEnemyHeal, CvUnit::changeExtraNeutralHeal, CvUnit::changeExtraFriendlyHeal
I'd suggest removing the asserts. They will trigger on any negative heal promotion.

CvPlayer::changeImprovementYieldChange

I'd suggest removing the last assert. Agriculture (as an example) will trigger it.
 
Kael said that he's going to fix it in patch "e," you'll see that in the first post in this thread.
I know it, but next patch could break save games (and it could appeared at the end of the week), and I have some really fun game now (first time from ages), which I don`t want to break. So I just want to fix it by myself in my game.
 
Any idea on why, when winning the race to infernal pact, I get the option to play as Hyborem/Infernal, and when I hit yes, Dis is already founded and has no demonic citizens?

patch c
 
Sorry, I wanted to test the code a bit longer and didn't think Kael's patch was coming up so soon. I am pretty sure he used the code I supplied to "fix" assimilation, but I learned in FF it broke UpgradeCivilization. Attached is the full (so far) working edit.

Spoiler :
Code:
CvCity* CvUnit::getUpgradeCity(UnitTypes eUnit, bool bSearch, int* iSearchValue) const
{
	if (eUnit == NO_UNIT)
	{
		return false;
	}

	CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
	CvUnitInfo& kUnitInfo = GC.getUnitInfo(eUnit);

//FfH: Modified by Kael 05/09/2008
//	if (GC.getCivilizationInfo(kPlayer.getCivilizationType()).getCivilizationUnits(kUnitInfo.getUnitClassType()) != eUnit)
//	{
//		return false;
//	}
    if (m_pUnitInfo->getUpgradeCiv() == NO_CIVILIZATION)
    {
/*************************************************************************************************/
/**	Xienwolf Tweak							08/20/08								Xienwolf	**/
/**																								**/
/**				Enables upgrades to Unique Units in Assimilated Cities							**/
/*************************************************************************************************/
/**								---- Start Original Code ----									**
        if (GC.getCivilizationInfo(kPlayer.getCivilizationType()).getCivilizationUnits(kUnitInfo.getUnitClassType()) != eUnit)
        {
            return false;
        }
/**								----  End Original Code  ----									**/
        if (!kPlayer.isAssimilation())
            if (GC.getCivilizationInfo(kPlayer.getCivilizationType()).getCivilizationUnits(kUnitInfo.getUnitClassType()) != eUnit)
                return false;
/*************************************************************************************************/
/**	Xienwolf Tweak							END													**/
/*************************************************************************************************/
    }
    else
    {
        if (GC.getCivilizationInfo((CivilizationTypes)m_pUnitInfo->getUpgradeCiv()).getCivilizationUnits(kUnitInfo.getUnitClassType()) != eUnit)
        {
            return false;
        }
    }
//FfH: End Modify

	if (!upgradeAvailable(getUnitType(), ((UnitClassTypes)(kUnitInfo.getUnitClassType()))))
	{
		return false;
	}

	if (kUnitInfo.getCargoSpace() < getCargo())
	{
		return false;
	}

	CLLNode<IDInfo>* pUnitNode = plot()->headUnitNode();
	while (pUnitNode != NULL)
	{
		CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = plot()->nextUnitNode(pUnitNode);

		if (pLoopUnit->getTransportUnit() == this)
		{
			if (kUnitInfo.getSpecialCargo() != NO_SPECIALUNIT)
			{
				if (kUnitInfo.getSpecialCargo() != pLoopUnit->getSpecialUnitType())
				{
					return false;
				}
			}

			if (kUnitInfo.getDomainCargo() != NO_DOMAIN)
			{
				if (kUnitInfo.getDomainCargo() != pLoopUnit->getDomainType())
				{
					return false;
				}
			}
		}
	}

	// sea units must be built on the coast
	bool bCoastalOnly = (getDomainType() == DOMAIN_SEA);

	// results
	int iBestValue = MAX_INT;
	CvCity* pBestCity = NULL;

	// if search is true, check every city for our team
	if (bSearch)
	{
		// air units can travel any distance
		bool bIgnoreDistance = (getDomainType() == DOMAIN_AIR);

		TeamTypes eTeam = getTeam();
		int iArea = getArea();
		int iX = getX_INLINE(), iY = getY_INLINE();

		// check every player on our team's cities
		for (int iI = 0; iI < MAX_PLAYERS; iI++)
		{
			// is this player on our team?
			CvPlayerAI& kLoopPlayer = GET_PLAYER((PlayerTypes)iI);
			if (kLoopPlayer.isAlive() && kLoopPlayer.getTeam() == eTeam)
			{
				int iLoop;
				for (CvCity* pLoopCity = kLoopPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = kLoopPlayer.nextCity(&iLoop))
				{
					// if coastal only, then make sure we are coast
					CvArea* pWaterArea = NULL;
					if (!bCoastalOnly || ((pWaterArea = pLoopCity->waterArea()) != NULL && !pWaterArea->isLake()))
					{
						// can this city tran this unit?

//FfH Units: Modified by Kael 05/24/2008
//						if (pLoopCity->canTrain(eUnit, false, false, true))
						if (pLoopCity->canUpgrade(eUnit, false, false, true))
//FfH: End Modify

						{
							// if we do not care about distance, then the first match will do
							if (bIgnoreDistance)
							{
								// if we do not care about distance, then return 1 for value
								if (iSearchValue != NULL)
								{
									*iSearchValue = 1;
								}

								return pLoopCity;
							}

							int iValue = plotDistance(iX, iY, pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE());

							// if not same area, not as good (lower numbers are better)
							if (iArea != pLoopCity->getArea() && (!bCoastalOnly || iArea != pWaterArea->getID()))
							{
								iValue *= 16;
							}

							// if we cannot path there, not as good (lower numbers are better)
							if (!generatePath(pLoopCity->plot(), 0, true))
							{
								iValue *= 16;
							}

							if (iValue < iBestValue)
							{
								iBestValue = iValue;
								pBestCity = pLoopCity;
							}
						}
					}
				}
			}
		}
	}
	else
	{
		// find the closest city
		CvCity* pClosestCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), NO_PLAYER, getTeam(), true, bCoastalOnly);
		if (pClosestCity != NULL)
		{
/*************************************************************************************************/
/**	Xienwolf Tweak							08/20/08								Xienwolf	**/
/**																								**/
/**				Enables upgrades to Unique Units in Assimilated Cities							**/
/*************************************************************************************************/
                    if (kPlayer.isAssimilation() && (m_pUnitInfo->getUpgradeCiv() == NO_CIVILIZATION))
                        if (GC.getCivilizationInfo(pClosestCity->getCivilizationType()).getCivilizationUnits(kUnitInfo.getUnitClassType()) != eUnit && GC.getCivilizationInfo(kPlayer.getCivilizationType()).getCivilizationUnits(kUnitInfo.getUnitClassType()) != eUnit)
                            return false;
/*************************************************************************************************/
/**	Xienwolf Tweak							END													**/
/*************************************************************************************************/
			// if we can train, then return this city (otherwise it will return NULL)

//FfH Units: Modified by Kael 08/07/2007
//			if (pClosestCity->canTrain(eUnit, false, false, true))
			if (pClosestCity->canUpgrade(eUnit, false, false, true))
//FfH: End Add

			{
				// did not search, always return 1 for search value
				iBestValue = 1;

				pBestCity = pClosestCity;
			}
		}
	}

	// return the best value, if non-NULL
	if (iSearchValue != NULL)
	{
		*iSearchValue = iBestValue;
	}

	return pBestCity;
}
 
So it`s the reason, why my Centaur Charger (Kuriotates) killed another Centaur Charger (Grigori) 10 minutes ago ;)
 
I've attached a save from patch D. In it you can see Ljosalfar Balor (!), Sheiam Wolfriders and Centaur as well as Basium when Hyborem hasn't entered the game yet.

The problem I had with immortal units being reborn when upgraded or sacrificing themselves to found religion was in patch B but I didn't get a chance to test it this game.

I was going for a cultural victory with Cardith Lorda. I noticed a quirk. When a city flips to Kuriotates, you are prompted if you want a settlement or city but the camera doesn't center on the city in question. After you choose you are told a city flips to you. Not a big deal since you can upgrade settlements now.
 

Attachments

0.33D:

just end the turn:

Code:
Traceback (most recent call last):

  File "CvSpellInterface", line 21, in canCast

  File "<string>", line 0, in ?

  File "CvSpellInterface", line 399, in reqCommanderJoin

NameError: global name 'pPlot' is not defined
ERR: Python function canCast failed, module CvSpellInterface
 
fire immune units get collateral damage from fireballs and if there are other units in the stack, which are not immune to fire, however, they are picked as defender, in most of the time.
think that is also true for all other non-physical damage.
 
It appears that wolf riders and centaurs have no upgrade requirement...

.33 Patch D.

Settings:
Standard Size
Erebus Map
19 Civs
Monarch
Raging Barbarians
Aggressive AI
Permanent Alliances
Require Complete Kills
Barbarian World
Blessing of Amathon
Living World

Conquest, Religious, Tower, and Altar Victories on.

My scout shows that he can upgrade to a Centaur and a Wolf rider right off the bat (once you get horseback riding or start on classical start)

I will try a clean install to ensure there are no changes...
 
I haven't tested it yet, but I am uncertain if the fix to Hidden Nationality being forceably removed is accurate.

Rather than:
Code:
        m_iHiddenNationality += iNewValue;
        if (!isHiddenNationality())
        {
            updatePlunder(-1, false);
            joinGroup(NULL, true);
            updatePlunder(1, false);
        }

I think it ought to be

Code:
        updatePlunder(-1, false);
        m_iHiddenNationality += iNewValue;
        joinGroup(NULL, true);
        updatePlunder(1, false);


This is because one of the first IF statements in updatePlunder checks "ifEnemy" which the unit will not be if it has already lost Hidden Nationality. So the blockade must be cleared before the Hidden Nationality is adjusted at all.


Also in CvPlayer::killUnits it might be appropriate to use a number much larger than -1 for changeImmortal(-1), as this would leave any unit which is both naturally Immortal AND has the Immortal Promotion quite alive. Negative numbers are not an issue since the changeImmortal function will never allow a full negative, so any larger number ought to suffice quite nicely (I think there were some other places where this was a minor issue, but I never remembered to look into the details for if it was actually an issue).
 
spellRobGrave uses goody logic, but dosen't respect the isNoBadGoodies Unit flag.

This causes an assert in CvPlayer::receiveGoody(). I'd remove the assert.
 
It seems my mimics can be upgraded into Brujah or Balor. Did anyone else get this? The Infernals are not in the game.

 
Back
Top Bottom