Maniac
Apolyton Sage
I'd like buildings to be able to change the yield of a specialist in their city alone (instead of empire-wide like Angkor Wat).
CCCP already had something like that. Unfortunately that mod was for Warlords 2.08. So some code needed to be changed. I don't know if I made some mistakes transferring, or if the original code was never working properly to begin with, but the code is working not properly at all.
I added this building which lets the Citizen produce +2 hammers, for a total of three. It leads to a bunch of strange situations though. Examples:
1) The Engineer doesn't produce any hammers at all anymore.
2) If I appoint two citizen specialist, the city yield is 9 hammers, while it should be seven (six from citizens, plus one from city square).
3) If I add the Genejack Factory (building which gives the extra hammers to citizens) in Worldbuilder while I already had two citizens appointed, there's no extra yield. When I remove the citizen specialists, the city production changes to -1...
There are also a bunch of troubles with gametext.
So therefore I'm wondering if anyone would be interested in having a look at the code, see if the problem is easy to fix, or if not, if someone would perhaps be interested in writing a modcomp for local specialist yield changes.
I'll list the changes to CvCity.cpp here:
For the following getExtraSpecialistYield code I found it strange Impaler (the writer of this code) removed the reference to FreeSpecialists. However neither with or without a reference to them, the same problems remain. For the record, in my mod all cities start with one free specialist.
In the Gametext file there are modifications in two places: specialisthelp and buildinghelp.
This is the Warlords code for buildinghelp:
Gametext seems to be done a little differently in BtS, so I changed it accordingly. szBuffer.append(NEWLINE); for instance.
Anyway, I don't know if this is what Impaler intended, but the help gave a list of ALL specialists for ALL buildings, and in the line there under what yield bonus they gave. Usually nothing.
So I tried modifying something myself, which resulted in this. Note that I don't really understand the code. I'm just kinda mimicking some stuff i've seen elsewhere, and hoping it works.
The result is only partially succesful. There is no longer a list of all specialists for all buildings. However I'd prefer the help text to say "+2 hammers from Citizen in this base". Instead it says "%s1_Yield from in This Base". and on the next line "+2 hammers". I've no idea how to create my desired help text.
Then there's the specialist help text. Impaler's code has a really inconsistent use of indentation, plus there even seemed to be some {}'s missing, so I don't really see how it could have worked. Here it is:
I figured I'd start more modest and only copy over part of the stuff.
While I'm looking at civilopedia from the start screen, there's no problem. However, when in a game the help for all specialists in Civilopedia says "+ some infinite number hammers, + infinite commerce". In the city screen, the citizen correctly says +3 hammers when there's a Genejack Factory though.
Can anyone make sense of this mess?
CCCP already had something like that. Unfortunately that mod was for Warlords 2.08. So some code needed to be changed. I don't know if I made some mistakes transferring, or if the original code was never working properly to begin with, but the code is working not properly at all.
I added this building which lets the Citizen produce +2 hammers, for a total of three. It leads to a bunch of strange situations though. Examples:
1) The Engineer doesn't produce any hammers at all anymore.
2) If I appoint two citizen specialist, the city yield is 9 hammers, while it should be seven (six from citizens, plus one from city square).
3) If I add the Genejack Factory (building which gives the extra hammers to citizens) in Worldbuilder while I already had two citizens appointed, there's no extra yield. When I remove the citizen specialists, the city production changes to -1...
There are also a bunch of troubles with gametext.
So therefore I'm wondering if anyone would be interested in having a look at the code, see if the problem is easy to fix, or if not, if someone would perhaps be interested in writing a modcomp for local specialist yield changes.
I'll list the changes to CvCity.cpp here:
Code:
CvCity::CvCity()
{
m_ppaaiLocalSpecialistExtraYield = NULL;
}
Code:
void CvCity::uninit()
{
int iI;
if (m_ppaaiLocalSpecialistExtraYield != NULL)
{
for (iI = 0; iI < GC.getNumSpecialistInfos(); iI++)
{
SAFE_DELETE_ARRAY(m_ppaaiLocalSpecialistExtraYield[iI]);
}
SAFE_DELETE_ARRAY(m_ppaaiLocalSpecialistExtraYield);
}
}
Code:
void CvCity::reset(int iID, PlayerTypes eOwner, int iX, int iY, bool bConstructorCall)
{
int iI;
if (!bConstructorCall)
{
FAssertMsg(0 < GC.getNumSpecialistInfos(), "GC.getNumSpecialistInfos() is not greater than zero but it is used to allocate memory in CvPlayer::reset");
FAssertMsg(m_ppaaiLocalSpecialistExtraYield==NULL, "about to leak memory, CvPlayer::m_ppaaiSpecialistExtraYield");
m_ppaaiLocalSpecialistExtraYield = new int*[GC.getNumSpecialistInfos()];
for (iI = 0; iI < GC.getNumSpecialistInfos(); iI++)
{
m_ppaaiLocalSpecialistExtraYield[iI] = new int[NUM_YIELD_TYPES];
for (int iJ = 0; iJ < NUM_YIELD_TYPES; iJ++)
{
m_ppaaiLocalSpecialistExtraYield[iI][iJ] = 0;
}
}
}
}
Code:
void CvCity::processBuilding(BuildingTypes eBuilding, int iChange, bool bObsolete)
{
int iI, iJ;
if (!(GET_TEAM(getTeam()).isObsoleteBuilding(eBuilding)) || bObsolete)
{
for (iI = 0; iI < GC.getNumSpecialistInfos(); iI++)
{
for (iJ = 0; iJ < NUM_YIELD_TYPES; iJ++)
{
changeLocalSpecialistYieldChange(((SpecialistTypes)iI), ((YieldTypes)iJ), (GC.getBuildingInfo(eBuilding).getLocalSpecialistYieldChange(iI, iJ) * iChange));
}
}
}
}
Code:
void CvCity::processSpecialist(SpecialistTypes eSpecialist, int iChange)
{
int iI;
for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
{
changeBaseYieldRate(((YieldTypes)iI), ((GC.getSpecialistInfo(eSpecialist).getYieldChange(iI) + getLocalSpecialistYieldChange(eSpecialist, YieldTypes(iI))) * iChange));
}
}
For the following getExtraSpecialistYield code I found it strange Impaler (the writer of this code) removed the reference to FreeSpecialists. However neither with or without a reference to them, the same problems remain. For the record, in my mod all cities start with one free specialist.
Code:
int CvCity::getExtraSpecialistYield(YieldTypes eIndex, SpecialistTypes eSpecialist) const
{
FAssertMsg(eIndex >= 0, "eIndex expected to be >= 0");
FAssertMsg(eIndex < NUM_YIELD_TYPES, "eIndex expected to be < NUM_YIELD_TYPES");
FAssertMsg(eSpecialist >= 0, "eSpecialist expected to be >= 0");
FAssertMsg(eSpecialist < GC.getNumSpecialistInfos(), "GC.getNumSpecialistInfos expected to be >= 0");
//return ((getSpecialistCount(eSpecialist) + getFreeSpecialistCount(eSpecialist)) * GET_PLAYER(getOwnerINLINE()).getSpecialistExtraYield(eSpecialist, eIndex)); // original
//return ((getSpecialistCount(eSpecialist) + getFreeSpecialistCount(eSpecialist)) * (GET_PLAYER(getOwnerINLINE()).getSpecialistExtraYield(eSpecialist, eIndex) + getLocalSpecialistYieldChange(eSpecialist, eIndex))); // Planetfall Maniac attempt
return (getSpecialistCount(eSpecialist) * (GET_PLAYER(getOwnerINLINE()).getSpecialistExtraYield(eSpecialist, eIndex) + getLocalSpecialistYieldChange(eSpecialist, eIndex))); // Impaler
}
int CvCity::getLocalSpecialistYieldChange(SpecialistTypes eSpecialist, YieldTypes eYield) const //Addition LocalSpecialistYieldChange by Impaler[WrG]
{
return m_ppaaiLocalSpecialistExtraYield[eSpecialist][eYield];
}
void CvCity::changeLocalSpecialistYieldChange(SpecialistTypes eSpecialist, YieldTypes eYield, int iChange) //Addition LocalSpecialistYieldChange by Impaler[WrG] 5/16/06
{
int iYield = m_ppaaiLocalSpecialistExtraYield[eSpecialist][eYield];
m_ppaaiLocalSpecialistExtraYield[eSpecialist][eYield] = iYield + iChange;
}
Code:
void CvCity::read(FDataStreamBase* pStream)
{
int iI;
for (iI=0;iI<GC.getNumSpecialistInfos();iI++)
{
pStream->Read(NUM_YIELD_TYPES, m_ppaaiLocalSpecialistExtraYield[iI]);
}
}
Code:
void CvCity::write(FDataStreamBase* pStream)
{
int iI;
for (iI=0;iI<GC.getNumSpecialistInfos();iI++)
{
pStream->Write(NUM_YIELD_TYPES, m_ppaaiLocalSpecialistExtraYield[iI]);
}
}
In the Gametext file there are modifications in two places: specialisthelp and buildinghelp.
This is the Warlords code for buildinghelp:
Code:
void CvGameTextMgr::setBuildingHelp(CvWString &szBuffer, BuildingTypes eBuilding, bool bCivilopediaText, bool bStrategyText, bool bTechChooserText, CvCity* pCity)
{
CvWString szFirstBuffer;
int iI;
for (iI = 0; iI < GC.getNumSpecialistInfos(); iI++)
{
szFirstBuffer += NEWLINE + gDLL->getText("TXT_KEY_BUILDING_FROM_THIS_CITY", GC.getSpecialistInfo((SpecialistTypes) iI).getTextKeyWide());
setYieldChangeHelp(szBuffer, L"", L"", szFirstBuffer, GC.getBuildingInfo(eBuilding).getLocalSpecialistYieldChangeArray(iI));
}
}
Gametext seems to be done a little differently in BtS, so I changed it accordingly. szBuffer.append(NEWLINE); for instance.
Anyway, I don't know if this is what Impaler intended, but the help gave a list of ALL specialists for ALL buildings, and in the line there under what yield bonus they gave. Usually nothing.
So I tried modifying something myself, which resulted in this. Note that I don't really understand the code. I'm just kinda mimicking some stuff i've seen elsewhere, and hoping it works.
Code:
void CvGameTextMgr::setBuildingHelp(CvWStringBuffer &szBuffer, BuildingTypes eBuilding, bool bCivilopediaText, bool bStrategyText, bool bTechChooserText, CvCity* pCity)
{
CvWString szFirstBuffer;
int iI;
int iJ;
for (iI = 0; iI < GC.getNumSpecialistInfos(); iI++)
{
for (iJ = 0; iJ < NUM_YIELD_TYPES; ++iJ)
{
if (GC.getBuildingInfo(eBuilding).getLocalSpecialistYieldChange(iI, iJ) != 0)
{
szBuffer.append(NEWLINE);
szBuffer.append(gDLL->getText("TXT_KEY_BUILDING_FROM_THIS_BASE", GC.getBuildingInfo(eBuilding).getLocalSpecialistYieldChangeArray(iI), GC.getSpecialistInfo((SpecialistTypes) iI).getTextKeyWide()));
setYieldChangeHelp(szBuffer, L"", L"", L"", GC.getBuildingInfo(eBuilding).getLocalSpecialistYieldChangeArray(iI));
}
}
}
}
Code:
<TEXT>
<Tag>TXT_KEY_BUILDING_FROM_THIS_BASE</Tag>
<English>%s1_Yield[SPACE]from [COLOR_UNIT_TEXT][LINK=literal]%s1_SpclstName[\LINK][COLOR_REVERT] in This Base</English>
<French>%s1_Yield[SPACE]de tous les [COLOR_UNIT_TEXT][LINK=literal]%s1_SpclstName[\LINK][COLOR_REVERT] dans toutes les villes</French>
<German>%s1_Yield[SPACE]per [LINK=literal]%s1:2_SpclstName[\LINK] in allen Städten</German>
<Italian>%s1_Yield[SPACE]per [COLOR_UNIT_TEXT][LINK=literal]%s1:2_SpclstName[\LINK][COLOR_REVERT] in tutte le città</Italian>
<Spanish>%s1_Yield[SPACE]por [COLOR_UNIT_TEXT][LINK=literal]%s1_SpclstName[\LINK][COLOR_REVERT] en todas las ciudades</Spanish>
</TEXT>
The result is only partially succesful. There is no longer a list of all specialists for all buildings. However I'd prefer the help text to say "+2 hammers from Citizen in this base". Instead it says "%s1_Yield from in This Base". and on the next line "+2 hammers". I've no idea how to create my desired help text.
Then there's the specialist help text. Impaler's code has a really inconsistent use of indentation, plus there even seemed to be some {}'s missing, so I don't really see how it could have worked. Here it is:
Code:
void CvGameTextMgr::parseSpecialistHelp(CvWString &szHelpString, SpecialistTypes eSpecialist, CvCity* pCity, bool bCivilopediaText)
{
CvWString szText;
int aiYields[NUM_YIELD_TYPES];
int aiCommerces[NUM_COMMERCE_TYPES];
int iI;
if (eSpecialist != NO_SPECIALIST)
{
if (!bCivilopediaText)
{
szHelpString=GC.getSpecialistInfo(eSpecialist).getDescription();
for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
{
//Start Change LocalSpecialistYieldChange by Impaler[WrG] 5/16/06
//ORIGINAL CODE aiYields[iI] = GET_PLAYER((pCity != NULL) ? pCity->getOwnerINLINE() : GC.getGameINLINE().getActivePlayer()).specialistYield(eSpecialist, ((YieldTypes)iI));
int LocalYieldChange = 0;
if (pCity != NULL)
LocalYieldChange = pCity->getLocalSpecialistYieldChange(eSpecialist, (YieldTypes)iI);
aiYields[iI] = GET_PLAYER((pCity != NULL) ? pCity->getOwnerINLINE() : GC.getGameINLINE().getActivePlayer()).specialistYield(eSpecialist, ((YieldTypes)iI)) + LocalYieldChange;
//End Change
}
setYieldChangeHelp(szHelpString, L"", L"", L"", aiYields);
if (bCivilopediaText)
{
for (int iY = 0; iY < NUM_YIELD_TYPES; iY++)
{
//Start Change SpecialistPediaStrings by Impaler[WrG]
//ORIGINAL CODE aiYields= GC.getSpecialistInfo(eSpecialist).getYieldChange(iI);
if (GC.getSpecialistInfo(eSpecialist).getYieldChange(iY) != 0)
{
szHelpString += gDLL->getText("TXT_KEY_BASE_SPECIALIST_OUTPUT", GC.getSpecialistInfo(eSpecialist).getYieldChange(iY), GC.getYieldInfo((YieldTypes)iY).getChar());
szHelpString += NEWLINE;
}
//End Change
}
szHelpString += NEWLINE;
for (int iYield = 0; iYield < NUM_YIELD_TYPES; iYield++)
{
for (int iBuilding = 0; iBuilding < GC.getNumBuildingInfos(); iBuilding++)
{
if(0 != GC.getBuildingInfo((BuildingTypes)iBuilding).getLocalSpecialistYieldChange(eSpecialist, iYield))
{
szHelpString += gDLL->getText("TXT_KEY_PEDIA_TECH_YIELD", GC.getYieldInfo((YieldTypes)iYield).getTextKeyWide(), GC.getBuildingInfo((BuildingTypes)iBuilding).getLocalSpecialistYieldChange(eSpecialist, iYield), GC.getYieldInfo((YieldTypes)iYield).getChar(), GC.getBuildingInfo((BuildingTypes)iBuilding).getTextKeyWide());
szHelpString += NEWLINE;
}
}
}
I figured I'd start more modest and only copy over part of the stuff.
Code:
void CvGameTextMgr::parseSpecialistHelp(CvWStringBuffer &szHelpString, SpecialistTypes eSpecialist, CvCity* pCity, bool bCivilopediaText)
{
PROFILE_FUNC();
CvWString szText;
int aiYields[NUM_YIELD_TYPES];
int aiCommerces[NUM_COMMERCE_TYPES];
int iI;
if (eSpecialist != NO_SPECIALIST)
{
if (!bCivilopediaText)
{
szHelpString.append(GC.getSpecialistInfo(eSpecialist).getDescription());
}
for (iI = 0; iI < NUM_YIELD_TYPES; ++iI)
{
if (GC.getGameINLINE().getActivePlayer() == NO_PLAYER)
{
aiYields[iI] = GC.getSpecialistInfo(eSpecialist).getYieldChange(iI);
}
else
{
int LocalYieldChange = 0;
if (pCity != NULL)
{
LocalYieldChange = pCity->getLocalSpecialistYieldChange(eSpecialist, (YieldTypes)iI);
aiYields[iI] = GET_PLAYER((pCity != NULL) ? pCity->getOwnerINLINE() : GC.getGameINLINE().getActivePlayer()).specialistYield(eSpecialist, ((YieldTypes)iI)) + LocalYieldChange;
}
}
}
setYieldChangeHelp(szHelpString, L"", L"", L"", aiYields);
...
While I'm looking at civilopedia from the start screen, there's no problem. However, when in a game the help for all specialists in Civilopedia says "+ some infinite number hammers, + infinite commerce". In the city screen, the citizen correctly says +3 hammers when there's a Genejack Factory though.
Can anyone make sense of this mess?