From fe39faf36c5c836a6a4ae2a4ce418a6f5b99976c Mon Sep 17 00:00:00 2001 From: Dydzio Date: Tue, 19 Dec 2023 19:52:40 +0100 Subject: [PATCH] Add UNTIL_OWN_ATTACK bonus duration and use for berserk --- AI/BattleAI/BattleEvaluator.cpp | 39 ++++++++++++---------- config/spells/timed.json | 2 +- docs/modders/Bonus/Bonus_Duration_Types.md | 3 +- lib/bonuses/Bonus.h | 5 +++ lib/bonuses/BonusEnum.cpp | 1 + lib/bonuses/BonusEnum.h | 3 +- lib/networkPacks/NetPacksLib.cpp | 3 ++ 7 files changed, 35 insertions(+), 21 deletions(-) diff --git a/AI/BattleAI/BattleEvaluator.cpp b/AI/BattleAI/BattleEvaluator.cpp index 3e53f8ad7..b424257c7 100644 --- a/AI/BattleAI/BattleEvaluator.cpp +++ b/AI/BattleAI/BattleEvaluator.cpp @@ -427,33 +427,36 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack) state->nextTurn(unit->unitId()); - PotentialTargets pt(unit, damageCache, state); + PotentialTargets potentialTargets(unit, damageCache, state); - if(!pt.possibleAttacks.empty()) + if(!potentialTargets.possibleAttacks.empty()) { - AttackPossibility ap = pt.bestAction(); + AttackPossibility attackPossibility = potentialTargets.bestAction(); - auto swb = state->getForUpdate(unit->unitId()); - *swb = *ap.attackerState; + auto stackWithBonuses = state->getForUpdate(unit->unitId()); + *stackWithBonuses = *attackPossibility.attackerState; - if(ap.defenderDamageReduce > 0) - swb->removeUnitBonus(Bonus::UntilAttack); - if(ap.attackerDamageReduce > 0) - swb->removeUnitBonus(Bonus::UntilBeingAttacked); - - for(auto affected : ap.affectedUnits) + if(attackPossibility.defenderDamageReduce > 0) { - swb = state->getForUpdate(affected->unitId()); - *swb = *affected; + stackWithBonuses->removeUnitBonus(Bonus::UntilAttack); + stackWithBonuses->removeUnitBonus(Bonus::UntilOwnAttack); + } + if(attackPossibility.attackerDamageReduce > 0) + stackWithBonuses->removeUnitBonus(Bonus::UntilBeingAttacked); - if(ap.defenderDamageReduce > 0) - swb->removeUnitBonus(Bonus::UntilBeingAttacked); - if(ap.attackerDamageReduce > 0 && ap.attack.defender->unitId() == affected->unitId()) - swb->removeUnitBonus(Bonus::UntilAttack); + for(auto affected : attackPossibility.affectedUnits) + { + stackWithBonuses = state->getForUpdate(affected->unitId()); + *stackWithBonuses = *affected; + + if(attackPossibility.defenderDamageReduce > 0) + stackWithBonuses->removeUnitBonus(Bonus::UntilBeingAttacked); + if(attackPossibility.attackerDamageReduce > 0 && attackPossibility.attack.defender->unitId() == affected->unitId()) + stackWithBonuses->removeUnitBonus(Bonus::UntilAttack); } } - auto bav = pt.bestActionValue(); + auto bav = potentialTargets.bestActionValue(); //best action is from effective owner`s point if view, we need to convert to our point if view if(state->battleGetOwner(unit) != playerID) diff --git a/config/spells/timed.json b/config/spells/timed.json index 0817cbad1..faeb8199e 100644 --- a/config/spells/timed.json +++ b/config/spells/timed.json @@ -1221,7 +1221,7 @@ "effects" : { "attacksNearestCreature" : { "type" : "ATTACKS_NEAREST_CREATURE", - "duration" : "UNTIL_ATTACK" + "duration" : "UNTIL_OWN_ATTACK" } } }, diff --git a/docs/modders/Bonus/Bonus_Duration_Types.md b/docs/modders/Bonus/Bonus_Duration_Types.md index 28056c6b1..1dd7359b7 100644 --- a/docs/modders/Bonus/Bonus_Duration_Types.md +++ b/docs/modders/Bonus/Bonus_Duration_Types.md @@ -13,4 +13,5 @@ Bonus may have any of these durations. They acts in disjunction. - UNTIL_BEING_ATTACKED: removed after any damage-inflicting attack - UNTIL_ATTACK: removed after attack and counterattacks are performed - STACK_GETS_TURN: removed when stack gets its turn - used for defensive stance -- COMMANDER_KILLED \ No newline at end of file +- COMMANDER_KILLED +- UNTIL_OWN_ATTACK: removed after attack (not counterattack) is performed \ No newline at end of file diff --git a/lib/bonuses/Bonus.h b/lib/bonuses/Bonus.h index 5f4a63608..51f3dc1de 100644 --- a/lib/bonuses/Bonus.h +++ b/lib/bonuses/Bonus.h @@ -162,6 +162,11 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this auto set = hb->duration & BonusDuration::COMMANDER_KILLED; return set.any(); } + static bool UntilOwnAttack(const Bonus *hb) + { + auto set = hb->duration & BonusDuration::UNTIL_OWN_ATTACK; + return set.any(); + } inline bool operator == (const BonusType & cf) const { return type == cf; diff --git a/lib/bonuses/BonusEnum.cpp b/lib/bonuses/BonusEnum.cpp index 326211b9a..903e3a32f 100644 --- a/lib/bonuses/BonusEnum.cpp +++ b/lib/bonuses/BonusEnum.cpp @@ -44,6 +44,7 @@ const std::map bonusDurationMap = BONUS_ITEM(UNTIL_ATTACK) BONUS_ITEM(STACK_GETS_TURN) BONUS_ITEM(COMMANDER_KILLED) + BONUS_ITEM(UNTIL_OWN_ATTACK) { "UNITL_BEING_ATTACKED", BonusDuration::UNTIL_BEING_ATTACKED }//typo, but used in some mods }; #undef BONUS_ITEM diff --git a/lib/bonuses/BonusEnum.h b/lib/bonuses/BonusEnum.h index 6b906338b..5eb5a9e9e 100644 --- a/lib/bonuses/BonusEnum.h +++ b/lib/bonuses/BonusEnum.h @@ -215,7 +215,7 @@ enum class BonusType }; namespace BonusDuration //when bonus is automatically removed { - using Type = std::bitset<10>; + using Type = std::bitset<11>; extern JsonNode toJson(const Type & duration); constexpr Type PERMANENT = 1 << 0; constexpr Type ONE_BATTLE = 1 << 1; //at the end of battle @@ -227,6 +227,7 @@ namespace BonusDuration //when bonus is automatically removed constexpr Type UNTIL_ATTACK = 1 << 7; /*removed after attack and counterattacks are performed*/ constexpr Type STACK_GETS_TURN = 1 << 8; /*removed when stack gets its turn - used for defensive stance*/ constexpr Type COMMANDER_KILLED = 1 << 9; + constexpr Type UNTIL_OWN_ATTACK = 1 << 10; /*removed after attack is performed (not counterattack)*/; }; enum class BonusSource { diff --git a/lib/networkPacks/NetPacksLib.cpp b/lib/networkPacks/NetPacksLib.cpp index 8868859a5..a0f3656e8 100644 --- a/lib/networkPacks/NetPacksLib.cpp +++ b/lib/networkPacks/NetPacksLib.cpp @@ -2260,6 +2260,9 @@ void BattleAttack::applyGs(CGameState * gs) stackAttacked.applyGs(gs); attacker->removeBonusesRecursive(Bonus::UntilAttack); + + if(!this->counter()) + attacker->removeBonusesRecursive(Bonus::UntilOwnAttack); } void StartAction::applyGs(CGameState *gs)