1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-17 00:07:41 +02:00

Code cleanup

This commit is contained in:
Ivan Savenko
2023-08-17 19:18:14 +03:00
parent c516b5a64e
commit 013417fb7e
27 changed files with 215 additions and 152 deletions

View File

@ -18,6 +18,7 @@
#include "../../lib/mapObjects/CGTownInstance.h" #include "../../lib/mapObjects/CGTownInstance.h"
#include "../../lib/spells/CSpellHandler.h" #include "../../lib/spells/CSpellHandler.h"
#include "../../lib/spells/ISpellMechanics.h" #include "../../lib/spells/ISpellMechanics.h"
#include "../../lib/battle/BattleAction.h"
#include "../../lib/battle/BattleStateInfoForRetreat.h" #include "../../lib/battle/BattleStateInfoForRetreat.h"
#include "../../lib/battle/CObstacleInstance.h" #include "../../lib/battle/CObstacleInstance.h"
#include "../../lib/CStack.h" // TODO: remove #include "../../lib/CStack.h" // TODO: remove
@ -781,7 +782,7 @@ bool CBattleAI::attemptCastingSpell()
LOGFL("Best spell is %s (value %d). Will cast.", castToPerform.spell->getNameTranslated() % castToPerform.value); LOGFL("Best spell is %s (value %d). Will cast.", castToPerform.spell->getNameTranslated() % castToPerform.value);
BattleAction spellcast; BattleAction spellcast;
spellcast.actionType = EActionType::HERO_SPELL; spellcast.actionType = EActionType::HERO_SPELL;
spellcast.actionSubtype = castToPerform.spell->id; spellcast.spell = castToPerform.spell->getId();
spellcast.setTarget(castToPerform.dest); spellcast.setTarget(castToPerform.dest);
spellcast.side = side; spellcast.side = side;
spellcast.stackNumber = (!side) ? -1 : -2; spellcast.stackNumber = (!side) ? -1 : -2;

View File

@ -12,6 +12,7 @@
#include "../../lib/CRandomGenerator.h" #include "../../lib/CRandomGenerator.h"
#include "../../lib/CStack.h" #include "../../lib/CStack.h"
#include "../../lib/battle/BattleAction.h"
void CEmptyAI::saveGame(BinarySerializer & h, const int version) void CEmptyAI::saveGame(BinarySerializer & h, const int version)
{ {
@ -73,3 +74,8 @@ void CEmptyAI::showMapObjectSelectDialog(QueryID askID, const Component & icon,
{ {
cb->selectionMade(0, askID); cb->selectionMade(0, askID);
} }
std::optional<BattleAction> CEmptyAI::makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState)
{
return std::nullopt;
}

View File

@ -32,6 +32,7 @@ public:
void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override; void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override;
void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override; void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override;
void showMapObjectSelectDialog(QueryID askID, const Component & icon, const MetaString & title, const MetaString & description, const std::vector<ObjectInstanceID> & objects) override; void showMapObjectSelectDialog(QueryID askID, const Component & icon, const MetaString & title, const MetaString & description, const std::vector<ObjectInstanceID> & objects) override;
std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override;
}; };
#define NAME "EmptyAI 0.1" #define NAME "EmptyAI 0.1"

View File

@ -13,6 +13,7 @@
#include "../../lib/CStack.h" #include "../../lib/CStack.h"
#include "../../CCallback.h" #include "../../CCallback.h"
#include "../../lib/CCreatureHandler.h" #include "../../lib/CCreatureHandler.h"
#include "../../lib/battle/BattleAction.h"
static std::shared_ptr<CBattleCallback> cbc; static std::shared_ptr<CBattleCallback> cbc;

View File

@ -2890,4 +2890,7 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
return true; return true;
} }
std::optional<BattleAction> VCAI::makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState)
{
return std::nullopt;
}

View File

@ -203,6 +203,7 @@ public:
void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) override; void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) override;
void battleEnd(const BattleResult * br, QueryID queryID) override; void battleEnd(const BattleResult * br, QueryID queryID) override;
std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override;
void makeTurn(); void makeTurn();
void mainLoop(); void mainLoop();

View File

@ -128,7 +128,6 @@ CPlayerInterface::CPlayerInterface(PlayerColor Player):
destinationTeleportPos = int3(-1); destinationTeleportPos = int3(-1);
GH.defActionsDef = 0; GH.defActionsDef = 0;
LOCPLINT = this; LOCPLINT = this;
curAction = nullptr;
playerID=Player; playerID=Player;
human=true; human=true;
battleInt = nullptr; battleInt = nullptr;
@ -769,8 +768,7 @@ void CPlayerInterface::actionStarted(const BattleAction &action)
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
curAction = new BattleAction(action); battleInt->startAction(action);
battleInt->startAction(curAction);
} }
void CPlayerInterface::actionFinished(const BattleAction &action) void CPlayerInterface::actionFinished(const BattleAction &action)
@ -778,9 +776,7 @@ void CPlayerInterface::actionFinished(const BattleAction &action)
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
battleInt->endAction(curAction); battleInt->endAction(action);
delete curAction;
curAction = nullptr;
} }
void CPlayerInterface::activeStack(const CStack * stack) //called when it's turn of that stack void CPlayerInterface::activeStack(const CStack * stack) //called when it's turn of that stack
@ -935,8 +931,6 @@ void CPlayerInterface::battleAttack(const BattleAttack * ba)
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN; BATTLE_EVENT_POSSIBLE_RETURN;
assert(curAction);
StackAttackInfo info; StackAttackInfo info;
info.attacker = cb->battleGetStackByID(ba->stackAttacking); info.attacker = cb->battleGetStackByID(ba->stackAttacking);
info.defender = nullptr; info.defender = nullptr;
@ -2110,3 +2104,8 @@ void CPlayerInterface::showWorldViewEx(const std::vector<ObjectPosInfo>& objectP
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
adventureInt->openWorldView(objectPositions, showTerrain ); adventureInt->openWorldView(objectPositions, showTerrain );
} }
std::optional<BattleAction> CPlayerInterface::makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState)
{
return std::nullopt;
}

View File

@ -66,7 +66,6 @@ class CPlayerInterface : public CGameInterface, public IUpdateable
int autosaveCount; int autosaveCount;
std::list<std::shared_ptr<CInfoWindow>> dialogs; //queue of dialogs awaiting to be shown (not currently shown!) std::list<std::shared_ptr<CInfoWindow>> dialogs; //queue of dialogs awaiting to be shown (not currently shown!)
const BattleAction *curAction; //during the battle - action currently performed by active stack (or nullptr)
ObjectInstanceID destinationTeleport; //contain -1 or object id if teleportation ObjectInstanceID destinationTeleport; //contain -1 or object id if teleportation
int3 destinationTeleportPos; int3 destinationTeleportPos;
@ -173,6 +172,7 @@ protected: // Call-ins from server, should not be called directly, but only via
void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
void battleGateStateChanged(const EGateState state) override; void battleGateStateChanged(const EGateState state) override;
void yourTacticPhase(int distance) override; void yourTacticPhase(int distance) override;
std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override;
public: // public interface for use by client via LOCPLINT access public: // public interface for use by client via LOCPLINT access

View File

@ -13,7 +13,6 @@
#include <vcmi/Environment.h> #include <vcmi/Environment.h>
#include "../lib/IGameCallback.h" #include "../lib/IGameCallback.h"
#include "../lib/battle/BattleAction.h"
#include "../lib/battle/CBattleInfoCallback.h" #include "../lib/battle/CBattleInfoCallback.h"
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
@ -25,6 +24,7 @@ class CBattleGameInterface;
class CGameInterface; class CGameInterface;
class BinaryDeserializer; class BinaryDeserializer;
class BinarySerializer; class BinarySerializer;
class BattleAction;
template<typename T> class CApplier; template<typename T> class CApplier;
@ -118,7 +118,7 @@ public:
std::map<PlayerColor, std::vector<std::shared_ptr<IBattleEventsReceiver>>> additionalBattleInts; std::map<PlayerColor, std::vector<std::shared_ptr<IBattleEventsReceiver>>> additionalBattleInts;
std::optional<BattleAction> curbaction; std::unique_ptr<BattleAction> currentBattleAction;
CClient(); CClient();
~CClient(); ~CClient();

View File

@ -784,7 +784,7 @@ void ApplyClientNetPackVisitor::visitBattleAttack(BattleAttack & pack)
void ApplyFirstClientNetPackVisitor::visitStartAction(StartAction & pack) void ApplyFirstClientNetPackVisitor::visitStartAction(StartAction & pack)
{ {
cl.curbaction = std::make_optional(pack.ba); cl.currentBattleAction = std::make_unique<BattleAction>(pack.ba);
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::actionStarted, pack.ba); callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::actionStarted, pack.ba);
} }
@ -830,8 +830,8 @@ void ApplyClientNetPackVisitor::visitCatapultAttack(CatapultAttack & pack)
void ApplyClientNetPackVisitor::visitEndAction(EndAction & pack) void ApplyClientNetPackVisitor::visitEndAction(EndAction & pack)
{ {
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::actionFinished, *cl.curbaction); callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::actionFinished, *cl.currentBattleAction);
cl.curbaction.reset(); cl.currentBattleAction.reset();
} }
void ApplyClientNetPackVisitor::visitPackageApplied(PackageApplied & pack) void ApplyClientNetPackVisitor::visitPackageApplied(PackageApplied & pack)

View File

@ -286,7 +286,7 @@ void BattleActionsController::castThisSpell(SpellID spellID)
{ {
heroSpellToCast = std::make_shared<BattleAction>(); heroSpellToCast = std::make_shared<BattleAction>();
heroSpellToCast->actionType = EActionType::HERO_SPELL; heroSpellToCast->actionType = EActionType::HERO_SPELL;
heroSpellToCast->actionSubtype = spellID; //spell number heroSpellToCast->spell = spellID;
heroSpellToCast->stackNumber = (owner.attackingHeroInstance->tempOwner == owner.curInt->playerID) ? -1 : -2; heroSpellToCast->stackNumber = (owner.attackingHeroInstance->tempOwner == owner.curInt->playerID) ? -1 : -2;
heroSpellToCast->side = owner.defendingHeroInstance ? (owner.curInt->playerID == owner.defendingHeroInstance->tempOwner) : false; heroSpellToCast->side = owner.defendingHeroInstance ? (owner.curInt->playerID == owner.defendingHeroInstance->tempOwner) : false;
@ -314,7 +314,7 @@ void BattleActionsController::castThisSpell(SpellID spellID)
const CSpell * BattleActionsController::getHeroSpellToCast( ) const const CSpell * BattleActionsController::getHeroSpellToCast( ) const
{ {
if (heroSpellToCast) if (heroSpellToCast)
return SpellID(heroSpellToCast->actionSubtype).toSpell(); return heroSpellToCast->spell.toSpell();
return nullptr; return nullptr;
} }

View File

@ -94,13 +94,13 @@ void BattleEffectsController::battleTriggerEffect(const BattleTriggerEffect & bt
owner.waitForAnimations(); owner.waitForAnimations();
} }
void BattleEffectsController::startAction(const BattleAction* action) void BattleEffectsController::startAction(const BattleAction & action)
{ {
owner.checkForAnimations(); owner.checkForAnimations();
const CStack *stack = owner.curInt->cb->battleGetStackByID(action->stackNumber); const CStack *stack = owner.curInt->cb->battleGetStackByID(action.stackNumber);
switch(action->actionType) switch(action.actionType)
{ {
case EActionType::WAIT: case EActionType::WAIT:
owner.appendBattleLog(stack->formatGeneralMessage(136)); owner.appendBattleLog(stack->formatGeneralMessage(136));

View File

@ -60,7 +60,7 @@ public:
BattleEffectsController(BattleInterface & owner); BattleEffectsController(BattleInterface & owner);
void startAction(const BattleAction* action); void startAction(const BattleAction & action);
//displays custom effect on the battlefield //displays custom effect on the battlefield
void displayEffect(EBattleEffect effect, const BattleHex & destTile); void displayEffect(EBattleEffect effect, const BattleHex & destTile);

View File

@ -234,7 +234,7 @@ void BattleInterface::newRound(int number)
console->addText(CGI->generaltexth->allTexts[412]); console->addText(CGI->generaltexth->allTexts[412]);
} }
void BattleInterface::giveCommand(EActionType action, BattleHex tile, si32 additional) void BattleInterface::giveCommand(EActionType action, BattleHex tile, SpellID spell)
{ {
const CStack * actor = nullptr; const CStack * actor = nullptr;
if(action != EActionType::HERO_SPELL && action != EActionType::RETREAT && action != EActionType::SURRENDER) if(action != EActionType::HERO_SPELL && action != EActionType::RETREAT && action != EActionType::SURRENDER)
@ -253,7 +253,7 @@ void BattleInterface::giveCommand(EActionType action, BattleHex tile, si32 addit
ba.side = side.value(); ba.side = side.value();
ba.actionType = action; ba.actionType = action;
ba.aimToHex(tile); ba.aimToHex(tile);
ba.actionSubtype = additional; ba.spell = spell;
sendCommand(ba, actor); sendCommand(ba, actor);
} }
@ -567,12 +567,12 @@ bool BattleInterface::makingTurn() const
return stacksController->getActiveStack() != nullptr; return stacksController->getActiveStack() != nullptr;
} }
void BattleInterface::endAction(const BattleAction* action) void BattleInterface::endAction(const BattleAction &action)
{ {
// it is possible that tactics mode ended while opening music is still playing // it is possible that tactics mode ended while opening music is still playing
waitForAnimations(); waitForAnimations();
const CStack *stack = curInt->cb->battleGetStackByID(action->stackNumber); const CStack *stack = curInt->cb->battleGetStackByID(action.stackNumber);
// Activate stack from stackToActivate because this might have been temporary disabled, e.g., during spell cast // Activate stack from stackToActivate because this might have been temporary disabled, e.g., during spell cast
activateStack(); activateStack();
@ -585,7 +585,7 @@ void BattleInterface::endAction(const BattleAction* action)
tacticNextStack(stack); tacticNextStack(stack);
//we have activated next stack after sending request that has been just realized -> blockmap due to movement has changed //we have activated next stack after sending request that has been just realized -> blockmap due to movement has changed
if(action->actionType == EActionType::HERO_SPELL) if(action.actionType == EActionType::HERO_SPELL)
fieldController->redrawBackgroundWithHexes(); fieldController->redrawBackgroundWithHexes();
} }
@ -594,15 +594,15 @@ void BattleInterface::appendBattleLog(const std::string & newEntry)
console->addText(newEntry); console->addText(newEntry);
} }
void BattleInterface::startAction(const BattleAction* action) void BattleInterface::startAction(const BattleAction & action)
{ {
if(action->actionType == EActionType::END_TACTIC_PHASE) if(action.actionType == EActionType::END_TACTIC_PHASE)
{ {
windowObject->tacticPhaseEnded(); windowObject->tacticPhaseEnded();
return; return;
} }
const CStack *stack = curInt->cb->battleGetStackByID(action->stackNumber); const CStack *stack = curInt->cb->battleGetStackByID(action.stackNumber);
if (stack) if (stack)
{ {
@ -610,17 +610,17 @@ void BattleInterface::startAction(const BattleAction* action)
} }
else else
{ {
assert(action->actionType == EActionType::HERO_SPELL); //only cast spell is valid action without acting stack number assert(action.actionType == EActionType::HERO_SPELL); //only cast spell is valid action without acting stack number
} }
stacksController->startAction(action); stacksController->startAction(action);
if(action->actionType == EActionType::HERO_SPELL) //when hero casts spell if(action.actionType == EActionType::HERO_SPELL) //when hero casts spell
return; return;
if (!stack) if (!stack)
{ {
logGlobal->error("Something wrong with stackNumber in actionStarted. Stack number: %d", action->stackNumber); logGlobal->error("Something wrong with stackNumber in actionStarted. Stack number: %d", action.stackNumber);
return; return;
} }

View File

@ -156,7 +156,7 @@ public:
void activateStack(); //sets activeStack to stackToActivate etc. //FIXME: No, it's not clear at all void activateStack(); //sets activeStack to stackToActivate etc. //FIXME: No, it's not clear at all
void requestAutofightingAIToTakeAction(); void requestAutofightingAIToTakeAction();
void giveCommand(EActionType action, BattleHex tile = BattleHex(), si32 additional = -1); void giveCommand(EActionType action, BattleHex tile = BattleHex(), SpellID spell = SpellID::NONE);
void sendCommand(BattleAction command, const CStack * actor = nullptr); void sendCommand(BattleAction command, const CStack * actor = nullptr);
const CGHeroInstance *getActiveHero(); //returns hero that can currently cast a spell const CGHeroInstance *getActiveHero(); //returns hero that can currently cast a spell
@ -188,7 +188,7 @@ public:
void addToAnimationStage( EAnimationEvents event, const AwaitingAnimationAction & action); void addToAnimationStage( EAnimationEvents event, const AwaitingAnimationAction & action);
//call-ins //call-ins
void startAction(const BattleAction* action); void startAction(const BattleAction & action);
void stackReset(const CStack * stack); void stackReset(const CStack * stack);
void stackAdded(const CStack * stack); //new stack appeared on battlefield void stackAdded(const CStack * stack); //new stack appeared on battlefield
void stackRemoved(uint32_t stackID); //stack disappeared from batlefiled void stackRemoved(uint32_t stackID); //stack disappeared from batlefiled
@ -211,7 +211,7 @@ public:
void displaySpellEffect(const CSpell * spell, BattleHex destinationTile); //displays spell`s affected animation void displaySpellEffect(const CSpell * spell, BattleHex destinationTile); //displays spell`s affected animation
void displaySpellHit(const CSpell * spell, BattleHex destinationTile); //displays spell`s affected animation void displaySpellHit(const CSpell * spell, BattleHex destinationTile); //displays spell`s affected animation
void endAction(const BattleAction* action); void endAction(const BattleAction & action);
void obstaclePlaced(const std::vector<std::shared_ptr<const CObstacleInstance>> oi); void obstaclePlaced(const std::vector<std::shared_ptr<const CObstacleInstance>> oi);
void obstacleRemoved(const std::vector<ObstacleChanges> & obstacles); void obstacleRemoved(const std::vector<ObstacleChanges> & obstacles);

View File

@ -31,6 +31,7 @@
#include "../../CCallback.h" #include "../../CCallback.h"
#include "../../lib/spells/ISpellMechanics.h" #include "../../lib/spells/ISpellMechanics.h"
#include "../../lib/battle/BattleAction.h"
#include "../../lib/battle/BattleHex.h" #include "../../lib/battle/BattleHex.h"
#include "../../lib/CStack.h" #include "../../lib/CStack.h"
#include "../../lib/CondSh.h" #include "../../lib/CondSh.h"
@ -663,7 +664,7 @@ bool BattleStacksController::shouldRotate(const CStack * stack, const BattleHex
return false; return false;
} }
void BattleStacksController::endAction(const BattleAction* action) void BattleStacksController::endAction(const BattleAction & action)
{ {
owner.checkForAnimations(); owner.checkForAnimations();
@ -688,7 +689,7 @@ void BattleStacksController::endAction(const BattleAction* action)
removeExpiredColorFilters(); removeExpiredColorFilters();
} }
void BattleStacksController::startAction(const BattleAction* action) void BattleStacksController::startAction(const BattleAction & action)
{ {
removeExpiredColorFilters(); removeExpiredColorFilters();
} }

View File

@ -115,8 +115,8 @@ public:
void stacksAreAttacked(std::vector<StackAttackedInfo> attackedInfos); //called when a certain amount of stacks has been attacked void stacksAreAttacked(std::vector<StackAttackedInfo> attackedInfos); //called when a certain amount of stacks has been attacked
void stackAttacking(const StackAttackInfo & info); //called when stack with id ID is attacking something on hex dest void stackAttacking(const StackAttackInfo & info); //called when stack with id ID is attacking something on hex dest
void startAction(const BattleAction* action); void startAction(const BattleAction & action);
void endAction(const BattleAction* action); void endAction(const BattleAction & action);
void deactivateStack(); //copy activeStack to stackToActivate, then set activeStack to nullptr to temporary disable current stack void deactivateStack(); //copy activeStack to stackToActivate, then set activeStack to nullptr to temporary disable current stack

View File

@ -9,7 +9,6 @@
*/ */
#pragma once #pragma once
#include "battle/BattleAction.h"
#include "IGameEventsReceiver.h" #include "IGameEventsReceiver.h"
#include "spells/ViewSpellInt.h" #include "spells/ViewSpellInt.h"
@ -36,6 +35,7 @@ class CCreatureSet;
class CArmedInstance; class CArmedInstance;
class IShipyard; class IShipyard;
class IMarket; class IMarket;
class BattleAction;
struct BattleResult; struct BattleResult;
struct BattleAttack; struct BattleAttack;
struct BattleStackAttacked; struct BattleStackAttacked;
@ -107,10 +107,7 @@ public:
virtual void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain){}; virtual void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain){};
virtual std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) virtual std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) = 0;
{
return std::nullopt;
}
virtual void saveGame(BinarySerializer & h, const int version) = 0; virtual void saveGame(BinarySerializer & h, const int version) = 0;
virtual void loadGame(BinaryDeserializer & h, const int version) = 0; virtual void loadGame(BinaryDeserializer & h, const int version) = 0;

View File

@ -2289,7 +2289,7 @@ void StartAction::applyGs(CGameState *gs)
assert(st || heroAction); // stack must exists for all non-hero actions assert(st || heroAction); // stack must exists for all non-hero actions
if(ba.actionType == EActionType::HERO_SPELL) if(ba.actionType == EActionType::HERO_SPELL)
gs->curB->sides[ba.side].usedSpellsHistory.emplace_back(ba.actionSubtype); gs->curB->sides[ba.side].usedSpellsHistory.push_back(ba.spell);
switch(ba.actionType) switch(ba.actionType)
{ {

View File

@ -20,8 +20,7 @@ static const int32_t INVALID_UNIT_ID = -1000;
BattleAction::BattleAction(): BattleAction::BattleAction():
side(-1), side(-1),
stackNumber(-1), stackNumber(-1),
actionType(EActionType::NO_ACTION), actionType(EActionType::NO_ACTION)
actionSubtype(-1)
{ {
} }
@ -80,7 +79,7 @@ BattleAction BattleAction::makeCreatureSpellcast(const battle::Unit * stack, con
{ {
BattleAction ba; BattleAction ba;
ba.actionType = EActionType::MONSTER_SPELL; ba.actionType = EActionType::MONSTER_SPELL;
ba.actionSubtype = spellID; ba.spell = spellID;
ba.setTarget(target); ba.setTarget(target);
ba.side = stack->unitSide(); ba.side = stack->unitSide();
ba.stackNumber = stack->unitId(); ba.stackNumber = stack->unitId();
@ -144,7 +143,7 @@ std::string BattleAction::toString() const
} }
boost::format fmt("{BattleAction: side '%d', stackNumber '%d', actionType '%s', actionSubtype '%d', target {%s}}"); boost::format fmt("{BattleAction: side '%d', stackNumber '%d', actionType '%s', actionSubtype '%d', target {%s}}");
fmt % static_cast<int>(side) % stackNumber % actionTypeStream.str() % actionSubtype % targetStream.str(); fmt % static_cast<int>(side) % stackNumber % actionTypeStream.str() % spell.getNum() % targetStream.str();
return fmt.str(); return fmt.str();
} }
@ -193,6 +192,44 @@ void BattleAction::setTarget(const battle::Target & target_)
} }
} }
bool BattleAction::isUnitAction() const
{
static const std::array<EActionType, 9> actions = {
EActionType::WALK,
EActionType::WAIT,
EActionType::DEFEND,
EActionType::WALK_AND_ATTACK,
EActionType::SHOOT,
EActionType::CATAPULT,
EActionType::MONSTER_SPELL,
EActionType::BAD_MORALE,
EActionType::STACK_HEAL
};
return vstd::contains(actions, actionType);
}
bool BattleAction::isSpellAction() const
{
static const std::array<EActionType, 2> actions = {
EActionType::HERO_SPELL,
EActionType::MONSTER_SPELL
};
return vstd::contains(actions, actionType);
}
bool BattleAction::isTacticsAction() const
{
static const std::array<EActionType, 9> actions = {
EActionType::WALK,
EActionType::END_TACTIC_PHASE,
EActionType::RETREAT,
EActionType::SURRENDER
};
return vstd::contains(actions, actionType);
}
std::ostream & operator<<(std::ostream & os, const BattleAction & ba) std::ostream & operator<<(std::ostream & os, const BattleAction & ba)
{ {

View File

@ -28,7 +28,7 @@ public:
ui32 stackNumber; //stack ID, -1 left hero, -2 right hero, ui32 stackNumber; //stack ID, -1 left hero, -2 right hero,
EActionType actionType; //use ActionType enum for values EActionType actionType; //use ActionType enum for values
si32 actionSubtype; SpellID spell;
BattleAction(); BattleAction();
@ -43,6 +43,9 @@ public:
static BattleAction makeRetreat(ui8 side); static BattleAction makeRetreat(ui8 side);
static BattleAction makeSurrender(ui8 side); static BattleAction makeSurrender(ui8 side);
bool isTacticsAction() const;
bool isUnitAction() const;
bool isSpellAction() const;
std::string toString() const; std::string toString() const;
void aimToHex(const BattleHex & destination); void aimToHex(const BattleHex & destination);
@ -56,7 +59,7 @@ public:
h & side; h & side;
h & stackNumber; h & stackNumber;
h & actionType; h & actionType;
h & actionSubtype; h & spell;
h & target; h & target;
} }
private: private:

View File

@ -58,16 +58,21 @@ bool BattleActionProcessor::doEmptyAction(const BattleAction & ba)
bool BattleActionProcessor::doEndTacticsAction(const BattleAction & ba) bool BattleActionProcessor::doEndTacticsAction(const BattleAction & ba)
{ {
if (gameHandler->gameState()->curB->tacticDistance == 0)
{
gameHandler->complain("Cannot end tactics mode - no tactics!");
return false;
}
return true; return true;
} }
bool BattleActionProcessor::doWaitAction(const BattleAction & ba) bool BattleActionProcessor::doWaitAction(const BattleAction & ba)
{ {
return true; const CStack * stack = gameHandler->battleGetStackByID(ba.stackNumber);
}
if (!canStackAct(stack))
return false;
bool BattleActionProcessor::doBadMoraleAction(const BattleAction & ba)
{
return true; return true;
} }
@ -113,10 +118,10 @@ bool BattleActionProcessor::doHeroSpellAction(const BattleAction & ba)
return false; return false;
} }
const CSpell * s = SpellID(ba.actionSubtype).toSpell(); const CSpell * s = ba.spell.toSpell();
if (!s) if (!s)
{ {
logGlobal->error("Wrong spell id (%d)!", ba.actionSubtype); logGlobal->error("Wrong spell id (%d)!", ba.spell.getNum());
return false; return false;
} }
@ -411,7 +416,7 @@ bool BattleActionProcessor::doUnitSpellAction(const BattleAction & ba)
{ {
const CStack * stack = gameHandler->gameState()->curB->battleGetStackByID(ba.stackNumber); const CStack * stack = gameHandler->gameState()->curB->battleGetStackByID(ba.stackNumber);
battle::Target target = ba.getTarget(gameHandler->gameState()->curB); battle::Target target = ba.getTarget(gameHandler->gameState()->curB);
SpellID spellID = SpellID(ba.actionSubtype); SpellID spellID = ba.spell;
if (!canStackAct(stack)) if (!canStackAct(stack))
return false; return false;
@ -479,8 +484,6 @@ bool BattleActionProcessor::doHealAction(const BattleAction & ba)
bool BattleActionProcessor::canStackAct(const CStack * stack) bool BattleActionProcessor::canStackAct(const CStack * stack)
{ {
const bool isAboutActiveStack = stack->unitId() == gameHandler->gameState()->curB->getActiveStackID();
if (!stack) if (!stack)
{ {
gameHandler->complain("No such stack!"); gameHandler->complain("No such stack!");
@ -500,11 +503,14 @@ bool BattleActionProcessor::canStackAct(const CStack * stack)
return false; return false;
} }
} }
else if (!isAboutActiveStack) else
{
if (stack->unitId() != gameHandler->gameState()->curB->getActiveStackID())
{ {
gameHandler->complain("Action has to be about active stack!"); gameHandler->complain("Action has to be about active stack!");
return false; return false;
} }
}
return true; return true;
} }
@ -536,8 +542,6 @@ bool BattleActionProcessor::dispatchBattleAction(const BattleAction & ba)
return doCatapultAction(ba); return doCatapultAction(ba);
case EActionType::MONSTER_SPELL: case EActionType::MONSTER_SPELL:
return doUnitSpellAction(ba); return doUnitSpellAction(ba);
case EActionType::BAD_MORALE:
return doBadMoraleAction(ba);
case EActionType::STACK_HEAL: case EActionType::STACK_HEAL:
return doHealAction(ba); return doHealAction(ba);
} }
@ -545,7 +549,7 @@ bool BattleActionProcessor::dispatchBattleAction(const BattleAction & ba)
return false; return false;
} }
bool BattleActionProcessor::makeBattleAction(const BattleAction &ba) bool BattleActionProcessor::makeBattleActionImpl(const BattleAction &ba)
{ {
logGlobal->trace("Making action: %s", ba.toString()); logGlobal->trace("Making action: %s", ba.toString());
const CStack * stack = gameHandler->gameState()->curB->battleGetStackByID(ba.stackNumber); const CStack * stack = gameHandler->gameState()->curB->battleGetStackByID(ba.stackNumber);
@ -1394,3 +1398,53 @@ void BattleActionProcessor::addGenericKilledLog(BattleLogMessage & blm, const CS
blm.lines.push_back(std::move(line)); blm.lines.push_back(std::move(line));
} }
} }
bool BattleActionProcessor::makeAutomaticBattleAction(const BattleAction & ba)
{
return makeBattleActionImpl(ba);
}
bool BattleActionProcessor::makePlayerBattleAction(PlayerColor player, const BattleAction &ba)
{
const BattleInfo * battle = gameHandler->gameState()->curB;
if(!battle && gameHandler->complain("Can not make action - there is no battle ongoing!"))
return false;
if (ba.side != 0 && ba.side != 1 && gameHandler->complain("Can not make action - invalid battle side!"))
return false;
if(battle->tacticDistance != 0)
{
if(!ba.isTacticsAction())
{
gameHandler->complain("Can not make actions while in tactics mode!");
return false;
}
if(player != battle->sides[ba.side].color)
{
gameHandler->complain("Can not make actions in battles you are not part of!");
return false;
}
}
else
{
if (ba.isUnitAction() && ba.stackNumber != battle->getActiveStackID())
{
gameHandler->complain("Can not make actions - stack is not active!");
return false;
}
auto active = battle->battleActiveUnit();
if(!active && gameHandler->complain("No active unit in battle!"))
return false;
auto unitOwner = battle->battleGetOwner(active);
if(player != unitOwner && gameHandler->complain("Can not make actions in battles you are not part of!"))
return false;
}
return makeBattleActionImpl(ba);
}

View File

@ -16,6 +16,7 @@ struct BattleAttack;
class BattleAction; class BattleAction;
struct BattleHex; struct BattleHex;
class CStack; class CStack;
class PlayerColor;
enum class BonusType; enum class BonusType;
namespace battle namespace battle
@ -64,14 +65,15 @@ class BattleActionProcessor : boost::noncopyable
bool doShootAction(const BattleAction & ba); bool doShootAction(const BattleAction & ba);
bool doCatapultAction(const BattleAction & ba); bool doCatapultAction(const BattleAction & ba);
bool doUnitSpellAction(const BattleAction & ba); bool doUnitSpellAction(const BattleAction & ba);
bool doBadMoraleAction(const BattleAction & ba);
bool doHealAction(const BattleAction & ba); bool doHealAction(const BattleAction & ba);
bool dispatchBattleAction(const BattleAction & ba); bool dispatchBattleAction(const BattleAction & ba);
bool makeBattleActionImpl(const BattleAction & ba);
public: public:
explicit BattleActionProcessor(BattleProcessor * owner); explicit BattleActionProcessor(BattleProcessor * owner);
void setGameHandler(CGameHandler * newGameHandler); void setGameHandler(CGameHandler * newGameHandler);
bool makeBattleAction(const BattleAction & ba); bool makeAutomaticBattleAction(const BattleAction & ba);
bool makePlayerBattleAction(PlayerColor player, const BattleAction & ba);
}; };

View File

@ -126,12 +126,8 @@ void BattleFlowProcessor::summonGuardiansHelper(std::vector<BattleHex> & output,
} }
} }
void BattleFlowProcessor::onBattleStarted() void BattleFlowProcessor::tryPlaceMoats()
{ {
gameHandler->setBattle(gameHandler->gameState()->curB);
assert(gameHandler->gameState()->curB);
//TODO: pre-tactic stuff, call scripts etc.
//Moat should be initialized here, because only here we can use spellcasting //Moat should be initialized here, because only here we can use spellcasting
if (gameHandler->gameState()->curB->town && gameHandler->gameState()->curB->town->fortLevel() >= CGTownInstance::CITADEL) if (gameHandler->gameState()->curB->town && gameHandler->gameState()->curB->town->fortLevel() >= CGTownInstance::CITADEL)
{ {
@ -142,6 +138,14 @@ void BattleFlowProcessor::onBattleStarted()
auto target = spells::Target(); auto target = spells::Target();
cast.cast(gameHandler->spellEnv, target); cast.cast(gameHandler->spellEnv, target);
} }
}
void BattleFlowProcessor::onBattleStarted()
{
gameHandler->setBattle(gameHandler->gameState()->curB);
assert(gameHandler->gameState()->curB);
tryPlaceMoats();
if (gameHandler->gameState()->curB->tacticDistance == 0) if (gameHandler->gameState()->curB->tacticDistance == 0)
onTacticsEnded(); onTacticsEnded();
@ -330,11 +334,7 @@ void BattleFlowProcessor::activateNextStack()
if (!tryMakeAutomaticAction(next)) if (!tryMakeAutomaticAction(next))
{ {
logGlobal->trace("Activating %s", next->nodeName()); setActiveStack(next);
auto nextId = next->unitId();
BattleSetActiveStack sas;
sas.stack = nextId;
gameHandler->sendAndApply(&sas);
break; break;
} }
} }
@ -529,36 +529,25 @@ void BattleFlowProcessor::onActionMade(const BattleAction &ba)
if(owner->checkBattleStateChanges()) if(owner->checkBattleStateChanges())
return; return;
bool heroAction = ba.actionType == EActionType::HERO_SPELL || ba.actionType ==EActionType::SURRENDER || ba.actionType ==EActionType::RETREAT; if (ba.isUnitAction())
bool tacticsAction = ba.actionType == EActionType::END_TACTIC_PHASE;
if (activeStack == nullptr && !tacticsAction)
{
throw std::runtime_error("Unexpected action - no active stack!");
}
if (heroAction || tacticsAction)
{
if (!tacticsAction && activeStack->alive())
{
// this is action made by hero AND unit is alive (e.g. not killed by casted spell)
// keep current active stack for next action
BattleSetActiveStack sas;
sas.stack = activeStack->unitId();
gameHandler->sendAndApply(&sas);
return;
}
}
else
{ {
assert(activeStack != nullptr);
assert(actedStack != nullptr); assert(actedStack != nullptr);
if (rollGoodMorale(actedStack)) if (rollGoodMorale(actedStack))
{ {
// Good morale - same stack makes 2nd turn // Good morale - same stack makes 2nd turn
BattleSetActiveStack sas; setActiveStack(actedStack);
sas.stack = actedStack->unitId(); return;
gameHandler->sendAndApply(&sas); }
}
else
{
if (activeStack && activeStack->alive())
{
// this is action made by hero AND unit is alive (e.g. not killed by casted spell)
// keep current active stack for next action
setActiveStack(actedStack);
return; return;
} }
} }
@ -752,3 +741,13 @@ void BattleFlowProcessor::stackTurnTrigger(const CStack *st)
} }
} }
} }
void BattleFlowProcessor::setActiveStack(const CStack * stack)
{
assert(stack);
logGlobal->trace("Activating %s", stack->nodeName());
BattleSetActiveStack sas;
sas.stack = stack->unitId();
gameHandler->sendAndApply(&sas);
}

View File

@ -32,6 +32,7 @@ class BattleFlowProcessor : boost::noncopyable
void summonGuardiansHelper(std::vector<BattleHex> & output, const BattleHex & targetPosition, ui8 side, bool targetIsTwoHex); void summonGuardiansHelper(std::vector<BattleHex> & output, const BattleHex & targetPosition, ui8 side, bool targetIsTwoHex);
void trySummonGuardians(const CStack * stack); void trySummonGuardians(const CStack * stack);
void tryPlaceMoats();
void castOpeningSpells(); void castOpeningSpells();
void activateNextStack(); void activateNextStack();
void startNextRound(bool isFirstRound); void startNextRound(bool isFirstRound);
@ -39,6 +40,7 @@ class BattleFlowProcessor : boost::noncopyable
void stackEnchantedTrigger(const CStack * stack); void stackEnchantedTrigger(const CStack * stack);
void removeObstacle(const CObstacleInstance & obstacle); void removeObstacle(const CObstacleInstance & obstacle);
void stackTurnTrigger(const CStack * stack); void stackTurnTrigger(const CStack * stack);
void setActiveStack(const CStack * stack);
void makeStackDoNothing(const CStack * next); void makeStackDoNothing(const CStack * next);
bool makeAutomaticAction(const CStack * stack, BattleAction & ba); //used when action is taken by stack without volition of player (eg. unguided catapult attack) bool makeAutomaticAction(const CStack * stack, BattleAction & ba); //used when action is taken by stack without volition of player (eg. unguided catapult attack)

View File

@ -151,7 +151,6 @@ void BattleProcessor::setupBattle(int3 tile, const CArmedInstance *armies[2], co
if (heroes[0] && heroes[0]->boat && heroes[1] && heroes[1]->boat) if (heroes[0] && heroes[0]->boat && heroes[1] && heroes[1]->boat)
terType = BattleField(*VLC->identifiers()->getIdentifier("core", "battlefield.ship_to_ship")); terType = BattleField(*VLC->identifiers()->getIdentifier("core", "battlefield.ship_to_ship"));
//send info about battles //send info about battles
BattleStart bs; BattleStart bs;
bs.info = BattleInfo::setupBattle(tile, terrain, terType, armies, heroes, creatureBank, town); bs.info = BattleInfo::setupBattle(tile, terrain, terType, armies, heroes, creatureBank, town);
@ -236,52 +235,9 @@ void BattleProcessor::updateGateState()
gameHandler->sendAndApply(&db); gameHandler->sendAndApply(&db);
} }
bool BattleProcessor::makePlayerBattleAction(PlayerColor player, BattleAction &ba) bool BattleProcessor::makePlayerBattleAction(PlayerColor player, const BattleAction &ba)
{ {
const BattleInfo * b = gameHandler->gameState()->curB; bool result = actionsProcessor->makePlayerBattleAction(player, ba);
if(!b && gameHandler->complain("Can not make action - there is no battle ongoing!"))
return false;
if (ba.side != 0 && ba.side != 1 && gameHandler->complain("Can not make action - invalid battle side!"))
return false;
if(b->tacticDistance)
{
if(ba.actionType != EActionType::WALK && ba.actionType != EActionType::END_TACTIC_PHASE
&& ba.actionType != EActionType::RETREAT && ba.actionType != EActionType::SURRENDER)
{
gameHandler->complain("Can not make actions while in tactics mode!");
return false;
}
if(player != b->sides[ba.side].color)
{
gameHandler->complain("Can not make actions in battles you are not part of!");
return false;
}
}
else
{
bool heroAction = ba.actionType == EActionType::HERO_SPELL || ba.actionType ==EActionType::SURRENDER || ba.actionType ==EActionType::RETREAT || ba.actionType == EActionType::END_TACTIC_PHASE;
if (ba.stackNumber != b->getActiveStackID() && heroAction == false)
{
gameHandler->complain("Can not make actions - stack is not active!");
return false;
}
auto active = b->battleActiveUnit();
if(!active && gameHandler->complain("No active unit in battle!"))
return false;
auto unitOwner = b->battleGetOwner(active);
if(player != unitOwner && gameHandler->complain("Can not make actions in battles you are not part of!"))
return false;
}
bool result = actionsProcessor->makeBattleAction(ba);
flowProcessor->onActionMade(ba); flowProcessor->onActionMade(ba);
return result; return result;
} }
@ -294,7 +250,7 @@ void BattleProcessor::setBattleResult(EBattleResult resultType, int victoriusSid
bool BattleProcessor::makeAutomaticBattleAction(const BattleAction &ba) bool BattleProcessor::makeAutomaticBattleAction(const BattleAction &ba)
{ {
return actionsProcessor->makeBattleAction(ba); return actionsProcessor->makeAutomaticBattleAction(ba);
} }
void BattleProcessor::endBattleConfirm(const BattleInfo * battleInfo) void BattleProcessor::endBattleConfirm(const BattleInfo * battleInfo)

View File

@ -64,7 +64,7 @@ public:
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, bool creatureBank = false); void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, bool creatureBank = false);
/// Processing of incoming battle action netpack /// Processing of incoming battle action netpack
bool makePlayerBattleAction(PlayerColor player, BattleAction & ba); bool makePlayerBattleAction(PlayerColor player, const BattleAction & ba);
/// Applies results of a battle once player agrees to them /// Applies results of a battle once player agrees to them
void endBattleConfirm(const BattleInfo * battleInfo); void endBattleConfirm(const BattleInfo * battleInfo);