mirror of
https://github.com/vcmi/vcmi.git
synced 2025-05-23 22:40:07 +02:00
Fix inability of unit to cast spell after receiving morale
This commit is contained in:
parent
5433b07e5f
commit
5550edeb9a
@ -568,7 +568,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
|
|||||||
ourTurnSpan++;
|
ourTurnSpan++;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->nextTurn(unit->unitId());
|
state->nextTurn(unit->unitId(), BattleUnitTurnReason::TURN_QUEUE);
|
||||||
|
|
||||||
PotentialTargets potentialTargets(unit, damageCache, state);
|
PotentialTargets potentialTargets(unit, damageCache, state);
|
||||||
|
|
||||||
|
@ -342,14 +342,14 @@ void HypotheticBattle::nextRound()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HypotheticBattle::nextTurn(uint32_t unitId)
|
void HypotheticBattle::nextTurn(uint32_t unitId, BattleUnitTurnReason reason)
|
||||||
{
|
{
|
||||||
activeUnitId = unitId;
|
activeUnitId = unitId;
|
||||||
auto unit = getForUpdate(unitId);
|
auto unit = getForUpdate(unitId);
|
||||||
|
|
||||||
unit->removeUnitBonus(Bonus::UntilGetsTurn);
|
unit->removeUnitBonus(Bonus::UntilGetsTurn);
|
||||||
|
|
||||||
unit->afterGetsTurn();
|
unit->afterGetsTurn(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HypotheticBattle::addUnit(uint32_t id, const JsonNode & data)
|
void HypotheticBattle::addUnit(uint32_t id, const JsonNode & data)
|
||||||
|
@ -137,7 +137,7 @@ public:
|
|||||||
battle::Units getUnitsIf(const battle::UnitFilter & predicate) const override;
|
battle::Units getUnitsIf(const battle::UnitFilter & predicate) const override;
|
||||||
|
|
||||||
void nextRound() override;
|
void nextRound() override;
|
||||||
void nextTurn(uint32_t unitId) override;
|
void nextTurn(uint32_t unitId, BattleUnitTurnReason reason) override;
|
||||||
|
|
||||||
void addUnit(uint32_t id, const JsonNode & data) override;
|
void addUnit(uint32_t id, const JsonNode & data) override;
|
||||||
void setUnitState(uint32_t id, const JsonNode & data, int64_t healthDelta) override;
|
void setUnitState(uint32_t id, const JsonNode & data, int64_t healthDelta) override;
|
||||||
|
@ -769,7 +769,7 @@ void ApplyClientNetPackVisitor::visitBattleNextRound(BattleNextRound & pack)
|
|||||||
|
|
||||||
void ApplyClientNetPackVisitor::visitBattleSetActiveStack(BattleSetActiveStack & pack)
|
void ApplyClientNetPackVisitor::visitBattleSetActiveStack(BattleSetActiveStack & pack)
|
||||||
{
|
{
|
||||||
if(!pack.askPlayerInterface)
|
if(pack.reason == BattleUnitTurnReason::AUTOMATIC_ACTION)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const CStack *activated = gs.getBattle(pack.battleID)->battleGetStackByID(pack.stack);
|
const CStack *activated = gs.getBattle(pack.battleID)->battleGetStackByID(pack.stack);
|
||||||
|
@ -418,6 +418,7 @@ set(lib_MAIN_HEADERS
|
|||||||
battle/BattleSide.h
|
battle/BattleSide.h
|
||||||
battle/BattleStateInfoForRetreat.h
|
battle/BattleStateInfoForRetreat.h
|
||||||
battle/BattleProxy.h
|
battle/BattleProxy.h
|
||||||
|
battle/BattleUnitTurnReason.h
|
||||||
battle/CBattleInfoCallback.h
|
battle/CBattleInfoCallback.h
|
||||||
battle/CBattleInfoEssentials.h
|
battle/CBattleInfoEssentials.h
|
||||||
battle/CObstacleInstance.h
|
battle/CObstacleInstance.h
|
||||||
|
@ -666,7 +666,7 @@ void BattleInfo::nextRound()
|
|||||||
obst->battleTurnPassed();
|
obst->battleTurnPassed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BattleInfo::nextTurn(uint32_t unitId)
|
void BattleInfo::nextTurn(uint32_t unitId, BattleUnitTurnReason reason)
|
||||||
{
|
{
|
||||||
activeStack = unitId;
|
activeStack = unitId;
|
||||||
|
|
||||||
@ -675,7 +675,7 @@ void BattleInfo::nextTurn(uint32_t unitId)
|
|||||||
//remove bonuses that last until when stack gets new turn
|
//remove bonuses that last until when stack gets new turn
|
||||||
st->removeBonusesRecursive(Bonus::UntilGetsTurn);
|
st->removeBonusesRecursive(Bonus::UntilGetsTurn);
|
||||||
|
|
||||||
st->afterGetsTurn();
|
st->afterGetsTurn(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BattleInfo::addUnit(uint32_t id, const JsonNode & data)
|
void BattleInfo::addUnit(uint32_t id, const JsonNode & data)
|
||||||
|
@ -128,7 +128,7 @@ public:
|
|||||||
// IBattleState
|
// IBattleState
|
||||||
|
|
||||||
void nextRound() override;
|
void nextRound() override;
|
||||||
void nextTurn(uint32_t unitId) override;
|
void nextTurn(uint32_t unitId, BattleUnitTurnReason reason) override;
|
||||||
|
|
||||||
void addUnit(uint32_t id, const JsonNode & data) override;
|
void addUnit(uint32_t id, const JsonNode & data) override;
|
||||||
void moveUnit(uint32_t id, const BattleHex & destination) override;
|
void moveUnit(uint32_t id, const BattleHex & destination) override;
|
||||||
|
28
lib/battle/BattleUnitTurnReason.h
Normal file
28
lib/battle/BattleUnitTurnReason.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* BattleUnitTurnReason.h, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
enum class BattleUnitTurnReason : int8_t
|
||||||
|
{
|
||||||
|
/// Unit gained turn due to becoming first unit in turn queue
|
||||||
|
TURN_QUEUE,
|
||||||
|
/// Unit gained turn due to morale triggering
|
||||||
|
MORALE,
|
||||||
|
/// Unit (re)gained turn due to hero casting a spell while this unit is active
|
||||||
|
HERO_SPELLCAST,
|
||||||
|
/// Unit gained turn due to casting a spell while having ability to cast spells without spending turn
|
||||||
|
UNIT_SPELLCAST,
|
||||||
|
/// Unit gained turn for automatic action, player can not select action for this unit
|
||||||
|
AUTOMATIC_ACTION
|
||||||
|
};
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_END
|
@ -920,11 +920,13 @@ void CUnitState::afterNewRound()
|
|||||||
makeGhost();
|
makeGhost();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CUnitState::afterGetsTurn()
|
void CUnitState::afterGetsTurn(BattleUnitTurnReason reason)
|
||||||
{
|
{
|
||||||
//if moving second time this round it must be high morale bonus
|
if(reason == BattleUnitTurnReason::MORALE)
|
||||||
if(movedThisRound)
|
{
|
||||||
hadMorale = true;
|
hadMorale = true;
|
||||||
|
castSpellThisTurn = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CUnitState::makeGhost()
|
void CUnitState::makeGhost()
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "BattleUnitTurnReason.h"
|
||||||
#include "Unit.h"
|
#include "Unit.h"
|
||||||
#include "../bonuses/BonusCache.h"
|
#include "../bonuses/BonusCache.h"
|
||||||
|
|
||||||
@ -254,7 +255,7 @@ public:
|
|||||||
|
|
||||||
void afterNewRound();
|
void afterNewRound();
|
||||||
|
|
||||||
void afterGetsTurn();
|
void afterGetsTurn(BattleUnitTurnReason reason);
|
||||||
|
|
||||||
void makeGhost();
|
void makeGhost();
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "CBattleInfoEssentials.h"
|
#include "CBattleInfoEssentials.h"
|
||||||
|
#include "BattleUnitTurnReason.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@ -80,7 +81,7 @@ class DLL_LINKAGE IBattleState : public IBattleInfo
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void nextRound() = 0;
|
virtual void nextRound() = 0;
|
||||||
virtual void nextTurn(uint32_t unitId) = 0;
|
virtual void nextTurn(uint32_t unitId, BattleUnitTurnReason reason) = 0;
|
||||||
|
|
||||||
virtual void addUnit(uint32_t id, const JsonNode & data) = 0;
|
virtual void addUnit(uint32_t id, const JsonNode & data) = 0;
|
||||||
virtual void setUnitState(uint32_t id, const JsonNode & data, int64_t healthDelta) = 0;
|
virtual void setUnitState(uint32_t id, const JsonNode & data, int64_t healthDelta) = 0;
|
||||||
|
@ -2007,7 +2007,7 @@ void BattleNextRound::applyGs(CGameState *gs)
|
|||||||
|
|
||||||
void BattleSetActiveStack::applyGs(CGameState *gs)
|
void BattleSetActiveStack::applyGs(CGameState *gs)
|
||||||
{
|
{
|
||||||
gs->getBattle(battleID)->nextTurn(stack);
|
gs->getBattle(battleID)->nextTurn(stack, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BattleTriggerEffect::applyGs(CGameState *gs)
|
void BattleTriggerEffect::applyGs(CGameState *gs)
|
||||||
|
@ -12,9 +12,10 @@
|
|||||||
#include "NetPacksBase.h"
|
#include "NetPacksBase.h"
|
||||||
#include "BattleChanges.h"
|
#include "BattleChanges.h"
|
||||||
#include "PacksForClient.h"
|
#include "PacksForClient.h"
|
||||||
#include "../battle/BattleHexArray.h"
|
|
||||||
#include "../battle/BattleAction.h"
|
#include "../battle/BattleAction.h"
|
||||||
#include "../battle/BattleInfo.h"
|
#include "../battle/BattleInfo.h"
|
||||||
|
#include "../battle/BattleHexArray.h"
|
||||||
|
#include "../battle/BattleUnitTurnReason.h"
|
||||||
#include "../texts/MetaString.h"
|
#include "../texts/MetaString.h"
|
||||||
|
|
||||||
class CClient;
|
class CClient;
|
||||||
@ -63,8 +64,8 @@ struct DLL_LINKAGE BattleSetActiveStack : public CPackForClient
|
|||||||
void applyGs(CGameState * gs) override;
|
void applyGs(CGameState * gs) override;
|
||||||
|
|
||||||
BattleID battleID = BattleID::NONE;
|
BattleID battleID = BattleID::NONE;
|
||||||
ui32 stack = 0;
|
uint32_t stack = 0;
|
||||||
ui8 askPlayerInterface = true;
|
BattleUnitTurnReason reason;
|
||||||
|
|
||||||
void visitTyped(ICPackVisitor & visitor) override;
|
void visitTyped(ICPackVisitor & visitor) override;
|
||||||
|
|
||||||
@ -72,7 +73,7 @@ struct DLL_LINKAGE BattleSetActiveStack : public CPackForClient
|
|||||||
{
|
{
|
||||||
h & battleID;
|
h & battleID;
|
||||||
h & stack;
|
h & stack;
|
||||||
h & askPlayerInterface;
|
h & reason;
|
||||||
assert(battleID != BattleID::NONE);
|
assert(battleID != BattleID::NONE);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -334,7 +334,7 @@ void BattleFlowProcessor::activateNextStack(const CBattleInfoCallback & battle)
|
|||||||
if (!tryMakeAutomaticAction(battle, next))
|
if (!tryMakeAutomaticAction(battle, next))
|
||||||
{
|
{
|
||||||
if(next->alive()) {
|
if(next->alive()) {
|
||||||
setActiveStack(battle, next);
|
setActiveStack(battle, next, BattleUnitTurnReason::TURN_QUEUE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -576,7 +576,7 @@ void BattleFlowProcessor::onActionMade(const CBattleInfoCallback & battle, const
|
|||||||
// NOTE: in case of random spellcaster, (e.g. Master Genie) spell has been selected by server and was not present in action received from player
|
// NOTE: in case of random spellcaster, (e.g. Master Genie) spell has been selected by server and was not present in action received from player
|
||||||
if(actedStack->castSpellThisTurn && ba.spell.hasValue() && ba.spell.toSpell()->canCastWithoutSkip())
|
if(actedStack->castSpellThisTurn && ba.spell.hasValue() && ba.spell.toSpell()->canCastWithoutSkip())
|
||||||
{
|
{
|
||||||
setActiveStack(battle, actedStack);
|
setActiveStack(battle, actedStack, BattleUnitTurnReason::UNIT_SPELLCAST);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -589,7 +589,7 @@ void BattleFlowProcessor::onActionMade(const CBattleInfoCallback & battle, const
|
|||||||
if (rollGoodMorale(battle, actedStack))
|
if (rollGoodMorale(battle, actedStack))
|
||||||
{
|
{
|
||||||
// Good morale - same stack makes 2nd turn
|
// Good morale - same stack makes 2nd turn
|
||||||
setActiveStack(battle, actedStack);
|
setActiveStack(battle, actedStack, BattleUnitTurnReason::MORALE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -599,7 +599,7 @@ void BattleFlowProcessor::onActionMade(const CBattleInfoCallback & battle, const
|
|||||||
{
|
{
|
||||||
// this is action made by hero AND unit is alive (e.g. not killed by casted spell)
|
// this is action made by hero AND unit is alive (e.g. not killed by casted spell)
|
||||||
// keep current active stack for next action
|
// keep current active stack for next action
|
||||||
setActiveStack(battle, activeStack);
|
setActiveStack(battle, activeStack, BattleUnitTurnReason::HERO_SPELLCAST);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -622,7 +622,7 @@ bool BattleFlowProcessor::makeAutomaticAction(const CBattleInfoCallback & battle
|
|||||||
BattleSetActiveStack bsa;
|
BattleSetActiveStack bsa;
|
||||||
bsa.battleID = battle.getBattle()->getBattleID();
|
bsa.battleID = battle.getBattle()->getBattleID();
|
||||||
bsa.stack = stack->unitId();
|
bsa.stack = stack->unitId();
|
||||||
bsa.askPlayerInterface = false;
|
bsa.reason = BattleUnitTurnReason::AUTOMATIC_ACTION;
|
||||||
gameHandler->sendAndApply(bsa);
|
gameHandler->sendAndApply(bsa);
|
||||||
|
|
||||||
bool ret = owner->makeAutomaticBattleAction(battle, ba);
|
bool ret = owner->makeAutomaticBattleAction(battle, ba);
|
||||||
@ -809,12 +809,13 @@ void BattleFlowProcessor::stackTurnTrigger(const CBattleInfoCallback & battle, c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BattleFlowProcessor::setActiveStack(const CBattleInfoCallback & battle, const battle::Unit * stack)
|
void BattleFlowProcessor::setActiveStack(const CBattleInfoCallback & battle, const battle::Unit * stack, BattleUnitTurnReason reason)
|
||||||
{
|
{
|
||||||
assert(stack);
|
assert(stack);
|
||||||
|
|
||||||
BattleSetActiveStack sas;
|
BattleSetActiveStack sas;
|
||||||
sas.battleID = battle.getBattle()->getBattleID();
|
sas.battleID = battle.getBattle()->getBattleID();
|
||||||
sas.stack = stack->unitId();
|
sas.stack = stack->unitId();
|
||||||
|
sas.reason = reason;
|
||||||
gameHandler->sendAndApply(sas);
|
gameHandler->sendAndApply(sas);
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../lib/battle/BattleSide.h"
|
#include "../lib/battle/BattleSide.h"
|
||||||
|
#include "../lib/battle/BattleUnitTurnReason.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
class CStack;
|
class CStack;
|
||||||
@ -48,7 +49,7 @@ class BattleFlowProcessor : boost::noncopyable
|
|||||||
void stackEnchantedTrigger(const CBattleInfoCallback & battle, const CStack * stack);
|
void stackEnchantedTrigger(const CBattleInfoCallback & battle, const CStack * stack);
|
||||||
void removeObstacle(const CBattleInfoCallback & battle, const CObstacleInstance & obstacle);
|
void removeObstacle(const CBattleInfoCallback & battle, const CObstacleInstance & obstacle);
|
||||||
void stackTurnTrigger(const CBattleInfoCallback & battle, const CStack * stack);
|
void stackTurnTrigger(const CBattleInfoCallback & battle, const CStack * stack);
|
||||||
void setActiveStack(const CBattleInfoCallback & battle, const battle::Unit * stack);
|
void setActiveStack(const CBattleInfoCallback & battle, const battle::Unit * stack, BattleUnitTurnReason reason);
|
||||||
|
|
||||||
void makeStackDoNothing(const CBattleInfoCallback & battle, const CStack * next);
|
void makeStackDoNothing(const CBattleInfoCallback & battle, const CStack * next);
|
||||||
bool makeAutomaticAction(const CBattleInfoCallback & battle, const CStack * stack, BattleAction & ba); //used when action is taken by stack without volition of player (eg. unguided catapult attack)
|
bool makeAutomaticAction(const CBattleInfoCallback & battle, const CStack * stack, BattleAction & ba); //used when action is taken by stack without volition of player (eg. unguided catapult attack)
|
||||||
|
@ -42,7 +42,7 @@ public:
|
|||||||
MOCK_CONST_METHOD1(getUsedSpells, std::vector<SpellID>(BattleSide));
|
MOCK_CONST_METHOD1(getUsedSpells, std::vector<SpellID>(BattleSide));
|
||||||
|
|
||||||
MOCK_METHOD0(nextRound, void());
|
MOCK_METHOD0(nextRound, void());
|
||||||
MOCK_METHOD1(nextTurn, void(uint32_t));
|
MOCK_METHOD2(nextTurn, void(uint32_t, BattleUnitTurnReason));
|
||||||
MOCK_METHOD2(addUnit, void(uint32_t, const JsonNode &));
|
MOCK_METHOD2(addUnit, void(uint32_t, const JsonNode &));
|
||||||
MOCK_METHOD3(setUnitState, void(uint32_t, const JsonNode &, int64_t));
|
MOCK_METHOD3(setUnitState, void(uint32_t, const JsonNode &, int64_t));
|
||||||
MOCK_METHOD2(moveUnit, void(uint32_t, const BattleHex &));
|
MOCK_METHOD2(moveUnit, void(uint32_t, const BattleHex &));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user