Przeglądaj źródła

Random with history for combat abilities

Ivan Savenko 5 miesięcy temu
rodzic
commit
157b4fea74

+ 15 - 6
lib/callback/GameRandomizer.cpp

@@ -69,7 +69,7 @@ bool GameRandomizer::rollMoraleLuck(std::map<ObjectInstanceID, BiasedRandomizer>
 	if(goodLuckChanceVector.size() == 0)
 		return false;
 
-	return seeds.at(actor).roll(goodLuckChanceVector[chanceIndex], luckDiceSize, biasValue);
+	return seeds.at(actor).roll(goodLuckChanceVector[chanceIndex], luckDiceSize, biasValueLuckMorale);
 }
 
 bool GameRandomizer::rollGoodMorale(ObjectInstanceID actor, int moraleValue)
@@ -92,11 +92,20 @@ bool GameRandomizer::rollBadLuck(ObjectInstanceID actor, int luckValue)
 	return rollMoraleLuck(badLuckSeed, actor, luckValue, EGameSettings::COMBAT_LUCK_DICE_SIZE, EGameSettings::COMBAT_BAD_LUCK_CHANCE);
 }
 
-//bool GameRandomizer::rollCombatAbility(ObjectInstanceID actor, int percentageChance)
-//{
-//
-//}
-//
+bool GameRandomizer::rollCombatAbility(ObjectInstanceID actor, int percentageChance)
+{
+	if (!combatAbilitySeed.count(actor))
+		combatAbilitySeed.emplace(actor, getDefault().nextInt());
+
+	if (percentageChance <= 0)
+		return false;
+
+	if (percentageChance >= 100)
+		return true;
+
+	return combatAbilitySeed.at(actor).roll(percentageChance, 100, biasValueAbility);
+}
+
 //HeroTypeID GameRandomizer::rollHero(PlayerColor player, FactionID faction)
 //{
 //

+ 4 - 4
lib/callback/GameRandomizer.h

@@ -37,7 +37,8 @@ public:
 
 class DLL_LINKAGE GameRandomizer final : public IGameRandomizer
 {
-	static constexpr int biasValue = 10;
+	static constexpr int biasValueLuckMorale = 10;
+	static constexpr int biasValueAbility = 25;
 
 	struct HeroSkillRandomizer
 	{
@@ -65,7 +66,6 @@ class DLL_LINKAGE GameRandomizer final : public IGameRandomizer
 	std::map<ObjectInstanceID, BiasedRandomizer> badMoraleSeed;
 	std::map<ObjectInstanceID, BiasedRandomizer> goodLuckSeed;
 	std::map<ObjectInstanceID, BiasedRandomizer> badLuckSeed;
-
 	std::map<ObjectInstanceID, BiasedRandomizer> combatAbilitySeed;
 
 	bool rollMoraleLuck(std::map<ObjectInstanceID, BiasedRandomizer> & seeds, ObjectInstanceID actor, int moraleLuckValue, EGameSettings diceSize, EGameSettings diceWeights);
@@ -80,8 +80,8 @@ public:
 	bool rollBadMorale(ObjectInstanceID actor, int moraleValue);
 	bool rollGoodLuck(ObjectInstanceID actor, int luckValue);
 	bool rollBadLuck(ObjectInstanceID actor, int luckValue);
-//
-//	bool rollCombatAbility(ObjectInstanceID actor, int percentageChance);
+
+	bool rollCombatAbility(ObjectInstanceID actor, int percentageChance);
 
 //	HeroTypeID rollHero(PlayerColor player, FactionID faction) override;
 

+ 21 - 28
server/battles/BattleActionProcessor.cpp

@@ -938,31 +938,22 @@ void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const
 		bat.flags |= BattleAttack::COUNTER;
 
 	const int attackerLuck = attacker->luckVal();
+	ObjectInstanceID ownerArmy = battle.getBattle()->getSideArmy(attacker->unitSide())->id;
 
-	if(attackerLuck > 0)
-	{
-		ObjectInstanceID ownerArmy = battle.getBattle()->getSideArmy(attacker->unitSide())->id;
-		if (gameHandler->randomizer->rollGoodLuck(ownerArmy, attackerLuck))
-			bat.flags |= BattleAttack::LUCKY;
-	}
+	if(attackerLuck > 0 && gameHandler->randomizer->rollGoodLuck(ownerArmy, attackerLuck))
+		bat.flags |= BattleAttack::LUCKY;
 
-	if(attackerLuck < 0)
-	{
-		ObjectInstanceID ownerArmy = battle.getBattle()->getSideArmy(attacker->unitSide())->id;
-		if (gameHandler->randomizer->rollBadLuck(ownerArmy, -attackerLuck))
-			bat.flags |= BattleAttack::UNLUCKY;
-	}
+	if(attackerLuck < 0 && gameHandler->randomizer->rollBadLuck(ownerArmy, -attackerLuck))
+		bat.flags |= BattleAttack::UNLUCKY;
 
-	if (gameHandler->getRandomGenerator().nextInt(99) < attacker->valOfBonuses(BonusType::DOUBLE_DAMAGE_CHANCE))
-	{
+	if (gameHandler->randomizer->rollCombatAbility(ownerArmy, attacker->valOfBonuses(BonusType::DOUBLE_DAMAGE_CHANCE)))
 		bat.flags |= BattleAttack::DEATH_BLOW;
-	}
 
 	const auto * owner = battle.battleGetFightingHero(attacker->unitSide());
 	if(owner)
 	{
 		int chance = owner->valOfBonuses(BonusType::BONUS_DAMAGE_CHANCE, BonusSubtypeID(attacker->creatureId()));
-		if (chance > gameHandler->getRandomGenerator().nextInt(99))
+		if (gameHandler->randomizer->rollCombatAbility(ownerArmy, chance))
 			bat.flags |= BattleAttack::BALLISTA_DOUBLE_DMG;
 	}
 
@@ -1120,6 +1111,8 @@ void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const
 
 void BattleActionProcessor::attackCasting(const CBattleInfoCallback & battle, bool ranged, BonusType attackMode, const battle::Unit * attacker, const CStack * defender)
 {
+	ObjectInstanceID ownerArmy = battle.getBattle()->getSideArmy(attacker->unitSide())->id;
+
 	if(attacker->hasBonusOfType(attackMode))
 	{
 		TConstBonusListPtr spells = attacker->getBonuses(Selector::type()(attackMode));
@@ -1163,7 +1156,7 @@ void BattleActionProcessor::attackCasting(const CBattleInfoCallback & battle, bo
 				continue;
 
 			//check if spell should be cast (probability handling)
-			if(gameHandler->getRandomGenerator().nextInt(99) >= chance)
+			if (!gameHandler->randomizer->rollCombatAbility(ownerArmy, chance))
 				continue;
 
 			//casting
@@ -1319,9 +1312,11 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
 
 	int64_t acidDamage = 0;
 	TConstBonusListPtr acidBreath = attacker->getBonuses(Selector::type()(BonusType::ACID_BREATH));
+	ObjectInstanceID ownerArmy = battle.getBattle()->getSideArmy(attacker->unitSide())->id;
+
 	for(const auto & b : *acidBreath)
 	{
-		if(b->additionalInfo[0] > gameHandler->getRandomGenerator().nextInt(99))
+		if (gameHandler->randomizer->rollCombatAbility(ownerArmy, b->additionalInfo[0]))
 			acidDamage += b->val;
 	}
 
@@ -1345,10 +1340,9 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
 
 	if(attacker->hasBonusOfType(BonusType::TRANSMUTATION) && defender->isLiving()) //transmutation mechanics, similar to WoG werewolf ability
 	{
-		double chanceToTrigger = attacker->valOfBonuses(BonusType::TRANSMUTATION) / 100.0f;
-		vstd::amin(chanceToTrigger, 1); //cap at 100%
-
-		if(gameHandler->getRandomGenerator().nextDouble(0, 1) > chanceToTrigger)
+		ObjectInstanceID ownerArmy = battle.getBattle()->getSideArmy(attacker->unitSide())->id;
+		int chanceToTrigger = attacker->valOfBonuses(BonusType::TRANSMUTATION);
+		if (!gameHandler->randomizer->rollCombatAbility(ownerArmy, chanceToTrigger))
 			return;
 
 		int bonusAdditionalInfo = attacker->getBonus(Selector::type()(BonusType::TRANSMUTATION))->additionalInfo[0];
@@ -1395,24 +1389,23 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
 
 	if(attacker->hasBonusOfType(BonusType::DESTRUCTION, BonusCustomSubtype::destructionKillPercentage) || attacker->hasBonusOfType(BonusType::DESTRUCTION, BonusCustomSubtype::destructionKillAmount))
 	{
-		double chanceToTrigger = 0;
+		int chanceToTrigger = 0;
 		int amountToDie = 0;
 
 		if(attacker->hasBonusOfType(BonusType::DESTRUCTION, BonusCustomSubtype::destructionKillPercentage)) //killing by percentage
 		{
-			chanceToTrigger = attacker->valOfBonuses(BonusType::DESTRUCTION, BonusCustomSubtype::destructionKillPercentage) / 100.0f;
+			chanceToTrigger = attacker->valOfBonuses(BonusType::DESTRUCTION, BonusCustomSubtype::destructionKillPercentage);
 			int percentageToDie = attacker->getBonus(Selector::type()(BonusType::DESTRUCTION).And(Selector::subtype()(BonusCustomSubtype::destructionKillPercentage)))->additionalInfo[0];
 			amountToDie = static_cast<int>(defender->getCount() * percentageToDie * 0.01f);
 		}
 		else if(attacker->hasBonusOfType(BonusType::DESTRUCTION, BonusCustomSubtype::destructionKillAmount)) //killing by count
 		{
-			chanceToTrigger = attacker->valOfBonuses(BonusType::DESTRUCTION, BonusCustomSubtype::destructionKillAmount) / 100.0f;
+			chanceToTrigger = attacker->valOfBonuses(BonusType::DESTRUCTION, BonusCustomSubtype::destructionKillAmount);
 			amountToDie = attacker->getBonus(Selector::type()(BonusType::DESTRUCTION).And(Selector::subtype()(BonusCustomSubtype::destructionKillAmount)))->additionalInfo[0];
 		}
 
-		vstd::amin(chanceToTrigger, 1); //cap trigger chance at 100%
-
-		if(gameHandler->getRandomGenerator().nextDouble(0, 1) > chanceToTrigger)
+		ObjectInstanceID ownerArmy = battle.getBattle()->getSideArmy(attacker->unitSide())->id;
+		if (!gameHandler->randomizer->rollCombatAbility(ownerArmy, chanceToTrigger))
 			return;
 
 		BattleStackAttacked bsa;

+ 5 - 4
server/battles/BattleFlowProcessor.cpp

@@ -390,7 +390,7 @@ bool BattleFlowProcessor::tryMakeAutomaticAction(const CBattleInfoCallback & bat
 	const CreatureID stackCreatureId = next->unitType()->getId();
 
 	if ((stackCreatureId == CreatureID::ARROW_TOWERS || stackCreatureId == CreatureID::BALLISTA)
-		&& (!curOwner || gameHandler->getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(BonusType::MANUAL_CONTROL, BonusSubtypeID(stackCreatureId))))
+	   && (!curOwner || !gameHandler->randomizer->rollCombatAbility(curOwner->id, curOwner->valOfBonuses(BonusType::MANUAL_CONTROL, BonusSubtypeID(stackCreatureId)))))
 	{
 		BattleAction attack;
 		attack.actionType = EActionType::SHOOT;
@@ -462,7 +462,7 @@ bool BattleFlowProcessor::tryMakeAutomaticAction(const CBattleInfoCallback & bat
 			return true;
 		}
 
-		if (!curOwner || gameHandler->getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(BonusType::MANUAL_CONTROL, BonusSubtypeID(CreatureID(CreatureID::CATAPULT))))
+		if (!curOwner || !gameHandler->randomizer->rollCombatAbility(curOwner->id, curOwner->valOfBonuses(BonusType::MANUAL_CONTROL, BonusSubtypeID(CreatureID(CreatureID::CATAPULT)))))
 		{
 			BattleAction attack;
 			attack.actionType = EActionType::CATAPULT;
@@ -487,7 +487,7 @@ bool BattleFlowProcessor::tryMakeAutomaticAction(const CBattleInfoCallback & bat
 			return true;
 		}
 
-		if (!curOwner || gameHandler->getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(BonusType::MANUAL_CONTROL, BonusSubtypeID(CreatureID(CreatureID::FIRST_AID_TENT))))
+		if (!curOwner || !gameHandler->randomizer->rollCombatAbility(curOwner->id, curOwner->valOfBonuses(BonusType::MANUAL_CONTROL, BonusSubtypeID(CreatureID(CreatureID::FIRST_AID_TENT)))))
 		{
 			RandomGeneratorUtil::randomShuffle(possibleStacks, gameHandler->getRandomGenerator());
 			const CStack * toBeHealed = possibleStacks.front();
@@ -738,6 +738,7 @@ void BattleFlowProcessor::stackTurnTrigger(const CBattleInfoCallback & battle, c
 		}
 		if (st->isLiving() && !st->hasBonusOfType(BonusType::FEARLESS))
 		{
+			ObjectInstanceID opponentArmyID = battle.battleGetArmyObject(battle.otherSide(st->unitSide()))->id;
 			bool fearsomeCreature = false;
 			for (const CStack * stack : battle.battleGetAllStacks(true))
 			{
@@ -749,7 +750,7 @@ void BattleFlowProcessor::stackTurnTrigger(const CBattleInfoCallback & battle, c
 			}
 			if (fearsomeCreature)
 			{
-				if (gameHandler->getRandomGenerator().nextInt(99) < 10) //fixed 10%
+				if (gameHandler->randomizer->rollCombatAbility(opponentArmyID, 10)) //fixed 10%
 				{
 					bte.effect = vstd::to_underlying(BonusType::FEAR);
 					gameHandler->sendAndApply(bte);