Modders Guide to FfH2

Well here is the XML, and I dont see anything that would remove the pig and give a Hill Giant to the player.

Spoiler :
Code:
        <EventTriggerInfo>
            <Type>EVENTTRIGGER_PIG_GIANT</Type>
            <WorldNewsTexts>
                <Text></Text>
            </WorldNewsTexts>
            <TriggerTexts>
                <TriggerText>
                    <Text>TXT_KEY_EVENT_PIG_GIANT</Text>
                    <Era>NONE</Era>
                </TriggerText>
            </TriggerTexts>
            <bSinglePlayer>0</bSinglePlayer>
            <iPercentGamesActive>100</iPercentGamesActive>
            <iWeight>400</iWeight>
            <bProbabilityUnitMultiply>0</bProbabilityUnitMultiply>
            <bProbabilityBuildingMultiply>0</bProbabilityBuildingMultiply>
            <Civic>NONE</Civic>
            <iMinTreasury>0</iMinTreasury>
            <iMinPopulation>0</iMinPopulation>
            <iMaxPopulation>0</iMaxPopulation>
            <iMinMapLandmass>0</iMinMapLandmass>
            <iMinOurLandmass>0</iMinOurLandmass>
            <iMaxOurLandmass>-1</iMaxOurLandmass>
            <MinDifficulty>NONE</MinDifficulty>
            <iAngry>0</iAngry>
            <iUnhealthy>0</iUnhealthy>
            <UnitsRequired>
            </UnitsRequired>
            <iNumUnits>0</iNumUnits>
            <iNumUnitsGlobal>0</iNumUnitsGlobal>
            <iUnitDamagedWeight>0</iUnitDamagedWeight>
            <iUnitDistanceWeight>0</iUnitDistanceWeight>
            <iUnitExperienceWeight>0</iUnitExperienceWeight>
            <bUnitsOnPlot>0</bUnitsOnPlot>
            <BuildingsRequired>
            </BuildingsRequired>
            <iNumBuildings>0</iNumBuildings>
            <iNumBuildingsGlobal>0</iNumBuildingsGlobal>
            <iNumPlotsRequired>1</iNumPlotsRequired>
            <bOwnPlot>1</bOwnPlot>
            <iPlotType>-1</iPlotType>
            <FeaturesRequired>
            </FeaturesRequired>
            <TerrainsRequired>
            </TerrainsRequired>
            <ImprovementsRequired>
            </ImprovementsRequired>
            <BonusesRequired>
                <BonusType>BONUS_PIG</BonusType>
            </BonusesRequired>
            <RoutesRequired>
            </RoutesRequired>
            <ReligionsRequired>
            </ReligionsRequired>
            <iNumReligions>0</iNumReligions>
            <CorporationsRequired>
            </CorporationsRequired>
            <iNumCorporations>0</iNumCorporations>
            <bPickReligion>0</bPickReligion>
            <bStateReligion>0</bStateReligion>
            <bHolyCity>0</bHolyCity>
            <bPickCorporation>0</bPickCorporation>
            <bHeadquarters>0</bHeadquarters>
            <Events>
                <Event>EVENT_PIG_GIANT_1</Event>
                <Event>EVENT_PIG_GIANT_2</Event>
                <Event>EVENT_PIG_GIANT_3</Event>
            </Events>
            <PrereqEvents>
            </PrereqEvents>
            <bPrereqEventPlot>0</bPrereqEventPlot>
            <OrPreReqs>
                <PrereqTech>TECH_ANIMAL_HUSBANDRY</PrereqTech>
            </OrPreReqs>
            <AndPreReqs>
            </AndPreReqs>
            <ObsoleteTechs>
            </ObsoleteTechs>
            <bRecurring>0</bRecurring>
            <bTeam>0</bTeam>
            <bGlobal>0</bGlobal>
            <bPickPlayer>0</bPickPlayer>
            <bOtherPlayerWar>0</bOtherPlayerWar>
            <bOtherPlayerHasReligion>0</bOtherPlayerHasReligion>
            <bOtherPlayerHasOtherReligion>0</bOtherPlayerHasOtherReligion>
            <bOtherPlayerAI>0</bOtherPlayerAI>
            <iOtherPlayerShareBorders>0</iOtherPlayerShareBorders>
            <OtherPlayerHasTech>NONE</OtherPlayerHasTech>
            <bPickCity>0</bPickCity>
            <bPickOtherPlayerCity>0</bPickOtherPlayerCity>
            <bShowPlot>1</bShowPlot>
            <iCityFoodWeight>0</iCityFoodWeight>
            <PythonCanDo>canTriggerPlotEmpty</PythonCanDo>
            <PythonCanDoCity></PythonCanDoCity>
            <PythonCanDoUnit></PythonCanDoUnit>
            <PythonCallback></PythonCallback>
            <iPrereqCrime>0</iPrereqCrime>
            <iPrereqGlobalCounter>0</iPrereqGlobalCounter>
            <PrereqAlignment>NONE</PrereqAlignment>
            <PrereqCivilizationPleased>NONE</PrereqCivilizationPleased>
            <PrereqLeader>NONE</PrereqLeader>
            <PrereqTrait>NONE</PrereqTrait>
        </EventTriggerInfo>
 
in globaldefinesalt.xml change MAX_EXPERIENCE_AFTER_UPGRADE from 10 to whatever value you want.

Thank you for this information. Is there a way to do this with a promotion, so that only certain units get to keep [X] experience after an upgrade while others use whatever is set in globaldefinesalt.xml?

Basically, I was thinking of a leader trait that would add such a promotion, so only units of that leader would retain more experience after an upgrade. (This is in reference to non-FfH mods of course.)
 
in globaldefinesalt.xml change MAX_EXPERIENCE_AFTER_UPGRADE from 10 to whatever value you want.
Thank you.

But that parameter is not always in globaldefinesalt.xml like in FfH.
In Lor I've found it in globaldefines.xml

In any case, now i know where to search and what.
 
I ran into a little debugging problem. I have a savegame that CTDs, but when I run FFH via the debugger (Visual Studio 2005), the game doesn't crash! How can I track down what's causing this issue and/or does anyone have any clue what I should be looking for?
 
You can set up a logging system. Civ4 already has some methods that easily allow you to write messages to log files.

Basically you write some messages to the log file when programs reaches some points in the code. So, if the game breaks, you can see what message was written last to the log file.

For a single crash it's probably not worth it to set up a logging system, unless it's a very serious crash.
 
Forgot to update my post. Turned out it was just my carelessness. I was trying to debug with a release DLL. Once I switched to the debug DLL I was able to track down the problem. Thanks for the suggestion about logging though. That's a useful trick to keep in mind.
 
I'm looking in the CvInfos section of the DLL, and wondering what exactly this does:

Spoiler :
Code:
SAFE_DELETE_ARRAY(m_pbMaintainFeatures);
	m_pbMaintainFeatures = new bool[GC.getNumFeatureInfos()];
	stream->Read(GC.getNumFeatureInfos(), m_pbMaintainFeatures);

There's another safe_delete_array function (though just a plain one) in another place in CvInfos, so it's hard to tell what this one is doing.

(I'm looking at this array as an analogy for a theoretical civilization specific terrain feature happiness, which is why I'm curious about this particular one.)

Edit: Turns out I think I know what it is. Than again, it is late, so I'm more likely than usual to mess something up, so might as well leave this up here just in case.
 
Got a couple other questions:


I've adjusted some improvements and the Guardian of Nature forest effect to provide fractional happiness. (.5 points rather than 1 point), which works in game, but how would I adjust the text links to get the civilopedia to display this properly? (currently it just shows 0 happiness for both.)

Spoiler :


Current version of improvement happiness:

Code:
		szBuffer.append(gDLL->getText("TXT_KEY_MISC_ICON_CHANGE_NEARBY_CITIES", .01f * abs(info.getHappiness()), (info.getHappiness() > 0 ? gDLL->getSymbolID(HAPPY_CHAR) : gDLL->getSymbolID(UNHAPPY_CHAR))));

Current version of feature happiness:

Code:
szFirstBuffer.Format(L"%.2f", NEWLINE, gDLL->getText("TXT_KEY_CIVIC_FEATURE_HAPPINESS", 0.01f * abs(GC.getCivicInfo(eCivic).getFeatureHappinessChanges(iI)), ((GC.getCivicInfo(eCivic).getFeatureHappinessChanges(iI) > 0) ? gDLL->getSymbolID(HAPPY_CHAR) : gDLL->getSymbolID(UNHAPPY_CHAR))).c_str());




Also, I've added some civilization specific terrain happiness effects into the game, but haven't yet changed the text manager for these. Would the happiness effects still show up in the city happiness section (at the top of the window), or in the number of angry citizens, or will I have to look more deeply to check the effects?
 
For the first question.... I'll just show an example. Our new AffinityInfos file doesn't even have ints, everything is a float. :lol:

Code:
fValue = kAffinity.getStrength();
szTemp.clear();
if (fValue != 0.0f)
{
    if (fValue == int(fValue))
    {
        szTemp.Format(L"%.0f", fValue);
    }
    else
    {
        szTemp.Format(L"%.2f", fValue);
    }        
    szHelpString.append(gDLL->getText("TXT_KEY_AFFINITY_STRENGTH", szTemp.GetCString()));
}

The textkey:
Code:
<TEXT>
    <Tag>TXT_KEY_AFFINITY_STRENGTH</Tag>
    <English>[ICON_BULLET]%s1 Strength</English>
    <French>[ICON_BULLET]%s1 Strength</French>
    <German>[ICON_BULLET]%s1 Strength</German>
    <Italian>[ICON_BULLET]%s1 Strength</Italian>
    <Spanish>[ICON_BULLET]%s1 Strength</Spanish>
</TEXT>

Point of szTemp is to only show the decimal if necessary; No 2.00.

For your second question, it should be reflected in the total value, but won't be reflected in the breakdown unless you add text for it. Check ::setHappyHelp().
 
On the second question; Thanks for the answer. Should come in handy in the future. (Turns out I didn't need it for the particular change I did, but it should definitely come in handy when messing around with other happiness effects.)


On the first question: I guess this will be a bit harder than I thought. :) (I suppose I'll just want to find some tutorial or description of overall what all the parts mean, since a lot of changes will need some sort of text adjustments.)

I can sort of tell that the "%.2f% seems to mean a floating number with two decimals is shown in the actual text (but might be wrong here), but the szTempBuffer, szBuffer, and such is kind of throwing me. (I can see that the format function allows some extra text properties to be added, but the other functions seem a bit more difficult to work out.)

The current civic function is this:

Code:
szFirstBuffer.Format(L"%.2f", NEWLINE, gDLL->getText("TXT_KEY_CIVIC_FEATURE_HAPPINESS", 0.01f * abs(GC.getCivicInfo(eCivic).getFeatureHappinessChanges(iI)), ((GC.getCivicInfo(eCivic).getFeatureHappinessChanges(iI) > 0) ? gDLL->getSymbolID(HAPPY_CHAR) : gDLL->getSymbolID(UNHAPPY_CHAR))).c_str());
CvWString szFeature;
szFeature.Format(L"<link=literal>%s</link>", GC.getFeatureInfo((FeatureTypes)iI).getDescription());
setListHelp(szHelpText, szFirstBuffer, szFeature, L", ", (GC.getCivicInfo(eCivic).getFeatureHappinessChanges(iI) != iLast));
iLast = GC.getCivicInfo(eCivic).getFeatureHappinessChanges(iI);

With the first line having a change the "%.2f". This version does show two decimals, but displays .00 rather than .50 (I did check the XML and in game on this, to rule out incorrect typing. :) )

The second function, for improvements, is the same as my above post. I tried just sticking some extra functions into it to see if something would work, but am really not sure how I would build off of it.
 
Well, to break down the specifics of what I posted...

fValue - Just a convenient way to reference the tag, rather than needing the full tag over and over.

szTemp - Temporary string, reset for each one. Most GameText functions have something similar to this; Believe it is szFirstBuffer for civics.

Aside from this, it's pretty simple.
Code:
Make sure fValue is not default.
    If fValue is equal to an Int (meaning, no decimal data)
        Format szTemp to display fValue to 0 decimal places.
    Else (meaning, decimal data)
        Format szTemp to display fValue to 2 decimal places.

    Add your textkey to the main string, passing szTemp as an argument (referenced as %s in the textkey, rather than %d)
In any case, rereading your post I realized that what you did was already done in Fall Further (and RifE as a result), so here's our text function for decimal happiness from features, for civics.

Code:
for (iI = 0; iI < GC.getNumFeatureInfos(); ++iI)
{
    if (GC.getCivicInfo(eCivic).getFeatureHappinessChanges(iI) != 0)
    {
        CvWString szHappyString;
        if (GC.getCivicInfo(eCivic).getFeatureHappinessChanges(iI) * 0.01f == int(GC.getCivicInfo(eCivic).getFeatureHappinessChanges(iI) * 0.01f))
        {
            szHappyString.Format(L"%.0f", 0.01f * GC.getCivicInfo(eCivic).getFeatureHappinessChanges(iI));
        }
        else
        {
            szHappyString.Format(L"%.2f", 0.01f * GC.getCivicInfo(eCivic).getFeatureHappinessChanges(iI));
        }
        szFirstBuffer.Format(L"%s%s", NEWLINE, gDLL->getText("TXT_KEY_CIVIC_FEATURE_HAPPINESS", szHappyString.GetCString(), ((GC.getCivicInfo(eCivic).getFeatureHappinessChanges(iI) > 0) ? gDLL->getSymbolID(HAPPY_CHAR) : gDLL->getSymbolID(UNHAPPY_CHAR))).c_str());
        CvWString szFeature;
        szFeature.Format(L"<link=literal>%s</link>", GC.getFeatureInfo((FeatureTypes)iI).getDescription());
        setListHelp(szHelpText, szFirstBuffer, szFeature, L", ", (GC.getCivicInfo(eCivic).getFeatureHappinessChanges(iI) != iLast));
        iLast = GC.getCivicInfo(eCivic).getFeatureHappinessChanges(iI);
    }
}
 
For the first question.... I'll just show an example. Our new AffinityInfos file doesn't even have ints, everything is a float. :lol:
you may get OOS if you use floats for gameplay. Xienwolf said that's the reason why Firaxis used int times 100 instead of float for traderoutes and why FF does not use floats for Experience.
 
you may get OOS if you use floats for gameplay. Xienwolf said that's the reason why Firaxis used int times 100 instead of float for traderoutes and why FF does not use floats for Experience.

I believe when he said that he included an "I think". :lol:

There are several floats used throughout the standard BtS code, and our floats are only used for calculation; The final result is converted to an int, before being added to the stat. It is only a float in order to allow effects to require multiple instances of a resource. ;)
 
floats are used in BTS code only for aesthetic stuff, no gameplay relevant things. For example the "real" population of a city is a float. Or the angle of camera is a float. But I just saw that the influence driven war modcomp uses float as well so you are probably fine.

That you use floats for calculation is actually the potential problem. Different OS have different mechanics to round floats. Maybe it's just a windows vs. mac issue which we modders do not have to worry about.
 
Thanks, Valk, it's working now. (Plus I think I understand it enough to work more things out on my own.)
 
I think the rounding differences are at compilation time. I'm sure all versions of Windows do it the same way. Firaxis using integers for most gameplay data probably is due to precision; floats just can't represent exact numbers very well, especially larger numbers.

If you're actually interested in learning about why:
http://steve.hollasch.net/cgindex/coding/ieeefloat.html
 
Back
Top Bottom