Unit Prereq BuildingClass Array

I just changed that and compiled. There is still no text in the civilopedia, and in game, as the Malinese, it says

"Unique building for city"
"Requires Castle"

When the spearman requires the forge, and the UB is the Mint...
 
Why does hovering over the Spearman say "Unique Building for Mali"? Well, you said "for city" and I have no idea what that means.

Regardless, looking at the last code I posted you can see that every possible way through it ends with adding a static message, so either you aren't using this code or you put this code in the wrong place or it's wrapped inside some other if() condition that is false. Can you post the entire function where this code lives?
 
Why does hovering over the Spearman say "Unique Building for Mali"? Well, you said "for city" and I have no idea what that means.

?? You coded it that way...

Code:
	else
	{
		szBuffer.append(NEWLINE L"Unique Building for City");
	}


Regardless, looking at the last code I posted you can see that every possible way through it ends with adding a static message, so either you aren't using this code or you put this code in the wrong place or it's wrapped inside some other if() condition that is false. Can you post the entire function where this code lives?

Here's the whole function, up to the end of my added section.

Code:
void CvGameTextMgr::setUnitHelp(CvWStringBuffer &szBuffer, UnitTypes eUnit, bool bCivilopediaText, bool bStrategyText, bool bTechChooserText, CvCity* pCity)
{
	PROFILE_FUNC();

	CvWString szTempBuffer;
	PlayerTypes ePlayer;
	bool bFirst;
	int iProduction;
	int iI;

	if (NO_UNIT == eUnit)
	{
		return;
	}

	if (pCity != NULL)
	{
		ePlayer = pCity->getOwnerINLINE();
	}
	else
	{
		ePlayer = GC.getGameINLINE().getActivePlayer();
	}

	if (!bCivilopediaText)
	{
		szTempBuffer.Format(SETCOLR L"%s" ENDCOLR , TEXT_COLOR("COLOR_UNIT_TEXT"), GC.getUnitInfo(eUnit).getDescription());
		szBuffer.append(szTempBuffer);

		if (GC.getUnitInfo(eUnit).getUnitCombatType() != NO_UNITCOMBAT)
		{
			szTempBuffer.Format(L" (%s)", GC.getUnitCombatInfo((UnitCombatTypes) GC.getUnitInfo(eUnit).getUnitCombatType()).getDescription());
			szBuffer.append(szTempBuffer);
		}
	}

	// test for unique unit
	UnitClassTypes eUnitClass = (UnitClassTypes)GC.getUnitInfo(eUnit).getUnitClassType();
	UnitTypes eDefaultUnit = (UnitTypes)GC.getUnitClassInfo(eUnitClass).getDefaultUnitIndex();

	if (NO_UNIT != eDefaultUnit && eDefaultUnit != eUnit)
	{
		for (iI  = 0; iI < GC.getNumCivilizationInfos(); ++iI)
		{
			UnitTypes eUniqueUnit = (UnitTypes)GC.getCivilizationInfo((CivilizationTypes)iI).getCivilizationUnits((int)eUnitClass);
			if (eUniqueUnit == eUnit)
			{
				szBuffer.append(NEWLINE);
				szBuffer.append(gDLL->getText("TXT_KEY_UNIQUE_UNIT", GC.getCivilizationInfo((CivilizationTypes)iI).getTextKeyWide()));
			}
		}

		szBuffer.append(NEWLINE);
		szBuffer.append(gDLL->getText("TXT_KEY_REPLACES_UNIT", GC.getUnitInfo(eDefaultUnit).getTextKeyWide()));
	}

	if (isWorldUnitClass(eUnitClass))
	{
		if (pCity == NULL)
		{
			szBuffer.append(NEWLINE);
			szBuffer.append(gDLL->getText("TXT_KEY_UNIT_WORLD_UNIT_ALLOWED", GC.getUnitClassInfo(eUnitClass).getMaxGlobalInstances()));
		}
		else
		{
			szBuffer.append(gDLL->getText("TXT_KEY_UNIT_WORLD_UNIT_LEFT", (GC.getUnitClassInfo(eUnitClass).getMaxGlobalInstances() - (ePlayer != NO_PLAYER ? GC.getGameINLINE().getUnitClassCreatedCount(eUnitClass) + GET_TEAM(GET_PLAYER(ePlayer).getTeam()).getUnitClassMaking(eUnitClass) : 0))));
		}
	}

	if (isTeamUnitClass(eUnitClass))
	{
		if (pCity == NULL)
		{
			szBuffer.append(NEWLINE);
			szBuffer.append(gDLL->getText("TXT_KEY_UNIT_TEAM_UNIT_ALLOWED", GC.getUnitClassInfo(eUnitClass).getMaxTeamInstances()));
		}
		else
		{
			szBuffer.append(gDLL->getText("TXT_KEY_UNIT_TEAM_UNIT_LEFT", (GC.getUnitClassInfo(eUnitClass).getMaxTeamInstances() - (ePlayer != NO_PLAYER ? GET_TEAM(GET_PLAYER(ePlayer).getTeam()).getUnitClassCountPlusMaking(eUnitClass) : 0))));
		}
	}

	if (isNationalUnitClass(eUnitClass))
	{
		if (pCity == NULL)
		{
			szBuffer.append(NEWLINE);
			szBuffer.append(gDLL->getText("TXT_KEY_UNIT_NATIONAL_UNIT_ALLOWED", GC.getUnitClassInfo(eUnitClass).getMaxPlayerInstances()));
		}
		else
		{
			szBuffer.append(gDLL->getText("TXT_KEY_UNIT_NATIONAL_UNIT_LEFT", (GC.getUnitClassInfo(eUnitClass).getMaxPlayerInstances() - (ePlayer != NO_PLAYER ? GET_PLAYER(ePlayer).getUnitClassCountPlusMaking(eUnitClass) : 0))));
		}
	}

	if (0 != GC.getUnitClassInfo(eUnitClass).getInstanceCostModifier())
	{
		szBuffer.append(NEWLINE);
		szBuffer.append(gDLL->getText("TXT_KEY_UNIT_INSTANCE_COST_MOD", GC.getUnitClassInfo(eUnitClass).getInstanceCostModifier()));
	}

	setBasicUnitHelp(szBuffer, eUnit, bCivilopediaText);

	if ((pCity == NULL) || !(pCity->canTrain(eUnit)))
	{
		if (pCity != NULL)
		{
			if (GC.getGameINLINE().isNoNukes())
			{
				if (GC.getUnitInfo(eUnit).getNukeRange() != -1)
				{
					szBuffer.append(NEWLINE);
					szBuffer.append(gDLL->getText("TXT_KEY_UNIT_NO_NUKES"));
				}
			}
		}

		if (GC.getUnitInfo(eUnit).getHolyCity() != NO_RELIGION)
		{
			if ((pCity == NULL) || !(pCity->isHolyCity((ReligionTypes)(GC.getUnitInfo(eUnit).getHolyCity()))))
			{
				szBuffer.append(NEWLINE);
				szBuffer.append(gDLL->getText("TXT_KEY_UNIT_REQUIRES_HOLY_CITY", GC.getReligionInfo((ReligionTypes)(GC.getUnitInfo(eUnit).getHolyCity())).getChar()));
			}
		}

		bFirst = true;

		if (GC.getUnitInfo(eUnit).getSpecialUnitType() != NO_SPECIALUNIT)
		{
			if ((pCity == NULL) || !(GC.getGameINLINE().isSpecialUnitValid((SpecialUnitTypes)(GC.getUnitInfo(eUnit).getSpecialUnitType()))))
			{
				for (iI = 0; iI < GC.getNumProjectInfos(); ++iI)
				{
					if (GC.getProjectInfo((ProjectTypes)iI).getEveryoneSpecialUnit() == GC.getUnitInfo(eUnit).getSpecialUnitType())
					{
						szTempBuffer.Format(L"%s%s", NEWLINE, gDLL->getText("TXT_KEY_REQUIRES").c_str());
						CvWString szProject;
						szProject.Format(L"<link=literal>%s</link>", GC.getProjectInfo((ProjectTypes)iI).getDescription());
						setListHelp(szBuffer, szTempBuffer, szProject, gDLL->getText("TXT_KEY_OR").c_str(), bFirst);
						bFirst = false;
					}
				}
			}
		}

		if (!bFirst)
		{
			szBuffer.append(ENDCOLR);
		}

		bFirst = true;

		if (GC.getUnitInfo(eUnit).getNukeRange() != -1)
		{
			if (NULL == pCity || !GC.getGameINLINE().isNukesValid())
			{
				for (iI = 0; iI < GC.getNumProjectInfos(); ++iI)
				{
					if (GC.getProjectInfo((ProjectTypes)iI).isAllowsNukes())
					{
						szTempBuffer.Format(L"%s%s", NEWLINE, gDLL->getText("TXT_KEY_REQUIRES").c_str());
						CvWString szProject;
						szProject.Format(L"<link=literal>%s</link>", GC.getProjectInfo((ProjectTypes)iI).getDescription());
						setListHelp(szBuffer, szTempBuffer, szProject, gDLL->getText("TXT_KEY_OR").c_str(), bFirst);
						bFirst = false;
					}
				}

				for (iI = 0; iI < GC.getNumBuildingInfos(); ++iI)
				{
					if (GC.getBuildingInfo((BuildingTypes)iI).isAllowsNukes())
					{
						szTempBuffer.Format(L"%s%s", NEWLINE, gDLL->getText("TXT_KEY_REQUIRES").c_str());
						CvWString szBuilding;
						szBuilding.Format(L"<link=literal>%s</link>", GC.getBuildingInfo((BuildingTypes)iI).getDescription());
						setListHelp(szBuffer, szTempBuffer, szBuilding, gDLL->getText("TXT_KEY_OR").c_str(), bFirst);
						bFirst = false;
					}
				}
			}
		}

		if (!bFirst)
		{
			szBuffer.append(ENDCOLR);
		}
/*************************************************************************************************/
/** Afforess	Vicinity Bonus Start		 07/29/09                                            */
/**                                                                                              */
/**                                                                                              */
/*************************************************************************************************/
		if (GC.getUnitInfo(eUnit).getPrereqVicinityBonus() != NO_BONUS)
		{
			if ((pCity == NULL) || !(pCity->canTrain(eUnit)))
			{
				szBuffer.append(NEWLINE);
				szBuffer.append(gDLL->getText("TXT_KEY_REQUIRES_VICINITY_BONUS", GC.getBonusInfo((BonusTypes)(GC.getUnitInfo(eUnit).getPrereqVicinityBonus())).getTextKeyWide()));
			}
		}

		bFirst = true;

		for (iI = 0; iI < GC.getNUM_UNIT_PREREQ_OR_BONUSES(); ++iI)
		{
			if (GC.getUnitInfo(eUnit).getPrereqOrVicinityBonuses(iI) != NO_BONUS)
			{
				if ((pCity == NULL) || !(pCity->canTrain(eUnit)))
				{
					szTempBuffer.Format(L"%s%s", NEWLINE, gDLL->getText("TXT_KEY_REQUIRES_IN_CITY_VICINITY").c_str());
					setListHelp(szBuffer, szTempBuffer, GC.getBonusInfo((BonusTypes) GC.getUnitInfo(eUnit).getPrereqOrVicinityBonuses(iI)).getDescription(), gDLL->getText("TXT_KEY_OR").c_str(), bFirst);
					bFirst = false;
				}
			}
		}

		if (!bFirst)
		{
			szBuffer.append(ENDCOLR);
		}
/*************************************************************************************************/
/** Afforess	Vicinity Bonus End       END                                                     */
/*************************************************************************************************/
		if (!bCivilopediaText)
		{
			if (GC.getUnitInfo(eUnit).getPrereqBuilding() != NO_BUILDING)
			{
				if ((pCity == NULL) || (pCity->getNumBuilding((BuildingTypes)(GC.getUnitInfo(eUnit).getPrereqBuilding())) <= 0))
				{
					szBuffer.append(NEWLINE);
					szBuffer.append(gDLL->getText("TXT_KEY_UNIT_REQUIRES_STRING", GC.getBuildingInfo((BuildingTypes)(GC.getUnitInfo(eUnit).getPrereqBuilding())).getTextKeyWide()));
				}
			}
			//Afforess Start
			BuildingTypes eRequiredBuilding = NO_BUILDING;

			if (!pCity)
			{
				if (GC.getGameINLINE().getActivePlayer() != NO_PLAYER)
				{
					// show unique building for active player
					eRequiredBuilding = (BuildingTypes)GC.getCivilizationInfo(GET_PLAYER(GC.getGameINLINE().getActivePlayer()).getCivilizationType()).getCivilizationBuildings(iI);
					szBuffer.append(NEWLINE L"Unique Building for Active Player");
				}
				else
				{
					// show default building
					eRequiredBuilding = (BuildingTypes)GC.getBuildingClassInfo((BuildingClassTypes)iI).getDefaultBuildingIndex();
					szBuffer.append(NEWLINE L"Default Building");
				}
			}
			else
			{
				// show unique building for city's owner if city doesn't have any
				eRequiredBuilding = (BuildingTypes)GC.getCivilizationInfo(pCity->getCivilizationType()).getCivilizationBuildings(iI);
				if (pCity->getNumActiveBuilding(eRequiredBuilding) > 0)
				{
					eRequiredBuilding = NO_BUILDING;
					szBuffer.append(NEWLINE L"City Has Unique Building");
				}
				else
				{
					szBuffer.append(NEWLINE L"Unique Building for City");
				}
			}
			if (eRequiredBuilding != NO_BUILDING)
			{
				szBuffer.append(NEWLINE);
				szBuffer.append(gDLL->getText("TXT_KEY_UNIT_REQUIRES_STRING", GC.getBuildingInfo(eRequiredBuilding).getTextKeyWide()));
			}
//Afforess END

...}
}
 
LOL, you said that no text appeared in the Civilopedia and I thought you meant that the static text I added didn't appear. But this problem is because you have these additions guarded by this check:

Code:
if (!bCivilopediaText)

Which means nothing new will ever appear in the Civilopedia! Move the code you added after this check so that it shows up.

As for showing "Castle", you are not looping over all the building classes to test which are required. iI just happens to have the building class for Castle here. You need to wrap all that code I posted with a for() loop over getNumBuildingClassInfos():

Code:
for (iI = 0; iI < GC.getNumBuildingClassInfos(); iI++)
{
    ... my code ...
}
 
LOL, you said that no text appeared in the Civilopedia and I thought you meant that the static text I added didn't appear. But this problem is because you have these additions guarded by this check:

Code:
if (!bCivilopediaText)
Which means nothing new will ever appear in the Civilopedia! Move the code you added after this check so that it shows up.

Well, that would make sense. :facepalm:
As for showing "Castle", you are not looping over all the building classes to test which are required. iI just happens to have the building class for Castle here. You need to wrap all that code I posted with a for() loop over getNumBuildingClassInfos():

Code:
for (iI = 0; iI < GC.getNumBuildingClassInfos(); iI++)
{
    ... my code ...
}

Another D'oh!
 
I'm getting a new problem now. Every unit, whether I set them to require a buildingclass or not, is requiring every building in the game, creating huge lists of red building requirements for each unit...

I moved my code near the end of the function, outside of the civilopedia function.

My current code:
Code:
	for (iI = 0; iI < GC.getNumBuildingClassInfos(); iI++)
	{
		BuildingTypes eRequiredBuilding = NO_BUILDING;
		if (!pCity)
		{
			if (GC.getGameINLINE().getActivePlayer() != NO_PLAYER)
			{
				// show unique building for active player
				eRequiredBuilding = (BuildingTypes)GC.getCivilizationInfo(GET_PLAYER(GC.getGameINLINE().getActivePlayer()).getCivilizationType()).getCivilizationBuildings(iI);
			}
			else
			{
				// show default building
				eRequiredBuilding = (BuildingTypes)GC.getBuildingClassInfo((BuildingClassTypes)iI).getDefaultBuildingIndex();
			}
		}
		else
		{
			// show unique building for city's owner if city doesn't have any
			eRequiredBuilding = (BuildingTypes)GC.getCivilizationInfo(pCity->getCivilizationType()).getCivilizationBuildings(iI);
			if (pCity->getNumActiveBuilding(eRequiredBuilding) > 0)
			{
				eRequiredBuilding = NO_BUILDING;
			}
		}
		if (eRequiredBuilding != NO_BUILDING)
		{
			szBuffer.append(NEWLINE);
			szBuffer.append(gDLL->getText("TXT_KEY_UNIT_REQUIRES_STRING", GC.getBuildingInfo(eRequiredBuilding).getTextKeyWide()));
		}
	}
 
You need to check if the unit requires the building class using your CvUnitInfo function.

Code:
CvUnitInfo& kUnit = GC.getUnitInfo(eUnit); // might already be set above
for (...)
{
    if (kUnit.isRequiresBuildingClass(iI)) // use the actual function name here of course
    {
        ...
    }
}
 
Great, everything is working perfectly. Now, I need to expose it to python, in CyPlot, and CyPlotInterface?
 
No just CvInfoInterfaceX.cpp (whichever one has the CvUnitInfo stuff in it). All you need to do is expose the function that says whether or not a unit type requires a given building class so the Civilopedia can add the icon(s).

Requires
Hunting and Bronze Working and Forge and (Copper or Iron)​
 
No just CvInfoInterfaceX.cpp (whichever one has the CvUnitInfo stuff in it). All you need to do is expose the function that says whether or not a unit type requires a given building class so the Civilopedia can add the icon(s).
Requires
Hunting and Bronze Working and (Copper or Iron) and Forge

I released that it was CvInfos that had the function, not CvPlot, a few seconds after posting.

So, I need to expose that getPrereqBuildingClass function, right?
 
That's correct. Exposing CvFooInfo functions are easier as you only need to do the last step of creating the single line of code in CvInfoInterfaceX.cpp. These classes don't have CyFooInfo wrappers like the other CvFoo classes do (CvCity, CvPlot, etc).
 
That's correct. Exposing CvFooInfo functions are easier as you only need to do the last step of creating the single line of code in CvInfoInterfaceX.cpp. These classes don't have CyFooInfo wrappers like the other CvFoo classes do (CvCity, CvPlot, etc).

Okay, exposed to python. Now, I'm using BUG 4.0, so what do I need to change/update?
 
Add the following to the very end of placeRequires(self) in Python/Contrib/SevoPedia/SevoPediaUnit.py:

Code:
		if (gc.getGame().getActivePlayer() >= 0):
			pCiv = gc.getCivilizationInfo(gc.getActivePlayer().getCivilizationType())
		else:
			pCiv = None
		for j in range(gc.getNumBuildingClassInfos()):
			if (gc.getUnitInfo(self.iUnit).getPrereqBuildingClass(j)):
				if (pCiv):
					iPrereq = pCiv.getCivilizationBuildings(j)
				else:
					iPrereq = gc.getBuildingClassInfo(j).getDefaultBuildingIndex()
				screen.attachImageButton(panelName, "", gc.getBuildingInfo(iPrereq).getButton(), GenericButtonSizes.BUTTON_SIZE_CUSTOM, WidgetTypes.WIDGET_PEDIA_JUMP_TO_BUILDING, iPrereq, -1, False)
 
I get a python exception upon opening the Civilopedia:

Traceback (most recent call last):

File "CvScreensInterface", line 431, in pediaJumpToUnit

File "SevoPediaMain", line 279, in pediaJump

File "SevoPediaUnit", line 93, in interfaceScreen

File "SevoPediaUnit", line 184, in placeRequires

AttributeError: 'int' object has no attribute 'getCivilizationType'
ERR: Python function pediaJumpToUnit failed, module CvScreensInterface
 
Hey, it works perfectly, even with UB's. Thanks a ton! One more project, checked off my list.
 
I thought I was done, but then, I remembered the most important part of Civ4. The AI... *groan.*

How does this look as far as AI statements go?
Code:
				for (iI = 0; iI < GC.getNumBuildingClassInfos(); iI++) //Afforess
				{
					if (GC.getUnitInfo(eUnit).getPrereqBuildingClass(iI))
					{
						for (iJ = 0; iI < GC.getNumUnitInfos(); iJ++)
						{
							if (GC.getUnitInfo((UnitTypes)iJ).getPrereqBuildingClass(iI) == eBuildingClass)
							{
								iValue += //Not sure what to use to increase the value, NumCities?
							}
						}
					}
				}

However, I'm not sure what to increase the value by. Is there a way to see if the Civ needs those units, or is making war plans?
 
What function is this? Context! :p I do believe there are functions to test what the player's current war plan is, and you could adjust accordingly. However, you really would want to have the AI build the required building for military units before it has begun war plans.

Perhaps just increase its desire to build buildings that are required for units for which the AI has the resource. So if MM has Copper, he'll slightly increase his valuation of the Mint. And sure, increase it slightly more if he is planning or in a war. The problem here is not to increase it so much that it overrides his dire need for Axeman or other units.

I have no idea if the AI has a clue about what counter units it needs at any given point. If Khan is next door and has Horses, will the AI favor Spearmen?
 
What function is this? Context! :p
Code:
int CvCityAI::AI_buildingValueThreshold(BuildingTypes eBuilding, int iFocusFlags, int iThreshold)

I do believe there are functions to test what the player's current war plan is, and you could adjust accordingly. However, you really would want to have the AI build the required building for military units before it has begun war plans.
Yes, very true.
Perhaps just increase its desire to build buildings that are required for units for which the AI has the resource. So if MM has Copper, he'll slightly increase his valuation of the Mint. And sure, increase it slightly more if he is planning or in a war. The problem here is not to increase it so much that it overrides his dire need for Axeman or other units.

I think this is a good idea. I'll need to loop and check for access to resources too then.
I have no idea if the AI has a clue about what counter units it needs at any given point. If Khan is next door and has Horses, will the AI favor Spearmen?

I hope they know, at least, I hope Better Ai has fixed that...
 
Back
Top Bottom