[MODCOMP] Occasional Promotions

killmeplease

Mk Z on Steam
Joined
Nov 22, 2007
Messages
2,794
Location
Samara
This modcomp makes it possible for units to receive promotions in non-ordinary way: any unit has a chanse to get free promotion depending on how well and in what conditions it fights.

take a look at this picture:


Jaguar Warrior has promoted to Cover. You can also notice that one of barbarian archers promoted to City Garrison I.

How does it work?
In every battle a unit has a chanse of getting a free promotion. Tougher battle it fights, higher chanse for it to get promotion. Chanse of it equals to (100-winning probability). E.g. if you have 50% chanse to win a battle, you will have 50% chanse of promotion as you won it. Also there is a bonus for saved HP. saved HP bonus = ((hp after battle)/(hp before battle))^2: +100% if you lose 0% hp, +25% if you lose 50% etc. So if you won a battle at 60% winning chanse and lost 20% of initial HP during it, you have a 40*1.64 = 65.6% chanse to get promotion.

Type of free promotion is determined by battle conditions and promotions your unit already has. E.g. for Jaguar Warrior on the picture above, it's possible to get either cover, or city raider I, or guerilla III (if he had guerilla I and II already), or Amphibious (if he had combat II), or Combat II (if he had combat I).

i hope you understand my english :blush:

Download here
 
Wow, nice modcomp. I might actually add it to my mod when I get it work again. :goodjob: Good job!
EDIT: This way units can have more promotions than normally (->awesome), or did I get the idea wrong?
 
This is quite something! I think this is how the promotion system should have been all along, and it makes more sense. I might add it in the final version of WoL.

Goodjob, anyhow.
 
A really great idea ;)

If I were to use it in a mod I'd allow certain promos to be received only through combat. Basic strength, flanking, movement.. from XP, but city attack/defense, anti-archer/melee/tank... only through direct combat in an appropriate way. City attack/defense from attacking/defending cities or forts only!
 
Very good idea. just one question please: if a unit get promotions by battle, is it not necessary to great more and weaker promotions, otherwise we get a lot of overly strong units in the game? What is the chance for a unit to get a battlepromotion? How is it chance changeable?
 
I want to thank everyone for your feedback!

Very good idea. just one question please: if a unit get promotions by battle, is it not necessary to great more and weaker promotions, otherwise we get a lot of overly strong units in the game? What is the chance for a unit to get a battlepromotion? How is it chance changeable?
Chanse to get a battle promotion is inversely proportional to a chanse of winning a battle, so it is difficult for a unit to get many promotions from battles. there is no mechanism to change this chanse so far. maybe i have to add a specific modifier tag to gameinfo.xml..
 
I want to thank everyone for your feedback!


Chanse to get a battle promotion is inversely proportional to a chanse of winning a battle, so it is difficult for a unit to get many promotions from battles. there is no mechanism to change this chanse so far. maybe i have to add a specific modifier tag to gameinfo.xml..

How it's defined what promotion will be given?
 
How it's defined what promotion will be given?

at first i define a vector to store info about what promotions can be obtained. then i loop through promotion types and add ones that fit conditions. if size of vector is greater than zero, i use RNG to test if a unit will get promotion. if it will, i use RNG again to determine what promotion to give.

code:
Spoiler :

Code:
	std::vector<PromotionTypes> aAttackerAvailablePromotions;
	std::vector<PromotionTypes> aDefenderAvailablePromotions;
	int iI;
	for (iI = 0; iI < GC.getNumPromotionInfos(); iI++)	//loop through promotions
	{
		if (pDefender->isDead() || bDefenderWithdrawn)
		{
			//* defender withdrawn, give him withdrawal promo
			if (bDefenderWithdrawn && GC.getPromotionInfo((PromotionTypes)iI).getWithdrawalChange() > 0 &&
				pDefender->canAcquirePromotion((PromotionTypes)iI))
			{
				aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
			}
		
			if (!canAcquirePromotion((PromotionTypes)iI)) //attacker can not acquire this promotion
			{
				continue;
			}

			//* attacker was crossing river
			if (GC.getPromotionInfo((PromotionTypes)iI).isRiver() && cdDefenderDetails.iRiverAttackModifier != 0)	//this bonus is being applied to defender
			{
				aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
			}
			//* attack from water
			else if (GC.getPromotionInfo((PromotionTypes)iI).isAmphib() && cdDefenderDetails.iAmphibAttackModifier != 0)
			{
				aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
			}
			//* attack terrain
			else if (GC.getPromotionInfo((PromotionTypes)iI).getTerrainAttackPercent((int)pPlot->getTerrainType()) > 0)
			{
				aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
			}
			//* attack feature
			else if (pPlot->getFeatureType() != NO_FEATURE && 
				GC.getPromotionInfo((PromotionTypes)iI).getFeatureAttackPercent((int)pPlot->getFeatureType()) > 0)
			{
				aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
			}
			//* attack hills
			else if (GC.getPromotionInfo((PromotionTypes)iI).getHillsAttackPercent() > 0 && pPlot->isHills())
			{
				aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
			}
			//* attack city
			else if (GC.getPromotionInfo((PromotionTypes)iI).getCityAttackPercent() > 0 && pPlot->isCity(true))	//count forts too
			{
				aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
			}
			//* first strikes/chanses promotions
			else if ((GC.getPromotionInfo((PromotionTypes)iI).getFirstStrikesChange() > 0 || 
				GC.getPromotionInfo((PromotionTypes)iI).getChanceFirstStrikesChange() > 0) && (firstStrikes() > 0 || chanceFirstStrikes() > 0)	)
			{
				aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
			}
			//* unit combat mod
			else if (GC.getPromotionInfo((PromotionTypes)iI).getUnitCombatModifierPercent((int)pDefender->getUnitCombatType()) > 0)
			{
				aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
			}
			//* combat strength promotions
			else if (GC.getPromotionInfo((PromotionTypes)iI).getCombatPercent() > 0)
			{
				aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
			}
			//* domain mod
			else if (GC.getPromotionInfo((PromotionTypes)iI).getDomainModifierPercent((int)pDefender->getDomainType()))
			{
				aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
			}
			//* blitz
			else if (GC.getPromotionInfo((PromotionTypes)iI).isBlitz() && bAttackerHasLostNoHP)
			{
				aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
			}
		}	//if defender is dead or withdrawn
		else	//attacker is dead or withdrawn
		{
			//* attacker withdrawn
			if (bAttackerWithdrawn && GC.getPromotionInfo((PromotionTypes)iI).getWithdrawalChange() > 0 && canAcquirePromotion((PromotionTypes)iI))
			{
				aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
			}
			
			if (!pDefender->canAcquirePromotion((PromotionTypes)iI)) 
			{
				continue;
			}

			//* defend terrain
			if (GC.getPromotionInfo((PromotionTypes)iI).getTerrainDefensePercent((int)pPlot->getTerrainType()) > 0)
			{
				aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
			}
			//* defend feature
			else if (pPlot->getFeatureType() != NO_FEATURE && 
				GC.getPromotionInfo((PromotionTypes)iI).getFeatureDefensePercent((int)pPlot->getFeatureType()) > 0)
			{
				aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
			}
			//* defend hills
			else if (GC.getPromotionInfo((PromotionTypes)iI).getHillsDefensePercent() > 0 && pPlot->isHills())
			{
				aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
			}
			//* defend city
			else if (GC.getPromotionInfo((PromotionTypes)iI).getCityDefensePercent() > 0 && pPlot->isCity(true))	//count forts too
			{
				aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
			}
			//* first strikes/chanses promotions
			else if ((GC.getPromotionInfo((PromotionTypes)iI).getFirstStrikesChange() > 0 || 
				GC.getPromotionInfo((PromotionTypes)iI).getChanceFirstStrikesChange() > 0) && 
				(pDefender->firstStrikes() > 0 || pDefender->chanceFirstStrikes() > 0))
			{
				aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
			}
			//* unit combat mod vs attacker unit type
			else if (GC.getPromotionInfo((PromotionTypes)iI).getUnitCombatModifierPercent((int)getUnitCombatType()) > 0)
			{
				aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
			}
			//* combat strength promotions
			else if (GC.getPromotionInfo((PromotionTypes)iI).getCombatPercent() > 0)
			{
				aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
			}
			//* domain mod
			else if (GC.getPromotionInfo((PromotionTypes)iI).getDomainModifierPercent((int)getDomainType()))
			{
				aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
			}
		}	//if attacker withdrawn
	}	//end promotion types cycle

	//promote attacker:
	if (!isDead() && aAttackerAvailablePromotions.size() > 0)
	{
		int iHealthPercent = (maxHitPoints() - getDamage()) * 100 / (maxHitPoints() - iAttackerInitialDamage);
		int iPromotionChanseModifier = iHealthPercent * iHealthPercent / maxHitPoints();
		int iPromotionChanse = (GC.getDefineINT("COMBAT_DIE_SIDES") - iWinningOdds) * (100 + iPromotionChanseModifier) / 100;
		
		if (GC.getGameINLINE().getSorenRandNum(GC.getDefineINT("COMBAT_DIE_SIDES"), "Occasional Promotion") < iPromotionChanse)
		{
			//select random promotion from available
			PromotionTypes ptPromotion = aAttackerAvailablePromotions[
				GC.getGameINLINE().getSorenRandNum(aAttackerAvailablePromotions.size(), "Select Promotion Type")];
			//promote
			setHasPromotion(ptPromotion, true);
			//show message
			CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOUR_UNIT_PROMOTED_IN_BATTLE", getNameKey(), GC.getPromotionInfo(ptPromotion).getText());
			gDLL->getInterfaceIFace()->addMessage(
				getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, 
				GC.getPromotionInfo((PromotionTypes)0).getSound(), MESSAGE_TYPE_INFO, NULL, 
				(ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), this->plot()->getX_INLINE(), this->plot()->getY_INLINE());
		}
	}
	//promote defender:
	if (!pDefender->isDead() && aDefenderAvailablePromotions.size() > 0)
	{
		int iHealthPercent = (maxHitPoints() - pDefender->getDamage()) * 100 / (maxHitPoints() - iDefenderInitialDamage);
		int iPromotionChanseModifier = iHealthPercent * iHealthPercent / maxHitPoints();
		int iPromotionChanse = iWinningOdds * (100 + iPromotionChanseModifier) / 100;
	
		if (GC.getGameINLINE().getSorenRandNum(GC.getDefineINT("COMBAT_DIE_SIDES"), "Occasional Promotion") < iPromotionChanse)
		{
			//select random promotion from available
			PromotionTypes ptPromotion = aDefenderAvailablePromotions[
				GC.getGameINLINE().getSorenRandNum(aDefenderAvailablePromotions.size(), "Select Promotion Type")];
			//promote
			pDefender->setHasPromotion(ptPromotion, true);
			//show message
			CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOUR_UNIT_PROMOTED_IN_BATTLE", pDefender->getNameKey(), 
				GC.getPromotionInfo(ptPromotion).getText());
			gDLL->getInterfaceIFace()->addMessage(
				pDefender->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, 
				GC.getPromotionInfo((PromotionTypes)0).getSound(), MESSAGE_TYPE_INFO, NULL, 
				(ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
		}
	}
p.s.: defender can not to withdraw in this modcomp, i added bDefenderWithdrawn check for compatibility with my other modcomp.
 
ok your mods are merged! :thumbsup: I am having some kind of issue with the commanders not promoting but I think that can easily be fixed. Also you were missing a little game text for the promotions in battle, here's all I noticed for now.

Code:
<TEXT>
		<Tag>TXT_KEY_MISC_YOUR_UNIT_PROMOTED_IN_BATTLE</Tag>
		<English>Your unit has been promoted in battle!</English>
		<French/>
		<German/>
		<Italian/>
		<Spanish/>
	</TEXT>

thanks
 
LOL, yea your right, I only copied the game text from commanders. :lol:
 
This modcomp is great! Thank you for making it!:goodjob: Afforess put it in A New Dawn so there is quite a lot of people playing with it.
 
Top Bottom