mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-25 22:42:04 +02:00
Random with history for combat abilities
This commit is contained in:
@@ -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)
|
||||
//{
|
||||
//
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user