There are a few array examples you can start with. CvCivicInfo has several itself; let's go with m_paiBuildingHappinessChanges because it's closest I think: number of slots in the array defined by XML rather than code and it has the same type (int).
Let's do the civic modifier value first since it's the same type as the example. I'm also going to call it "CivicAttitude
Changes" because Modifier in code tends to mean a percentage whereas Change means an added value.
You declare it easily enough in the header file by adding a * after its type (int):
Code:
// Arrays
...
int** m_ppiImprovementYieldChanges;
[B]int* m_piCivicAttitudeChanges;[/B]
In the source (.ccp) file you need to initialize it in the constructor,
Code:
CvCivicInfo::CvCivicInfo() :
...
m_ppiImprovementYieldChanges(NULL)[B],[/B] [I]// don't forget to add a comma[/I]
[B]m_piCivicAttitudeChanges(NULL)[/B]
{
}
delete it in the destructor,
Code:
CvCivicInfo::~CvCivicInfo()
{
...
if (m_ppiImprovementYieldChanges != NULL)
{ ... }
[B]SAFE_DELETE_ARRAY(m_piCivicAttitudeChanges);[/B]
}
provide access to its values (don't forget to declare this new function in the header file),
Code:
int CvCivicInfo::getCivicAttitudeChange(int i) const
{
FAssertMsg(i < GC.getNumCivicInfos(), "Index out of bounds");
FAssertMsg(i > -1, "Index out of bounds");
return m_piCivicAttitudeChanges ? m_piCivicAttitudeChanges[i] : 0;
}
read/write it to a saved game (I leave this to you as it's exactly like example), and read them from XML. This last one is tricky because it will have the message text keys paired up with the civics and modifiers rather than number-of-civics values in a list.
Note that the way I've coded this allows for civic to have modifiers applied to civics in different option lists (legal versus government). For example, Free Religion could be angered by a Police State. To constrain the modifiers to within the same civic option actually makes the code harder, so I think this is the way to go. Nothing forces you to actually have any modifiers cross any option groupings, but the option is there for those that want it.
To access these modifiers in the game you need to take this cross-option grouping into account and check for a modifier for each civic combination the pair of players is running. Let's say player X is running A, B, C, D, and E while player Y is running 1, 2, 3, 4, and 5. You need to list the modifiers for A1, A2, A3, ... E3, E4, E5 (5 x 5 = 25 total possible modifiers.
Code:
int CvPlayerAI::AI_getCivicAttitudeModifier(PlayerTypes ePlayer) const
{
int iAttitude = 0;
// add modifier for every combination of civics between the two players
for (int iI = 0; iI < GC.getNumCivicOptionInfos(); iI++)
{
for (int iJ = 0; iJ < GC.getNumCivicOptionInfos(); iJ++)
{
iAttitude += GC.getCivicInfo(getCivics((CivicOptionTypes)iI)).getCivicAttitudeChange(GET_PLAYER(ePlayer).getCivics((CivicOptionTypes)iJ));
}
}
return iAttitude;
}
This code assumes that the modifiers in Civic X determine how a player running that civic feel about players running the other civics. I had originally thought it would be the other way around. You need to decide which you'd prefer in XML where users will deal with it:
- Slavery has a list of modifiers that affect other player's attitude toward a Slavery player, or
- Slavery stores a list of modifiers that affect a Slavery player's attitude toward other players.
If you prefer the first method in XML instead, use this line in the above code:
Code:
iAttitude += GC.getCivicInfo(GET_PLAYER(ePlayer).getCivics((CivicOptionTypes)iJ)).getCivicAttitudeChange(getCivics((CivicOptionTypes)iI));
You will use a similar nested loop in CvGameTextMgr to display all these individual attitude modifiers and their messages. Instead of adding to a single value, if the value isn't zero you'll add its message containing the value to the string buffer.
So now, reading from XML.
This is the trickiest part and will have to come later. For now, you can set a few test values in the function that does the XML reading after creating the array.
Hmm, actually it's going to be tougher than I thought. The problem is that you cannot reference CIVIC_FOO strings while parsing the civics. You may have to first read all the values into temporary arrays and then post-process these arrays into the real arrays after reading all civics. Is there a function that gets called after reading in all civics or after reading all XML data?
What I mean is that while reading in the definitions for civics you cannot look up a civic by its key (that civic may not have been parsed yet). Instead you'll store the key itself ("CIVIC_SLAVERY") in the CvCivicInfo. Once all civics have been read in you can now look them up by key, so you call another function that loops over all civics and performs the lookup to build the actual arrays.
Homework for you: Find a function that gets called either a) after all civics have been processed or b) after all XML has been processed. It will be in the core XML loading routines outside of CvInfo.cpp. I recall seeing functions with SecondPass in the name. These are good starts as this is what we will need to do, a second pass over the data you just read to process it further.
xienwolf can probably tell you straight away where to look or the actual function itself.