SDK for SetHasTrait

OrionVeteran

Deity
Joined
Dec 25, 2003
Messages
2,443
Location
Newport News VA
I would like to obtain an SDK command to add an additional trait to a specified Leaderhead and respective player. This command would need to work like the setHasTech does now for a player. It would need to be exposed to python. Which SDK files would I have to modify and how can this be done? Does anyone have any example code of how this can be done? I need to be walked through all required changes to make this work.
 
This is already done in FFH. If you look at the source code there and search for 'sethastrait', you can probably just copy the relevant code.

I performed a search though all of the SDK files for FFH2 and could not find setHasTrait. Are you sure the function exists?
 
I performed a search though all of the SDK files for FFH2 and could not find setHasTrait. Are you sure the function exists?

Yep. Here are my search results through the SDK files:

Code:
Find all "sethastrait", Subfolders, Find Results 1, "Current Project"
  D:\working\ffh2\Debug - CvGameCoreDLL\CvPlayer.h(1272):	void setHasTrait(TraitTypes eTrait, bool bNewValue);
  D:\working\ffh2\Debug - CvGameCoreDLL\CyPlayer.h(687):    void setHasTrait(int /*TraitTypes*/ iIndex, bool bNewValue);
  D:\working\ffh2\Debug - CvGameCoreDLL\CvPlayer.cpp(324):                setHasTrait((TraitTypes)iI, true);
  D:\working\ffh2\Debug - CvGameCoreDLL\CvPlayer.cpp(333):            setHasTrait((TraitTypes)GC.getCivilizationInfo(getCivilizationType()).getCivTrait(), true);
  D:\working\ffh2\Debug - CvGameCoreDLL\CvPlayer.cpp(555):                setHasTrait((TraitTypes)iI, true);
  D:\working\ffh2\Debug - CvGameCoreDLL\CvPlayer.cpp(562):            setHasTrait((TraitTypes)GC.getCivilizationInfo(getCivilizationType()).getCivTrait(), true);
  D:\working\ffh2\Debug - CvGameCoreDLL\CvPlayer.cpp(3569):void CvPlayer::setHasTrait(TraitTypes eTrait, bool bNewValue)
  D:\working\ffh2\Debug - CvGameCoreDLL\CvUnit.cpp(992):					GET_PLAYER(getOwnerINLINE()).setHasTrait((TraitTypes)iTrait, false);
  D:\working\ffh2\Debug - CvGameCoreDLL\CyPlayer.cpp(2835):void CyPlayer::setHasTrait(int /*TraitTypes*/ iIndex, bool bNewValue)
  D:\working\ffh2\Debug - CvGameCoreDLL\CyPlayer.cpp(2837):	return m_pPlayer ? m_pPlayer->setHasTrait((TraitTypes) iIndex, bNewValue) : false;
  D:\working\ffh2\Debug - CvGameCoreDLL\CyPlayerInterface2.cpp(173):        .def("setHasTrait", &CyPlayer::setHasTrait, "TraitTypes (eTrait), bool (bNewValue)")
  Matching lines: 11    Matching files: 6    Total files searched: 208

and here's the main function itself.

Code:
//FfH: Scriptable Leader Traits: Added by Kael 08/08/2007
void CvPlayer::setHasTrait(TraitTypes eTrait, bool bNewValue)
{
	FAssertMsg((eTrait >= 0), "eTrait is less than zero");

	int iI, iChange;

    if (bNewValue)
    {
        iChange = 1;
    }
    else
    {
        iChange = -1;
    }

	if (m_pbTraits[(int)eTrait] == bNewValue)
	{
		return;
	}

	m_pbTraits[(int)eTrait] = bNewValue;

	changeExtraHealth(GC.getTraitInfo(eTrait).getHealth() * iChange);
	changeExtraHappiness(GC.getTraitInfo(eTrait).getHappiness() * iChange);

	for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
	{
		changeExtraBuildingHappiness((BuildingTypes)iI, GC.getBuildingInfo((BuildingTypes)iI).getHappinessTraits((int)eTrait) * iChange);
	}

	changeUpkeepModifier(GC.getTraitInfo(eTrait).getUpkeepModifier() * iChange);
	changeLevelExperienceModifier(GC.getTraitInfo(eTrait).getLevelExperienceModifier() * iChange);
	changeGreatPeopleRateModifier(GC.getTraitInfo(eTrait).getGreatPeopleRateModifier() * iChange);
	changeGreatGeneralRateModifier(GC.getTraitInfo(eTrait).getGreatGeneralRateModifier() * iChange);
	changeDomesticGreatGeneralRateModifier(GC.getTraitInfo(eTrait).getDomesticGreatGeneralRateModifier() * iChange);

	changeMaxGlobalBuildingProductionModifier(GC.getTraitInfo(eTrait).getMaxGlobalBuildingProductionModifier() * iChange);
	changeMaxTeamBuildingProductionModifier(GC.getTraitInfo(eTrait).getMaxTeamBuildingProductionModifier() * iChange);
	changeMaxPlayerBuildingProductionModifier(GC.getTraitInfo(eTrait).getMaxPlayerBuildingProductionModifier() * iChange);

	for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
	{
		changeTradeYieldModifier(((YieldTypes)iI), GC.getTraitInfo(eTrait).getTradeYieldModifier(iI) * iChange);
	}

	for (iI = 0; iI < NUM_COMMERCE_TYPES; iI++)
    {
		changeFreeCityCommerce(((CommerceTypes)iI), GC.getTraitInfo(eTrait).getCommerceChange(iI) * iChange);
		changeCommerceRateModifier(((CommerceTypes)iI), GC.getTraitInfo(eTrait).getCommerceModifier(iI) * iChange);
	}

	for (iI = 0; iI < GC.getNumCivicOptionInfos(); iI++)
	{
		if (GC.getCivicOptionInfo((CivicOptionTypes) iI).getTraitNoUpkeep(int(eTrait)))
		{
			changeNoCivicUpkeepCount(((CivicOptionTypes)iI), iChange);
		}
	}

    if (GC.getTraitInfo(eTrait).isAdaptive())
    {
        setAdaptive(bNewValue);
    }
    if (GC.getTraitInfo(eTrait).isAgnostic())
    {
        setAgnostic(bNewValue);
    }
    if (GC.getTraitInfo(eTrait).isAssimilation())
    {
        setAssimilation(bNewValue);
    }
    if (GC.getTraitInfo(eTrait).isBarbarianAlly())
    {
        GET_TEAM(getTeam()).setBarbarianAlly(bNewValue);
    }
    if (GC.getTraitInfo(eTrait).isIgnoreFood())
    {
        setIgnoreFood(bNewValue);
    }
    if (GC.getTraitInfo(eTrait).isInsane())
    {
        setInsane(bNewValue);
    }
    if (GC.getTraitInfo(eTrait).isSprawling())
    {
        setSprawling(bNewValue);
    }
	changeFreeXPFromCombat(GC.getTraitInfo(eTrait).getFreeXPFromCombat() * iChange);
    if (GC.getTraitInfo(eTrait).getMaxCities() != -1)
    {
        if (iChange == 1)
        {
            setMaxCities(GC.getTraitInfo(eTrait).getMaxCities() + GC.getWorldInfo(GC.getMapINLINE().getWorldSize()).getMaxCitiesMod());
        }
        else
        {
            setMaxCities(-1);
        }
    }
	changePillagingGold(GC.getTraitInfo(eTrait).getPillagingGold() * iChange);
	changeStartingGold(GC.getTraitInfo(eTrait).getStartingGold() * iChange);
	changeSummonDuration(GC.getTraitInfo(eTrait).getSummonDuration() * iChange);
	changeUpgradeCostModifier(GC.getTraitInfo(eTrait).getUpgradeCostModifier() * iChange);

	for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
	{
		updateExtraYieldThreshold((YieldTypes)iI);
	}

	updateMaxAnarchyTurns();
}
 
Yep. Here are my search results through the SDK files:

Spoiler :

Code:
Find all "sethastrait", Subfolders, Find Results 1, "Current Project"
  D:\working\ffh2\Debug - CvGameCoreDLL\CvPlayer.h(1272):	void setHasTrait(TraitTypes eTrait, bool bNewValue);
  D:\working\ffh2\Debug - CvGameCoreDLL\CyPlayer.h(687):    void setHasTrait(int /*TraitTypes*/ iIndex, bool bNewValue);
  D:\working\ffh2\Debug - CvGameCoreDLL\CvPlayer.cpp(324):                setHasTrait((TraitTypes)iI, true);
  D:\working\ffh2\Debug - CvGameCoreDLL\CvPlayer.cpp(333):            setHasTrait((TraitTypes)GC.getCivilizationInfo(getCivilizationType()).getCivTrait(), true);
  D:\working\ffh2\Debug - CvGameCoreDLL\CvPlayer.cpp(555):                setHasTrait((TraitTypes)iI, true);
  D:\working\ffh2\Debug - CvGameCoreDLL\CvPlayer.cpp(562):            setHasTrait((TraitTypes)GC.getCivilizationInfo(getCivilizationType()).getCivTrait(), true);
  D:\working\ffh2\Debug - CvGameCoreDLL\CvPlayer.cpp(3569):void CvPlayer::setHasTrait(TraitTypes eTrait, bool bNewValue)
  D:\working\ffh2\Debug - CvGameCoreDLL\CvUnit.cpp(992):					GET_PLAYER(getOwnerINLINE()).setHasTrait((TraitTypes)iTrait, false);
  D:\working\ffh2\Debug - CvGameCoreDLL\CyPlayer.cpp(2835):void CyPlayer::setHasTrait(int /*TraitTypes*/ iIndex, bool bNewValue)
  D:\working\ffh2\Debug - CvGameCoreDLL\CyPlayer.cpp(2837):	return m_pPlayer ? m_pPlayer->setHasTrait((TraitTypes) iIndex, bNewValue) : false;
  D:\working\ffh2\Debug - CvGameCoreDLL\CyPlayerInterface2.cpp(173):        .def("setHasTrait", &CyPlayer::setHasTrait, "TraitTypes (eTrait), bool (bNewValue)")
  Matching lines: 11    Matching files: 6    Total files searched: 208


and here's the main function itself.

Spoiler :

Code:
//FfH: Scriptable Leader Traits: Added by Kael 08/08/2007
void CvPlayer::setHasTrait(TraitTypes eTrait, bool bNewValue)
{
	FAssertMsg((eTrait >= 0), "eTrait is less than zero");

	int iI, iChange;

    if (bNewValue)
    {
        iChange = 1;
    }
    else
    {
        iChange = -1;
    }

	if (m_pbTraits[(int)eTrait] == bNewValue)
	{
		return;
	}

	m_pbTraits[(int)eTrait] = bNewValue;

	changeExtraHealth(GC.getTraitInfo(eTrait).getHealth() * iChange);
	changeExtraHappiness(GC.getTraitInfo(eTrait).getHappiness() * iChange);

	for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
	{
		changeExtraBuildingHappiness((BuildingTypes)iI, GC.getBuildingInfo((BuildingTypes)iI).getHappinessTraits((int)eTrait) * iChange);
	}

	changeUpkeepModifier(GC.getTraitInfo(eTrait).getUpkeepModifier() * iChange);
	changeLevelExperienceModifier(GC.getTraitInfo(eTrait).getLevelExperienceModifier() * iChange);
	changeGreatPeopleRateModifier(GC.getTraitInfo(eTrait).getGreatPeopleRateModifier() * iChange);
	changeGreatGeneralRateModifier(GC.getTraitInfo(eTrait).getGreatGeneralRateModifier() * iChange);
	changeDomesticGreatGeneralRateModifier(GC.getTraitInfo(eTrait).getDomesticGreatGeneralRateModifier() * iChange);

	changeMaxGlobalBuildingProductionModifier(GC.getTraitInfo(eTrait).getMaxGlobalBuildingProductionModifier() * iChange);
	changeMaxTeamBuildingProductionModifier(GC.getTraitInfo(eTrait).getMaxTeamBuildingProductionModifier() * iChange);
	changeMaxPlayerBuildingProductionModifier(GC.getTraitInfo(eTrait).getMaxPlayerBuildingProductionModifier() * iChange);

	for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
	{
		changeTradeYieldModifier(((YieldTypes)iI), GC.getTraitInfo(eTrait).getTradeYieldModifier(iI) * iChange);
	}

	for (iI = 0; iI < NUM_COMMERCE_TYPES; iI++)
    {
		changeFreeCityCommerce(((CommerceTypes)iI), GC.getTraitInfo(eTrait).getCommerceChange(iI) * iChange);
		changeCommerceRateModifier(((CommerceTypes)iI), GC.getTraitInfo(eTrait).getCommerceModifier(iI) * iChange);
	}

	for (iI = 0; iI < GC.getNumCivicOptionInfos(); iI++)
	{
		if (GC.getCivicOptionInfo((CivicOptionTypes) iI).getTraitNoUpkeep(int(eTrait)))
		{
			changeNoCivicUpkeepCount(((CivicOptionTypes)iI), iChange);
		}
	}

    if (GC.getTraitInfo(eTrait).isAdaptive())
    {
        setAdaptive(bNewValue);
    }
    if (GC.getTraitInfo(eTrait).isAgnostic())
    {
        setAgnostic(bNewValue);
    }
    if (GC.getTraitInfo(eTrait).isAssimilation())
    {
        setAssimilation(bNewValue);
    }
    if (GC.getTraitInfo(eTrait).isBarbarianAlly())
    {
        GET_TEAM(getTeam()).setBarbarianAlly(bNewValue);
    }
    if (GC.getTraitInfo(eTrait).isIgnoreFood())
    {
        setIgnoreFood(bNewValue);
    }
    if (GC.getTraitInfo(eTrait).isInsane())
    {
        setInsane(bNewValue);
    }
    if (GC.getTraitInfo(eTrait).isSprawling())
    {
        setSprawling(bNewValue);
    }
	changeFreeXPFromCombat(GC.getTraitInfo(eTrait).getFreeXPFromCombat() * iChange);
    if (GC.getTraitInfo(eTrait).getMaxCities() != -1)
    {
        if (iChange == 1)
        {
            setMaxCities(GC.getTraitInfo(eTrait).getMaxCities() + GC.getWorldInfo(GC.getMapINLINE().getWorldSize()).getMaxCitiesMod());
        }
        else
        {
            setMaxCities(-1);
        }
    }
	changePillagingGold(GC.getTraitInfo(eTrait).getPillagingGold() * iChange);
	changeStartingGold(GC.getTraitInfo(eTrait).getStartingGold() * iChange);
	changeSummonDuration(GC.getTraitInfo(eTrait).getSummonDuration() * iChange);
	changeUpgradeCostModifier(GC.getTraitInfo(eTrait).getUpgradeCostModifier() * iChange);

	for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
	{
		updateExtraYieldThreshold((YieldTypes)iI);
	}

	updateMaxAnarchyTurns();
}
Spoiler :




I must have an old set of source files for FFH2, as I can't find "setHasTrait" in any of the files you specified. Can you post the updated source files for FFH2?
 
Reference...

Tholal,

I have a couple of questions concerning the main function for setHasTrait:

You have several lines that show:

if (GC.getTraitInfo(eTrait).isAdaptive())

...isAgnostic()
...isAssimilation()
etc.

1. Are these kind of lines necessary for standard BTS traits or can they be removed?

2. Is the bool value "iChange" required for a trait change in standard BTS?
 
You have several lines that show:

if (GC.getTraitInfo(eTrait).isAdaptive())

...isAgnostic()
...isAssimilation()
etc.

1. Are these kind of lines necessary for standard BTS traits or can they be removed?

Those are for FFH specific traits and can be removed.

2. Is the bool value "iChange" required for a trait change in standard BTS?

Depends on how you implement it, though I suspect you would want to keep that part. The iChange variable is used to tell the function whether you're adding the trait or removing it from the player.
 
Those are for FFH specific traits and can be removed.

Great, they are gone.

Depends on how you implement it, though I suspect you would want to keep that part. The iChange variable is used to tell the function whether you're adding the trait or removing it from the player.

Add/remove. Excellent. My purpose is to use the function in Python to add another trait to a specified player.

Here is the main setHasTrait function. Did I leave out anything important?


Spoiler :

Code:
void CvPlayer::setHasTrait(TraitTypes eTrait, bool bNewValue)
{
	FAssertMsg((eTrait >= 0), "eTrait is less than zero");

	int iI, iChange;

	if (bNewValue)
	{
		iChange = 1;
	}
	else
	{
		iChange = -1;
	}

	changeExtraHealth(GC.getTraitInfo(eTrait).getHealth() * iChange);
	changeExtraHappiness(GC.getTraitInfo(eTrait).getHappiness() * iChange);

	for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
	{
		changeExtraBuildingHappiness((BuildingTypes)iI, GC.getBuildingInfo((BuildingTypes)iI).getHappinessTraits((int)eTrait) * iChange);
	}

	changeUpkeepModifier(GC.getTraitInfo(eTrait).getUpkeepModifier() * iChange);
	changeLevelExperienceModifier(GC.getTraitInfo(eTrait).getLevelExperienceModifier() * iChange);
	changeGreatPeopleRateModifier(GC.getTraitInfo(eTrait).getGreatPeopleRateModifier() * iChange);
	changeGreatGeneralRateModifier(GC.getTraitInfo(eTrait).getGreatGeneralRateModifier() * iChange);
	changeDomesticGreatGeneralRateModifier(GC.getTraitInfo(eTrait).getDomesticGreatGeneralRateModifier() * iChange);

	changeMaxGlobalBuildingProductionModifier(GC.getTraitInfo(eTrait).getMaxGlobalBuildingProductionModifier() * iChange);
	changeMaxTeamBuildingProductionModifier(GC.getTraitInfo(eTrait).getMaxTeamBuildingProductionModifier() * iChange);
	changeMaxPlayerBuildingProductionModifier(GC.getTraitInfo(eTrait).getMaxPlayerBuildingProductionModifier() * iChange);

	for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
	{
		changeTradeYieldModifier(((YieldTypes)iI), GC.getTraitInfo(eTrait).getTradeYieldModifier(iI) * iChange);
	}

	for (iI = 0; iI < NUM_COMMERCE_TYPES; iI++)
	{
		changeFreeCityCommerce(((CommerceTypes)iI), GC.getTraitInfo(eTrait).getCommerceChange(iI) * iChange);
		changeCommerceRateModifier(((CommerceTypes)iI), GC.getTraitInfo(eTrait).getCommerceModifier(iI) * iChange);
	}

	for (iI = 0; iI < GC.getNumCivicOptionInfos(); iI++)
	{
		if (GC.getCivicOptionInfo((CivicOptionTypes) iI).getTraitNoUpkeep(int(eTrait)))
		{
			changeNoCivicUpkeepCount(((CivicOptionTypes)iI), iChange);
		}
	}
}
 
Looks good to me offhand. I suggest that you go through all the trait effects in your mod and make sure they are all accounted for in this function.

OK. I have built a test mod. The mod has a new Wonder, which is supposed to provide a new trait when built. I have a Python function to execute the new SDK function, as written above in post 10:

Spoiler :

Code:
def onBuildingBuilt(self, argsList):
	'Building Completed'
	pCity, iBuildingType = argsList
	game = gc.getGame()
# Begin Traits
	iOwner = pCity.getOwner()
	pPlayer = gc.getPlayer(iOwner)
	#iPlayer = pPlayer.getID( )
		
	if iOwner == game.getActivePlayer():
		if iBuildingType == gc.getInfoTypeForString("BUILDING_MYSTERIES"):
			pPlayer.setHasTrait(gc.getInfoTypeForString("TRAIT_INDUSTRIOUS"), 1)
			CyInterface().addImmediateMessage("A", "")
# End Traits


I ran the mod and there were no bugs...everything ran. The Python confirmation message came up when the new Wonder was built. However, my leader does not show the new "test" trait (INDUSTRIOUS). Again, no errors came up, when the Wonder was built.

I need the new test trait (INDUSTRIOUS) and all of its effects to appear in the Leader information (Sevopeadia), just as the two default traits appear for any leader. What have I left out? :confused:
 
I think you need single quotes around the trait name. Here's the format FFH uses:

Code:
pPlayer.setHasTrait(gc.getInfoTypeForString('TRAIT_ORGANIZED'),True)
 
I think you need single quotes around the trait name. Here's the format FFH uses:

Code:
pPlayer.setHasTrait(gc.getInfoTypeForString('TRAIT_ORGANIZED'),True)

The result with this quote change made no difference to the Trait list for the leader. Both formats allowed the python to reach and execute the python test message.
 
You're missing the part in setHasTrait() where the Trait is actually being set

Code:
	if (m_pbTraits[(int)eTrait] == bNewValue)
	{
		return;
	}

	m_pbTraits[(int)eTrait] = bNewValue;

This code is adding the trait to the players list of traits so that it will be saved.
 
Back
Top Bottom