Help for a mod that enables resources to change beakers, gold etc with buildings

SaibotLieh

Emperor
Joined
Sep 25, 2009
Messages
1,576
I'm trying to write a mod that gives the possibility to modify the output of beakers, gold, culture and espionage through the combination of certain resources and buildings. To say it in other words, I would like to add a "BonusCommerceModifiers" option for buildings. For this purpose, I basically copied each "BonusYieldModifier" entry in the CvInfo.cpp, CvInfo.h and CvGameTextMgr.cpp files and replaced the Yield with Commerce. The .dll could be created successfully this way, the mod starts with no errors and the bonus through the resource is displayed as it should be, but it has no effect on the output of the city at all.
I have no clue what is still missing now, any help is highly appreciate. My modifications in the files are all marked with "BCM:", the mod version in the attachment has the palace modified to add 100% to anything if supplied with wheat.

CvInfo.cpp modifications:
Spoiler :

m_ppaiBonusCommerceModifier(NULL),

(...)

if (m_ppaiBonusCommerceModifier != NULL)
{
for(int i=0;i<GC.getNumBonusInfos();i++)
{
SAFE_DELETE_ARRAY(m_ppaiBonusCommerceModifier);
}
SAFE_DELETE_ARRAY(m_ppaiBonusCommerceModifier);
}

(...)

int CvBuildingInfo::getBonusCommerceModifier(int i, int j) const
{
FAssertMsg(i < GC.getNumBonusInfos(), "Index out of bounds");
FAssertMsg(i > -1, "Index out of bounds");
FAssertMsg(j < NUM_COMMERCE_TYPES, "Index out of bounds");
FAssertMsg(j > -1, "Index out of bounds");
return m_ppaiBonusCommerceModifier ? m_ppaiBonusCommerceModifier[j] : -1;
}

int* CvBuildingInfo::getBonusCommerceModifierArray(int i) const
{
FAssertMsg(i < GC.getNumBonusInfos(), "Index out of bounds");
FAssertMsg(i > -1, "Index out of bounds");
return m_ppaiBonusCommerceModifier;
}

(...)

if (m_ppaiBonusCommerceModifier != NULL)
{
for(i=0;i<GC.getNumBonusInfos();i++)
{
SAFE_DELETE_ARRAY(m_ppaiBonusCommerceModifier);
}
SAFE_DELETE_ARRAY(m_ppaiBonusCommerceModifier);
}

m_ppaiBonusCommerceModifier = new int*[GC.getNumBonusInfos()];
for(i=0;i<GC.getNumBonusInfos();i++)
{
m_ppaiBonusCommerceModifier = new int[NUM_COMMERCE_TYPES];
stream->Read(NUM_COMMERCE_TYPES, m_ppaiBonusCommerceModifier);
}

(...)

for(i=0;i<GC.getNumBonusInfos();i++)
{
stream->Write(NUM_COMMERCE_TYPES, m_ppaiBonusCommerceModifier);
}

(...)

pXML->Init2DIntList(&m_ppaiBonusCommerceModifier, GC.getNumBonusInfos(), NUM_COMMERCE_TYPES);
if (gDLL->getXMLIFace()->SetToChildByTagName(pXML->GetXML(),"BonusCommerceModifiers"))
{
iNumChildren = gDLL->getXMLIFace()->GetNumChildren(pXML->GetXML());

if (gDLL->getXMLIFace()->SetToChildByTagName(pXML->GetXML(),"BonusCommerceModifier"))
{
for(j=0;j<iNumChildren;j++)
{
pXML->GetChildXmlValByName(szTextVal, "BonusType");
k = pXML->FindInInfoClass(szTextVal);
if (k > -1)
{
// delete the array since it will be reallocated
SAFE_DELETE_ARRAY(m_ppaiBonusCommerceModifier[k]);
if (gDLL->getXMLIFace()->SetToChildByTagName(pXML->GetXML(),"CommerceModifiers"))
{
// call the function that sets the commerce change variable
pXML->SetCommerce(&m_ppaiBonusCommerceModifier[k]);
gDLL->getXMLIFace()->SetToParent(pXML->GetXML());
}
else
{
pXML->InitList(&m_ppaiBonusCommerceModifier[k], NUM_COMMERCE_TYPES);
}

}

if (!gDLL->getXMLIFace()->NextSibling(pXML->GetXML()))
{
break;
}
}

// set the current xml node to it's parent node
gDLL->getXMLIFace()->SetToParent(pXML->GetXML());
}

// set the current xml node to it's parent node
gDLL->getXMLIFace()->SetToParent(pXML->GetXML());
}

(...)


CvInfo.h modifications:
Spoiler :

DllExport int getBonusCommerceModifier(int i, int j) const; // Exposed to Python
int* getBonusCommerceModifierArray(int i) const;

(...)

int** m_ppaiBonusCommerceModifier;


CvGameTextMgr.cpp modifications:
Spoiler :

for (iI = 0; iI < GC.getNumBonusInfos(); ++iI)
{
szFirstBuffer = gDLL->getText("TXT_KEY_BUILDING_WITH_BONUS", GC.getBonusInfo((BonusTypes) iI).getTextKeyWide());
setCommerceChangeHelp(szBuffer, L"", L"", szFirstBuffer, kBuilding.getBonusCommerceModifierArray(iI), true);
}
 
The XML is having no effect because your code doesn't actually do anything. That's because you need to edit more files. I think you need to modify CvCity. Look at the "CorporationCommerce" tag in CvCity and try to mimic it's functionality.
 
Thanks, while I slowly begin to understand the code language I still don't know which file does what. Modified the CvCity.cpp and the CvCity.h now, mostly took the BonusYieldRateModifier as template (the additional "Rate" didn't really help to identify it as the BonusYieldModifier from the other files :crazyeye:). Here are the modifications:

CvCity.cpp
Spoiler :

m_aiBonusCommerceRateModifier = new int[NUM_COMMERCE_TYPES];

(...)

SAFE_DELETE_ARRAY(m_aiBonusCommerceRateModifier);

(...)

for (iI = 0; iI < NUM_COMMERCE_TYPES; iI++)
{
m_aiCommerceRate[iI] = 0;
m_aiProductionToCommerceModifier[iI] = 0;
m_aiBuildingCommerce[iI] = 0;
m_aiSpecialistCommerce[iI] = 0;
m_aiReligionCommerce[iI] = 0;
m_aiCorporationCommerce[iI] = 0;
m_aiCommerceRateModifier[iI] = 0;
m_aiCommerceHappinessPer[iI] = 0;
m_aiBonusCommerceRateModifier[iI] = 0;
}

(...)

int CvCity::getBonusCommerceRateModifier(CommerceTypes eIndex, BonusTypes eBonus) const
{
int iModifier;
int iI;

iModifier = 0;

for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
{
iModifier += getNumActiveBuilding((BuildingTypes)iI) * GC.getBuildingInfo((BuildingTypes) iI).getBonusCommerceModifier(eBonus, eIndex);
}

return iModifier;
}

(...)

void CvCity::processBonus(BonusTypes eBonus, int iChange)
{
int iI;
int iValue;
int iGoodValue;
int iBadValue;

iValue = GC.getBonusInfo(eBonus).getHealth();
iGoodValue = std::max(0, iValue);
iBadValue = std::min(0, iValue);

for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
{
iValue = GC.getBuildingInfo((BuildingTypes) iI).getBonusHealthChanges(eBonus) * getNumActiveBuilding((BuildingTypes)iI);

if (iValue >= 0)
{
iGoodValue += iValue;
}
else
{
iBadValue += iValue;
}
}

changeBonusGoodHealth(iGoodValue * iChange);
changeBonusBadHealth(iBadValue * iChange);


iValue = GC.getBonusInfo(eBonus).getHappiness();
iGoodValue = std::max(0, iValue);
iBadValue = std::min(0, iValue);

for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
{
iValue = getNumActiveBuilding((BuildingTypes)iI) * GC.getBuildingInfo((BuildingTypes) iI).getBonusHappinessChanges(eBonus);

if (iValue >= 0)
{
iGoodValue += iValue;
}
else
{
iBadValue += iValue;
}
}

changeBonusGoodHappiness(iGoodValue * iChange);
changeBonusBadHappiness(iBadValue * iChange);

changePowerCount((getBonusPower(eBonus, true) * iChange), true);
changePowerCount((getBonusPower(eBonus, false) * iChange), false);

for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
{
changeBonusYieldRateModifier(((YieldTypes)iI), (getBonusYieldRateModifier(((YieldTypes)iI), eBonus) * iChange));
}

for (iI = 0; iI < NUM_COMMERCE_TYPES; iI++)
{
changeBonusCommerceRateModifier(((CommerceTypes)iI), (getBonusCommerceRateModifier(((CommerceTypes)iI), eBonus) * iChange));
}
}

(...)

void CvCity::processBuilding(BuildingTypes eBuilding, int iChange, bool bObsolete)
{
UnitTypes eGreatPeopleUnit;
int iI, iJ;

if (!(GET_TEAM(getTeam()).isObsoleteBuilding(eBuilding)) || bObsolete)
{
if (iChange > 0)
{
CorporationTypes eCorporation = (CorporationTypes)GC.getBuildingInfo(eBuilding).getFoundsCorporation();
if (NO_CORPORATION != eCorporation && !GC.getGameINLINE().isCorporationFounded(eCorporation))
{
setHeadquarters(eCorporation);
}
}

if (GC.getBuildingInfo(eBuilding).getNoBonus() != NO_BONUS)
{
changeNoBonusCount(((BonusTypes)(GC.getBuildingInfo(eBuilding).getNoBonus())), iChange);
}

if (GC.getBuildingInfo(eBuilding).getFreeBonus() != NO_BONUS)
{
changeFreeBonus(((BonusTypes)(GC.getBuildingInfo(eBuilding).getFreeBonus())), (GC.getGameINLINE().getNumFreeBonuses(eBuilding) * iChange));
}

if (GC.getBuildingInfo(eBuilding).getFreePromotion() != NO_PROMOTION)
{
changeFreePromotionCount(((PromotionTypes)(GC.getBuildingInfo(eBuilding).getFreePromotion())), iChange);
}

changeEspionageDefenseModifier(GC.getBuildingInfo(eBuilding).getEspionageDefenseModifier() * iChange);
changeGreatPeopleRateModifier(GC.getBuildingInfo(eBuilding).getGreatPeopleRateModifier() * iChange);
changeFreeExperience(GC.getBuildingInfo(eBuilding).getFreeExperience() * iChange);
changeMaxFoodKeptPercent(GC.getBuildingInfo(eBuilding).getFoodKept() * iChange);
changeMaxAirlift(GC.getBuildingInfo(eBuilding).getAirlift() * iChange);
changeAirModifier(GC.getBuildingInfo(eBuilding).getAirModifier() * iChange);
changeAirUnitCapacity(GC.getBuildingInfo(eBuilding).getAirUnitCapacity() * iChange);
changeNukeModifier(GC.getBuildingInfo(eBuilding).getNukeModifier() * iChange);
changeFreeSpecialist(GC.getBuildingInfo(eBuilding).getFreeSpecialist() * iChange);
changeMaintenanceModifier(GC.getBuildingInfo(eBuilding).getMaintenanceModifier() * iChange);
changeWarWearinessModifier(GC.getBuildingInfo(eBuilding).getWarWearinessModifier() * iChange);
changeHurryAngerModifier(GC.getBuildingInfo(eBuilding).getHurryAngerModifier() * iChange);
changeHealRate(GC.getBuildingInfo(eBuilding).getHealRateChange() * iChange);
if (GC.getBuildingInfo(eBuilding).getHealth() > 0)
{
changeBuildingGoodHealth(GC.getBuildingInfo(eBuilding).getHealth() * iChange);
}
else
{
changeBuildingBadHealth(GC.getBuildingInfo(eBuilding).getHealth() * iChange);
}
if (GC.getBuildingInfo(eBuilding).getHappiness() > 0)
{
changeBuildingGoodHappiness(GC.getBuildingInfo(eBuilding).getHappiness() * iChange);
}
else
{
changeBuildingBadHappiness(GC.getBuildingInfo(eBuilding).getHappiness() * iChange);
}
if (GC.getBuildingInfo(eBuilding).getReligionType() != NO_RELIGION)
{
changeStateReligionHappiness(((ReligionTypes)(GC.getBuildingInfo(eBuilding).getReligionType())), (GC.getBuildingInfo(eBuilding).getStateReligionHappiness() * iChange));
}
changeMilitaryProductionModifier(GC.getBuildingInfo(eBuilding).getMilitaryProductionModifier() * iChange);
changeSpaceProductionModifier(GC.getBuildingInfo(eBuilding).getSpaceProductionModifier() * iChange);
changeExtraTradeRoutes(GC.getBuildingInfo(eBuilding).getTradeRoutes() * iChange);
changeTradeRouteModifier(GC.getBuildingInfo(eBuilding).getTradeRouteModifier() * iChange);
changeForeignTradeRouteModifier(GC.getBuildingInfo(eBuilding).getForeignTradeRouteModifier() * iChange);
changePowerCount(((GC.getBuildingInfo(eBuilding).isPower()) ? iChange : 0), GC.getBuildingInfo(eBuilding).isDirtyPower());
changeGovernmentCenterCount((GC.getBuildingInfo(eBuilding).isGovernmentCenter()) ? iChange : 0);
changeNoUnhappinessCount((GC.getBuildingInfo(eBuilding).isNoUnhappiness()) ? iChange : 0);
changeNoUnhealthyPopulationCount((GC.getBuildingInfo(eBuilding).isNoUnhealthyPopulation()) ? iChange : 0);
changeBuildingOnlyHealthyCount((GC.getBuildingInfo(eBuilding).isBuildingOnlyHealthy()) ? iChange : 0);

for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
{
changeSeaPlotYield(((YieldTypes)iI), (GC.getBuildingInfo(eBuilding).getSeaPlotYieldChange(iI) * iChange));
changeRiverPlotYield(((YieldTypes)iI), (GC.getBuildingInfo(eBuilding).getRiverPlotYieldChange(iI) * iChange));
changeBaseYieldRate(((YieldTypes)iI), ((GC.getBuildingInfo(eBuilding).getYieldChange(iI) + getBuildingYieldChange((BuildingClassTypes)GC.getBuildingInfo(eBuilding).getBuildingClassType(), (YieldTypes)iI))* iChange));
changeYieldRateModifier(((YieldTypes)iI), (GC.getBuildingInfo(eBuilding).getYieldModifier(iI) * iChange));
changePowerYieldRateModifier(((YieldTypes)iI), (GC.getBuildingInfo(eBuilding).getPowerYieldModifier(iI) * iChange));
}

for (iI = 0; iI < NUM_COMMERCE_TYPES; iI++)
{
changeCommerceRateModifier(((CommerceTypes)iI), (GC.getBuildingInfo(eBuilding).getCommerceModifier(iI) * iChange));
changeCommerceHappinessPer(((CommerceTypes)iI), (GC.getBuildingInfo(eBuilding).getCommerceHappiness(iI) * iChange));
}

for (iI = 0; iI < GC.getNumReligionInfos(); iI++)
{
changeReligionInfluence(((ReligionTypes)iI), (GC.getBuildingInfo(eBuilding).getReligionChange(iI) * iChange));
}

for (iI = 0; iI < GC.getNumSpecialistInfos(); iI++)
{
changeMaxSpecialistCount(((SpecialistTypes)iI), GC.getBuildingInfo(eBuilding).getSpecialistCount(iI) * iChange);
changeFreeSpecialistCount(((SpecialistTypes)iI), GC.getBuildingInfo(eBuilding).getFreeSpecialistCount(iI) * iChange);
}

for (iI = 0; iI < GC.getNumImprovementInfos(); ++iI)
{
changeImprovementFreeSpecialists((ImprovementTypes)iI, GC.getBuildingInfo(eBuilding).getImprovementFreeSpecialist(iI) * iChange);
}

FAssertMsg((0 < GC.getNumBonusInfos()) && "GC.getNumBonusInfos() is not greater than zero but an array is being allocated in CvPlotGroup::reset", "GC.getNumBonusInfos() is not greater than zero but an array is being allocated in CvPlotGroup::reset");
for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
{
if (hasBonus((BonusTypes)iI))
{
if (GC.getBuildingInfo(eBuilding).getBonusHealthChanges(iI) > 0)
{
changeBonusGoodHealth(GC.getBuildingInfo(eBuilding).getBonusHealthChanges(iI) * iChange);
}
else
{
changeBonusBadHealth(GC.getBuildingInfo(eBuilding).getBonusHealthChanges(iI) * iChange);
}
if (GC.getBuildingInfo(eBuilding).getBonusHappinessChanges(iI) > 0)
{
changeBonusGoodHappiness(GC.getBuildingInfo(eBuilding).getBonusHappinessChanges(iI) * iChange);
}
else
{
changeBonusBadHappiness(GC.getBuildingInfo(eBuilding).getBonusHappinessChanges(iI) * iChange);
}

if (GC.getBuildingInfo(eBuilding).getPowerBonus() == iI)
{
changePowerCount(iChange, GC.getBuildingInfo(eBuilding).isDirtyPower());
}

for (iJ = 0; iJ < NUM_YIELD_TYPES; iJ++)
{
changeBonusYieldRateModifier(((YieldTypes)iJ), (GC.getBuildingInfo(eBuilding).getBonusYieldModifier(iI, iJ) * iChange));
}

for (iJ = 0; iJ < NUM_COMMERCE_TYPES; iJ++)
{
changeBonusCommerceRateModifier(((CommerceTypes)iJ), (GC.getBuildingInfo(eBuilding).getBonusCommerceModifier(iI, iJ) * iChange));
}
}
}

(...)

int CvCity::getTotalCommerceRateModifier(CommerceTypes eIndex) const
{
return std::max(0, (getCommerceRateModifier(eIndex) + getBonusCommerceRateModifier(eIndex) + GET_PLAYER(getOwnerINLINE()).getCommerceRateModifier(eIndex) + ((isCapital()) ? GET_PLAYER(getOwnerINLINE()).getCapitalCommerceRateModifier(eIndex) : 0) + 100));
}

(...)

pStream->Read(NUM_YIELD_TYPES, m_aiBonusCommerceRateModifier);

(...)

pStream->Write(NUM_YIELD_TYPES, m_aiBonusCommerceRateModifier);


CvCity.h
Spoiler :

int getBonusCommerceRateModifier(CommerceTypes eIndex, BonusTypes eBonus) const; // Exposed to Python

(...)

int getBonusCommerceRateModifier(CommerceTypes eIndex) const; // Exposed to Python
void changeBonusCommerceRateModifier(CommerceTypes eIndex, int iChange);

(...)

int* m_aiBonusCommerceRateModifier;


Now I get some errors while creating the .dll:
Spoiler :

1>Microsoft (R) Program Maintenance Utility, Version 8.00.50727.42
1>Copyright (C) Microsoft Corporation. Alle Rechte vorbehalten.
1> "C:\Programme\Microsoft Visual C++ Toolkit 2003/bin/cl.exe" /nologo /MD /Gd /G7 /GR /O2 /W3 /EHsc /DWIN32 /DNDEBUG /D_WINDOWS /D_USRDLL /DCVGAMECOREDLL_EXPORTS /DFINAL_RELEASE /IBoost-1.32.0/include /IPython24/include /I"C:\Programme\Microsoft Visual C++ Toolkit 2003/include" /I"C:\Programme\Microsoft Platform SDK/Include" /c CvCity.cpp /FoFinal_Release/CvCity.obj
1>CvCity.cpp
1> "C:\Programme\Microsoft Visual C++ Toolkit 2003/bin/link.exe" /dll /nologo /LIBPATH:python24/libs /LIBPATH:boost-1.32.0/libs/ /LIBPATH:"C:\Programme\Microsoft Visual C++ Toolkit 2003/lib" /LIBPATH:"C:\Programme\Microsoft Platform SDK/Lib" /out:Final_Release\CvGameCoreDLL.dll boost_python-vc71-mt-1_32.lib winmm.lib user32.lib Final_Release\CvArea.obj Final_Release\CvArtFileMgr.obj Final_Release\CvCity.obj Final_Release\CvCityAI.obj Final_Release\CvDLLButtonPopup.obj Final_Release\CvDLLEntity.obj Final_Release\CvDLLPython.obj Final_Release\CvDLLWidgetData.obj Final_Release\CvDeal.obj Final_Release\CvDiploParameters.obj Final_Release\CvFractal.obj Final_Release\CvGame.obj Final_Release\CvGameAI.obj Final_Release\CvGameCoreDLL.obj Final_Release\CvGameCoreUtils.obj Final_Release\CvGameInterface.obj Final_Release\CvGameTextMgr.obj Final_Release\CvGlobals.obj Final_Release\CvHallOfFameInfo.obj Final_Release\CvInfoWater.obj Final_Release\CvInfos.obj Final_Release\CvInitCore.obj Final_Release\CvMap.obj Final_Release\CvMapGenerator.obj Final_Release\CvPlayer.obj Final_Release\CvPlayerAI.obj Final_Release\CvPlot.obj Final_Release\CvPlotGroup.obj Final_Release\CvPopupInfo.obj Final_Release\CvPopupReturn.obj Final_Release\CvRandom.obj Final_Release\CvReplayInfo.obj Final_Release\CvReplayMessage.obj Final_Release\CvSelectionGroup.obj Final_Release\CvSelectionGroupAI.obj Final_Release\CvStructs.obj Final_Release\CvTalkingHeadMessage.obj Final_Release\CvTeam.obj Final_Release\CvTeamAI.obj Final_Release\CvUnit.obj Final_Release\CvUnitAI.obj Final_Release\CvXMLLoadUtility.obj Final_Release\CvXMLLoadUtilityGet.obj Final_Release\CvXMLLoadUtilityInit.obj Final_Release\CvXMLLoadUtilitySet.obj Final_Release\CyArea.obj Final_Release\CyAreaInterface.obj Final_Release\CyArgsList.obj Final_Release\CyArtFileMgr.obj Final_Release\CyArtFileMgrInterface.obj Final_Release\CyCity.obj Final_Release\CyCityInterface1.obj Final_Release\CyDeal.obj Final_Release\CyEnumsInterface.obj Final_Release\CyGame.obj Final_Release\CyGameCoreUtils.obj Final_Release\CyGameCoreUtilsInterface.obj Final_Release\CyGameInterface.obj Final_Release\CyGameTextMgr.obj Final_Release\CyGameTextMgrInterface.obj Final_Release\CyGlobalContext.obj Final_Release\CyGlobalContextInterface1.obj Final_Release\CyGlobalContextInterface2.obj Final_Release\CyGlobalContextInterface3.obj Final_Release\CyGlobalContextInterface4.obj Final_Release\CyHallOfFameInfo.obj Final_Release\CyHallOfFameInterface.obj Final_Release\CyInfoInterface1.obj Final_Release\CyInfoInterface2.obj Final_Release\CyInfoInterface3.obj Final_Release\CyMap.obj Final_Release\CyMapGenerator.obj Final_Release\CyMapGeneratorInterface.obj Final_Release\CyMapInterface.obj Final_Release\CyPlayer.obj Final_Release\CyPlayerInterface1.obj Final_Release\CyPlayerInterface2.obj Final_Release\CyPlot.obj Final_Release\CyPlotInterface1.obj Final_Release\CyRandomInterface.obj Final_Release\CyReplayInfo.obj Final_Release\CySelectionGroup.obj Final_Release\CySelectionGroupInterface.obj Final_Release\CyStructsInterface1.obj Final_Release\CyTeam.obj Final_Release\CyTeamInterface.obj Final_Release\CyUnit.obj Final_Release\CyUnitInterface1.obj Final_Release\FAssert.obj Final_Release\FDialogTemplate.obj Final_Release\_precompile.obj /debug /INCREMENTAL:NO /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF
1> Creating library Final_Release\CvGameCoreDLL.lib and object Final_Release\CvGameCoreDLL.exp
1>CvCity.obj : error LNK2019: unresolved external symbol "public: int __thiscall CvCity::getBonusCommerceRateModifier(enum CommerceTypes)const " (?getBonusCommerceRateModifier@CvCity@@QBEHW4CommerceTypes@@@Z) referenced in function "public: int __thiscall CvCity::getTotalCommerceRateModifier(enum CommerceTypes)const " (?getTotalCommerceRateModifier@CvCity@@QBEHW4CommerceTypes@@@Z)
1>CvCity.obj : error LNK2019: unresolved external symbol "public: void __thiscall CvCity::changeBonusCommerceRateModifier(enum CommerceTypes,int)" (?changeBonusCommerceRateModifier@CvCity@@QAEXW4CommerceTypes@@H@Z) referenced in function "public: void __thiscall CvCity::processBonus(enum BonusTypes,int)" (?processBonus@CvCity@@QAEXW4BonusTypes@@H@Z)
1>Final_Release\CvGameCoreDLL.dll : fatal error LNK1120: 2 unresolved externals
1>NMAKE : fatal error U1077: ""C:\Programme\Microsoft Visual C++ Toolkit 2003/bin/link.exe"": R³ckgabe-Code "0x460"
1>Stop.


Any ideas?
 
Unresolved external symbol means you declared something in the header file (.h) without using it in the .cpp file.

It looks like you forgot this section.

Code:
void CvCity::changeBonusCommerceRateModifier(CommerceTypes eIndex, int iChange)
{
	FAssertMsg(eIndex >= 0, "eIndex expected to be >= 0");
	FAssertMsg(eIndex < GC.getNumBonusInfos(), "eIndex expected to be < GC.getNumBonusInfos()");
	m_aiBonusCommerceRateModifier[eIndex] = (m_aiBonusCommerceRateModifier[eIndex] + iChange);
}

Also, once you get CvCity.cpp, you still have the hardest file left to edit. CvCityAI.cpp. You'll need to add AI logic for your modifiers. Otherwise, they'll never consider the modifiers when choosing buildings to build.
 
Ah yes, that did the trick, the .dll could be created and the effect takes place now, thanks a lot! The only thing is that the bonus isn't displayed in the city calculator of the commerce item. In the example picuture a bouns of +100% for science is active. 9 beakers translate into 18 beakers alright, this translation is just not mentioned. I guess I can live with this, but of course, if you also know how to correct this I would try to get this working, too. ;)
Hmm, CvCityAI.cpp, hoped the flavor values would be sufficient for the computer players to know what to build. Oh well, any hints for this file?

Again, thanks a lot, you made my day!
 

Attachments

  • example.jpg
    example.jpg
    183.6 KB · Views: 94
Ah yes, that did the trick, the .dll could be created and the effect takes place now, thanks a lot! The only thing is that the bonus isn't displayed in the city calculator of the commerce item. In the example picuture a bouns of +100% for science is active. 9 beakers translate into 18 beakers alright, this translation is just not mentioned. I guess I can live with this, but of course, if you also know how to correct this I would try to get this working, too. ;)
Hmm, CvCityAI.cpp, hoped the flavor values would be sufficient for the computer players to know what to build. Oh well, any hints for this file?

Again, thanks a lot, you made my day!

That's because you missed something in CvGameTextMgr.cpp.

Try adding this to "void CvGameTextMgr::setCommerceHelp(CvWStringBuffer &szBuffer, CvCity& city, CommerceTypes eCommerceType)"

Code:
int iBonusCommerce = city.getBonusCommerceModifier(eBonus, eIndex);
    if (0 != iBonusCommerce)
    {
        szBuffer.append(gDLL->getText("TXT_KEY_MISC_HELP_BONUS_COMMERCE", iBonusCommerce, info.getChar()));
        szBuffer.append(NEWLINE);
        iBaseCommerceRate += 100 * iBonusCommerce;
    }

It might not be exactly right, but pretty close to what you need. Of course, you'll need to make a text file for the TXT_KEY, since it doesn't exist yet.
 
Yep, now the calculator also works. Hopefully it will do so in a real game, too.

CvCityAI.cpp next, but I guess not today, I'm rather beaten now... :)
 

Attachments

  • example02.jpg
    example02.jpg
    32.7 KB · Views: 109
Yep, now the calculator also works. Hopefully it will do so in a real game, too.

CvCityAI.cpp next, but I guess not today, I'm rather beaten now... :)

I'm glad you got it all working. The SDK opens up nearly limitless opportunities in Civ4.
 
Cetainly, but it also opens the path to nearly as much headaches. ;)

So, I've tried me at the CvCityAI.cpp now. I'm pretty in the dark here, so I took the getCommerceModifier as template and added my getBonusCommerceModifier to whatever variable the getCommerceModifier was changing. Had to go through all bonustypes of course, thus I had to add a for-loop for them. The modifications look like this now:

Code:
if (bCulturalVictory1)
							{
								BuildingTypes eLoopBuilding = (BuildingTypes) iI;
								CvBuildingInfo& kLoopBuilding = GC.getBuildingInfo(eLoopBuilding);
								int iLoopBuildingCultureModifier = kLoopBuilding.getCommerceModifier(COMMERCE_CULTURE);

//BCM:Added 27.9.09
								
								for (iJ = 0; iJ < GC.getNumBonusInfos(); iJ++)
								{
									iLoopBuildingCultureModifier += kLoopBuilding.getBonusCommerceModifier(iJ,COMMERCE_CULTURE);
								}
								
//BCM:End
								
								if (iLoopBuildingCultureModifier > 0)

(...)

for (iI = 0; iI < NUM_COMMERCE_TYPES; iI++)
				{
					iTempValue = 0;

					iTempValue += (kBuilding.getCommerceChange(iI) * 4);
					iTempValue += (kBuilding.getObsoleteSafeCommerceChange(iI) * 4);
					iTempValue *= 100 + kBuilding.getCommerceModifier(iI);

//BCM:Added 27.9.09
					
					for (iJ = 0; iJ < GC.getNumBonusInfos(); iJ++)
					{
						iTempValue *= 100 + kBuilding.getBonusCommerceModifier(iJ,iI);
					}
					
//BCM:End
					
					iTempValue /= 100;
					
					if ((CommerceTypes)iI == COMMERCE_CULTURE)
					{
					    if (bCulturalVictory1)
					    {
					        iTempValue *= 2;					        
					    }
					}

					if (kBuilding.getCommerceChangeDoubleTime(iI) > 0)
					{
						if ((kBuilding.getCommerceChange(iI) > 0) || (kBuilding.getObsoleteSafeCommerceChange(iI) > 0))
						{
							iTempValue += (1000 / kBuilding.getCommerceChangeDoubleTime(iI));
						}
					}
					
					// add value for a commerce modifier
					
					int iCommerceModifier = kBuilding.getCommerceModifier(iI);

//BCM:Added 27.9.09	
					
					for (iJ = 0; iJ < GC.getNumBonusInfos(); iJ++)
					{
						iCommerceModifier += kBuilding.getBonusCommerceModifier(iJ,iI);
					}

//BCM:End

(...)

if (iFocusFlags & BUILDINGFOCUS_GOLD)
				{
				
					iTempValue = ((kBuilding.getCommerceModifier(COMMERCE_GOLD) * getBaseCommerceRate(COMMERCE_GOLD)) / 40);

//BCM:Added 27.9.09
					
					for (iJ = 0; iJ < GC.getNumBonusInfos(); iJ++)
					{
						iTempValue += ((kBuilding.getBonusCommerceModifier(iJ,COMMERCE_GOLD) * getBaseCommerceRate(COMMERCE_GOLD)) / 40);
					}
					
//BCM:End

(...)

				if (iFocusFlags & BUILDINGFOCUS_RESEARCH)
				{
				
					iTempValue = ((kBuilding.getCommerceModifier(COMMERCE_RESEARCH) * getBaseCommerceRate(COMMERCE_RESEARCH)) / 40);
					
//BCM:Added 27.9.09					

					for (iJ = 0; iJ < GC.getNumBonusInfos(); iJ++)
					{
						iTempValue += ((kBuilding.getBonusCommerceModifier(iJ,COMMERCE_RESEARCH) * getBaseCommerceRate(COMMERCE_RESEARCH)) / 40);
					}
					
//BCM:End

(...)

//BCM:Added 27.9.09
					
					iValue += ((kBuilding.getCommerceModifier(COMMERCE_CULTURE) * getBaseCommerceRate(COMMERCE_CULTURE)) / 15);
					
					for (iJ = 0; iJ < GC.getNumBonusInfos(); iJ++)
					{
						iValue += ((kBuilding.getBonusCommerceModifier(iJ,COMMERCE_CULTURE) * getBaseCommerceRate(COMMERCE_CULTURE)) / 15);
					}
					
					if (GC.getGameINLINE().isOption(GAMEOPTION_NO_ESPIONAGE))
					{
						iValue += ((kBuilding.getCommerceModifier(COMMERCE_ESPIONAGE) * getBaseCommerceRate(COMMERCE_ESPIONAGE)) / 15);
						
						for (iJ = 0; iJ < GC.getNumBonusInfos(); iJ++)
						{
							iValue += ((kBuilding.getBonusCommerceModifier(iJ,COMMERCE_ESPIONAGE) * getBaseCommerceRate(COMMERCE_ESPIONAGE)) / 15);
						}
					}
					
				}
				
                if (iFocusFlags & BUILDINGFOCUS_BIGCULTURE)
				{
					iTempValue = (kBuilding.getCommerceModifier(COMMERCE_CULTURE) / 5);
					
					for (iJ = 0; iJ < GC.getNumBonusInfos(); iJ++)
					{
						iTempValue += (kBuilding.getBonusCommerceModifier(iJ,COMMERCE_CULTURE) / 5);
					}
					
					if (iTempValue != 0)
					{
						if (MAX_INT == aiCommerceRank[COMMERCE_CULTURE])
						{
							aiCommerceRank[COMMERCE_CULTURE] = findCommerceRateRank(COMMERCE_CULTURE);
						}

						// if this is a limited wonder, and we are not one of the top 4 in this category, 
						// do not count the culture value
						// we probably do not want to build this here (but we might)
						if (bIsLimitedWonder && (aiCommerceRank[COMMERCE_CULTURE] > (3 + iLimitedWonderLimit)))
						{
							iTempValue  = 0;
						}

						iValue += iTempValue;
					}
				}
				
				if (iFocusFlags & BUILDINGFOCUS_ESPIONAGE || (GC.getGameINLINE().isOption(GAMEOPTION_NO_ESPIONAGE) && (iFocusFlags & BUILDINGFOCUS_CULTURE)))
				{
					iTempValue = ((kBuilding.getCommerceModifier(COMMERCE_ESPIONAGE) * getBaseCommerceRate(COMMERCE_ESPIONAGE)) / 60);
					
					for (iJ = 0; iJ < GC.getNumBonusInfos(); iJ++)
					{
						iTempValue += ((kBuilding.getBonusCommerceModifier(iJ,COMMERCE_ESPIONAGE) * getBaseCommerceRate(COMMERCE_ESPIONAGE)) / 60);
					}
					
					if (iTempValue != 0)
					{
						if (MAX_INT == aiCommerceRank[COMMERCE_ESPIONAGE])
						{
							aiCommerceRank[COMMERCE_ESPIONAGE] = findCommerceRateRank(COMMERCE_ESPIONAGE);
						}

						// if this is a limited wonder, and we are not one of the top 4 in this category, subtract the value
						// we do _not_ want to build this here (unless the value was small anyway)
						if (bIsLimitedWonder && (aiCommerceRank[COMMERCE_ESPIONAGE] > (3 + iLimitedWonderLimit)))
						{
							iTempValue *= -1;
						}

						iValue += iTempValue;
					}
					iTempValue = (kBuilding.getCommerceChange(COMMERCE_ESPIONAGE) * 3);
					iTempValue += (kBuilding.getObsoleteSafeCommerceChange(COMMERCE_ESPIONAGE) * 3);
					iTempValue *= 100 + kBuilding.getCommerceModifier(COMMERCE_ESPIONAGE);
					
					for (iJ = 0; iJ < GC.getNumBonusInfos(); iJ++)
					{
						iTempValue *= 100 + kBuilding.getBonusCommerceModifier(iJ,COMMERCE_ESPIONAGE);
					}
					
					iValue += iTempValue / 100;
				}
			}
			
//BCM:End

There are some entries with getCommerceModifier I haven't touched, these are
Code:
if (eProductionBuilding != NO_BUILDING)
			{
				if (GC.getBuildingInfo(eProductionBuilding).getCommerceModifier(COMMERCE_GOLD) > 0)
				{
					if (GET_PLAYER(getOwnerINLINE()).AI_isFinancialTrouble())
					{
						if (getBaseCommerceRate(COMMERCE_GOLD) >= 16)
						{
							iMinTurns = std::min(iMinTurns, 10);
						}
					}
				}
			}

			if (eProductionBuilding != NO_BUILDING)
			{
				if (GC.getBuildingInfo(eProductionBuilding).getCommerceModifier(COMMERCE_RESEARCH) > 0)
				{
					if (!(GET_PLAYER(getOwnerINLINE()).AI_avoidScience()))
					{
						if (getBaseCommerceRate(COMMERCE_RESEARCH) >= 16)
						{
							iMinTurns = std::min(iMinTurns, 10);
						}
					}
				}
			}

but I hope the computer player can do without the bonus information at these places. The .dll got constructed with no errors and the game runs without problems so far, will have to do some playtesting now.
 
That AI logic looks fine to me, but it's hard to tell without actually playing games and seeing if they overbuild or under-build those buildings.
 
Well, unsurprisingly there are some problems with my mod. Both games I played so far kicked the bucket around 500 b.c.. I guess there are some internal variables that got an overflow or something like this. Civ 4 sadly keeps quite about the reason it shut down, is there some way to get to know why it did so? Or should I now try to drop as much changed code as possible? For example, I would start to create a .dll without the CvCityAI.cpp.
 
Well, unsurprisingly there are some problems with my mod. Both games I played so far kicked the bucket around 500 b.c.. I guess there are some internal variables that got an overflow or something like this. Civ 4 sadly keeps quite about the reason it shut down, is there some way to get to know why it did so? Or should I now try to drop as much changed code as possible? For example, I would start to create a .dll without the CvCityAI.cpp.

Are you using VS 2008? If so, compile a Debug DLL and load that troubled save. See what errors pop up.
 
I'm using Visual C++ 2005 Express. I tried to compile a Debug.dll, got a 12,5 MB file that says "Failed initializing Python" when I try to start the mod. Guess tomorrow I'll have to dig in the explanations how to create this file right.
 
So I now successfully build a Debug.dll using the instructions from Fagan:
http://forums.civfanatics.com/showthread.php?t=196283&page=12
(I'm using BTS 3.17 btw)
The .dll is 12,5 MB in size, the game loads with no problems, but I just can't find the debug menu. Also, under "About this build" my build is still called FINAL RELEASE, which leaves me a bit confused. :confused:
 
So I now successfully build a Debug.dll using the instructions from Fagan:
http://forums.civfanatics.com/showthread.php?t=196283&page=12
(I'm using BTS 3.17 btw)
The .dll is 12,5 MB in size, the game loads with no problems, but I just can't find the debug menu. Also, under "About this build" my build is still called FINAL RELEASE, which leaves me a bit confused. :confused:

Once you've gotten Civ4 loaded with your mod, or whatever, in VS (While Civ is running. I advise running Civ in windowed mode.), under the debug column, choose "attach to Process" and from the list, select the civilization4bts process. Then, load up the save with the CTD, or play until you get an assert. Then you can hit "debug" on the assert, and it will take you to the code.
 
Okay, done. VS gives any error before the game fully dies on me and after that I get this screen. Does this help?
 

Attachments

  • VSScreen.jpg
    VSScreen.jpg
    211.2 KB · Views: 93
Okay, done. VS gives any error before the game fully dies on me and after that I get this screen. Does this help?

Yes and no. It tells you roughly where the error is, but what would be better, is to right click on that section and select "Show Source Code" so you can actually see the code that is failing.
 
Hmmm, there are two pop-up error messages. The first one says (more or less, I have to translate):
"Untreated exception at 0x01eec350 (CvGameCoreDLL.dll) in Civ4BeyondSword.exe: 0xC0000005: access violation while reading position 0x00000010."
Second one:
"No source code available for current position"
with the option "Display disassembly"
After chosing this option, the screen shown in the screen shot appears. Right click on the section shows that "Show Source Code" is activated. Only option not activated is "Show codebytes". But that one only adds some numbers, 8B 51 10 for the section.
 
Hmmm, there are two pop-up error messages. The first one says (more or less, I have to translate):
"Untreated exception at 0x01eec350 (CvGameCoreDLL.dll) in Civ4BeyondSword.exe: 0xC0000005: access violation while reading position 0x00000010."
Second one:
"No source code available for current position"
with the option "Display disassembly"
After chosing this option, the screen shown in the screen shot appears. Right click on the section shows that "Show Source Code" is activated. Only option not activated is "Show codebytes". But that one only adds some numbers, 8B 51 10 for the section.


You should be able to maneuver to the sources that are causing the problems. Once there, if you hover over variables, it will display the values in them. Play around with a bit, see if you can get it to work.
 
Top Bottom