Modders Guide to FfH2

A question occurs:

Why do we even HAVE the ImmortalFlee and ImmortalRebirth functions? Couldn't the entire Immortal Process be handled as a simple IF statement early in the CvUnit::kill Function? Seems that it ought to work quite nicely then, as it would cover every possible method of losing the unit (spells, Combat, anything which is invented in the future). Sure you'd have to delete the unit twice in order to remove it from the game willingly, and you could "cheat" by deleting it to get a free trip back to the capital, but that first isn't a bother really, and the last kinda makes sense, and is balanced by not returning to the Capital with full health.
 
Just wanted to say that some time ago I asked some question about how to create a wildshaper. I tried it and tested it out, using permanent summon and kill kaster mecahnism. I found out that a wildshape could be a realy realy fun unit. With only the simple form of
-bear
-tiger
-wolf
-seamonster
-eagle
one could have realy versile unit. Being able to explore the world much faster than any other unit and being able to fly from one city to another could be a realy nice thing.

A bear is a strength 5 unit, so it could maybe be made available about the same time you get the ranger (strength 7 unit)? The versality of the wildshaper more than compensates for the strength.

Sadly I did not have the patiency to make it work 100% correctly.
 
CvUnit.cpp:

Code:
	for (iI = 0; iI < GC.getNumPromotionInfos(); iI++)
	{
	    if (isHasPromotion((PromotionTypes)iI))
	    {
	        if (GC.getPromotionInfo((PromotionTypes)iI).getPromotionSummonPerk() != NO_PROMOTION)
	        {
	            pUnit->setHasPromotion((PromotionTypes)GC.getPromotionInfo((PromotionTypes)iI).getPromotionSummonPerk(), true);
	        }
	    }
	}
   	if (GC.getSpellInfo((SpellTypes)spell).getCreateUnitPromotion() != NO_PROMOTION)
   	{
        pUnit->setHasPromotion((PromotionTypes)GC.getSpellInfo((SpellTypes)spell).getCreateUnitPromotion(), true);
   	}
   	if (isHiddenNationality())
   	{
        pUnit->setHasPromotion((PromotionTypes)GC.getDefineINT("HIDDEN_NATIONALITY_PROMOTION"), true);
   	}


The last bit is the one which seems needless. Why Hardcode HN of any type (assuming a Mod-mod adds another method of being HN) to apply HN to your summons? Would it not be better to use the first bit, <PromotionSummonPerk>, to have HN softcoded to apply HN to summons?
 
CvUnit.cpp:

Code:
	for (iI = 0; iI < GC.getNumPromotionInfos(); iI++)
	{
	    if (isHasPromotion((PromotionTypes)iI))
	    {
	        if (GC.getPromotionInfo((PromotionTypes)iI).getPromotionSummonPerk() != NO_PROMOTION)
	        {
	            pUnit->setHasPromotion((PromotionTypes)GC.getPromotionInfo((PromotionTypes)iI).getPromotionSummonPerk(), true);
	        }
	    }
	}
   	if (GC.getSpellInfo((SpellTypes)spell).getCreateUnitPromotion() != NO_PROMOTION)
   	{
        pUnit->setHasPromotion((PromotionTypes)GC.getSpellInfo((SpellTypes)spell).getCreateUnitPromotion(), true);
   	}
   	if (isHiddenNationality())
   	{
        pUnit->setHasPromotion((PromotionTypes)GC.getDefineINT("HIDDEN_NATIONALITY_PROMOTION"), true);
   	}


The last bit is the one which seems needless. Why Hardcode HN of any type (assuming a Mod-mod adds another method of being HN) to apply HN to your summons? Would it not be better to use the first bit, <PromotionSummonPerk>, to have HN softcoded to apply HN to summons?

Uhh... uhh...uhhh.. No good answer here. I'll switch it as you recommend. :)
 
A question occurs:

Why do we even HAVE the ImmortalFlee and ImmortalRebirth functions? Couldn't the entire Immortal Process be handled as a simple IF statement early in the CvUnit::kill Function? Seems that it ought to work quite nicely then, as it would cover every possible method of losing the unit (spells, Combat, anything which is invented in the future). Sure you'd have to delete the unit twice in order to remove it from the game willingly, and you could "cheat" by deleting it to get a free trip back to the capital, but that first isn't a bother really, and the last kinda makes sense, and is balanced by not returning to the Capital with full health.

Im playing with this and it looks like its going to work, simplify the code and catch all death conditions for immortality instead of just combat. Great idea!
 
Just so long as one doesn't get flesh golems from them with Mokka's Cauldron, and isn't able to sacrifice them at a demon's altar. Probably want to avoid having them trigger the soul forge as well. And the spirit guide promotion shouldn't kick in until true death as well.
 
SpiritGuide removes all XP from the unit, so shouldn't be an issue unless the Immortal unit is also getting free XP.

Pretty sure you aren't allowed to Sacrifice or Graft Immortal Units already, but Mokka & SoulForge would need new blocks put in place to ignore Immortal Units.
 
SpiritGuide removes all XP from the unit, so shouldn't be an issue unless the Immortal unit is also getting free XP.

Pretty sure you aren't allowed to Sacrifice or Graft Immortal Units already, but Mokka & SoulForge would need new blocks put in place to ignore Immortal Units.

Good point, I'll also block angel/mane creation and captures.
 
When extracting the CvGameCoreDLL032l.zip file from this thread you get a CvGameCoreDLL.032k folder, is it still L and you forgot to rename the folder, or is it actually K?
 
The UnitArtStyleTypes enum doesn't seem to be exposed to python.

I can call the getArtInfo method from a CvUnitInfo object but it gives me an error and wants a UnitArtStyleType object passed to it as the 3rd parameter...
 
I would like to know how can i increase the xp needed for a unit to reach a new level and get a new promotion....i'm interested to change xp neded for levels from:

Normal
Level 1 2xp

Level 2 5xp

Level 3 10 xp

Level 4 17 xp

to

Level 1 5xp

Level 2 10xp

Level 3 18 xp

Level 4 29xp


and so on.....
 
In CvGameUtils.py:

Code:
	def getExperienceNeeded(self, argsList):
		# use this function to set how much experience a unit needs
		iLevel, iOwner = argsList
		
		iExperienceNeeded = 0

		# regular epic game experience		
		iExperienceNeeded = iLevel * iLevel + 1

		iModifier = gc.getPlayer(iOwner).getLevelExperienceModifier()
		if (0 != iModifier):
			iExperienceNeeded += (iExperienceNeeded * iModifier + 99) / 100   # ROUND UP
			
		return iExperienceNeeded

Modify the formula in there and you modify how much XP is required per level.
 
In CvGameUtils.py:

Code:
....

Modify the formula in there and you modify how much XP is required per level.

Are you sure that just isn't cosmetic? I did a quick code search and getExperienceNeeded is just defined in CvGameInterface.py as a call to gameUtils. Is it actually used in the code anywhere?
 
Below is some python that runs after particular unit is killed and gives it to a particular civ. "Immortal" isn't used because I don't want the unit just returned to whatever civ owned it when killed. What I'd like to do is have a 50% chance that it goes to the specified civ. The rest of the time it's given to another one. One picked randomly from among the civs met. What's a good way to do that?

ATM I'm imagining a list of all the possible civs and having a "roll" pick one at random. Then I'd check to see if it's in the game. (Or just if it's been met?) But I'm not certain how to do even that, and I doubt it's a good way to do it.

:help:

Spoiler :

Code:
	for iPlayer in range(gc.getMAX_PLAYERS()):
		pPlayer = gc.getPlayer(iPlayer)
		if (pPlayer.isAlive()):
			if pPlayer.getCivilizationType() == gc.getInfoTypeForString('CIVILIZATION_SCIONS'):
				pCity = pPlayer.getCapitalCity()
				newUnit = pPlayer.initUnit(gc.getInfoTypeForString('UNIT_MIT0'), pCity.getX(), pCity.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
/a few more lines to copy over the promotions, etc./
 
I'd think that the best way would be a loop over all players, check for if they are alive, check for if their team has met the active team, and if they meet those conditions then you add them to a list. Once the check is done, you do a Random(listsize * 2) check and send the unit to the capital of whichever list entry matches the random number, or if the number is too high for the list size then you send them to the Scions (or whoever the 50% chance was).

Here is how you could do such a loop in C++
Spoiler :
Code:
int CvTeam::getHasMetCivCount(bool bIgnoreMinors) const
{
	int iCount;
	int iI;

	iCount = 0;

	for (iI = 0; iI < MAX_CIV_TEAMS; iI++)
	{
		if (GET_TEAM((TeamTypes)iI).isAlive())
		{
			if (iI != getID())
			{
				if (!bIgnoreMinors || !(GET_TEAM((TeamTypes)iI).isMinorCiv()))
				{
					if (isHasMet((TeamTypes)iI))
					{
						FAssert(iI != getID());
						iCount++;
					}
				}
			}
		}
	}

	return iCount;
}

You don't need the MinorCiv check really, but it is exposed to Python, as is the isHasMet command.


So final code should be along the lines of:
Spoiler :

Code:
	listPlayers = []
	pTeam1 = pUnit.getTeam()
	for iPlayer in range(gc.getMAX_PLAYERS()):
		pPlayer = gc.getPlayer(iPlayer)
		iTeam2 = pPlayer.getTeam()
		if (pPlayer.isAlive()):
			if pTeam1.isHasMet(iTeam2):
				listPlayers.append(pPlayer)

	if CyGame().getSorenRandNum(len(listPlayers) * 2, "Gift") <= len(listPlayers):
		pCity = listPlayers[Gift].getCapitalCity()
	else:
		pCity = gc.getPlayer(pUnit.getOwner()).getCapitalCity()
	newUnit = listPlayers[Gift].initUnit(gc.getInfoTypeForString('UNIT_MIT0'), pCity.getX(), pCity.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
/a few more lines to copy over the promotions, etc./


Note, I am NOT proficient at Python, so probably used an improper term somewhere in there (like len(xxx) for length of list), and I am assuming that the unit who is going to die was initially referred to as pUnit.
 
Back
Top Bottom