Sample SDK Code (basic)

Sounds good to me, hopefully he is successful!
 
Kael said:
Just a simple example of a change that can be made in CvUnit::maxCombatStr(). This applies a combat modifier based on the existence of the "Elf" promotion on the defender and the "Elf Slaying" promotion on the attacker. maxCombatStr is called from the perspective of the defender and I have the 2 checks in so that the bonus is applied on attack and defense.

Changes are in bold.

CvUnit::maxCombatStr()

Code:
		if (getUnitCombatType() != NO_UNITCOMBAT)
		{
			iModifier -= pAttacker->unitCombatModifier(getUnitCombatType());
			if (pCombatDetails != NULL)
			{
				pCombatDetails->iCombatModifierT = -(pAttacker->unitCombatModifier(getUnitCombatType()));
			}
		}

[b]		if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_ELF")))
		{
		    if (pAttacker->isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_ELF_SLAYING")))
		    {
		        iModifier = iModifier - 40;
		    }
		}
		if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_ELF_SLAYING")))
		{
		    if (pAttacker->isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_ELF")))
		    {
		        iModifier = iModifier + 40;
		    }
		}[/b]

		iModifier += domainModifier(pAttacker->getDomainType());
		if (pCombatDetails != NULL)
		{
			pCombatDetails->iDomainModifierA = domainModifier(pAttacker->getDomainType());
		}

Why use this? It provides the ability to specify anti-unit combat bonuses without having to make new unit combats or declare specific unitclasses. Also since its easy to add and remove promotions as you play it can allow you to create pretty dynamic bonuses.

Outside of that just being familiar with the effect of changing maxCombatStr can be very helpful to anyone who wants to effect the combat odds. Changes made here are reflect both in the actual combat odds as well as the display.

I know these will seem like very basic questions, but i only started with XML this week and im in at the deep end :confused:

1 - Im not sure where the file is that this set of instructions needs to be added to, anyone? (i did a search for .cpp files on my HD but couldnt find a single one, and browsing around the vanilla files as well as a few mods i can only see .py files)

2 - Anyone know where i can download a FREE c++ editor/compiler to load and edit the .cpp file? (when i find it) :)

3 - Can I just copy the code into the place shown in the example, with my own promotions replacing PROMOTION_ELF (to PROMOTION_BORG) and PROMOTION_ELFSLAYING (PROMOTION_RUSE1), or do i need to declare the variables somewhere else?
 
jenks said:
I know these will seem like very basic questions, but i only started with XML this week and im in at the deep end :confused:

1 - Im not sure where the file is that this set of instructions needs to be added to, anyone? (i did a search for .cpp files on my HD but couldnt find a single one, and browsing around the vanilla files as well as a few mods i can only see .py files)

Its in the CvUnit.cpp file in the SDK.

2 - Anyone know where i can download a FREE c++ editor/compiler to load and edit the .cpp file? (when i find it) :)

The instructions for a free editor are here: http://forums.civfanatics.com/showthread.php?t=166933

3 - Can I just copy the code into the place shown in the example, with my own promotions replacing PROMOTION_ELF (to PROMOTION_BORG) and PROMOTION_ELFSLAYING (PROMOTION_RUSE1), or do i need to declare the variables somewhere else?

You can just replace them with your promotion names. Check out my post here though for other options: http://forums.civfanatics.com/showthread.php?t=174455
 
Ok, yes, all the problems I ran into were Civcraft: SC related. So, this should work for Civ4, although I haven't really tested it in a normal Civ4 environment.

Under Civ4, any unit can be upgraded to any other unit if there exists a "path" of upgrades. Thus, a warrior can in one turn upgrade to a Mech Infantry, because there exists a path...

Warrior->Spearman->Pikeman->Rifleman->Infantry->Mech Inf.

Typically, the disadvantage to this is that it costs a ton of money. But perhaps you want to make it even tougher, by forcing the player to only be able to upgrade a few rungs up the ladder at a time.

Code:
bool CvUnit::upgradeAvailable(UnitTypes eFromUnit, UnitClassTypes eToUnitClass, int iCount) const
{
	UnitTypes eLoopUnit;
	int iI;

	[b]/* Modifed by Gerikes to disable recursive upgrade*/[/b]
	[b]//[/b]if (iCount > GC.getNumUnitClassInfos())
	[b]if (iCount > 0)[/b]
	[b]/* End Modifed by Gerikes to disable recursive upgrade*/[/b]
	{
		return false;
	}

	if (GC.getUnitInfo(eFromUnit).getUpgradeUnitClass(eToUnitClass))
	{
		return true;
	}

	for (iI = 0; iI < GC.getNumUnitClassInfos(); iI++)
	{
		if (GC.getUnitInfo(eFromUnit).getUpgradeUnitClass(iI))
		{
			eLoopUnit = ((UnitTypes)(GC.getCivilizationInfo(getCivilizationType()).getCivilizationUnits(iI)));

			if (eLoopUnit != NO_UNIT)
			{
				if (upgradeAvailable(eLoopUnit, eToUnitClass, (iCount + 1))) [b]// Recursive call[/b]
				{
					return true;
				}
			}
		}
	}

	return false;
}

This function is a recursive function. That means that during the course of running through the code, the function will actually call itself. This is important to realize for what we're doing.

When the function is first called, the eFromUnit value (say, UNIT_WARRIOR) and the eToUnitClass value (say, UNITCLASS_SAM_INFANTRY) are passed in, along with the number for iCount (by default, 0). In the first run, there is a check to see if the unit can upgrade to the unitclass only by checking it's upgrades. This would return true if eToUnitClass were, say, a Spearman or Axeman. But it's not, so it's false.

What happens next is that big for-loop mess will check every single unitclass that the warrior CAN upgrade to all by itself. It will then, for each one, call the function upgradeAvailable AGAIN, only this time using the new eFromUnit (say, a Spearman), the same eToUnitClass, and an incremented count.

If you're not familar with recursive functions, the next sentence may not make sense, but trust me on it. For every "hop" on the upgrade path the unit has to make to get to it's destination, iCount will increase. Thus, by checking what iCount is at the beginning of each function, you can control how far you're willing to search the "path" of upgrades.

By changing that first if-block, I'm changing how far I'm allowing the recursive function to dive. In this case, where I check iCount for 0, it will allow through the first pass, checking all of the Warriors "direct" upgrades. But, during the recursive calls, while trying to check all the upgrades from the spearman, axeman, etc., iCount will be incremented to one, which is greater than zero, so it will fail, and return false.

The moral of this story, is that you can control the depth of how far you can "search" the tree to upgrade. Rather than making it a magic number, you can make it a define:

Code:
	[b]/* Modifed by Gerikes to change recursive upgrade max depth*/[/b]
	[b]//[/b]if (iCount > GC.getNumUnitClassInfos())
	[b]if (iCount >= GC.getDefineINT("MAX_UPGRADE_DEPTH"))[/b]
	[b]/* End Modifed by Gerikes to change recursive upgrade max depth*/[/b]

Now, you can set a variable in the XML to define how far an upgrade can go. Note I changed the ">" to a ">=". Now, a value of 0 will disable upgrades, a value of 1 will allow upgrades of depth 1, a value of 5 will allow upgrades up to depth 5.
 
K, here is a pretty easy one:

So that Players can be queried to see if they have certain bonuses in any of their cities
version: 0.15

CvPlayer.cpp

Code:
//FfH: Added by Kael 07/19/2006

bool CvPlayer::hasBonus(BonusTypes eIndex)
{
	CvCity* pLoopCity;

	int iLoop;
	for (pLoopCity = firstCity(&iLoop); pLoopCity != NULL; pLoopCity = nextCity(&iLoop))
	{
		if (pLoopCity->hasBonus(eIndex))
		{
            return true;
		}
	}
	return false;
}

//FfH: End Add

CvPlayer.h

Code:
//FfH: Added by Kael 07/19/2006

    bool hasBonus(BonusTypes eIndex);

//FfH: End Add

Basically I wanted a new function I could call from other places in the SDK that would tell me if the player had a resource available in any of his cities. The code is faily simple, just a new function tacked on to the bottom of the CvPlayer.cpp file and defined in the CvPlayer.h file.

Once its in I can do a:

Code:
 if (pPlayer.hasBonus(eBonus))

and get a true or false if the player has it anywhere or not. As it is it is only available in the SDK, although its not that hard to extend this function to python.

Why am I doing this in the SDk instead of in Python? Mostly because the function that are going to be using it are in the SDK so its similiar to have the function there. Its also faster to parse through the players cities in complied code instead of a scripted language like Python.

Specifically I added the ability to have promotions require resources. You can have your mages learn fire spells unless you have access to fire mana in some of your cities. Since the canAcquirePromotion function is a SDK function I wanted the new hasBonus to be as close to it as possible.
 
How to make civics to suport negative religion hapiness?

For example I want to make theocracy to give +3 happy with state religion and 3 unhappy with non state religion. If I insert -3 in xml the game gives me value of 246583. I saw this suport in several mods. Kael you did it in your mod too. How to do this?
 
LittleRedPoint said:
How to make civics to suport negative religion hapiness?

For example I want to make theocracy to give +3 happy with state religion and 3 unhappy with non state religion. If I insert -3 in xml the game gives me value of 246583. I saw this suport in several mods. Kael you did it in your mod too. How to do this?

Replyed in PM.
 
Thanks for the city-has-bonus SDK implementation. And yes, python scripted functions do have a disadvantage over C++ due to the whole compiled-vs-interpreted coding.

I was looking over Ffh and liked the whole sprawling vs non-sprawling 3 vs. 2 city radius you all did. Could you post how. Or maybe I should ask this on the Ffh thread. Same with the negative civics. XML changes don't quite seem to work.

Also, have you tried a recursive SDK implemented search through of units in the whole has promotion vs. does have promotions. Python gets the job done, but searching through 200+ units can cause lag time that aren't pretty :lol:

Edit: Nevermind. I think I figuered it out.
 
So Lifesparks heal units in their stack that are about to die during combat
version 0.15

CvUnit.cpp
void CvUnit::updateCombat(bool bQuick)

Code:
//FfH: Added by Kael 08/08/2006

						if ((pDefender->getDamage() + iDamage) >= pDefender->maxHitPoints())
						{
                            CvUnit* pLoopUnit;
                            int iLoop;
                            for (iLoop=0; iLoop <= pPlot->getNumUnits(); iLoop++)
                            {
                                pLoopUnit = pPlot->getUnit(iLoop);
                                if (pLoopUnit != NULL && pLoopUnit->getUnitClassType() == (UnitClassTypes)GC.getInfoTypeForString("UNITCLASS_LIFESPARK"))
                                {
                                    pDefender->changeDamage(-40);
                                    szBuffer = gDLL->getText("TXT_KEY_MESSAGE_LIFESPARK_USED", pDefender->getNameKey());
                                    gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getDefineINT("EVENT_MESSAGE_TIME"), szBuffer, GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitDefeatScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                                    pLoopUnit->kill(false);
                                    break;
                                }
                            }
						}

//FfH: End Add

What it does: Inserted in the updateCombat function (specifically in the section where the attacker wins the roll just before the attackers damage is applied to the defender) this code checks the defenders stack to see if their is a unit it it with the unit class of "UNITCLASS_LIFESPARK". If there is it heals the defender 40% and kills the lifespark.

I wanted to add some defensive magic to the game. In this case a creature that could be summoned that helps guard the stack it is in. Since their is no real interface here (if the unit is about to die it performs the heal) the AI doesn't have to know more than to include it in stacks to be good at it, and players don't have to manage anything except keep it around.

Why? I admit this specific implementation is a very FfH concept. But it can easily be converted into anything you would like to do during the combat step. If you want to have a unit heal when it does damage to an opponent, add it here. If you want to give a chance to break combat everytime the defender hits when he is inside a fort, this is the place to do it. Have archery units in the defenders stack apply some damage to attackers on each combat turn. Have defending helicopters flee if they get to low on damage. Have the defending unit have a chance to turn into the Hulk everytime he is hurt and start destroying everyone.
 
Grey Fox said:
Modern programming languages often Copy syntax from C/C++. *I think* that C or C++ was the first object-oriented language aswell, which another reason its copied. The first being its probably one of the most popular programming languages.

"Object-oriented programming developed as the dominant programming methodology during the mid-1980s, largely due to the influence of C++, an extension of the C programming language."

I did computer science (badly) many years ago, and i could sort of understand C, but was lost when we hit C++ partly because of the whole OO bit which never really became clear to my feeble brain. :blush:

Pascal, on the other hand... whatever happened to pascal? It was fun :crazyeye:
 
C is not OO, C++ is not the first OO, smalltalk is often assigned as being the thing that is pure OO (there are very different ways to do OO, but in C++/Java/Python/Ruby + most others you don't care). C++ may well have been what made OO popular.

An object holds state and has methods which manipulate or do work based on that state. They are VERY useful for many problems - in Civ4, see CvUnit - it contains just about all the game information for one unit, and has methods to do stuff with or to a unit.
 
To allow for a Fatigued promotion that lasts until the unit rests (spends a turn without taking an action).

CvUnit.cpp
void CvUnit::doTurn()

Code:
	if (hasMoved())
	{
		if (isAlwaysHeal())
		{
			doHeal();
		}
	}
	else
	{
		if (isHurt())
		{
			doHeal();
		}

		changeFortifyTurns(1);

//FfH: Added by Kael 10/05/2006
        if (isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_FATIGUED")))
        {
            setHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_FATIGUED"), false);
        }
//FfH: End Add

	}

What it does: This is pretty minor. Just an additional routine that kicks off if the unit hasMoved() is false that removes the promotion.

Why? You can have the promotion do whatever you'd like, I think I ours gives -10% to the units combat strength and is applied to the unit when they use the Sprint ability to boost their movement. Fatigue could be applied if units move through hazardous terrain, withdrawal from combat, or maybe spend x amount of turns otuside of their civilizations zone of control.
 
Hey Kael, this could prove useful to people like myself and Dom Pedro in the future. What I am wondering, though, is what would you replace the if (hasmoved()) line with if you wanted to represent units being 'out of supply'. I am guessing it would probably have to be some kind of if (isPlot()) routine, am I right?

Aussie_Lurker.
 
Aussie_Lurker said:
Hey Kael, this could prove useful to people like myself and Dom Pedro in the future. What I am wondering, though, is what would you replace the if (hasmoved()) line with if you wanted to represent units being 'out of supply'. I am guessing it would probably have to be some kind of if (isPlot()) routine, am I right?

Aussie_Lurker.

What exactly would you want the effect of being "out of supply" to be?
 
Well its effects would be identical to the Fatigue function you describe. The only difference is that, rather than being based on whether the unit moved, it would be based on how far the plot said unit is on is from a friendly/home plot.
Does that make sense?

Aussie_Lurker.
 
Aussie_Lurker said:
Well its effects would be identical to the Fatigue function you describe. The only difference is that, rather than being based on whether the unit moved, it would be based on how far the plot said unit is on is from a friendly/home plot.
Does that make sense?

Aussie_Lurker.

If you don't want to have it effected by the units movement you probably want to keep it in CvUnit.cpp doTurn() but outside of the hasMoved section I displayed. That way its just a check on each unit each turn.

You could also do the same from python in the begin player turn function. Just cycling through the units and applying or removing fatgiue based on whatever criteria you setup.
 
Well, I do try and avoid python where I can, as I have had the greatest success with SDK. So if I can do it in SDK, that will always be my preferred option.

Aussie_Lurker.
 
Top Bottom