mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-10 22:31:40 +02:00
Cleanup
This commit is contained in:
@@ -88,7 +88,7 @@ public:
|
||||
//void battleResultsApplied() override; //called when all effects of last battle are applied
|
||||
//void battleNewRoundFirst(int round) override; //called at the beginning of each turn before changes are applied;
|
||||
//void battleNewRound(int round) override; //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
|
||||
//void battleStackMoved(const CStack * stack, std::vector<BattleHex> dest, int distance) override;
|
||||
//void battleStackMoved(const CStack * stack, BattleHexArray dest, int distance) override;
|
||||
//void battleSpellCast(const BattleSpellCast *sc) override;
|
||||
//void battleStacksEffectsSet(const SetStackEffect & sse) override;//called when a specific effect is set to stacks
|
||||
//void battleTriggerEffect(const BattleTriggerEffect & bte) override;
|
||||
|
@@ -1,49 +1,49 @@
|
||||
/*
|
||||
* ExplorationHelper.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
|
||||
|
||||
#include "../AIUtility.h"
|
||||
|
||||
#include "../../../lib/GameConstants.h"
|
||||
#include "../../../lib/VCMI_Lib.h"
|
||||
#include "../Goals/AbstractGoal.h"
|
||||
|
||||
namespace NKAI
|
||||
{
|
||||
|
||||
class ExplorationHelper
|
||||
{
|
||||
private:
|
||||
const CGHeroInstance * hero;
|
||||
int sightRadius;
|
||||
float bestValue;
|
||||
Goals::TSubgoal bestGoal;
|
||||
int3 bestTile;
|
||||
int bestTilesDiscovered;
|
||||
const Nullkiller * ai;
|
||||
CCallback * cbp;
|
||||
const TeamState * ts;
|
||||
int3 ourPos;
|
||||
bool allowDeadEndCancellation;
|
||||
bool useCPathfinderAccessibility;
|
||||
|
||||
public:
|
||||
ExplorationHelper(const CGHeroInstance * hero, const Nullkiller * ai, bool useCPathfinderAccessibility = false);
|
||||
Goals::TSubgoal makeComposition() const;
|
||||
bool scanSector(int scanRadius);
|
||||
bool scanMap();
|
||||
int howManyTilesWillBeDiscovered(const int3 & pos) const;
|
||||
|
||||
private:
|
||||
void scanTile(const int3 & tile);
|
||||
bool hasReachableneighbour(const int3 & pos) const;
|
||||
};
|
||||
|
||||
}
|
||||
/*
|
||||
* ExplorationHelper.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
|
||||
|
||||
#include "../AIUtility.h"
|
||||
|
||||
#include "../../../lib/GameConstants.h"
|
||||
#include "../../../lib/VCMI_Lib.h"
|
||||
#include "../Goals/AbstractGoal.h"
|
||||
|
||||
namespace NKAI
|
||||
{
|
||||
|
||||
class ExplorationHelper
|
||||
{
|
||||
private:
|
||||
const CGHeroInstance * hero;
|
||||
int sightRadius;
|
||||
float bestValue;
|
||||
Goals::TSubgoal bestGoal;
|
||||
int3 bestTile;
|
||||
int bestTilesDiscovered;
|
||||
const Nullkiller * ai;
|
||||
CCallback * cbp;
|
||||
const TeamState * ts;
|
||||
int3 ourPos;
|
||||
bool allowDeadEndCancellation;
|
||||
bool useCPathfinderAccessibility;
|
||||
|
||||
public:
|
||||
ExplorationHelper(const CGHeroInstance * hero, const Nullkiller * ai, bool useCPathfinderAccessibility = false);
|
||||
Goals::TSubgoal makeComposition() const;
|
||||
bool scanSector(int scanRadius);
|
||||
bool scanMap();
|
||||
int howManyTilesWillBeDiscovered(const int3 & pos) const;
|
||||
|
||||
private:
|
||||
void scanTile(const int3 & tile);
|
||||
bool hasReachableNeighbor(const int3 & pos) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -399,7 +399,7 @@ void AINodeStorage::calculateNeighbours(
|
||||
|
||||
#if NKAI_PATHFINDER_TRACE_LEVEL >= 2
|
||||
logAi->trace(
|
||||
"Node %s added to neighbours of %s, layer %d",
|
||||
"Node %s added to neighbors of %s, layer %d",
|
||||
neighbour.toString(),
|
||||
source.coord.toString(),
|
||||
static_cast<int32_t>(layer));
|
||||
|
@@ -56,9 +56,9 @@ void ObjectGraphCalculator::calculateConnections()
|
||||
removeExtraConnections();
|
||||
}
|
||||
|
||||
float ObjectGraphCalculator::getneighbourConnectionsCost(const int3 & pos, std::vector<AIPath> & pathCache)
|
||||
float ObjectGraphCalculator::getNeighborConnectionsCost(const int3 & pos, std::vector<AIPath> & pathCache)
|
||||
{
|
||||
float neighbourCost = std::numeric_limits<float>::max();
|
||||
float neighborCost = std::numeric_limits<float>::max();
|
||||
|
||||
if(NKAI_GRAPH_TRACE_LEVEL >= 2)
|
||||
{
|
||||
@@ -68,24 +68,24 @@ float ObjectGraphCalculator::getneighbourConnectionsCost(const int3 & pos, std::
|
||||
foreach_neighbour(
|
||||
ai->cb.get(),
|
||||
pos,
|
||||
[this, &neighbourCost, &pathCache](const CPlayerSpecificInfoCallback * cb, const int3 & neighbour)
|
||||
[this, &neighborCost, &pathCache](const CPlayerSpecificInfoCallback * cb, const int3 & neighbor)
|
||||
{
|
||||
ai->pathfinder->calculatePathInfo(pathCache, neighbour);
|
||||
ai->pathfinder->calculatePathInfo(pathCache, neighbor);
|
||||
|
||||
auto costTotal = this->getConnectionsCost(pathCache);
|
||||
|
||||
if(costTotal.connectionsCount > 2 && costTotal.avg < neighbourCost)
|
||||
if(costTotal.connectionsCount > 2 && costTotal.avg < neighborCost)
|
||||
{
|
||||
neighbourCost = costTotal.avg;
|
||||
neighborCost = costTotal.avg;
|
||||
|
||||
if(NKAI_GRAPH_TRACE_LEVEL >= 2)
|
||||
{
|
||||
logAi->trace("Better node found at %s", neighbour.toString());
|
||||
logAi->trace("Better node found at %s", neighbor.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return neighbourCost;
|
||||
return neighborCost;
|
||||
}
|
||||
|
||||
void ObjectGraphCalculator::addMinimalDistanceJunctions()
|
||||
@@ -105,9 +105,9 @@ void ObjectGraphCalculator::addMinimalDistanceJunctions()
|
||||
if(currentCost.connectionsCount <= 2)
|
||||
return;
|
||||
|
||||
float neighbourCost = getneighbourConnectionsCost(pos, paths);
|
||||
float neighborCost = getNeighborConnectionsCost(pos, paths);
|
||||
|
||||
if(currentCost.avg < neighbourCost)
|
||||
if(currentCost.avg < neighborCost)
|
||||
{
|
||||
junctions.insert(pos);
|
||||
}
|
||||
@@ -137,17 +137,17 @@ void ObjectGraphCalculator::calculateConnections(const int3 & pos, std::vector<A
|
||||
foreach_neighbour(
|
||||
ai->cb.get(),
|
||||
pos,
|
||||
[this, &pos, &pathCache](const CPlayerSpecificInfoCallback * cb, const int3 & neighbour)
|
||||
[this, &pos, &pathCache](const CPlayerSpecificInfoCallback * cb, const int3 & neighbor)
|
||||
{
|
||||
if(target->hasNodeAt(neighbour))
|
||||
if(target->hasNodeAt(neighbor))
|
||||
{
|
||||
ai->pathfinder->calculatePathInfo(pathCache, neighbour);
|
||||
ai->pathfinder->calculatePathInfo(pathCache, neighbor);
|
||||
|
||||
for(auto & path : pathCache)
|
||||
{
|
||||
if(pos == path.targetHero->visitablePos())
|
||||
{
|
||||
target->tryAddConnection(pos, neighbour, path.movementCost(), path.getTotalDanger());
|
||||
target->tryAddConnection(pos, neighbor, path.movementCost(), path.getTotalDanger());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,56 +1,56 @@
|
||||
/*
|
||||
* ObjectGraphCalculator.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
|
||||
|
||||
#include "ObjectGraph.h"
|
||||
#include "../AIUtility.h"
|
||||
|
||||
namespace NKAI
|
||||
{
|
||||
|
||||
struct ConnectionCostInfo
|
||||
{
|
||||
float totalCost = 0;
|
||||
float avg = 0;
|
||||
int connectionsCount = 0;
|
||||
};
|
||||
|
||||
class ObjectGraphCalculator
|
||||
{
|
||||
private:
|
||||
ObjectGraph * target;
|
||||
const Nullkiller * ai;
|
||||
std::mutex syncLock;
|
||||
|
||||
std::map<const CGHeroInstance *, HeroRole> actors;
|
||||
std::map<const CGHeroInstance *, const CGObjectInstance *> actorObjectMap;
|
||||
|
||||
std::vector<std::unique_ptr<CGBoat>> temporaryBoats;
|
||||
std::vector<std::unique_ptr<CGHeroInstance>> temporaryActorHeroes;
|
||||
|
||||
public:
|
||||
ObjectGraphCalculator(ObjectGraph * target, const Nullkiller * ai);
|
||||
void setGraphObjects();
|
||||
void calculateConnections();
|
||||
float getneighbourConnectionsCost(const int3 & pos, std::vector<AIPath> & pathCache);
|
||||
void addMinimalDistanceJunctions();
|
||||
|
||||
private:
|
||||
void updatePaths();
|
||||
void calculateConnections(const int3 & pos, std::vector<AIPath> & pathCache);
|
||||
bool isExtraConnection(float direct, float side1, float side2) const;
|
||||
void removeExtraConnections();
|
||||
void addObjectActor(const CGObjectInstance * obj);
|
||||
void addJunctionActor(const int3 & visitablePos, bool isVirtualBoat = false);
|
||||
ConnectionCostInfo getConnectionsCost(std::vector<AIPath> & paths) const;
|
||||
};
|
||||
|
||||
}
|
||||
/*
|
||||
* ObjectGraphCalculator.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
|
||||
|
||||
#include "ObjectGraph.h"
|
||||
#include "../AIUtility.h"
|
||||
|
||||
namespace NKAI
|
||||
{
|
||||
|
||||
struct ConnectionCostInfo
|
||||
{
|
||||
float totalCost = 0;
|
||||
float avg = 0;
|
||||
int connectionsCount = 0;
|
||||
};
|
||||
|
||||
class ObjectGraphCalculator
|
||||
{
|
||||
private:
|
||||
ObjectGraph * target;
|
||||
const Nullkiller * ai;
|
||||
std::mutex syncLock;
|
||||
|
||||
std::map<const CGHeroInstance *, HeroRole> actors;
|
||||
std::map<const CGHeroInstance *, const CGObjectInstance *> actorObjectMap;
|
||||
|
||||
std::vector<std::unique_ptr<CGBoat>> temporaryBoats;
|
||||
std::vector<std::unique_ptr<CGHeroInstance>> temporaryActorHeroes;
|
||||
|
||||
public:
|
||||
ObjectGraphCalculator(ObjectGraph * target, const Nullkiller * ai);
|
||||
void setGraphObjects();
|
||||
void calculateConnections();
|
||||
float getNeighborConnectionsCost(const int3 & pos, std::vector<AIPath> & pathCache);
|
||||
void addMinimalDistanceJunctions();
|
||||
|
||||
private:
|
||||
void updatePaths();
|
||||
void calculateConnections(const int3 & pos, std::vector<AIPath> & pathCache);
|
||||
bool isExtraConnection(float direct, float side1, float side2) const;
|
||||
void removeExtraConnections();
|
||||
void addObjectActor(const CGObjectInstance * obj);
|
||||
void addJunctionActor(const int3 & visitablePos, bool isVirtualBoat = false);
|
||||
ConnectionCostInfo getConnectionsCost(std::vector<AIPath> & paths) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -1,56 +1,56 @@
|
||||
/*
|
||||
* StupidAI.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
|
||||
|
||||
#include "../../lib/battle/BattleHex.h"
|
||||
#include "../../lib/battle/ReachabilityInfo.h"
|
||||
#include "../../lib/CGameInterface.h"
|
||||
|
||||
class EnemyInfo;
|
||||
|
||||
class CStupidAI : public CBattleGameInterface
|
||||
{
|
||||
BattleSide side;
|
||||
std::shared_ptr<CBattleCallback> cb;
|
||||
std::shared_ptr<Environment> env;
|
||||
|
||||
bool wasWaitingForRealize;
|
||||
bool wasUnlockingGs;
|
||||
|
||||
void print(const std::string &text) const;
|
||||
public:
|
||||
CStupidAI();
|
||||
~CStupidAI();
|
||||
|
||||
void initBattleInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB) override;
|
||||
void initBattleInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB, AutocombatPreferences autocombatPreferences) override;
|
||||
|
||||
void actionFinished(const BattleID & battleID, const BattleAction &action) override;//occurs AFTER every action taken by any stack or by the hero
|
||||
void actionStarted(const BattleID & battleID, const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero
|
||||
void activeStack(const BattleID & battleID, const CStack * stack) override; //called when it's turn of that stack
|
||||
void yourTacticPhase(const BattleID & battleID, int distance) override;
|
||||
|
||||
void battleAttack(const BattleID & battleID, const BattleAttack *ba) override; //called when stack is performing attack
|
||||
void battleStacksAttacked(const BattleID & battleID, const std::vector<BattleStackAttacked> & bsa, bool ranged) override; //called when stack receives damage (after battleAttack())
|
||||
void battleEnd(const BattleID & battleID, const BattleResult *br, QueryID queryID) override;
|
||||
//void battleResultsApplied() override; //called when all effects of last battle are applied
|
||||
void battleNewRoundFirst(const BattleID & battleID) override; //called at the beginning of each turn before changes are applied;
|
||||
void battleNewRound(const BattleID & battleID) override; //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
|
||||
void battleStackMoved(const BattleID & battleID, const CStack * stack, BattleHexArray dest, int distance, bool teleport) override;
|
||||
void battleSpellCast(const BattleID & battleID, const BattleSpellCast *sc) override;
|
||||
void battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse) override;//called when a specific effect is set to stacks
|
||||
//void battleTriggerEffect(const BattleTriggerEffect & bte) override;
|
||||
void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide side, bool replayAllowed) override; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||
void battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) override; //called when catapult makes an attack
|
||||
|
||||
private:
|
||||
BattleAction goTowards(const BattleID & battleID, const CStack * stack, BattleHexArray hexes) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* StupidAI.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
|
||||
|
||||
#include "../../lib/battle/BattleHex.h"
|
||||
#include "../../lib/battle/ReachabilityInfo.h"
|
||||
#include "../../lib/CGameInterface.h"
|
||||
|
||||
class EnemyInfo;
|
||||
|
||||
class CStupidAI : public CBattleGameInterface
|
||||
{
|
||||
BattleSide side;
|
||||
std::shared_ptr<CBattleCallback> cb;
|
||||
std::shared_ptr<Environment> env;
|
||||
|
||||
bool wasWaitingForRealize;
|
||||
bool wasUnlockingGs;
|
||||
|
||||
void print(const std::string &text) const;
|
||||
public:
|
||||
CStupidAI();
|
||||
~CStupidAI();
|
||||
|
||||
void initBattleInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB) override;
|
||||
void initBattleInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CBattleCallback> CB, AutocombatPreferences autocombatPreferences) override;
|
||||
|
||||
void actionFinished(const BattleID & battleID, const BattleAction &action) override;//occurs AFTER every action taken by any stack or by the hero
|
||||
void actionStarted(const BattleID & battleID, const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero
|
||||
void activeStack(const BattleID & battleID, const CStack * stack) override; //called when it's turn of that stack
|
||||
void yourTacticPhase(const BattleID & battleID, int distance) override;
|
||||
|
||||
void battleAttack(const BattleID & battleID, const BattleAttack *ba) override; //called when stack is performing attack
|
||||
void battleStacksAttacked(const BattleID & battleID, const std::vector<BattleStackAttacked> & bsa, bool ranged) override; //called when stack receives damage (after battleAttack())
|
||||
void battleEnd(const BattleID & battleID, const BattleResult *br, QueryID queryID) override;
|
||||
//void battleResultsApplied() override; //called when all effects of last battle are applied
|
||||
void battleNewRoundFirst(const BattleID & battleID) override; //called at the beginning of each turn before changes are applied;
|
||||
void battleNewRound(const BattleID & battleID) override; //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
|
||||
void battleStackMoved(const BattleID & battleID, const CStack * stack, BattleHexArray dest, int distance, bool teleport) override;
|
||||
void battleSpellCast(const BattleID & battleID, const BattleSpellCast *sc) override;
|
||||
void battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse) override;//called when a specific effect is set to stacks
|
||||
//void battleTriggerEffect(const BattleTriggerEffect & bte) override;
|
||||
void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide side, bool replayAllowed) override; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||
void battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) override; //called when catapult makes an attack
|
||||
|
||||
private:
|
||||
BattleAction goTowards(const BattleID & battleID, const CStack * stack, BattleHexArray hexes) const;
|
||||
};
|
||||
|
||||
|
@@ -1,448 +1,448 @@
|
||||
/*
|
||||
* Explore.cpp, 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
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "Goals.h"
|
||||
#include "../VCAI.h"
|
||||
#include "../AIUtility.h"
|
||||
#include "../AIhelper.h"
|
||||
#include "../FuzzyHelper.h"
|
||||
#include "../ResourceManager.h"
|
||||
#include "../BuildingManager.h"
|
||||
#include "../../../lib/constants/StringConstants.h"
|
||||
#include "../../../lib/CPlayerState.h"
|
||||
|
||||
using namespace Goals;
|
||||
|
||||
namespace Goals
|
||||
{
|
||||
struct ExplorationHelper
|
||||
{
|
||||
HeroPtr hero;
|
||||
int sightRadius;
|
||||
float bestValue;
|
||||
TSubgoal bestGoal;
|
||||
VCAI * aip;
|
||||
CCallback * cbp;
|
||||
const TeamState * ts;
|
||||
int3 ourPos;
|
||||
bool allowDeadEndCancellation;
|
||||
bool allowGatherArmy;
|
||||
|
||||
ExplorationHelper(HeroPtr h, bool gatherArmy)
|
||||
{
|
||||
cbp = cb;
|
||||
aip = ai;
|
||||
hero = h;
|
||||
ts = cbp->getPlayerTeam(ai->playerID);
|
||||
sightRadius = hero->getSightRadius();
|
||||
bestGoal = sptr(Goals::Invalid());
|
||||
bestValue = 0;
|
||||
ourPos = h->visitablePos();
|
||||
allowDeadEndCancellation = true;
|
||||
allowGatherArmy = gatherArmy;
|
||||
}
|
||||
|
||||
void scanSector(int scanRadius)
|
||||
{
|
||||
int3 tile = int3(0, 0, ourPos.z);
|
||||
|
||||
const auto & slice = ts->fogOfWarMap[ourPos.z];
|
||||
|
||||
for(tile.x = ourPos.x - scanRadius; tile.x <= ourPos.x + scanRadius; tile.x++)
|
||||
{
|
||||
for(tile.y = ourPos.y - scanRadius; tile.y <= ourPos.y + scanRadius; tile.y++)
|
||||
{
|
||||
|
||||
if(cbp->isInTheMap(tile) && slice[tile.x][tile.y])
|
||||
{
|
||||
scanTile(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scanMap()
|
||||
{
|
||||
int3 mapSize = cbp->getMapSize();
|
||||
int perimeter = 2 * sightRadius * (mapSize.x + mapSize.y);
|
||||
|
||||
std::vector<int3> from;
|
||||
std::vector<int3> to;
|
||||
|
||||
from.reserve(perimeter);
|
||||
to.reserve(perimeter);
|
||||
|
||||
foreach_tile_pos([&](const int3 & pos)
|
||||
{
|
||||
if(ts->fogOfWarMap[pos.z][pos.x][pos.y])
|
||||
{
|
||||
bool hasInvisibleneighbour = false;
|
||||
|
||||
foreach_neighbour(cbp, pos, [&](CCallback * cbp, int3 neighbour)
|
||||
{
|
||||
if(!ts->fogOfWarMap[neighbour.z][neighbour.x][neighbour.y])
|
||||
{
|
||||
hasInvisibleneighbour = true;
|
||||
}
|
||||
});
|
||||
|
||||
if(hasInvisibleneighbour)
|
||||
from.push_back(pos);
|
||||
}
|
||||
});
|
||||
|
||||
logAi->debug("Exploration scan visible area perimeter for hero %s", hero.name);
|
||||
|
||||
for(const int3 & tile : from)
|
||||
{
|
||||
scanTile(tile);
|
||||
}
|
||||
|
||||
if(!bestGoal->invalid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
allowDeadEndCancellation = false;
|
||||
|
||||
for(int i = 0; i < sightRadius; i++)
|
||||
{
|
||||
getVisibleNeighbours(from, to);
|
||||
vstd::concatenate(from, to);
|
||||
vstd::removeDuplicates(from);
|
||||
}
|
||||
|
||||
logAi->debug("Exploration scan all possible tiles for hero %s", hero.name);
|
||||
|
||||
for(const int3 & tile : from)
|
||||
{
|
||||
scanTile(tile);
|
||||
}
|
||||
}
|
||||
|
||||
void scanTile(const int3 & tile)
|
||||
{
|
||||
if(tile == ourPos
|
||||
|| !aip->ah->isTileAccessible(hero, tile)) //shouldn't happen, but it does
|
||||
return;
|
||||
|
||||
int tilesDiscovered = howManyTilesWillBeDiscovered(tile);
|
||||
if(!tilesDiscovered)
|
||||
return;
|
||||
|
||||
auto waysToVisit = aip->ah->howToVisitTile(hero, tile, allowGatherArmy);
|
||||
for(auto goal : waysToVisit)
|
||||
{
|
||||
if(goal->evaluationContext.movementCost <= 0.0) // should not happen
|
||||
continue;
|
||||
|
||||
float ourValue = (float)tilesDiscovered * tilesDiscovered / goal->evaluationContext.movementCost;
|
||||
|
||||
if(ourValue > bestValue) //avoid costly checks of tiles that don't reveal much
|
||||
{
|
||||
auto obj = cb->getTopObj(tile);
|
||||
|
||||
// picking up resources does not yield any exploration at all.
|
||||
// if it blocks the way to some explorable tile AIPathfinder will take care of it
|
||||
if(obj && obj->isBlockedVisitable())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(isSafeToVisit(hero, tile))
|
||||
{
|
||||
bestGoal = goal;
|
||||
bestValue = ourValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void getVisibleNeighbours(const std::vector<int3> & tiles, std::vector<int3> & out) const
|
||||
{
|
||||
for(const int3 & tile : tiles)
|
||||
{
|
||||
foreach_neighbour(cbp, tile, [&](CCallback * cbp, int3 neighbour)
|
||||
{
|
||||
if(ts->fogOfWarMap[neighbour.z][neighbour.x][neighbour.y])
|
||||
{
|
||||
out.push_back(neighbour);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
int howManyTilesWillBeDiscovered(const int3 & pos) const
|
||||
{
|
||||
int ret = 0;
|
||||
int3 npos = int3(0, 0, pos.z);
|
||||
|
||||
const auto & slice = ts->fogOfWarMap[pos.z];
|
||||
|
||||
for(npos.x = pos.x - sightRadius; npos.x <= pos.x + sightRadius; npos.x++)
|
||||
{
|
||||
for(npos.y = pos.y - sightRadius; npos.y <= pos.y + sightRadius; npos.y++)
|
||||
{
|
||||
if(cbp->isInTheMap(npos)
|
||||
&& pos.dist2d(npos) - 0.5 < sightRadius
|
||||
&& !slice[npos.x][npos.y])
|
||||
{
|
||||
if(allowDeadEndCancellation
|
||||
&& !hasReachableneighbour(npos))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool hasReachableneighbour(const int3 &pos) const
|
||||
{
|
||||
for(crint3 dir : int3::getDirs())
|
||||
{
|
||||
int3 tile = pos + dir;
|
||||
if(cbp->isInTheMap(tile))
|
||||
{
|
||||
auto isAccessible = aip->ah->isTileAccessible(hero, tile);
|
||||
|
||||
if(isAccessible)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bool Explore::operator==(const Explore & other) const
|
||||
{
|
||||
return other.hero.h == hero.h && other.allowGatherArmy == allowGatherArmy;
|
||||
}
|
||||
|
||||
std::string Explore::completeMessage() const
|
||||
{
|
||||
return "Hero " + hero.get()->getNameTranslated() + " completed exploration";
|
||||
}
|
||||
|
||||
TSubgoal Explore::whatToDoToAchieve()
|
||||
{
|
||||
return fh->chooseSolution(getAllPossibleSubgoals());
|
||||
}
|
||||
|
||||
TGoalVec Explore::getAllPossibleSubgoals()
|
||||
{
|
||||
TGoalVec ret;
|
||||
std::vector<const CGHeroInstance *> heroes;
|
||||
|
||||
if(hero)
|
||||
{
|
||||
heroes.push_back(hero.h);
|
||||
}
|
||||
else
|
||||
{
|
||||
//heroes = ai->getUnblockedHeroes();
|
||||
heroes = cb->getHeroesInfo();
|
||||
vstd::erase_if(heroes, [](const HeroPtr h)
|
||||
{
|
||||
if(ai->getGoal(h)->goalType == EXPLORE) //do not reassign hero who is already explorer
|
||||
return true;
|
||||
|
||||
if(!ai->isAbleToExplore(h))
|
||||
return true;
|
||||
|
||||
return !h->movementPointsRemaining(); //saves time, immobile heroes are useless anyway
|
||||
});
|
||||
}
|
||||
|
||||
//try to use buildings that uncover map
|
||||
std::vector<const CGObjectInstance *> objs;
|
||||
for(auto obj : ai->visitableObjs)
|
||||
{
|
||||
if(!vstd::contains(ai->alreadyVisited, obj))
|
||||
{
|
||||
switch(obj->ID.num)
|
||||
{
|
||||
case Obj::REDWOOD_OBSERVATORY:
|
||||
case Obj::PILLAR_OF_FIRE:
|
||||
case Obj::CARTOGRAPHER:
|
||||
objs.push_back(obj);
|
||||
break;
|
||||
case Obj::MONOLITH_ONE_WAY_ENTRANCE:
|
||||
case Obj::MONOLITH_TWO_WAY:
|
||||
case Obj::SUBTERRANEAN_GATE:
|
||||
auto tObj = dynamic_cast<const CGTeleport *>(obj);
|
||||
assert(ai->knownTeleportChannels.find(tObj->channel) != ai->knownTeleportChannels.end());
|
||||
if(TeleportChannel::IMPASSABLE != ai->knownTeleportChannels[tObj->channel]->passability)
|
||||
objs.push_back(obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(obj->ID.num)
|
||||
{
|
||||
case Obj::MONOLITH_TWO_WAY:
|
||||
case Obj::SUBTERRANEAN_GATE:
|
||||
auto tObj = dynamic_cast<const CGTeleport *>(obj);
|
||||
if(TeleportChannel::IMPASSABLE == ai->knownTeleportChannels[tObj->channel]->passability)
|
||||
break;
|
||||
for(auto exit : ai->knownTeleportChannels[tObj->channel]->exits)
|
||||
{
|
||||
if(!cb->getObj(exit))
|
||||
{ // Always attempt to visit two-way teleports if one of channel exits is not visible
|
||||
objs.push_back(obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(auto h : heroes)
|
||||
{
|
||||
for(auto obj : objs) //double loop, performance risk?
|
||||
{
|
||||
auto waysToVisitObj = ai->ah->howToVisitObj(h, obj, allowGatherArmy);
|
||||
|
||||
vstd::concatenate(ret, waysToVisitObj);
|
||||
}
|
||||
|
||||
TSubgoal goal = exploreNearestNeighbour(h);
|
||||
|
||||
if(!goal->invalid())
|
||||
{
|
||||
ret.push_back(goal);
|
||||
}
|
||||
}
|
||||
|
||||
if(ret.empty())
|
||||
{
|
||||
for(auto h : heroes)
|
||||
{
|
||||
logAi->trace("Exploration searching for a new point for hero %s", h->getNameTranslated());
|
||||
|
||||
TSubgoal goal = explorationNewPoint(h);
|
||||
|
||||
if(goal->invalid())
|
||||
{
|
||||
ai->markHeroUnableToExplore(h); //there is no freely accessible tile, do not poll this hero anymore
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.push_back(goal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//we either don't have hero yet or none of heroes can explore
|
||||
if((!hero || ret.empty()) && ai->canRecruitAnyHero())
|
||||
ret.push_back(sptr(RecruitHero()));
|
||||
|
||||
if(ret.empty())
|
||||
{
|
||||
throw goalFulfilledException(sptr(Explore().sethero(hero)));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Explore::fulfillsMe(TSubgoal goal)
|
||||
{
|
||||
if(goal->goalType == EXPLORE)
|
||||
{
|
||||
if(goal->hero)
|
||||
return hero == goal->hero;
|
||||
else
|
||||
return true; //cancel ALL exploration
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TSubgoal Explore::explorationBestNeighbour(int3 hpos, HeroPtr h) const
|
||||
{
|
||||
ExplorationHelper scanResult(h, allowGatherArmy);
|
||||
|
||||
for(crint3 dir : int3::getDirs())
|
||||
{
|
||||
int3 tile = hpos + dir;
|
||||
if(cb->isInTheMap(tile))
|
||||
{
|
||||
scanResult.scanTile(tile);
|
||||
}
|
||||
}
|
||||
|
||||
return scanResult.bestGoal;
|
||||
}
|
||||
|
||||
|
||||
TSubgoal Explore::explorationNewPoint(HeroPtr h) const
|
||||
{
|
||||
ExplorationHelper scanResult(h, allowGatherArmy);
|
||||
|
||||
scanResult.scanSector(10);
|
||||
|
||||
if(!scanResult.bestGoal->invalid())
|
||||
{
|
||||
return scanResult.bestGoal;
|
||||
}
|
||||
|
||||
scanResult.scanMap();
|
||||
|
||||
return scanResult.bestGoal;
|
||||
}
|
||||
|
||||
|
||||
TSubgoal Explore::exploreNearestNeighbour(HeroPtr h) const
|
||||
{
|
||||
TimeCheck tc("where to explore");
|
||||
int3 hpos = h->visitablePos();
|
||||
|
||||
//look for nearby objs -> visit them if they're close enough
|
||||
const int DIST_LIMIT = 3;
|
||||
const float COST_LIMIT = .2f; //todo: fine tune
|
||||
|
||||
std::vector<const CGObjectInstance *> nearbyVisitableObjs;
|
||||
for(int x = hpos.x - DIST_LIMIT; x <= hpos.x + DIST_LIMIT; ++x) //get only local objects instead of all possible objects on the map
|
||||
{
|
||||
for(int y = hpos.y - DIST_LIMIT; y <= hpos.y + DIST_LIMIT; ++y)
|
||||
{
|
||||
for(auto obj : cb->getVisitableObjs(int3(x, y, hpos.z), false))
|
||||
{
|
||||
if(ai->isGoodForVisit(obj, h, COST_LIMIT))
|
||||
{
|
||||
nearbyVisitableObjs.push_back(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(nearbyVisitableObjs.size())
|
||||
{
|
||||
vstd::removeDuplicates(nearbyVisitableObjs); //one object may occupy multiple tiles
|
||||
boost::sort(nearbyVisitableObjs, CDistanceSorter(h.get()));
|
||||
|
||||
TSubgoal pickupNearestObj = fh->chooseSolution(ai->ah->howToVisitObj(h, nearbyVisitableObjs.back(), false));
|
||||
|
||||
if(!pickupNearestObj->invalid())
|
||||
{
|
||||
return pickupNearestObj;
|
||||
}
|
||||
}
|
||||
|
||||
//check if nearby tiles allow us to reveal anything - this is quick
|
||||
return explorationBestNeighbour(hpos, h);
|
||||
}
|
||||
/*
|
||||
* Explore.cpp, 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
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "Goals.h"
|
||||
#include "../VCAI.h"
|
||||
#include "../AIUtility.h"
|
||||
#include "../AIhelper.h"
|
||||
#include "../FuzzyHelper.h"
|
||||
#include "../ResourceManager.h"
|
||||
#include "../BuildingManager.h"
|
||||
#include "../../../lib/constants/StringConstants.h"
|
||||
#include "../../../lib/CPlayerState.h"
|
||||
|
||||
using namespace Goals;
|
||||
|
||||
namespace Goals
|
||||
{
|
||||
struct ExplorationHelper
|
||||
{
|
||||
HeroPtr hero;
|
||||
int sightRadius;
|
||||
float bestValue;
|
||||
TSubgoal bestGoal;
|
||||
VCAI * aip;
|
||||
CCallback * cbp;
|
||||
const TeamState * ts;
|
||||
int3 ourPos;
|
||||
bool allowDeadEndCancellation;
|
||||
bool allowGatherArmy;
|
||||
|
||||
ExplorationHelper(HeroPtr h, bool gatherArmy)
|
||||
{
|
||||
cbp = cb;
|
||||
aip = ai;
|
||||
hero = h;
|
||||
ts = cbp->getPlayerTeam(ai->playerID);
|
||||
sightRadius = hero->getSightRadius();
|
||||
bestGoal = sptr(Goals::Invalid());
|
||||
bestValue = 0;
|
||||
ourPos = h->visitablePos();
|
||||
allowDeadEndCancellation = true;
|
||||
allowGatherArmy = gatherArmy;
|
||||
}
|
||||
|
||||
void scanSector(int scanRadius)
|
||||
{
|
||||
int3 tile = int3(0, 0, ourPos.z);
|
||||
|
||||
const auto & slice = ts->fogOfWarMap[ourPos.z];
|
||||
|
||||
for(tile.x = ourPos.x - scanRadius; tile.x <= ourPos.x + scanRadius; tile.x++)
|
||||
{
|
||||
for(tile.y = ourPos.y - scanRadius; tile.y <= ourPos.y + scanRadius; tile.y++)
|
||||
{
|
||||
|
||||
if(cbp->isInTheMap(tile) && slice[tile.x][tile.y])
|
||||
{
|
||||
scanTile(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scanMap()
|
||||
{
|
||||
int3 mapSize = cbp->getMapSize();
|
||||
int perimeter = 2 * sightRadius * (mapSize.x + mapSize.y);
|
||||
|
||||
std::vector<int3> from;
|
||||
std::vector<int3> to;
|
||||
|
||||
from.reserve(perimeter);
|
||||
to.reserve(perimeter);
|
||||
|
||||
foreach_tile_pos([&](const int3 & pos)
|
||||
{
|
||||
if(ts->fogOfWarMap[pos.z][pos.x][pos.y])
|
||||
{
|
||||
bool hasInvisibleNeighbor = false;
|
||||
|
||||
foreach_neighbour(cbp, pos, [&](CCallback * cbp, int3 neighbour)
|
||||
{
|
||||
if(!ts->fogOfWarMap[neighbour.z][neighbour.x][neighbour.y])
|
||||
{
|
||||
hasInvisibleNeighbor = true;
|
||||
}
|
||||
});
|
||||
|
||||
if(hasInvisibleNeighbor)
|
||||
from.push_back(pos);
|
||||
}
|
||||
});
|
||||
|
||||
logAi->debug("Exploration scan visible area perimeter for hero %s", hero.name);
|
||||
|
||||
for(const int3 & tile : from)
|
||||
{
|
||||
scanTile(tile);
|
||||
}
|
||||
|
||||
if(!bestGoal->invalid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
allowDeadEndCancellation = false;
|
||||
|
||||
for(int i = 0; i < sightRadius; i++)
|
||||
{
|
||||
getVisibleNeighbours(from, to);
|
||||
vstd::concatenate(from, to);
|
||||
vstd::removeDuplicates(from);
|
||||
}
|
||||
|
||||
logAi->debug("Exploration scan all possible tiles for hero %s", hero.name);
|
||||
|
||||
for(const int3 & tile : from)
|
||||
{
|
||||
scanTile(tile);
|
||||
}
|
||||
}
|
||||
|
||||
void scanTile(const int3 & tile)
|
||||
{
|
||||
if(tile == ourPos
|
||||
|| !aip->ah->isTileAccessible(hero, tile)) //shouldn't happen, but it does
|
||||
return;
|
||||
|
||||
int tilesDiscovered = howManyTilesWillBeDiscovered(tile);
|
||||
if(!tilesDiscovered)
|
||||
return;
|
||||
|
||||
auto waysToVisit = aip->ah->howToVisitTile(hero, tile, allowGatherArmy);
|
||||
for(auto goal : waysToVisit)
|
||||
{
|
||||
if(goal->evaluationContext.movementCost <= 0.0) // should not happen
|
||||
continue;
|
||||
|
||||
float ourValue = (float)tilesDiscovered * tilesDiscovered / goal->evaluationContext.movementCost;
|
||||
|
||||
if(ourValue > bestValue) //avoid costly checks of tiles that don't reveal much
|
||||
{
|
||||
auto obj = cb->getTopObj(tile);
|
||||
|
||||
// picking up resources does not yield any exploration at all.
|
||||
// if it blocks the way to some explorable tile AIPathfinder will take care of it
|
||||
if(obj && obj->isBlockedVisitable())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(isSafeToVisit(hero, tile))
|
||||
{
|
||||
bestGoal = goal;
|
||||
bestValue = ourValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void getVisibleNeighbours(const std::vector<int3> & tiles, std::vector<int3> & out) const
|
||||
{
|
||||
for(const int3 & tile : tiles)
|
||||
{
|
||||
foreach_neighbour(cbp, tile, [&](CCallback * cbp, int3 neighbour)
|
||||
{
|
||||
if(ts->fogOfWarMap[neighbour.z][neighbour.x][neighbour.y])
|
||||
{
|
||||
out.push_back(neighbour);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
int howManyTilesWillBeDiscovered(const int3 & pos) const
|
||||
{
|
||||
int ret = 0;
|
||||
int3 npos = int3(0, 0, pos.z);
|
||||
|
||||
const auto & slice = ts->fogOfWarMap[pos.z];
|
||||
|
||||
for(npos.x = pos.x - sightRadius; npos.x <= pos.x + sightRadius; npos.x++)
|
||||
{
|
||||
for(npos.y = pos.y - sightRadius; npos.y <= pos.y + sightRadius; npos.y++)
|
||||
{
|
||||
if(cbp->isInTheMap(npos)
|
||||
&& pos.dist2d(npos) - 0.5 < sightRadius
|
||||
&& !slice[npos.x][npos.y])
|
||||
{
|
||||
if(allowDeadEndCancellation
|
||||
&& !hasReachableNeighbor(npos))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool hasReachableNeighbor(const int3 &pos) const
|
||||
{
|
||||
for(crint3 dir : int3::getDirs())
|
||||
{
|
||||
int3 tile = pos + dir;
|
||||
if(cbp->isInTheMap(tile))
|
||||
{
|
||||
auto isAccessible = aip->ah->isTileAccessible(hero, tile);
|
||||
|
||||
if(isAccessible)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bool Explore::operator==(const Explore & other) const
|
||||
{
|
||||
return other.hero.h == hero.h && other.allowGatherArmy == allowGatherArmy;
|
||||
}
|
||||
|
||||
std::string Explore::completeMessage() const
|
||||
{
|
||||
return "Hero " + hero.get()->getNameTranslated() + " completed exploration";
|
||||
}
|
||||
|
||||
TSubgoal Explore::whatToDoToAchieve()
|
||||
{
|
||||
return fh->chooseSolution(getAllPossibleSubgoals());
|
||||
}
|
||||
|
||||
TGoalVec Explore::getAllPossibleSubgoals()
|
||||
{
|
||||
TGoalVec ret;
|
||||
std::vector<const CGHeroInstance *> heroes;
|
||||
|
||||
if(hero)
|
||||
{
|
||||
heroes.push_back(hero.h);
|
||||
}
|
||||
else
|
||||
{
|
||||
//heroes = ai->getUnblockedHeroes();
|
||||
heroes = cb->getHeroesInfo();
|
||||
vstd::erase_if(heroes, [](const HeroPtr h)
|
||||
{
|
||||
if(ai->getGoal(h)->goalType == EXPLORE) //do not reassign hero who is already explorer
|
||||
return true;
|
||||
|
||||
if(!ai->isAbleToExplore(h))
|
||||
return true;
|
||||
|
||||
return !h->movementPointsRemaining(); //saves time, immobile heroes are useless anyway
|
||||
});
|
||||
}
|
||||
|
||||
//try to use buildings that uncover map
|
||||
std::vector<const CGObjectInstance *> objs;
|
||||
for(auto obj : ai->visitableObjs)
|
||||
{
|
||||
if(!vstd::contains(ai->alreadyVisited, obj))
|
||||
{
|
||||
switch(obj->ID.num)
|
||||
{
|
||||
case Obj::REDWOOD_OBSERVATORY:
|
||||
case Obj::PILLAR_OF_FIRE:
|
||||
case Obj::CARTOGRAPHER:
|
||||
objs.push_back(obj);
|
||||
break;
|
||||
case Obj::MONOLITH_ONE_WAY_ENTRANCE:
|
||||
case Obj::MONOLITH_TWO_WAY:
|
||||
case Obj::SUBTERRANEAN_GATE:
|
||||
auto tObj = dynamic_cast<const CGTeleport *>(obj);
|
||||
assert(ai->knownTeleportChannels.find(tObj->channel) != ai->knownTeleportChannels.end());
|
||||
if(TeleportChannel::IMPASSABLE != ai->knownTeleportChannels[tObj->channel]->passability)
|
||||
objs.push_back(obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(obj->ID.num)
|
||||
{
|
||||
case Obj::MONOLITH_TWO_WAY:
|
||||
case Obj::SUBTERRANEAN_GATE:
|
||||
auto tObj = dynamic_cast<const CGTeleport *>(obj);
|
||||
if(TeleportChannel::IMPASSABLE == ai->knownTeleportChannels[tObj->channel]->passability)
|
||||
break;
|
||||
for(auto exit : ai->knownTeleportChannels[tObj->channel]->exits)
|
||||
{
|
||||
if(!cb->getObj(exit))
|
||||
{ // Always attempt to visit two-way teleports if one of channel exits is not visible
|
||||
objs.push_back(obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(auto h : heroes)
|
||||
{
|
||||
for(auto obj : objs) //double loop, performance risk?
|
||||
{
|
||||
auto waysToVisitObj = ai->ah->howToVisitObj(h, obj, allowGatherArmy);
|
||||
|
||||
vstd::concatenate(ret, waysToVisitObj);
|
||||
}
|
||||
|
||||
TSubgoal goal = exploreNearestNeighbour(h);
|
||||
|
||||
if(!goal->invalid())
|
||||
{
|
||||
ret.push_back(goal);
|
||||
}
|
||||
}
|
||||
|
||||
if(ret.empty())
|
||||
{
|
||||
for(auto h : heroes)
|
||||
{
|
||||
logAi->trace("Exploration searching for a new point for hero %s", h->getNameTranslated());
|
||||
|
||||
TSubgoal goal = explorationNewPoint(h);
|
||||
|
||||
if(goal->invalid())
|
||||
{
|
||||
ai->markHeroUnableToExplore(h); //there is no freely accessible tile, do not poll this hero anymore
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.push_back(goal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//we either don't have hero yet or none of heroes can explore
|
||||
if((!hero || ret.empty()) && ai->canRecruitAnyHero())
|
||||
ret.push_back(sptr(RecruitHero()));
|
||||
|
||||
if(ret.empty())
|
||||
{
|
||||
throw goalFulfilledException(sptr(Explore().sethero(hero)));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Explore::fulfillsMe(TSubgoal goal)
|
||||
{
|
||||
if(goal->goalType == EXPLORE)
|
||||
{
|
||||
if(goal->hero)
|
||||
return hero == goal->hero;
|
||||
else
|
||||
return true; //cancel ALL exploration
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TSubgoal Explore::explorationBestNeighbour(int3 hpos, HeroPtr h) const
|
||||
{
|
||||
ExplorationHelper scanResult(h, allowGatherArmy);
|
||||
|
||||
for(crint3 dir : int3::getDirs())
|
||||
{
|
||||
int3 tile = hpos + dir;
|
||||
if(cb->isInTheMap(tile))
|
||||
{
|
||||
scanResult.scanTile(tile);
|
||||
}
|
||||
}
|
||||
|
||||
return scanResult.bestGoal;
|
||||
}
|
||||
|
||||
|
||||
TSubgoal Explore::explorationNewPoint(HeroPtr h) const
|
||||
{
|
||||
ExplorationHelper scanResult(h, allowGatherArmy);
|
||||
|
||||
scanResult.scanSector(10);
|
||||
|
||||
if(!scanResult.bestGoal->invalid())
|
||||
{
|
||||
return scanResult.bestGoal;
|
||||
}
|
||||
|
||||
scanResult.scanMap();
|
||||
|
||||
return scanResult.bestGoal;
|
||||
}
|
||||
|
||||
|
||||
TSubgoal Explore::exploreNearestNeighbour(HeroPtr h) const
|
||||
{
|
||||
TimeCheck tc("where to explore");
|
||||
int3 hpos = h->visitablePos();
|
||||
|
||||
//look for nearby objs -> visit them if they're close enough
|
||||
const int DIST_LIMIT = 3;
|
||||
const float COST_LIMIT = .2f; //todo: fine tune
|
||||
|
||||
std::vector<const CGObjectInstance *> nearbyVisitableObjs;
|
||||
for(int x = hpos.x - DIST_LIMIT; x <= hpos.x + DIST_LIMIT; ++x) //get only local objects instead of all possible objects on the map
|
||||
{
|
||||
for(int y = hpos.y - DIST_LIMIT; y <= hpos.y + DIST_LIMIT; ++y)
|
||||
{
|
||||
for(auto obj : cb->getVisitableObjs(int3(x, y, hpos.z), false))
|
||||
{
|
||||
if(ai->isGoodForVisit(obj, h, COST_LIMIT))
|
||||
{
|
||||
nearbyVisitableObjs.push_back(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(nearbyVisitableObjs.size())
|
||||
{
|
||||
vstd::removeDuplicates(nearbyVisitableObjs); //one object may occupy multiple tiles
|
||||
boost::sort(nearbyVisitableObjs, CDistanceSorter(h.get()));
|
||||
|
||||
TSubgoal pickupNearestObj = fh->chooseSolution(ai->ah->howToVisitObj(h, nearbyVisitableObjs.back(), false));
|
||||
|
||||
if(!pickupNearestObj->invalid())
|
||||
{
|
||||
return pickupNearestObj;
|
||||
}
|
||||
}
|
||||
|
||||
//check if nearby tiles allow us to reveal anything - this is quick
|
||||
return explorationBestNeighbour(hpos, h);
|
||||
}
|
||||
|
@@ -1,66 +1,66 @@
|
||||
/*
|
||||
* Explore.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
|
||||
|
||||
#include "CGoal.h"
|
||||
|
||||
struct HeroPtr;
|
||||
class VCAI;
|
||||
class FuzzyHelper;
|
||||
|
||||
namespace Goals
|
||||
{
|
||||
struct ExplorationHelper;
|
||||
|
||||
class DLL_EXPORT Explore : public CGoal<Explore>
|
||||
{
|
||||
private:
|
||||
bool allowGatherArmy;
|
||||
|
||||
public:
|
||||
Explore(bool allowGatherArmy)
|
||||
: CGoal(Goals::EXPLORE), allowGatherArmy(allowGatherArmy)
|
||||
{
|
||||
priority = 1;
|
||||
}
|
||||
|
||||
Explore()
|
||||
: Explore(true)
|
||||
{
|
||||
}
|
||||
|
||||
Explore(HeroPtr h)
|
||||
: CGoal(Goals::EXPLORE)
|
||||
{
|
||||
hero = h;
|
||||
priority = 1;
|
||||
}
|
||||
TGoalVec getAllPossibleSubgoals() override;
|
||||
TSubgoal whatToDoToAchieve() override;
|
||||
std::string completeMessage() const override;
|
||||
bool fulfillsMe(TSubgoal goal) override;
|
||||
bool operator==(const Explore & other) const override;
|
||||
|
||||
private:
|
||||
TSubgoal exploreNearestNeighbour(HeroPtr h) const;
|
||||
TSubgoal explorationNewPoint(HeroPtr h) const;
|
||||
TSubgoal explorationBestNeighbour(int3 hpos, HeroPtr h) const;
|
||||
void explorationScanTile(const int3 & tile, ExplorationHelper & scanResult) const;
|
||||
bool hasReachableneighbour(const int3 &pos, HeroPtr hero, CCallback * cbp, VCAI * vcai) const;
|
||||
|
||||
void getVisibleNeighbours(
|
||||
const std::vector<int3> & tiles,
|
||||
std::vector<int3> & out,
|
||||
CCallback * cbp,
|
||||
const TeamState * ts) const;
|
||||
|
||||
int howManyTilesWillBeDiscovered(const int3 & pos, ExplorationHelper & scanResult) const;
|
||||
};
|
||||
}
|
||||
/*
|
||||
* Explore.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
|
||||
|
||||
#include "CGoal.h"
|
||||
|
||||
struct HeroPtr;
|
||||
class VCAI;
|
||||
class FuzzyHelper;
|
||||
|
||||
namespace Goals
|
||||
{
|
||||
struct ExplorationHelper;
|
||||
|
||||
class DLL_EXPORT Explore : public CGoal<Explore>
|
||||
{
|
||||
private:
|
||||
bool allowGatherArmy;
|
||||
|
||||
public:
|
||||
Explore(bool allowGatherArmy)
|
||||
: CGoal(Goals::EXPLORE), allowGatherArmy(allowGatherArmy)
|
||||
{
|
||||
priority = 1;
|
||||
}
|
||||
|
||||
Explore()
|
||||
: Explore(true)
|
||||
{
|
||||
}
|
||||
|
||||
Explore(HeroPtr h)
|
||||
: CGoal(Goals::EXPLORE)
|
||||
{
|
||||
hero = h;
|
||||
priority = 1;
|
||||
}
|
||||
TGoalVec getAllPossibleSubgoals() override;
|
||||
TSubgoal whatToDoToAchieve() override;
|
||||
std::string completeMessage() const override;
|
||||
bool fulfillsMe(TSubgoal goal) override;
|
||||
bool operator==(const Explore & other) const override;
|
||||
|
||||
private:
|
||||
TSubgoal exploreNearestNeighbour(HeroPtr h) const;
|
||||
TSubgoal explorationNewPoint(HeroPtr h) const;
|
||||
TSubgoal explorationBestNeighbour(int3 hpos, HeroPtr h) const;
|
||||
void explorationScanTile(const int3 & tile, ExplorationHelper & scanResult) const;
|
||||
bool hasReachableNeighbor(const int3 &pos, HeroPtr hero, CCallback * cbp, VCAI * vcai) const;
|
||||
|
||||
void getVisibleNeighbours(
|
||||
const std::vector<int3> & tiles,
|
||||
std::vector<int3> & out,
|
||||
CCallback * cbp,
|
||||
const TeamState * ts) const;
|
||||
|
||||
int howManyTilesWillBeDiscovered(const int3 & pos, ExplorationHelper & scanResult) const;
|
||||
};
|
||||
}
|
||||
|
@@ -819,6 +819,9 @@ BattleHex BattleFieldController::fromWhichHexAttack(BattleHex attackTarget)
|
||||
|
||||
bool BattleFieldController::isTileAttackable(const BattleHex & number) const
|
||||
{
|
||||
if(!number.isValid())
|
||||
return false;
|
||||
|
||||
for (auto & elem : occupiableHexes)
|
||||
{
|
||||
if (BattleHex::mutualPosition(elem, number) != -1 || elem == number)
|
||||
|
@@ -1,141 +1,141 @@
|
||||
/*
|
||||
* BattleFieldController.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
|
||||
|
||||
#include "../../lib/battle/BattleHexArray.h"
|
||||
#include "../../lib/Point.h"
|
||||
#include "../gui/CIntObject.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class CStack;
|
||||
class Rect;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class BattleHero;
|
||||
class CAnimation;
|
||||
class Canvas;
|
||||
class IImage;
|
||||
class BattleInterface;
|
||||
|
||||
/// Handles battlefield grid as well as rendering of background layer of battle interface
|
||||
class BattleFieldController : public CIntObject
|
||||
{
|
||||
BattleInterface & owner;
|
||||
|
||||
std::shared_ptr<IImage> background;
|
||||
std::shared_ptr<IImage> cellBorder;
|
||||
std::shared_ptr<IImage> cellUnitMovementHighlight;
|
||||
std::shared_ptr<IImage> cellUnitMaxMovementHighlight;
|
||||
std::shared_ptr<IImage> cellShade;
|
||||
std::shared_ptr<CAnimation> rangedFullDamageLimitImages;
|
||||
std::shared_ptr<CAnimation> shootingRangeLimitImages;
|
||||
|
||||
std::shared_ptr<CAnimation> attackCursors;
|
||||
std::shared_ptr<CAnimation> spellCursors;
|
||||
|
||||
/// Canvas that contains background, hex grid (if enabled), absolute obstacles and movement range of active stack
|
||||
std::unique_ptr<Canvas> backgroundWithHexes;
|
||||
|
||||
/// direction which will be used to perform attack with current cursor position
|
||||
Point currentAttackOriginPoint;
|
||||
|
||||
/// hex currently under mouse hover
|
||||
BattleHex hoveredHex;
|
||||
|
||||
/// hexes to which currently active stack can move
|
||||
BattleHexArray occupiableHexes;
|
||||
|
||||
/// hexes that when in front of a unit cause it's amount box to move back
|
||||
std::array<bool, GameConstants::BFIELD_SIZE> stackCountOutsideHexes;
|
||||
|
||||
void showHighlightedHex(Canvas & to, std::shared_ptr<IImage> highlight, BattleHex hex, bool darkBorder);
|
||||
|
||||
BattleHexArray getHighlightedHexesForActiveStack();
|
||||
BattleHexArray getMovementRangeForHoveredStack();
|
||||
BattleHexArray getHighlightedHexesForSpellRange();
|
||||
BattleHexArray getHighlightedHexesForMovementTarget();
|
||||
|
||||
// Range limit highlight helpers
|
||||
|
||||
/// get all hexes within a certain distance of given hex
|
||||
BattleHexArray getRangeHexes(BattleHex sourceHex, uint8_t distance);
|
||||
|
||||
/// get only hexes at the limit of a range
|
||||
BattleHexArray getRangeLimitHexes(BattleHex hoveredHex, BattleHexArray hexRange, uint8_t distanceToLimit);
|
||||
|
||||
/// calculate if a hex is in range limit and return its index in range
|
||||
bool IsHexInRangeLimit(BattleHex hex, BattleHexArray & rangeLimitHexes, int * hexIndexInRangeLimit);
|
||||
|
||||
/// get an array that has for each hex in range, an array with all directions where an outside neighbour hex exists
|
||||
std::vector<std::vector<BattleHex::EDir>> getOutsideNeighbourDirectionsForLimitHexes(BattleHexArray rangeHexes, BattleHexArray rangeLimitHexes);
|
||||
|
||||
/// calculates what image to use as range limit, depending on the direction of neighbours
|
||||
/// a mask is used internally to mark the directions of all neighbours
|
||||
/// based on this mask the corresponding image is selected
|
||||
std::vector<std::shared_ptr<IImage>> calculateRangeLimitHighlightImages(std::vector<std::vector<BattleHex::EDir>> hexesNeighbourDirections, std::shared_ptr<CAnimation> limitImages);
|
||||
|
||||
/// calculates all hexes for a range limit and what images to be shown as highlight for each of the hexes
|
||||
void calculateRangeLimitAndHighlightImages(uint8_t distance, std::shared_ptr<CAnimation> rangeLimitImages, BattleHexArray & rangeLimitHexes, std::vector<std::shared_ptr<IImage>> & rangeLimitHexesHighlights);
|
||||
|
||||
void showBackground(Canvas & canvas);
|
||||
void showBackgroundImage(Canvas & canvas);
|
||||
void showBackgroundImageWithHexes(Canvas & canvas);
|
||||
void showHighlightedHexes(Canvas & canvas);
|
||||
void updateAccessibleHexes();
|
||||
|
||||
BattleHex getHexAtPosition(Point hoverPosition);
|
||||
|
||||
/// Checks whether selected pixel is transparent, uses local coordinates of a hex
|
||||
bool isPixelInHex(Point const & position);
|
||||
size_t selectBattleCursor(BattleHex myNumber);
|
||||
|
||||
void gesture(bool on, const Point & initialPosition, const Point & finalPosition) override;
|
||||
void gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) override;
|
||||
void mouseMoved(const Point & cursorPosition, const Point & lastUpdateDistance) override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void activate() override;
|
||||
|
||||
void showAll(Canvas & to) override;
|
||||
void show(Canvas & to) override;
|
||||
void tick(uint32_t msPassed) override;
|
||||
|
||||
bool receiveEvent(const Point & position, int eventType) const override;
|
||||
|
||||
public:
|
||||
BattleFieldController(BattleInterface & owner);
|
||||
|
||||
void createHeroes();
|
||||
|
||||
void redrawBackgroundWithHexes();
|
||||
void renderBattlefield(Canvas & canvas);
|
||||
|
||||
/// Returns position of hex relative to owner (BattleInterface)
|
||||
Rect hexPositionLocal(BattleHex hex) const;
|
||||
|
||||
/// Returns position of hex relative to game window
|
||||
Rect hexPositionAbsolute(BattleHex hex) const;
|
||||
|
||||
/// Returns ID of currently hovered hex or BattleHex::INVALID if none
|
||||
BattleHex getHoveredHex();
|
||||
|
||||
/// Returns the currently hovered stack
|
||||
const CStack* getHoveredStack();
|
||||
|
||||
/// returns true if selected tile can be attacked in melee by current stack
|
||||
bool isTileAttackable(const BattleHex & number) const;
|
||||
|
||||
/// returns true if stack should render its stack count image in default position - outside own hex
|
||||
bool stackCountOutsideHex(const BattleHex & number) const;
|
||||
|
||||
BattleHex::EDir selectAttackDirection(BattleHex myNumber);
|
||||
|
||||
BattleHex fromWhichHexAttack(BattleHex myNumber);
|
||||
};
|
||||
/*
|
||||
* BattleFieldController.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
|
||||
|
||||
#include "../../lib/battle/BattleHexArray.h"
|
||||
#include "../../lib/Point.h"
|
||||
#include "../gui/CIntObject.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class CStack;
|
||||
class Rect;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class BattleHero;
|
||||
class CAnimation;
|
||||
class Canvas;
|
||||
class IImage;
|
||||
class BattleInterface;
|
||||
|
||||
/// Handles battlefield grid as well as rendering of background layer of battle interface
|
||||
class BattleFieldController : public CIntObject
|
||||
{
|
||||
BattleInterface & owner;
|
||||
|
||||
std::shared_ptr<IImage> background;
|
||||
std::shared_ptr<IImage> cellBorder;
|
||||
std::shared_ptr<IImage> cellUnitMovementHighlight;
|
||||
std::shared_ptr<IImage> cellUnitMaxMovementHighlight;
|
||||
std::shared_ptr<IImage> cellShade;
|
||||
std::shared_ptr<CAnimation> rangedFullDamageLimitImages;
|
||||
std::shared_ptr<CAnimation> shootingRangeLimitImages;
|
||||
|
||||
std::shared_ptr<CAnimation> attackCursors;
|
||||
std::shared_ptr<CAnimation> spellCursors;
|
||||
|
||||
/// Canvas that contains background, hex grid (if enabled), absolute obstacles and movement range of active stack
|
||||
std::unique_ptr<Canvas> backgroundWithHexes;
|
||||
|
||||
/// direction which will be used to perform attack with current cursor position
|
||||
Point currentAttackOriginPoint;
|
||||
|
||||
/// hex currently under mouse hover
|
||||
BattleHex hoveredHex;
|
||||
|
||||
/// hexes to which currently active stack can move
|
||||
BattleHexArray occupiableHexes;
|
||||
|
||||
/// hexes that when in front of a unit cause it's amount box to move back
|
||||
std::array<bool, GameConstants::BFIELD_SIZE> stackCountOutsideHexes;
|
||||
|
||||
void showHighlightedHex(Canvas & to, std::shared_ptr<IImage> highlight, BattleHex hex, bool darkBorder);
|
||||
|
||||
BattleHexArray getHighlightedHexesForActiveStack();
|
||||
BattleHexArray getMovementRangeForHoveredStack();
|
||||
BattleHexArray getHighlightedHexesForSpellRange();
|
||||
BattleHexArray getHighlightedHexesForMovementTarget();
|
||||
|
||||
// Range limit highlight helpers
|
||||
|
||||
/// get all hexes within a certain distance of given hex
|
||||
BattleHexArray getRangeHexes(BattleHex sourceHex, uint8_t distance);
|
||||
|
||||
/// get only hexes at the limit of a range
|
||||
BattleHexArray getRangeLimitHexes(BattleHex hoveredHex, BattleHexArray hexRange, uint8_t distanceToLimit);
|
||||
|
||||
/// calculate if a hex is in range limit and return its index in range
|
||||
bool IsHexInRangeLimit(BattleHex hex, BattleHexArray & rangeLimitHexes, int * hexIndexInRangeLimit);
|
||||
|
||||
/// get an array that has for each hex in range, an array with all directions where an outside neighbour hex exists
|
||||
std::vector<std::vector<BattleHex::EDir>> getOutsideNeighbourDirectionsForLimitHexes(BattleHexArray rangeHexes, BattleHexArray rangeLimitHexes);
|
||||
|
||||
/// calculates what image to use as range limit, depending on the direction of neighbours
|
||||
/// a mask is used internally to mark the directions of all neighbours
|
||||
/// based on this mask the corresponding image is selected
|
||||
std::vector<std::shared_ptr<IImage>> calculateRangeLimitHighlightImages(std::vector<std::vector<BattleHex::EDir>> hexesNeighbourDirections, std::shared_ptr<CAnimation> limitImages);
|
||||
|
||||
/// calculates all hexes for a range limit and what images to be shown as highlight for each of the hexes
|
||||
void calculateRangeLimitAndHighlightImages(uint8_t distance, std::shared_ptr<CAnimation> rangeLimitImages, BattleHexArray & rangeLimitHexes, std::vector<std::shared_ptr<IImage>> & rangeLimitHexesHighlights);
|
||||
|
||||
void showBackground(Canvas & canvas);
|
||||
void showBackgroundImage(Canvas & canvas);
|
||||
void showBackgroundImageWithHexes(Canvas & canvas);
|
||||
void showHighlightedHexes(Canvas & canvas);
|
||||
void updateAccessibleHexes();
|
||||
|
||||
BattleHex getHexAtPosition(Point hoverPosition);
|
||||
|
||||
/// Checks whether selected pixel is transparent, uses local coordinates of a hex
|
||||
bool isPixelInHex(Point const & position);
|
||||
size_t selectBattleCursor(BattleHex myNumber);
|
||||
|
||||
void gesture(bool on, const Point & initialPosition, const Point & finalPosition) override;
|
||||
void gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) override;
|
||||
void mouseMoved(const Point & cursorPosition, const Point & lastUpdateDistance) override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void activate() override;
|
||||
|
||||
void showAll(Canvas & to) override;
|
||||
void show(Canvas & to) override;
|
||||
void tick(uint32_t msPassed) override;
|
||||
|
||||
bool receiveEvent(const Point & position, int eventType) const override;
|
||||
|
||||
public:
|
||||
BattleFieldController(BattleInterface & owner);
|
||||
|
||||
void createHeroes();
|
||||
|
||||
void redrawBackgroundWithHexes();
|
||||
void renderBattlefield(Canvas & canvas);
|
||||
|
||||
/// Returns position of hex relative to owner (BattleInterface)
|
||||
Rect hexPositionLocal(BattleHex hex) const;
|
||||
|
||||
/// Returns position of hex relative to game window
|
||||
Rect hexPositionAbsolute(BattleHex hex) const;
|
||||
|
||||
/// Returns ID of currently hovered hex or BattleHex::INVALID if none
|
||||
BattleHex getHoveredHex();
|
||||
|
||||
/// Returns the currently hovered stack
|
||||
const CStack* getHoveredStack();
|
||||
|
||||
/// returns true if selected tile can be attacked in melee by current stack
|
||||
bool isTileAttackable(const BattleHex & number) const;
|
||||
|
||||
/// returns true if stack should render its stack count image in default position - outside own hex
|
||||
bool stackCountOutsideHex(const BattleHex & number) const;
|
||||
|
||||
BattleHex::EDir selectAttackDirection(BattleHex myNumber);
|
||||
|
||||
BattleHex fromWhichHexAttack(BattleHex myNumber);
|
||||
};
|
||||
|
@@ -1,232 +1,232 @@
|
||||
/*
|
||||
* BattleInterface.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
|
||||
|
||||
#include "BattleConstants.h"
|
||||
#include "../gui/CIntObject.h"
|
||||
#include "../../lib/spells/CSpellHandler.h" //CSpell::TAnimation
|
||||
#include "../ConditionalWait.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CCreatureSet;
|
||||
class CGHeroInstance;
|
||||
class CStack;
|
||||
struct BattleResult;
|
||||
struct BattleSpellCast;
|
||||
struct CObstacleInstance;
|
||||
struct SetStackEffect;
|
||||
class BattleAction;
|
||||
class CGTownInstance;
|
||||
struct CatapultAttack;
|
||||
struct BattleTriggerEffect;
|
||||
struct BattleHex;
|
||||
struct InfoAboutHero;
|
||||
class ObstacleChanges;
|
||||
class CPlayerBattleCallback;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class BattleHero;
|
||||
class Canvas;
|
||||
class BattleResultWindow;
|
||||
class StackQueue;
|
||||
class CPlayerInterface;
|
||||
struct BattleEffect;
|
||||
class IImage;
|
||||
class StackQueue;
|
||||
|
||||
class BattleProjectileController;
|
||||
class BattleSiegeController;
|
||||
class BattleObstacleController;
|
||||
class BattleFieldController;
|
||||
class BattleRenderer;
|
||||
class BattleWindow;
|
||||
class BattleStacksController;
|
||||
class BattleActionsController;
|
||||
class BattleEffectsController;
|
||||
class BattleConsole;
|
||||
|
||||
/// Small struct which contains information about the id of the attacked stack, the damage dealt,...
|
||||
struct StackAttackedInfo
|
||||
{
|
||||
const CStack *defender;
|
||||
const CStack *attacker;
|
||||
|
||||
int64_t damageDealt;
|
||||
uint32_t amountKilled;
|
||||
SpellID spellEffect;
|
||||
|
||||
bool indirectAttack; //if true, stack was attacked indirectly - spell or ranged attack
|
||||
bool killed; //if true, stack has been killed
|
||||
bool rebirth; //if true, play rebirth animation after all
|
||||
bool cloneKilled;
|
||||
bool fireShield;
|
||||
};
|
||||
|
||||
struct StackAttackInfo
|
||||
{
|
||||
const CStack *attacker;
|
||||
const CStack *defender;
|
||||
std::vector< const CStack *> secondaryDefender;
|
||||
|
||||
SpellID spellEffect;
|
||||
BattleHex tile;
|
||||
|
||||
bool indirectAttack;
|
||||
bool lucky;
|
||||
bool unlucky;
|
||||
bool deathBlow;
|
||||
bool lifeDrain;
|
||||
};
|
||||
|
||||
/// Main class for battles, responsible for relaying information from server to various battle entities
|
||||
class BattleInterface
|
||||
{
|
||||
using AwaitingAnimationAction = std::function<void()>;
|
||||
|
||||
struct AwaitingAnimationEvents {
|
||||
AwaitingAnimationAction action;
|
||||
EAnimationEvents event;
|
||||
};
|
||||
|
||||
/// Conditional variables that are set depending on ongoing animations on the battlefield
|
||||
ConditionalWait ongoingAnimationsState;
|
||||
|
||||
/// List of events that are waiting to be triggered
|
||||
std::vector<AwaitingAnimationEvents> awaitingEvents;
|
||||
|
||||
/// used during tactics mode, points to the interface of player with higher tactics (can be either attacker or defender in hot-seat), valid onloy for human players
|
||||
std::shared_ptr<CPlayerInterface> tacticianInterface;
|
||||
|
||||
/// attacker interface, not null if attacker is human in our vcmiclient
|
||||
std::shared_ptr<CPlayerInterface> attackerInt;
|
||||
|
||||
/// defender interface, not null if attacker is human in our vcmiclient
|
||||
std::shared_ptr<CPlayerInterface> defenderInt;
|
||||
|
||||
/// if set to true, battle is still starting and waiting for intro sound to end / key press from player
|
||||
bool battleOpeningDelayActive;
|
||||
|
||||
/// ID of ongoing battle
|
||||
BattleID battleID;
|
||||
|
||||
void playIntroSoundAndUnlockInterface();
|
||||
void onIntroSoundPlayed();
|
||||
public:
|
||||
/// copy of initial armies (for result window)
|
||||
const CCreatureSet *army1;
|
||||
const CCreatureSet *army2;
|
||||
|
||||
std::shared_ptr<BattleWindow> windowObject;
|
||||
std::shared_ptr<BattleConsole> console;
|
||||
|
||||
/// currently active player interface
|
||||
std::shared_ptr<CPlayerInterface> curInt;
|
||||
|
||||
const CGHeroInstance *attackingHeroInstance;
|
||||
const CGHeroInstance *defendingHeroInstance;
|
||||
|
||||
bool tacticsMode;
|
||||
ui32 round;
|
||||
|
||||
std::unique_ptr<BattleProjectileController> projectilesController;
|
||||
std::unique_ptr<BattleSiegeController> siegeController;
|
||||
std::unique_ptr<BattleObstacleController> obstacleController;
|
||||
std::unique_ptr<BattleFieldController> fieldController;
|
||||
std::unique_ptr<BattleStacksController> stacksController;
|
||||
std::unique_ptr<BattleActionsController> actionsController;
|
||||
std::unique_ptr<BattleEffectsController> effectsController;
|
||||
|
||||
std::shared_ptr<BattleHero> attackingHero;
|
||||
std::shared_ptr<BattleHero> defendingHero;
|
||||
|
||||
bool openingPlaying() const;
|
||||
void openingEnd();
|
||||
|
||||
bool makingTurn() const;
|
||||
|
||||
BattleID getBattleID() const;
|
||||
std::shared_ptr<CPlayerBattleCallback> getBattle() const;
|
||||
|
||||
BattleInterface(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, const CGHeroInstance *hero1, const CGHeroInstance *hero2, std::shared_ptr<CPlayerInterface> att, std::shared_ptr<CPlayerInterface> defen, std::shared_ptr<CPlayerInterface> spectatorInt = nullptr);
|
||||
~BattleInterface();
|
||||
|
||||
void trySetActivePlayer( PlayerColor player ); // if in hotseat, will activate interface of chosen player
|
||||
void activateStack(); //sets activeStack to stackToActivate etc. //FIXME: No, it's not clear at all
|
||||
void requestAutofightingAIToTakeAction();
|
||||
|
||||
void giveCommand(EActionType action, BattleHex tile = BattleHex(), SpellID spell = SpellID::NONE);
|
||||
void sendCommand(BattleAction command, const CStack * actor = nullptr);
|
||||
|
||||
const CGHeroInstance *getActiveHero(); //returns hero that can currently cast a spell
|
||||
|
||||
void showInterface(Canvas & to);
|
||||
|
||||
void setHeroAnimation(BattleSide side, EHeroAnimType phase);
|
||||
|
||||
void executeSpellCast(); //called when a hero casts a spell
|
||||
|
||||
void appendBattleLog(const std::string & newEntry);
|
||||
|
||||
void redrawBattlefield(); //refresh GUI after changing stack range / grid settings
|
||||
CPlayerInterface *getCurrentPlayerInterface() const;
|
||||
|
||||
void tacticNextStack(const CStack *current);
|
||||
void tacticPhaseEnd();
|
||||
|
||||
void setBattleQueueVisibility(bool visible);
|
||||
void setStickyHeroWindowsVisibility(bool visible);
|
||||
void setStickyQuickSpellWindowVisibility(bool visible);
|
||||
|
||||
void endNetwork();
|
||||
void executeStagedAnimations();
|
||||
void executeAnimationStage( EAnimationEvents event);
|
||||
void onAnimationsStarted();
|
||||
void onAnimationsFinished();
|
||||
void waitForAnimations();
|
||||
bool hasAnimations();
|
||||
void checkForAnimations();
|
||||
void addToAnimationStage( EAnimationEvents event, const AwaitingAnimationAction & action);
|
||||
|
||||
//call-ins
|
||||
void startAction(const BattleAction & action);
|
||||
void stackReset(const CStack * stack);
|
||||
void stackAdded(const CStack * stack); //new stack appeared on battlefield
|
||||
void stackRemoved(uint32_t stackID); //stack disappeared from batlefiled
|
||||
void stackActivated(const CStack *stack); //active stack has been changed
|
||||
void stackMoved(const CStack *stack, const BattleHexArray & destHex, int distance, bool teleport); //stack with id number moved to destHex
|
||||
void stacksAreAttacked(std::vector<StackAttackedInfo> attackedInfos); //called when a certain amount of stacks has been attacked
|
||||
void stackAttacking(const StackAttackInfo & attackInfo); //called when stack with id ID is attacking something on hex dest
|
||||
void newRoundFirst();
|
||||
void newRound(); //called when round is ended;
|
||||
void stackIsCatapulting(const CatapultAttack & ca); //called when a stack is attacking walls
|
||||
void battleFinished(const BattleResult& br, QueryID queryID); //called when battle is finished - battleresult window should be printed
|
||||
void spellCast(const BattleSpellCast *sc); //called when a hero casts a spell
|
||||
void battleStacksEffectsSet(const SetStackEffect & sse); //called when a specific effect is set to stacks
|
||||
void castThisSpell(SpellID spellID); //called when player has chosen a spell from spellbook
|
||||
|
||||
void displayBattleLog(const std::vector<MetaString> & battleLog);
|
||||
|
||||
void displaySpellAnimationQueue(const CSpell * spell, const CSpell::TAnimationQueue & q, BattleHex destinationTile, bool isHit);
|
||||
void displaySpellCast(const CSpell * spell, BattleHex destinationTile); //displays spell`s cast 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 endAction(const BattleAction & action);
|
||||
|
||||
void obstaclePlaced(const std::vector<std::shared_ptr<const CObstacleInstance>> oi);
|
||||
void obstacleRemoved(const std::vector<ObstacleChanges> & obstacles);
|
||||
|
||||
void gateStateChanged(const EGateState state);
|
||||
|
||||
const CGHeroInstance *currentHero() const;
|
||||
InfoAboutHero enemyHero() const;
|
||||
};
|
||||
/*
|
||||
* BattleInterface.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
|
||||
|
||||
#include "BattleConstants.h"
|
||||
#include "../gui/CIntObject.h"
|
||||
#include "../../lib/spells/CSpellHandler.h" //CSpell::TAnimation
|
||||
#include "../ConditionalWait.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CCreatureSet;
|
||||
class CGHeroInstance;
|
||||
class CStack;
|
||||
struct BattleResult;
|
||||
struct BattleSpellCast;
|
||||
struct CObstacleInstance;
|
||||
struct SetStackEffect;
|
||||
class BattleAction;
|
||||
class CGTownInstance;
|
||||
struct CatapultAttack;
|
||||
struct BattleTriggerEffect;
|
||||
struct BattleHex;
|
||||
struct InfoAboutHero;
|
||||
class ObstacleChanges;
|
||||
class CPlayerBattleCallback;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class BattleHero;
|
||||
class Canvas;
|
||||
class BattleResultWindow;
|
||||
class StackQueue;
|
||||
class CPlayerInterface;
|
||||
struct BattleEffect;
|
||||
class IImage;
|
||||
class StackQueue;
|
||||
|
||||
class BattleProjectileController;
|
||||
class BattleSiegeController;
|
||||
class BattleObstacleController;
|
||||
class BattleFieldController;
|
||||
class BattleRenderer;
|
||||
class BattleWindow;
|
||||
class BattleStacksController;
|
||||
class BattleActionsController;
|
||||
class BattleEffectsController;
|
||||
class BattleConsole;
|
||||
|
||||
/// Small struct which contains information about the id of the attacked stack, the damage dealt,...
|
||||
struct StackAttackedInfo
|
||||
{
|
||||
const CStack *defender;
|
||||
const CStack *attacker;
|
||||
|
||||
int64_t damageDealt;
|
||||
uint32_t amountKilled;
|
||||
SpellID spellEffect;
|
||||
|
||||
bool indirectAttack; //if true, stack was attacked indirectly - spell or ranged attack
|
||||
bool killed; //if true, stack has been killed
|
||||
bool rebirth; //if true, play rebirth animation after all
|
||||
bool cloneKilled;
|
||||
bool fireShield;
|
||||
};
|
||||
|
||||
struct StackAttackInfo
|
||||
{
|
||||
const CStack *attacker;
|
||||
const CStack *defender;
|
||||
std::vector< const CStack *> secondaryDefender;
|
||||
|
||||
SpellID spellEffect;
|
||||
BattleHex tile;
|
||||
|
||||
bool indirectAttack;
|
||||
bool lucky;
|
||||
bool unlucky;
|
||||
bool deathBlow;
|
||||
bool lifeDrain;
|
||||
};
|
||||
|
||||
/// Main class for battles, responsible for relaying information from server to various battle entities
|
||||
class BattleInterface
|
||||
{
|
||||
using AwaitingAnimationAction = std::function<void()>;
|
||||
|
||||
struct AwaitingAnimationEvents {
|
||||
AwaitingAnimationAction action;
|
||||
EAnimationEvents event;
|
||||
};
|
||||
|
||||
/// Conditional variables that are set depending on ongoing animations on the battlefield
|
||||
ConditionalWait ongoingAnimationsState;
|
||||
|
||||
/// List of events that are waiting to be triggered
|
||||
std::vector<AwaitingAnimationEvents> awaitingEvents;
|
||||
|
||||
/// used during tactics mode, points to the interface of player with higher tactics (can be either attacker or defender in hot-seat), valid onloy for human players
|
||||
std::shared_ptr<CPlayerInterface> tacticianInterface;
|
||||
|
||||
/// attacker interface, not null if attacker is human in our vcmiclient
|
||||
std::shared_ptr<CPlayerInterface> attackerInt;
|
||||
|
||||
/// defender interface, not null if attacker is human in our vcmiclient
|
||||
std::shared_ptr<CPlayerInterface> defenderInt;
|
||||
|
||||
/// if set to true, battle is still starting and waiting for intro sound to end / key press from player
|
||||
bool battleOpeningDelayActive;
|
||||
|
||||
/// ID of ongoing battle
|
||||
BattleID battleID;
|
||||
|
||||
void playIntroSoundAndUnlockInterface();
|
||||
void onIntroSoundPlayed();
|
||||
public:
|
||||
/// copy of initial armies (for result window)
|
||||
const CCreatureSet *army1;
|
||||
const CCreatureSet *army2;
|
||||
|
||||
std::shared_ptr<BattleWindow> windowObject;
|
||||
std::shared_ptr<BattleConsole> console;
|
||||
|
||||
/// currently active player interface
|
||||
std::shared_ptr<CPlayerInterface> curInt;
|
||||
|
||||
const CGHeroInstance *attackingHeroInstance;
|
||||
const CGHeroInstance *defendingHeroInstance;
|
||||
|
||||
bool tacticsMode;
|
||||
ui32 round;
|
||||
|
||||
std::unique_ptr<BattleProjectileController> projectilesController;
|
||||
std::unique_ptr<BattleSiegeController> siegeController;
|
||||
std::unique_ptr<BattleObstacleController> obstacleController;
|
||||
std::unique_ptr<BattleFieldController> fieldController;
|
||||
std::unique_ptr<BattleStacksController> stacksController;
|
||||
std::unique_ptr<BattleActionsController> actionsController;
|
||||
std::unique_ptr<BattleEffectsController> effectsController;
|
||||
|
||||
std::shared_ptr<BattleHero> attackingHero;
|
||||
std::shared_ptr<BattleHero> defendingHero;
|
||||
|
||||
bool openingPlaying() const;
|
||||
void openingEnd();
|
||||
|
||||
bool makingTurn() const;
|
||||
|
||||
BattleID getBattleID() const;
|
||||
std::shared_ptr<CPlayerBattleCallback> getBattle() const;
|
||||
|
||||
BattleInterface(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, const CGHeroInstance *hero1, const CGHeroInstance *hero2, std::shared_ptr<CPlayerInterface> att, std::shared_ptr<CPlayerInterface> defen, std::shared_ptr<CPlayerInterface> spectatorInt = nullptr);
|
||||
~BattleInterface();
|
||||
|
||||
void trySetActivePlayer( PlayerColor player ); // if in hotseat, will activate interface of chosen player
|
||||
void activateStack(); //sets activeStack to stackToActivate etc. //FIXME: No, it's not clear at all
|
||||
void requestAutofightingAIToTakeAction();
|
||||
|
||||
void giveCommand(EActionType action, BattleHex tile = BattleHex(), SpellID spell = SpellID::NONE);
|
||||
void sendCommand(BattleAction command, const CStack * actor = nullptr);
|
||||
|
||||
const CGHeroInstance *getActiveHero(); //returns hero that can currently cast a spell
|
||||
|
||||
void showInterface(Canvas & to);
|
||||
|
||||
void setHeroAnimation(BattleSide side, EHeroAnimType phase);
|
||||
|
||||
void executeSpellCast(); //called when a hero casts a spell
|
||||
|
||||
void appendBattleLog(const std::string & newEntry);
|
||||
|
||||
void redrawBattlefield(); //refresh GUI after changing stack range / grid settings
|
||||
CPlayerInterface *getCurrentPlayerInterface() const;
|
||||
|
||||
void tacticNextStack(const CStack *current);
|
||||
void tacticPhaseEnd();
|
||||
|
||||
void setBattleQueueVisibility(bool visible);
|
||||
void setStickyHeroWindowsVisibility(bool visible);
|
||||
void setStickyQuickSpellWindowVisibility(bool visible);
|
||||
|
||||
void endNetwork();
|
||||
void executeStagedAnimations();
|
||||
void executeAnimationStage( EAnimationEvents event);
|
||||
void onAnimationsStarted();
|
||||
void onAnimationsFinished();
|
||||
void waitForAnimations();
|
||||
bool hasAnimations();
|
||||
void checkForAnimations();
|
||||
void addToAnimationStage( EAnimationEvents event, const AwaitingAnimationAction & action);
|
||||
|
||||
//call-ins
|
||||
void startAction(const BattleAction & action);
|
||||
void stackReset(const CStack * stack);
|
||||
void stackAdded(const CStack * stack); //new stack appeared on battlefield
|
||||
void stackRemoved(uint32_t stackID); //stack disappeared from batlefiled
|
||||
void stackActivated(const CStack *stack); //active stack has been changed
|
||||
void stackMoved(const CStack *stack, const BattleHexArray & destHex, int distance, bool teleport); //stack with id number moved to destHex
|
||||
void stacksAreAttacked(std::vector<StackAttackedInfo> attackedInfos); //called when a certain amount of stacks has been attacked
|
||||
void stackAttacking(const StackAttackInfo & attackInfo); //called when stack with id ID is attacking something on hex dest
|
||||
void newRoundFirst();
|
||||
void newRound(); //called when round is ended;
|
||||
void stackIsCatapulting(const CatapultAttack & ca); //called when a stack is attacking walls
|
||||
void battleFinished(const BattleResult& br, QueryID queryID); //called when battle is finished - battleresult window should be printed
|
||||
void spellCast(const BattleSpellCast *sc); //called when a hero casts a spell
|
||||
void battleStacksEffectsSet(const SetStackEffect & sse); //called when a specific effect is set to stacks
|
||||
void castThisSpell(SpellID spellID); //called when player has chosen a spell from spellbook
|
||||
|
||||
void displayBattleLog(const std::vector<MetaString> & battleLog);
|
||||
|
||||
void displaySpellAnimationQueue(const CSpell * spell, const CSpell::TAnimationQueue & q, BattleHex destinationTile, bool isHit);
|
||||
void displaySpellCast(const CSpell * spell, BattleHex destinationTile); //displays spell`s cast 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 endAction(const BattleAction & action);
|
||||
|
||||
void obstaclePlaced(const std::vector<std::shared_ptr<const CObstacleInstance>> oi);
|
||||
void obstacleRemoved(const std::vector<ObstacleChanges> & obstacles);
|
||||
|
||||
void gateStateChanged(const EGateState state);
|
||||
|
||||
const CGHeroInstance *currentHero() const;
|
||||
InfoAboutHero enemyHero() const;
|
||||
};
|
||||
|
@@ -1,149 +1,149 @@
|
||||
/*
|
||||
* BattleStacksController.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
|
||||
|
||||
#include "../render/ColorFilter.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct BattleHex;
|
||||
class BattleHexArray;
|
||||
class BattleAction;
|
||||
class CStack;
|
||||
class CSpell;
|
||||
class SpellID;
|
||||
class Point;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
struct StackAttackedInfo;
|
||||
struct StackAttackInfo;
|
||||
|
||||
class ColorFilter;
|
||||
class Canvas;
|
||||
class BattleInterface;
|
||||
class BattleAnimation;
|
||||
class CreatureAnimation;
|
||||
class BattleAnimation;
|
||||
class BattleRenderer;
|
||||
class IImage;
|
||||
|
||||
struct BattleStackFilterEffect
|
||||
{
|
||||
ColorFilter effect;
|
||||
const CStack * target;
|
||||
const CSpell * source;
|
||||
bool persistent;
|
||||
};
|
||||
|
||||
/// Class responsible for handling stacks in battle
|
||||
/// Handles ordering of stacks animation
|
||||
/// As well as rendering of stacks, their amount boxes
|
||||
/// And any other effect applied to stacks
|
||||
class BattleStacksController
|
||||
{
|
||||
BattleInterface & owner;
|
||||
|
||||
std::shared_ptr<IImage> amountNormal;
|
||||
std::shared_ptr<IImage> amountNegative;
|
||||
std::shared_ptr<IImage> amountPositive;
|
||||
std::shared_ptr<IImage> amountEffNeutral;
|
||||
|
||||
/// currently displayed animations <anim, initialized>
|
||||
std::vector<BattleAnimation *> currentAnimations;
|
||||
|
||||
/// currently active color effects on stacks, in order of their addition (which corresponds to their apply order)
|
||||
std::vector<BattleStackFilterEffect> stackFilterEffects;
|
||||
|
||||
/// animations of creatures from fighting armies (order by BattleInfo's stacks' ID)
|
||||
std::map<int32_t, std::shared_ptr<CreatureAnimation>> stackAnimation;
|
||||
|
||||
/// <creatureID, if false reverse creature's animation> //TODO: move it to battle callback
|
||||
std::map<int, bool> stackFacingRight;
|
||||
|
||||
/// Stacks have amount box hidden due to ongoing animations
|
||||
std::set<int> stackAmountBoxHidden;
|
||||
|
||||
/// currently active stack; nullptr - no one
|
||||
const CStack *activeStack;
|
||||
|
||||
/// stacks or their battle queue images below mouse pointer (multiple stacks possible while spellcasting), used for border animation
|
||||
std::vector<const CStack *> mouseHoveredStacks;
|
||||
|
||||
///when animation is playing, we should wait till the end to make the next stack active; nullptr of none
|
||||
const CStack *stackToActivate;
|
||||
|
||||
/// for giving IDs for animations
|
||||
ui32 animIDhelper;
|
||||
|
||||
bool stackNeedsAmountBox(const CStack * stack) const;
|
||||
void showStackAmountBox(Canvas & canvas, const CStack * stack);
|
||||
BattleHex getStackCurrentPosition(const CStack * stack) const;
|
||||
|
||||
std::shared_ptr<IImage> getStackAmountBox(const CStack * stack);
|
||||
|
||||
void removeExpiredColorFilters();
|
||||
|
||||
void initializeBattleAnimations();
|
||||
void tickFrameBattleAnimations(uint32_t msPassed);
|
||||
|
||||
void updateBattleAnimations(uint32_t msPassed);
|
||||
|
||||
std::vector<const CStack *> selectHoveredStacks();
|
||||
|
||||
bool shouldAttackFacingRight(const CStack * attacker, const CStack * defender);
|
||||
|
||||
public:
|
||||
BattleStacksController(BattleInterface & owner);
|
||||
|
||||
bool shouldRotate(const CStack * stack, const BattleHex & oldPos, const BattleHex & nextHex) const;
|
||||
bool facingRight(const CStack * stack) const;
|
||||
|
||||
void stackReset(const CStack * stack);
|
||||
void stackAdded(const CStack * stack, bool instant); //new stack appeared on battlefield
|
||||
void stackRemoved(uint32_t stackID); //stack disappeared from batlefiled
|
||||
void stackActivated(const CStack *stack); //active stack has been changed
|
||||
void stackMoved(const CStack *stack, const BattleHexArray & destHex, int distance); //stack with id number moved to destHex
|
||||
void stackTeleported(const CStack *stack, const BattleHexArray & destHex, int distance); //stack with id number moved to destHex
|
||||
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 startAction(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 activateStack(); //copy stackToActivate to activeStack to enable controls of the stack
|
||||
|
||||
void setActiveStack(const CStack *stack);
|
||||
|
||||
void showAliveStack(Canvas & canvas, const CStack * stack);
|
||||
void showStack(Canvas & canvas, const CStack * stack);
|
||||
|
||||
void updateHoveredStacks();
|
||||
|
||||
void collectRenderableObjects(BattleRenderer & renderer);
|
||||
|
||||
/// Adds new color filter effect targeting stack
|
||||
/// Effect will last as long as stack is affected by specified spell (unless effect is persistent)
|
||||
/// If effect from same (target, source) already exists, it will be updated
|
||||
void setStackColorFilter(const ColorFilter & effect, const CStack * target, const CSpell *source, bool persistent);
|
||||
void addNewAnim(BattleAnimation *anim); //adds new anim to pendingAnims
|
||||
|
||||
const CStack* getActiveStack() const;
|
||||
const std::vector<uint32_t> getHoveredStacksUnitIds() const;
|
||||
|
||||
void tick(uint32_t msPassed);
|
||||
|
||||
/// returns position of animation needed to place stack in specific hex
|
||||
Point getStackPositionAtHex(BattleHex hexNum, const CStack * creature) const;
|
||||
|
||||
friend class BattleAnimation; // for exposing pendingAnims/creAnims/creDir to animations
|
||||
};
|
||||
/*
|
||||
* BattleStacksController.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
|
||||
|
||||
#include "../render/ColorFilter.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct BattleHex;
|
||||
class BattleHexArray;
|
||||
class BattleAction;
|
||||
class CStack;
|
||||
class CSpell;
|
||||
class SpellID;
|
||||
class Point;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
struct StackAttackedInfo;
|
||||
struct StackAttackInfo;
|
||||
|
||||
class ColorFilter;
|
||||
class Canvas;
|
||||
class BattleInterface;
|
||||
class BattleAnimation;
|
||||
class CreatureAnimation;
|
||||
class BattleAnimation;
|
||||
class BattleRenderer;
|
||||
class IImage;
|
||||
|
||||
struct BattleStackFilterEffect
|
||||
{
|
||||
ColorFilter effect;
|
||||
const CStack * target;
|
||||
const CSpell * source;
|
||||
bool persistent;
|
||||
};
|
||||
|
||||
/// Class responsible for handling stacks in battle
|
||||
/// Handles ordering of stacks animation
|
||||
/// As well as rendering of stacks, their amount boxes
|
||||
/// And any other effect applied to stacks
|
||||
class BattleStacksController
|
||||
{
|
||||
BattleInterface & owner;
|
||||
|
||||
std::shared_ptr<IImage> amountNormal;
|
||||
std::shared_ptr<IImage> amountNegative;
|
||||
std::shared_ptr<IImage> amountPositive;
|
||||
std::shared_ptr<IImage> amountEffNeutral;
|
||||
|
||||
/// currently displayed animations <anim, initialized>
|
||||
std::vector<BattleAnimation *> currentAnimations;
|
||||
|
||||
/// currently active color effects on stacks, in order of their addition (which corresponds to their apply order)
|
||||
std::vector<BattleStackFilterEffect> stackFilterEffects;
|
||||
|
||||
/// animations of creatures from fighting armies (order by BattleInfo's stacks' ID)
|
||||
std::map<int32_t, std::shared_ptr<CreatureAnimation>> stackAnimation;
|
||||
|
||||
/// <creatureID, if false reverse creature's animation> //TODO: move it to battle callback
|
||||
std::map<int, bool> stackFacingRight;
|
||||
|
||||
/// Stacks have amount box hidden due to ongoing animations
|
||||
std::set<int> stackAmountBoxHidden;
|
||||
|
||||
/// currently active stack; nullptr - no one
|
||||
const CStack *activeStack;
|
||||
|
||||
/// stacks or their battle queue images below mouse pointer (multiple stacks possible while spellcasting), used for border animation
|
||||
std::vector<const CStack *> mouseHoveredStacks;
|
||||
|
||||
///when animation is playing, we should wait till the end to make the next stack active; nullptr of none
|
||||
const CStack *stackToActivate;
|
||||
|
||||
/// for giving IDs for animations
|
||||
ui32 animIDhelper;
|
||||
|
||||
bool stackNeedsAmountBox(const CStack * stack) const;
|
||||
void showStackAmountBox(Canvas & canvas, const CStack * stack);
|
||||
BattleHex getStackCurrentPosition(const CStack * stack) const;
|
||||
|
||||
std::shared_ptr<IImage> getStackAmountBox(const CStack * stack);
|
||||
|
||||
void removeExpiredColorFilters();
|
||||
|
||||
void initializeBattleAnimations();
|
||||
void tickFrameBattleAnimations(uint32_t msPassed);
|
||||
|
||||
void updateBattleAnimations(uint32_t msPassed);
|
||||
|
||||
std::vector<const CStack *> selectHoveredStacks();
|
||||
|
||||
bool shouldAttackFacingRight(const CStack * attacker, const CStack * defender);
|
||||
|
||||
public:
|
||||
BattleStacksController(BattleInterface & owner);
|
||||
|
||||
bool shouldRotate(const CStack * stack, const BattleHex & oldPos, const BattleHex & nextHex) const;
|
||||
bool facingRight(const CStack * stack) const;
|
||||
|
||||
void stackReset(const CStack * stack);
|
||||
void stackAdded(const CStack * stack, bool instant); //new stack appeared on battlefield
|
||||
void stackRemoved(uint32_t stackID); //stack disappeared from batlefiled
|
||||
void stackActivated(const CStack *stack); //active stack has been changed
|
||||
void stackMoved(const CStack *stack, const BattleHexArray & destHex, int distance); //stack with id number moved to destHex
|
||||
void stackTeleported(const CStack *stack, const BattleHexArray & destHex, int distance); //stack with id number moved to destHex
|
||||
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 startAction(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 activateStack(); //copy stackToActivate to activeStack to enable controls of the stack
|
||||
|
||||
void setActiveStack(const CStack *stack);
|
||||
|
||||
void showAliveStack(Canvas & canvas, const CStack * stack);
|
||||
void showStack(Canvas & canvas, const CStack * stack);
|
||||
|
||||
void updateHoveredStacks();
|
||||
|
||||
void collectRenderableObjects(BattleRenderer & renderer);
|
||||
|
||||
/// Adds new color filter effect targeting stack
|
||||
/// Effect will last as long as stack is affected by specified spell (unless effect is persistent)
|
||||
/// If effect from same (target, source) already exists, it will be updated
|
||||
void setStackColorFilter(const ColorFilter & effect, const CStack * target, const CSpell *source, bool persistent);
|
||||
void addNewAnim(BattleAnimation *anim); //adds new anim to pendingAnims
|
||||
|
||||
const CStack* getActiveStack() const;
|
||||
const std::vector<uint32_t> getHoveredStacksUnitIds() const;
|
||||
|
||||
void tick(uint32_t msPassed);
|
||||
|
||||
/// returns position of animation needed to place stack in specific hex
|
||||
Point getStackPositionAtHex(BattleHex hexNum, const CStack * creature) const;
|
||||
|
||||
friend class BattleAnimation; // for exposing pendingAnims/creAnims/creDir to animations
|
||||
};
|
||||
|
@@ -1,104 +1,104 @@
|
||||
/*
|
||||
* RNG.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
|
||||
|
||||
namespace vstd
|
||||
{
|
||||
|
||||
class DLL_LINKAGE RNG
|
||||
{
|
||||
public:
|
||||
virtual ~RNG() = default;
|
||||
|
||||
/// Returns random number in range [lower, upper]
|
||||
virtual int nextInt(int lower, int upper) = 0;
|
||||
|
||||
/// Returns random number in range [lower, upper]
|
||||
virtual int64_t nextInt64(int64_t lower, int64_t upper) = 0;
|
||||
|
||||
/// Returns random number in range [lower, upper]
|
||||
virtual double nextDouble(double lower, double upper) = 0;
|
||||
|
||||
/// Returns random number in range [0, upper]
|
||||
virtual int nextInt(int upper) = 0;
|
||||
|
||||
/// Returns random number in range [0, upper]
|
||||
virtual int64_t nextInt64(int64_t upper) = 0;
|
||||
|
||||
/// Returns random number in range [0, upper]
|
||||
virtual double nextDouble(double upper) = 0;
|
||||
|
||||
/// Generates an integer between 0 and the maximum value it can hold.
|
||||
/// Should be only used for seeding other generators
|
||||
virtual int nextInt() = 0;
|
||||
|
||||
/// Returns integer using binomial distribution
|
||||
/// returned value is number of successfull coin flips with chance 'coinChance' out of 'coinsCount' attempts
|
||||
virtual int nextBinomialInt(int coinsCount, double coinChance) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace RandomGeneratorUtil
|
||||
{
|
||||
template<typename Container>
|
||||
auto nextItem(const Container & container, vstd::RNG & rand) -> decltype(std::begin(container))
|
||||
{
|
||||
if(container.empty())
|
||||
throw std::runtime_error("Unable to select random item from empty container!");
|
||||
|
||||
return std::next(container.begin(), rand.nextInt64(0, container.size() - 1));
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
auto nextItem(Container & container, vstd::RNG & rand) -> decltype(std::begin(container))
|
||||
{
|
||||
if(container.empty())
|
||||
throw std::runtime_error("Unable to select random item from empty container!");
|
||||
|
||||
return std::next(container.begin(), rand.nextInt64(0, container.size() - 1));
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
size_t nextItemWeighted(Container & container, vstd::RNG & rand)
|
||||
{
|
||||
assert(!container.empty());
|
||||
|
||||
int64_t totalWeight = std::accumulate(container.begin(), container.end(), 0);
|
||||
assert(totalWeight > 0);
|
||||
|
||||
int64_t roll = rand.nextInt64(0, totalWeight - 1);
|
||||
|
||||
for (size_t i = 0; i < container.size(); ++i)
|
||||
{
|
||||
roll -= container[i];
|
||||
if(roll < 0)
|
||||
return i;
|
||||
}
|
||||
return container.size() - 1;
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
void randomShuffle(Container & container, vstd::RNG & rand)
|
||||
{
|
||||
int64_t n = std::distance(container.begin(), container.end());
|
||||
|
||||
for(int64_t i = n - 1; i > 0; --i)
|
||||
{
|
||||
auto randIndex = rand.nextInt64(0, i);
|
||||
std::swap(*(container.begin() + i), *(container.begin() + randIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* RNG.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
|
||||
|
||||
namespace vstd
|
||||
{
|
||||
|
||||
class DLL_LINKAGE RNG
|
||||
{
|
||||
public:
|
||||
virtual ~RNG() = default;
|
||||
|
||||
/// Returns random number in range [lower, upper]
|
||||
virtual int nextInt(int lower, int upper) = 0;
|
||||
|
||||
/// Returns random number in range [lower, upper]
|
||||
virtual int64_t nextInt64(int64_t lower, int64_t upper) = 0;
|
||||
|
||||
/// Returns random number in range [lower, upper]
|
||||
virtual double nextDouble(double lower, double upper) = 0;
|
||||
|
||||
/// Returns random number in range [0, upper]
|
||||
virtual int nextInt(int upper) = 0;
|
||||
|
||||
/// Returns random number in range [0, upper]
|
||||
virtual int64_t nextInt64(int64_t upper) = 0;
|
||||
|
||||
/// Returns random number in range [0, upper]
|
||||
virtual double nextDouble(double upper) = 0;
|
||||
|
||||
/// Generates an integer between 0 and the maximum value it can hold.
|
||||
/// Should be only used for seeding other generators
|
||||
virtual int nextInt() = 0;
|
||||
|
||||
/// Returns integer using binomial distribution
|
||||
/// returned value is number of successfull coin flips with chance 'coinChance' out of 'coinsCount' attempts
|
||||
virtual int nextBinomialInt(int coinsCount, double coinChance) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace RandomGeneratorUtil
|
||||
{
|
||||
template<typename Container>
|
||||
auto nextItem(const Container & container, vstd::RNG & rand) -> decltype(std::begin(container))
|
||||
{
|
||||
if(container.empty())
|
||||
throw std::runtime_error("Unable to select random item from empty container!");
|
||||
|
||||
return std::next(container.begin(), rand.nextInt64(0, container.size() - 1));
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
auto nextItem(Container & container, vstd::RNG & rand) -> decltype(std::begin(container))
|
||||
{
|
||||
if(container.empty())
|
||||
throw std::runtime_error("Unable to select random item from empty container!");
|
||||
|
||||
return std::next(container.begin(), rand.nextInt64(0, container.size() - 1));
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
size_t nextItemWeighted(Container & container, vstd::RNG & rand)
|
||||
{
|
||||
assert(!container.empty());
|
||||
|
||||
int64_t totalWeight = std::accumulate(container.begin(), container.end(), 0);
|
||||
assert(totalWeight > 0);
|
||||
|
||||
int64_t roll = rand.nextInt64(0, totalWeight - 1);
|
||||
|
||||
for (size_t i = 0; i < container.size(); ++i)
|
||||
{
|
||||
roll -= container[i];
|
||||
if(roll < 0)
|
||||
return i;
|
||||
}
|
||||
return container.size() - 1;
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
void randomShuffle(Container & container, vstd::RNG & rand)
|
||||
{
|
||||
int64_t n = std::distance(container.begin(), container.end());
|
||||
|
||||
for(int64_t i = n - 1; i > 0; --i)
|
||||
{
|
||||
auto randIndex = rand.nextInt64(0, i);
|
||||
std::swap(*(container.begin() + i), *(container.begin() + randIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,101 +1,101 @@
|
||||
/*
|
||||
* BattleFieldHandler.cpp, 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
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
|
||||
#include <vcmi/Entity.h>
|
||||
#include "BattleFieldHandler.h"
|
||||
#include "json/JsonBonus.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
std::shared_ptr<BattleFieldInfo> BattleFieldHandler::loadFromJson(const std::string & scope, const JsonNode & json, const std::string & identifier, size_t index)
|
||||
{
|
||||
assert(identifier.find(':') == std::string::npos);
|
||||
|
||||
auto info = std::make_shared<BattleFieldInfo>(BattleField(index), identifier);
|
||||
|
||||
info->modScope = scope;
|
||||
info->graphics = ImagePath::fromJson(json["graphics"]);
|
||||
info->icon = json["icon"].String();
|
||||
info->name = json["name"].String();
|
||||
for(const auto & b : json["bonuses"].Vector())
|
||||
{
|
||||
auto bonus = JsonUtils::parseBonus(b);
|
||||
|
||||
bonus->source = BonusSource::TERRAIN_OVERLAY;
|
||||
bonus->sid = BonusSourceID(info->getId());
|
||||
bonus->duration = BonusDuration::ONE_BATTLE;
|
||||
|
||||
info->bonuses.push_back(bonus);
|
||||
}
|
||||
|
||||
info->isSpecial = json["isSpecial"].Bool();
|
||||
for(auto node : json["impassableHexes"].Vector())
|
||||
info->impassableHexes.insert(node.Integer());
|
||||
|
||||
info->openingSoundFilename = AudioPath::fromJson(json["openingSound"]);
|
||||
info->musicFilename = AudioPath::fromJson(json["music"]);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
std::vector<JsonNode> BattleFieldHandler::loadLegacyData()
|
||||
{
|
||||
return std::vector<JsonNode>();
|
||||
}
|
||||
|
||||
const std::vector<std::string> & BattleFieldHandler::getTypeNames() const
|
||||
{
|
||||
static const auto types = std::vector<std::string> { "battlefield" };
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
int32_t BattleFieldInfo::getIndex() const
|
||||
{
|
||||
return battlefield.getNum();
|
||||
}
|
||||
|
||||
int32_t BattleFieldInfo::getIconIndex() const
|
||||
{
|
||||
return iconIndex;
|
||||
}
|
||||
|
||||
std::string BattleFieldInfo::getJsonKey() const
|
||||
{
|
||||
return modScope + ':' + identifier;
|
||||
}
|
||||
|
||||
std::string BattleFieldInfo::getModScope() const
|
||||
{
|
||||
return modScope;
|
||||
}
|
||||
|
||||
std::string BattleFieldInfo::getNameTextID() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string BattleFieldInfo::getNameTranslated() const
|
||||
{
|
||||
return name; // TODO?
|
||||
}
|
||||
|
||||
void BattleFieldInfo::registerIcons(const IconRegistar & cb) const
|
||||
{
|
||||
//cb(getIconIndex(), "BATTLEFIELD", icon);
|
||||
}
|
||||
|
||||
BattleField BattleFieldInfo::getId() const
|
||||
{
|
||||
return battlefield;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* BattleFieldHandler.cpp, 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
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
|
||||
#include <vcmi/Entity.h>
|
||||
#include "BattleFieldHandler.h"
|
||||
#include "json/JsonBonus.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
std::shared_ptr<BattleFieldInfo> BattleFieldHandler::loadFromJson(const std::string & scope, const JsonNode & json, const std::string & identifier, size_t index)
|
||||
{
|
||||
assert(identifier.find(':') == std::string::npos);
|
||||
|
||||
auto info = std::make_shared<BattleFieldInfo>(BattleField(index), identifier);
|
||||
|
||||
info->modScope = scope;
|
||||
info->graphics = ImagePath::fromJson(json["graphics"]);
|
||||
info->icon = json["icon"].String();
|
||||
info->name = json["name"].String();
|
||||
for(const auto & b : json["bonuses"].Vector())
|
||||
{
|
||||
auto bonus = JsonUtils::parseBonus(b);
|
||||
|
||||
bonus->source = BonusSource::TERRAIN_OVERLAY;
|
||||
bonus->sid = BonusSourceID(info->getId());
|
||||
bonus->duration = BonusDuration::ONE_BATTLE;
|
||||
|
||||
info->bonuses.push_back(bonus);
|
||||
}
|
||||
|
||||
info->isSpecial = json["isSpecial"].Bool();
|
||||
for(auto node : json["impassableHexes"].Vector())
|
||||
info->impassableHexes.insert(node.Integer());
|
||||
|
||||
info->openingSoundFilename = AudioPath::fromJson(json["openingSound"]);
|
||||
info->musicFilename = AudioPath::fromJson(json["music"]);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
std::vector<JsonNode> BattleFieldHandler::loadLegacyData()
|
||||
{
|
||||
return std::vector<JsonNode>();
|
||||
}
|
||||
|
||||
const std::vector<std::string> & BattleFieldHandler::getTypeNames() const
|
||||
{
|
||||
static const auto types = std::vector<std::string> { "battlefield" };
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
int32_t BattleFieldInfo::getIndex() const
|
||||
{
|
||||
return battlefield.getNum();
|
||||
}
|
||||
|
||||
int32_t BattleFieldInfo::getIconIndex() const
|
||||
{
|
||||
return iconIndex;
|
||||
}
|
||||
|
||||
std::string BattleFieldInfo::getJsonKey() const
|
||||
{
|
||||
return modScope + ':' + identifier;
|
||||
}
|
||||
|
||||
std::string BattleFieldInfo::getModScope() const
|
||||
{
|
||||
return modScope;
|
||||
}
|
||||
|
||||
std::string BattleFieldInfo::getNameTextID() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string BattleFieldInfo::getNameTranslated() const
|
||||
{
|
||||
return name; // TODO?
|
||||
}
|
||||
|
||||
void BattleFieldInfo::registerIcons(const IconRegistar & cb) const
|
||||
{
|
||||
//cb(getIconIndex(), "BATTLEFIELD", icon);
|
||||
}
|
||||
|
||||
BattleField BattleFieldInfo::getId() const
|
||||
{
|
||||
return battlefield;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,80 +1,80 @@
|
||||
/*
|
||||
* BattleFieldHandler.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
|
||||
|
||||
#include <vcmi/EntityService.h>
|
||||
#include <vcmi/Entity.h>
|
||||
#include "bonuses/Bonus.h"
|
||||
#include "GameConstants.h"
|
||||
#include "IHandlerBase.h"
|
||||
#include "battle/BattleHexArray.h"
|
||||
#include "filesystem/ResourcePath.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class BattleFieldInfo : public EntityT<BattleField>
|
||||
{
|
||||
public:
|
||||
BattleField battlefield;
|
||||
std::vector<std::shared_ptr<Bonus>> bonuses;
|
||||
bool isSpecial;
|
||||
ImagePath graphics;
|
||||
std::string name;
|
||||
std::string modScope;
|
||||
std::string identifier;
|
||||
std::string icon;
|
||||
si32 iconIndex;
|
||||
BattleHexArray impassableHexes;
|
||||
AudioPath openingSoundFilename;
|
||||
AudioPath musicFilename;
|
||||
|
||||
BattleFieldInfo()
|
||||
: BattleFieldInfo(BattleField::NONE, "")
|
||||
{
|
||||
}
|
||||
|
||||
BattleFieldInfo(BattleField battlefield, std::string identifier):
|
||||
isSpecial(false),
|
||||
battlefield(battlefield),
|
||||
identifier(identifier),
|
||||
iconIndex(battlefield.getNum()),
|
||||
name(identifier)
|
||||
{
|
||||
}
|
||||
|
||||
int32_t getIndex() const override;
|
||||
int32_t getIconIndex() const override;
|
||||
std::string getJsonKey() const override;
|
||||
std::string getModScope() const override;
|
||||
std::string getNameTextID() const override;
|
||||
std::string getNameTranslated() const override;
|
||||
void registerIcons(const IconRegistar & cb) const override;
|
||||
BattleField getId() const override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE BattleFieldService : public EntityServiceT<BattleField, BattleFieldInfo>
|
||||
{
|
||||
public:
|
||||
};
|
||||
|
||||
class BattleFieldHandler : public CHandlerBase<BattleField, BattleFieldInfo, BattleFieldInfo, BattleFieldService>
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<BattleFieldInfo> loadFromJson(
|
||||
const std::string & scope,
|
||||
const JsonNode & json,
|
||||
const std::string & identifier,
|
||||
size_t index) override;
|
||||
|
||||
const std::vector<std::string> & getTypeNames() const override;
|
||||
std::vector<JsonNode> loadLegacyData() override;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* BattleFieldHandler.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
|
||||
|
||||
#include <vcmi/EntityService.h>
|
||||
#include <vcmi/Entity.h>
|
||||
#include "bonuses/Bonus.h"
|
||||
#include "GameConstants.h"
|
||||
#include "IHandlerBase.h"
|
||||
#include "battle/BattleHexArray.h"
|
||||
#include "filesystem/ResourcePath.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class BattleFieldInfo : public EntityT<BattleField>
|
||||
{
|
||||
public:
|
||||
BattleField battlefield;
|
||||
std::vector<std::shared_ptr<Bonus>> bonuses;
|
||||
bool isSpecial;
|
||||
ImagePath graphics;
|
||||
std::string name;
|
||||
std::string modScope;
|
||||
std::string identifier;
|
||||
std::string icon;
|
||||
si32 iconIndex;
|
||||
BattleHexArray impassableHexes;
|
||||
AudioPath openingSoundFilename;
|
||||
AudioPath musicFilename;
|
||||
|
||||
BattleFieldInfo()
|
||||
: BattleFieldInfo(BattleField::NONE, "")
|
||||
{
|
||||
}
|
||||
|
||||
BattleFieldInfo(BattleField battlefield, std::string identifier):
|
||||
isSpecial(false),
|
||||
battlefield(battlefield),
|
||||
identifier(identifier),
|
||||
iconIndex(battlefield.getNum()),
|
||||
name(identifier)
|
||||
{
|
||||
}
|
||||
|
||||
int32_t getIndex() const override;
|
||||
int32_t getIconIndex() const override;
|
||||
std::string getJsonKey() const override;
|
||||
std::string getModScope() const override;
|
||||
std::string getNameTextID() const override;
|
||||
std::string getNameTranslated() const override;
|
||||
void registerIcons(const IconRegistar & cb) const override;
|
||||
BattleField getId() const override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE BattleFieldService : public EntityServiceT<BattleField, BattleFieldInfo>
|
||||
{
|
||||
public:
|
||||
};
|
||||
|
||||
class BattleFieldHandler : public CHandlerBase<BattleField, BattleFieldInfo, BattleFieldInfo, BattleFieldService>
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<BattleFieldInfo> loadFromJson(
|
||||
const std::string & scope,
|
||||
const JsonNode & json,
|
||||
const std::string & identifier,
|
||||
size_t index) override;
|
||||
|
||||
const std::vector<std::string> & getTypeNames() const override;
|
||||
std::vector<JsonNode> loadLegacyData() override;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,129 +1,129 @@
|
||||
/*
|
||||
* ObstacleHandler.cpp, 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
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "ObstacleHandler.h"
|
||||
#include "BattleFieldHandler.h"
|
||||
#include "json/JsonNode.h"
|
||||
#include "modding/IdentifierStorage.h"
|
||||
#include "VCMI_Lib.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
int32_t ObstacleInfo::getIndex() const
|
||||
{
|
||||
return obstacle.getNum();
|
||||
}
|
||||
|
||||
int32_t ObstacleInfo::getIconIndex() const
|
||||
{
|
||||
return iconIndex;
|
||||
}
|
||||
|
||||
std::string ObstacleInfo::getJsonKey() const
|
||||
{
|
||||
return modScope + ':' + identifier;
|
||||
}
|
||||
|
||||
std::string ObstacleInfo::getModScope() const
|
||||
{
|
||||
return modScope;
|
||||
}
|
||||
|
||||
std::string ObstacleInfo::getNameTranslated() const
|
||||
{
|
||||
return identifier;
|
||||
}
|
||||
|
||||
std::string ObstacleInfo::getNameTextID() const
|
||||
{
|
||||
return identifier; // TODO?
|
||||
}
|
||||
|
||||
void ObstacleInfo::registerIcons(const IconRegistar & cb) const
|
||||
{
|
||||
}
|
||||
|
||||
Obstacle ObstacleInfo::getId() const
|
||||
{
|
||||
return obstacle;
|
||||
}
|
||||
|
||||
BattleHexArray ObstacleInfo::getBlocked(BattleHex hex) const
|
||||
{
|
||||
if(isAbsoluteObstacle)
|
||||
{
|
||||
assert(!hex.isValid());
|
||||
return BattleHexArray(blockedTiles);
|
||||
}
|
||||
|
||||
BattleHexArray ret;
|
||||
for(int offset : blockedTiles)
|
||||
{
|
||||
BattleHex toBlock = hex + offset;
|
||||
if((hex.getY() & 1) && !(toBlock.getY() & 1))
|
||||
toBlock += BattleHex::LEFT;
|
||||
|
||||
if(!toBlock.isValid())
|
||||
logGlobal->error("Misplaced obstacle!");
|
||||
else
|
||||
ret.insert(toBlock);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ObstacleInfo::isAppropriate(const TerrainId terrainType, const BattleField & battlefield) const
|
||||
{
|
||||
const auto * bgInfo = battlefield.getInfo();
|
||||
|
||||
if(bgInfo->isSpecial)
|
||||
return vstd::contains(allowedSpecialBfields, bgInfo->identifier);
|
||||
|
||||
return vstd::contains(allowedTerrains, terrainType);
|
||||
}
|
||||
|
||||
std::shared_ptr<ObstacleInfo> ObstacleHandler::loadFromJson(const std::string & scope, const JsonNode & json, const std::string & identifier, size_t index)
|
||||
{
|
||||
assert(identifier.find(':') == std::string::npos);
|
||||
|
||||
auto info = std::make_shared<ObstacleInfo>(Obstacle(index), identifier);
|
||||
|
||||
info->modScope = scope;
|
||||
info->animation = AnimationPath::fromJson(json["animation"]);
|
||||
info->width = json["width"].Integer();
|
||||
info->height = json["height"].Integer();
|
||||
for(const auto & t : json["allowedTerrains"].Vector())
|
||||
{
|
||||
VLC->identifiers()->requestIdentifier("terrain", t, [info](int32_t identifier){
|
||||
info->allowedTerrains.emplace_back(identifier);
|
||||
});
|
||||
}
|
||||
for(const auto & t : json["specialBattlefields"].Vector())
|
||||
|
||||
info->allowedSpecialBfields.emplace_back(t.String());
|
||||
info->blockedTiles = json["blockedTiles"].convertTo<std::vector<si16>>();
|
||||
info->isAbsoluteObstacle = json["absolute"].Bool();
|
||||
info->isForegroundObstacle = json["foreground"].Bool();
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
std::vector<JsonNode> ObstacleHandler::loadLegacyData()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::vector<std::string> & ObstacleHandler::getTypeNames() const
|
||||
{
|
||||
static const std::vector<std::string> types = { "obstacle" };
|
||||
return types;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* ObstacleHandler.cpp, 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
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "ObstacleHandler.h"
|
||||
#include "BattleFieldHandler.h"
|
||||
#include "json/JsonNode.h"
|
||||
#include "modding/IdentifierStorage.h"
|
||||
#include "VCMI_Lib.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
int32_t ObstacleInfo::getIndex() const
|
||||
{
|
||||
return obstacle.getNum();
|
||||
}
|
||||
|
||||
int32_t ObstacleInfo::getIconIndex() const
|
||||
{
|
||||
return iconIndex;
|
||||
}
|
||||
|
||||
std::string ObstacleInfo::getJsonKey() const
|
||||
{
|
||||
return modScope + ':' + identifier;
|
||||
}
|
||||
|
||||
std::string ObstacleInfo::getModScope() const
|
||||
{
|
||||
return modScope;
|
||||
}
|
||||
|
||||
std::string ObstacleInfo::getNameTranslated() const
|
||||
{
|
||||
return identifier;
|
||||
}
|
||||
|
||||
std::string ObstacleInfo::getNameTextID() const
|
||||
{
|
||||
return identifier; // TODO?
|
||||
}
|
||||
|
||||
void ObstacleInfo::registerIcons(const IconRegistar & cb) const
|
||||
{
|
||||
}
|
||||
|
||||
Obstacle ObstacleInfo::getId() const
|
||||
{
|
||||
return obstacle;
|
||||
}
|
||||
|
||||
BattleHexArray ObstacleInfo::getBlocked(BattleHex hex) const
|
||||
{
|
||||
if(isAbsoluteObstacle)
|
||||
{
|
||||
assert(!hex.isValid());
|
||||
return BattleHexArray(blockedTiles);
|
||||
}
|
||||
|
||||
BattleHexArray ret;
|
||||
for(int offset : blockedTiles)
|
||||
{
|
||||
BattleHex toBlock = hex + offset;
|
||||
if((hex.getY() & 1) && !(toBlock.getY() & 1))
|
||||
toBlock += BattleHex::LEFT;
|
||||
|
||||
if(!toBlock.isValid())
|
||||
logGlobal->error("Misplaced obstacle!");
|
||||
else
|
||||
ret.insert(toBlock);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ObstacleInfo::isAppropriate(const TerrainId terrainType, const BattleField & battlefield) const
|
||||
{
|
||||
const auto * bgInfo = battlefield.getInfo();
|
||||
|
||||
if(bgInfo->isSpecial)
|
||||
return vstd::contains(allowedSpecialBfields, bgInfo->identifier);
|
||||
|
||||
return vstd::contains(allowedTerrains, terrainType);
|
||||
}
|
||||
|
||||
std::shared_ptr<ObstacleInfo> ObstacleHandler::loadFromJson(const std::string & scope, const JsonNode & json, const std::string & identifier, size_t index)
|
||||
{
|
||||
assert(identifier.find(':') == std::string::npos);
|
||||
|
||||
auto info = std::make_shared<ObstacleInfo>(Obstacle(index), identifier);
|
||||
|
||||
info->modScope = scope;
|
||||
info->animation = AnimationPath::fromJson(json["animation"]);
|
||||
info->width = json["width"].Integer();
|
||||
info->height = json["height"].Integer();
|
||||
for(const auto & t : json["allowedTerrains"].Vector())
|
||||
{
|
||||
VLC->identifiers()->requestIdentifier("terrain", t, [info](int32_t identifier){
|
||||
info->allowedTerrains.emplace_back(identifier);
|
||||
});
|
||||
}
|
||||
for(const auto & t : json["specialBattlefields"].Vector())
|
||||
|
||||
info->allowedSpecialBfields.emplace_back(t.String());
|
||||
info->blockedTiles = json["blockedTiles"].convertTo<std::vector<si16>>();
|
||||
info->isAbsoluteObstacle = json["absolute"].Bool();
|
||||
info->isForegroundObstacle = json["foreground"].Bool();
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
std::vector<JsonNode> ObstacleHandler::loadLegacyData()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::vector<std::string> & ObstacleHandler::getTypeNames() const
|
||||
{
|
||||
static const std::vector<std::string> types = { "obstacle" };
|
||||
return types;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,79 +1,79 @@
|
||||
/*
|
||||
* ObstacleHandler.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
|
||||
|
||||
#include <vcmi/EntityService.h>
|
||||
#include <vcmi/Entity.h>
|
||||
#include "GameConstants.h"
|
||||
#include "IHandlerBase.h"
|
||||
#include "battle/BattleHexArray.h"
|
||||
#include "filesystem/ResourcePath.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class DLL_LINKAGE ObstacleInfo : public EntityT<Obstacle>
|
||||
{
|
||||
public:
|
||||
ObstacleInfo(): obstacle(-1), width(0), height(0), isAbsoluteObstacle(false), iconIndex(0), isForegroundObstacle(false)
|
||||
{}
|
||||
|
||||
ObstacleInfo(Obstacle obstacle, std::string identifier)
|
||||
: obstacle(obstacle), identifier(identifier), iconIndex(obstacle.getNum()), width(0), height(0), isAbsoluteObstacle(false), isForegroundObstacle(false)
|
||||
{
|
||||
}
|
||||
|
||||
Obstacle obstacle;
|
||||
si32 iconIndex;
|
||||
std::string modScope;
|
||||
std::string identifier;
|
||||
AudioPath appearSound;
|
||||
AnimationPath appearAnimation;
|
||||
AnimationPath animation;
|
||||
std::vector<TerrainId> allowedTerrains;
|
||||
std::vector<std::string> allowedSpecialBfields;
|
||||
|
||||
bool isAbsoluteObstacle; //there may only one such obstacle in battle and its position is always the same
|
||||
bool isForegroundObstacle;
|
||||
si32 width; //how much space to the right and up is needed to place obstacle (affects only placement algorithm)
|
||||
si32 height;
|
||||
std::vector<si16> blockedTiles; //offsets relative to obstacle position (that is its left bottom corner)
|
||||
|
||||
int32_t getIndex() const override;
|
||||
int32_t getIconIndex() const override;
|
||||
std::string getJsonKey() const override;
|
||||
std::string getModScope() const override;
|
||||
std::string getNameTranslated() const override;
|
||||
std::string getNameTextID() const override;
|
||||
void registerIcons(const IconRegistar & cb) const override;
|
||||
Obstacle getId() const override;
|
||||
|
||||
BattleHexArray getBlocked(BattleHex hex) const; //returns vector of hexes blocked by obstacle when it's placed on hex 'hex'
|
||||
|
||||
bool isAppropriate(const TerrainId terrainType, const BattleField & specialBattlefield) const;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE ObstacleService : public EntityServiceT<Obstacle, ObstacleInfo>
|
||||
{
|
||||
public:
|
||||
};
|
||||
|
||||
class ObstacleHandler: public CHandlerBase<Obstacle, ObstacleInfo, ObstacleInfo, ObstacleService>
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<ObstacleInfo> loadFromJson(const std::string & scope,
|
||||
const JsonNode & json,
|
||||
const std::string & identifier,
|
||||
size_t index) override;
|
||||
|
||||
const std::vector<std::string> & getTypeNames() const override;
|
||||
std::vector<JsonNode> loadLegacyData() override;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* ObstacleHandler.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
|
||||
|
||||
#include <vcmi/EntityService.h>
|
||||
#include <vcmi/Entity.h>
|
||||
#include "GameConstants.h"
|
||||
#include "IHandlerBase.h"
|
||||
#include "battle/BattleHexArray.h"
|
||||
#include "filesystem/ResourcePath.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class DLL_LINKAGE ObstacleInfo : public EntityT<Obstacle>
|
||||
{
|
||||
public:
|
||||
ObstacleInfo(): obstacle(-1), width(0), height(0), isAbsoluteObstacle(false), iconIndex(0), isForegroundObstacle(false)
|
||||
{}
|
||||
|
||||
ObstacleInfo(Obstacle obstacle, std::string identifier)
|
||||
: obstacle(obstacle), identifier(identifier), iconIndex(obstacle.getNum()), width(0), height(0), isAbsoluteObstacle(false), isForegroundObstacle(false)
|
||||
{
|
||||
}
|
||||
|
||||
Obstacle obstacle;
|
||||
si32 iconIndex;
|
||||
std::string modScope;
|
||||
std::string identifier;
|
||||
AudioPath appearSound;
|
||||
AnimationPath appearAnimation;
|
||||
AnimationPath animation;
|
||||
std::vector<TerrainId> allowedTerrains;
|
||||
std::vector<std::string> allowedSpecialBfields;
|
||||
|
||||
bool isAbsoluteObstacle; //there may only one such obstacle in battle and its position is always the same
|
||||
bool isForegroundObstacle;
|
||||
si32 width; //how much space to the right and up is needed to place obstacle (affects only placement algorithm)
|
||||
si32 height;
|
||||
std::vector<si16> blockedTiles; //offsets relative to obstacle position (that is its left bottom corner)
|
||||
|
||||
int32_t getIndex() const override;
|
||||
int32_t getIconIndex() const override;
|
||||
std::string getJsonKey() const override;
|
||||
std::string getModScope() const override;
|
||||
std::string getNameTranslated() const override;
|
||||
std::string getNameTextID() const override;
|
||||
void registerIcons(const IconRegistar & cb) const override;
|
||||
Obstacle getId() const override;
|
||||
|
||||
BattleHexArray getBlocked(BattleHex hex) const; //returns vector of hexes blocked by obstacle when it's placed on hex 'hex'
|
||||
|
||||
bool isAppropriate(const TerrainId terrainType, const BattleField & specialBattlefield) const;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE ObstacleService : public EntityServiceT<Obstacle, ObstacleInfo>
|
||||
{
|
||||
public:
|
||||
};
|
||||
|
||||
class ObstacleHandler: public CHandlerBase<Obstacle, ObstacleInfo, ObstacleInfo, ObstacleService>
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<ObstacleInfo> loadFromJson(const std::string & scope,
|
||||
const JsonNode & json,
|
||||
const std::string & identifier,
|
||||
size_t index) override;
|
||||
|
||||
const std::vector<std::string> & getTypeNames() const override;
|
||||
std::vector<JsonNode> loadLegacyData() override;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,138 +1,138 @@
|
||||
/*
|
||||
* BattleHex.cpp, 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
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "BattleHex.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
BattleHex::BattleHex() : hex(INVALID) {}
|
||||
|
||||
BattleHex::BattleHex(si16 _hex) : hex(_hex) {}
|
||||
|
||||
BattleHex::BattleHex(si16 x, si16 y)
|
||||
{
|
||||
setXY(x, y);
|
||||
}
|
||||
|
||||
BattleHex::BattleHex(std::pair<si16, si16> xy)
|
||||
{
|
||||
setXY(xy);
|
||||
}
|
||||
|
||||
BattleHex::operator si16() const
|
||||
{
|
||||
return hex;
|
||||
}
|
||||
|
||||
void BattleHex::setX(si16 x)
|
||||
{
|
||||
setXY(x, getY());
|
||||
}
|
||||
|
||||
void BattleHex::setY(si16 y)
|
||||
{
|
||||
setXY(getX(), y);
|
||||
}
|
||||
|
||||
void BattleHex::setXY(si16 x, si16 y, bool hasToBeValid)
|
||||
{
|
||||
if(hasToBeValid)
|
||||
{
|
||||
if(x < 0 || x >= GameConstants::BFIELD_WIDTH || y < 0 || y >= GameConstants::BFIELD_HEIGHT)
|
||||
throw std::runtime_error("Valid hex required");
|
||||
}
|
||||
|
||||
hex = x + y * GameConstants::BFIELD_WIDTH;
|
||||
}
|
||||
|
||||
void BattleHex::setXY(std::pair<si16, si16> xy)
|
||||
{
|
||||
setXY(xy.first, xy.second);
|
||||
}
|
||||
|
||||
si16 BattleHex::getX() const
|
||||
{
|
||||
return hex % GameConstants::BFIELD_WIDTH;
|
||||
}
|
||||
|
||||
si16 BattleHex::getY() const
|
||||
{
|
||||
return hex / GameConstants::BFIELD_WIDTH;
|
||||
}
|
||||
|
||||
std::pair<si16, si16> BattleHex::getXY() const
|
||||
{
|
||||
return std::make_pair(getX(), getY());
|
||||
}
|
||||
|
||||
BattleHex & BattleHex::moveInDirection(EDir dir, bool hasToBeValid)
|
||||
{
|
||||
si16 x = getX();
|
||||
si16 y = getY();
|
||||
switch(dir)
|
||||
{
|
||||
case TOP_LEFT:
|
||||
setXY((y%2) ? x-1 : x, y-1, hasToBeValid);
|
||||
break;
|
||||
case TOP_RIGHT:
|
||||
setXY((y%2) ? x : x+1, y-1, hasToBeValid);
|
||||
break;
|
||||
case RIGHT:
|
||||
setXY(x+1, y, hasToBeValid);
|
||||
break;
|
||||
case BOTTOM_RIGHT:
|
||||
setXY((y%2) ? x : x+1, y+1, hasToBeValid);
|
||||
break;
|
||||
case BOTTOM_LEFT:
|
||||
setXY((y%2) ? x-1 : x, y+1, hasToBeValid);
|
||||
break;
|
||||
case LEFT:
|
||||
setXY(x-1, y, hasToBeValid);
|
||||
break;
|
||||
case NONE:
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Disaster: wrong direction in BattleHex::operator+=!\n");
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
BattleHex & BattleHex::operator+=(BattleHex::EDir dir)
|
||||
{
|
||||
return moveInDirection(dir);
|
||||
}
|
||||
|
||||
BattleHex BattleHex::cloneInDirection(BattleHex::EDir dir, bool hasToBeValid) const
|
||||
{
|
||||
BattleHex result(hex);
|
||||
result.moveInDirection(dir, hasToBeValid);
|
||||
return result;
|
||||
}
|
||||
|
||||
BattleHex BattleHex::operator+(BattleHex::EDir dir) const
|
||||
{
|
||||
return cloneInDirection(dir);
|
||||
}
|
||||
|
||||
BattleHex::EDir BattleHex::mutualPosition(BattleHex hex1, BattleHex hex2)
|
||||
{
|
||||
for(auto dir : hexagonalDirections())
|
||||
if(hex2 == hex1.cloneInDirection(dir, false))
|
||||
return dir;
|
||||
return NONE;
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream & os, const BattleHex & hex)
|
||||
{
|
||||
return os << boost::str(boost::format("{BattleHex: x '%d', y '%d', hex '%d'}") % hex.getX() % hex.getY() % hex.hex);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* BattleHex.cpp, 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
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "BattleHex.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
BattleHex::BattleHex() : hex(INVALID) {}
|
||||
|
||||
BattleHex::BattleHex(si16 _hex) : hex(_hex) {}
|
||||
|
||||
BattleHex::BattleHex(si16 x, si16 y)
|
||||
{
|
||||
setXY(x, y);
|
||||
}
|
||||
|
||||
BattleHex::BattleHex(std::pair<si16, si16> xy)
|
||||
{
|
||||
setXY(xy);
|
||||
}
|
||||
|
||||
BattleHex::operator si16() const
|
||||
{
|
||||
return hex;
|
||||
}
|
||||
|
||||
void BattleHex::setX(si16 x)
|
||||
{
|
||||
setXY(x, getY());
|
||||
}
|
||||
|
||||
void BattleHex::setY(si16 y)
|
||||
{
|
||||
setXY(getX(), y);
|
||||
}
|
||||
|
||||
void BattleHex::setXY(si16 x, si16 y, bool hasToBeValid)
|
||||
{
|
||||
if(hasToBeValid)
|
||||
{
|
||||
if(x < 0 || x >= GameConstants::BFIELD_WIDTH || y < 0 || y >= GameConstants::BFIELD_HEIGHT)
|
||||
throw std::runtime_error("Valid hex required");
|
||||
}
|
||||
|
||||
hex = x + y * GameConstants::BFIELD_WIDTH;
|
||||
}
|
||||
|
||||
void BattleHex::setXY(std::pair<si16, si16> xy)
|
||||
{
|
||||
setXY(xy.first, xy.second);
|
||||
}
|
||||
|
||||
si16 BattleHex::getX() const
|
||||
{
|
||||
return hex % GameConstants::BFIELD_WIDTH;
|
||||
}
|
||||
|
||||
si16 BattleHex::getY() const
|
||||
{
|
||||
return hex / GameConstants::BFIELD_WIDTH;
|
||||
}
|
||||
|
||||
std::pair<si16, si16> BattleHex::getXY() const
|
||||
{
|
||||
return std::make_pair(getX(), getY());
|
||||
}
|
||||
|
||||
BattleHex & BattleHex::moveInDirection(EDir dir, bool hasToBeValid)
|
||||
{
|
||||
si16 x = getX();
|
||||
si16 y = getY();
|
||||
switch(dir)
|
||||
{
|
||||
case TOP_LEFT:
|
||||
setXY((y%2) ? x-1 : x, y-1, hasToBeValid);
|
||||
break;
|
||||
case TOP_RIGHT:
|
||||
setXY((y%2) ? x : x+1, y-1, hasToBeValid);
|
||||
break;
|
||||
case RIGHT:
|
||||
setXY(x+1, y, hasToBeValid);
|
||||
break;
|
||||
case BOTTOM_RIGHT:
|
||||
setXY((y%2) ? x : x+1, y+1, hasToBeValid);
|
||||
break;
|
||||
case BOTTOM_LEFT:
|
||||
setXY((y%2) ? x-1 : x, y+1, hasToBeValid);
|
||||
break;
|
||||
case LEFT:
|
||||
setXY(x-1, y, hasToBeValid);
|
||||
break;
|
||||
case NONE:
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Disaster: wrong direction in BattleHex::operator+=!\n");
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
BattleHex & BattleHex::operator+=(BattleHex::EDir dir)
|
||||
{
|
||||
return moveInDirection(dir);
|
||||
}
|
||||
|
||||
BattleHex BattleHex::cloneInDirection(BattleHex::EDir dir, bool hasToBeValid) const
|
||||
{
|
||||
BattleHex result(hex);
|
||||
result.moveInDirection(dir, hasToBeValid);
|
||||
return result;
|
||||
}
|
||||
|
||||
BattleHex BattleHex::operator+(BattleHex::EDir dir) const
|
||||
{
|
||||
return cloneInDirection(dir);
|
||||
}
|
||||
|
||||
BattleHex::EDir BattleHex::mutualPosition(BattleHex hex1, BattleHex hex2)
|
||||
{
|
||||
for(auto dir : hexagonalDirections())
|
||||
if(hex2 == hex1.cloneInDirection(dir, false))
|
||||
return dir;
|
||||
return NONE;
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream & os, const BattleHex & hex)
|
||||
{
|
||||
return os << boost::str(boost::format("{BattleHex: x '%d', y '%d', hex '%d'}") % hex.getX() % hex.getY() % hex.hex);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,127 +1,127 @@
|
||||
/*
|
||||
* BattleHex.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
|
||||
|
||||
#include "BattleSide.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
//TODO: change to enum class
|
||||
|
||||
namespace GameConstants
|
||||
{
|
||||
const int BFIELD_WIDTH = 17;
|
||||
const int BFIELD_HEIGHT = 11;
|
||||
const int BFIELD_SIZE = BFIELD_WIDTH * BFIELD_HEIGHT;
|
||||
}
|
||||
|
||||
// for battle stacks' positions
|
||||
struct DLL_LINKAGE BattleHex //TODO: decide if this should be changed to class for better code design
|
||||
{
|
||||
// helpers for siege
|
||||
static constexpr si16 CASTLE_CENTRAL_TOWER = -2;
|
||||
static constexpr si16 CASTLE_BOTTOM_TOWER = -3;
|
||||
static constexpr si16 CASTLE_UPPER_TOWER = -4;
|
||||
|
||||
// hexes for interaction with heroes
|
||||
static constexpr si16 HERO_ATTACKER = 0;
|
||||
static constexpr si16 HERO_DEFENDER = GameConstants::BFIELD_WIDTH - 1;
|
||||
|
||||
// helpers for rendering
|
||||
static constexpr si16 HEX_BEFORE_ALL = std::numeric_limits<si16>::min();
|
||||
static constexpr si16 HEX_AFTER_ALL = std::numeric_limits<si16>::max();
|
||||
|
||||
static constexpr si16 DESTRUCTIBLE_WALL_1 = 29;
|
||||
static constexpr si16 DESTRUCTIBLE_WALL_2 = 78;
|
||||
static constexpr si16 DESTRUCTIBLE_WALL_3 = 130;
|
||||
static constexpr si16 DESTRUCTIBLE_WALL_4 = 182;
|
||||
static constexpr si16 GATE_BRIDGE = 94;
|
||||
static constexpr si16 GATE_OUTER = 95;
|
||||
static constexpr si16 GATE_INNER = 96;
|
||||
|
||||
si16 hex;
|
||||
static constexpr si16 INVALID = -1;
|
||||
enum EDir
|
||||
{
|
||||
NONE = -1,
|
||||
|
||||
TOP_LEFT,
|
||||
TOP_RIGHT,
|
||||
RIGHT,
|
||||
BOTTOM_RIGHT,
|
||||
BOTTOM_LEFT,
|
||||
LEFT,
|
||||
|
||||
//Note: unused by BattleHex class, used by other code
|
||||
TOP,
|
||||
BOTTOM
|
||||
};
|
||||
|
||||
BattleHex();
|
||||
BattleHex(si16 _hex);
|
||||
BattleHex(si16 x, si16 y);
|
||||
BattleHex(std::pair<si16, si16> xy);
|
||||
operator si16() const;
|
||||
inline bool isValid() const
|
||||
{
|
||||
return hex >= 0 && hex < GameConstants::BFIELD_SIZE;
|
||||
}
|
||||
|
||||
bool isAvailable() const //valid position not in first or last column
|
||||
{
|
||||
return isValid() && getX() > 0 && getX() < GameConstants::BFIELD_WIDTH - 1;
|
||||
}
|
||||
|
||||
void setX(si16 x);
|
||||
void setY(si16 y);
|
||||
void setXY(si16 x, si16 y, bool hasToBeValid = true);
|
||||
void setXY(std::pair<si16, si16> xy);
|
||||
si16 getX() const;
|
||||
si16 getY() const;
|
||||
std::pair<si16, si16> getXY() const;
|
||||
BattleHex& moveInDirection(EDir dir, bool hasToBeValid = true);
|
||||
BattleHex& operator+=(EDir dir);
|
||||
BattleHex cloneInDirection(EDir dir, bool hasToBeValid = true) const;
|
||||
BattleHex operator+(EDir dir) const;
|
||||
|
||||
static EDir mutualPosition(BattleHex hex1, BattleHex hex2);
|
||||
static uint8_t getDistance(BattleHex hex1, BattleHex hex2)
|
||||
{
|
||||
int y1 = hex1.getY();
|
||||
int y2 = hex2.getY();
|
||||
|
||||
// FIXME: why there was * 0.5 instead of / 2?
|
||||
int x1 = static_cast<int>(hex1.getX() + y1 / 2);
|
||||
int x2 = static_cast<int>(hex2.getX() + y2 / 2);
|
||||
|
||||
int xDst = x2 - x1;
|
||||
int yDst = y2 - y1;
|
||||
|
||||
if((xDst >= 0 && yDst >= 0) || (xDst < 0 && yDst < 0))
|
||||
return std::max(std::abs(xDst), std::abs(yDst));
|
||||
|
||||
return std::abs(xDst) + std::abs(yDst);
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
void serialize(Handler &h)
|
||||
{
|
||||
h & hex;
|
||||
}
|
||||
|
||||
//Constexpr defined array with all directions used in battle
|
||||
static constexpr auto hexagonalDirections() {
|
||||
return std::array<EDir,6>{BattleHex::TOP_LEFT, BattleHex::TOP_RIGHT, BattleHex::RIGHT, BattleHex::BOTTOM_RIGHT, BattleHex::BOTTOM_LEFT, BattleHex::LEFT};
|
||||
}
|
||||
};
|
||||
|
||||
DLL_EXPORT std::ostream & operator<<(std::ostream & os, const BattleHex & hex);
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* BattleHex.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
|
||||
|
||||
#include "BattleSide.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
//TODO: change to enum class
|
||||
|
||||
namespace GameConstants
|
||||
{
|
||||
const int BFIELD_WIDTH = 17;
|
||||
const int BFIELD_HEIGHT = 11;
|
||||
const int BFIELD_SIZE = BFIELD_WIDTH * BFIELD_HEIGHT;
|
||||
}
|
||||
|
||||
// for battle stacks' positions
|
||||
struct DLL_LINKAGE BattleHex //TODO: decide if this should be changed to class for better code design
|
||||
{
|
||||
// helpers for siege
|
||||
static constexpr si16 CASTLE_CENTRAL_TOWER = -2;
|
||||
static constexpr si16 CASTLE_BOTTOM_TOWER = -3;
|
||||
static constexpr si16 CASTLE_UPPER_TOWER = -4;
|
||||
|
||||
// hexes for interaction with heroes
|
||||
static constexpr si16 HERO_ATTACKER = 0;
|
||||
static constexpr si16 HERO_DEFENDER = GameConstants::BFIELD_WIDTH - 1;
|
||||
|
||||
// helpers for rendering
|
||||
static constexpr si16 HEX_BEFORE_ALL = std::numeric_limits<si16>::min();
|
||||
static constexpr si16 HEX_AFTER_ALL = std::numeric_limits<si16>::max();
|
||||
|
||||
static constexpr si16 DESTRUCTIBLE_WALL_1 = 29;
|
||||
static constexpr si16 DESTRUCTIBLE_WALL_2 = 78;
|
||||
static constexpr si16 DESTRUCTIBLE_WALL_3 = 130;
|
||||
static constexpr si16 DESTRUCTIBLE_WALL_4 = 182;
|
||||
static constexpr si16 GATE_BRIDGE = 94;
|
||||
static constexpr si16 GATE_OUTER = 95;
|
||||
static constexpr si16 GATE_INNER = 96;
|
||||
|
||||
si16 hex;
|
||||
static constexpr si16 INVALID = -1;
|
||||
enum EDir
|
||||
{
|
||||
NONE = -1,
|
||||
|
||||
TOP_LEFT,
|
||||
TOP_RIGHT,
|
||||
RIGHT,
|
||||
BOTTOM_RIGHT,
|
||||
BOTTOM_LEFT,
|
||||
LEFT,
|
||||
|
||||
//Note: unused by BattleHex class, used by other code
|
||||
TOP,
|
||||
BOTTOM
|
||||
};
|
||||
|
||||
BattleHex();
|
||||
BattleHex(si16 _hex);
|
||||
BattleHex(si16 x, si16 y);
|
||||
BattleHex(std::pair<si16, si16> xy);
|
||||
operator si16() const;
|
||||
inline bool isValid() const
|
||||
{
|
||||
return hex >= 0 && hex < GameConstants::BFIELD_SIZE;
|
||||
}
|
||||
|
||||
bool isAvailable() const //valid position not in first or last column
|
||||
{
|
||||
return isValid() && getX() > 0 && getX() < GameConstants::BFIELD_WIDTH - 1;
|
||||
}
|
||||
|
||||
void setX(si16 x);
|
||||
void setY(si16 y);
|
||||
void setXY(si16 x, si16 y, bool hasToBeValid = true);
|
||||
void setXY(std::pair<si16, si16> xy);
|
||||
si16 getX() const;
|
||||
si16 getY() const;
|
||||
std::pair<si16, si16> getXY() const;
|
||||
BattleHex& moveInDirection(EDir dir, bool hasToBeValid = true);
|
||||
BattleHex& operator+=(EDir dir);
|
||||
BattleHex cloneInDirection(EDir dir, bool hasToBeValid = true) const;
|
||||
BattleHex operator+(EDir dir) const;
|
||||
|
||||
static EDir mutualPosition(BattleHex hex1, BattleHex hex2);
|
||||
static uint8_t getDistance(BattleHex hex1, BattleHex hex2)
|
||||
{
|
||||
int y1 = hex1.getY();
|
||||
int y2 = hex2.getY();
|
||||
|
||||
// FIXME: why there was * 0.5 instead of / 2?
|
||||
int x1 = static_cast<int>(hex1.getX() + y1 / 2);
|
||||
int x2 = static_cast<int>(hex2.getX() + y2 / 2);
|
||||
|
||||
int xDst = x2 - x1;
|
||||
int yDst = y2 - y1;
|
||||
|
||||
if((xDst >= 0 && yDst >= 0) || (xDst < 0 && yDst < 0))
|
||||
return std::max(std::abs(xDst), std::abs(yDst));
|
||||
|
||||
return std::abs(xDst) + std::abs(yDst);
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
void serialize(Handler &h)
|
||||
{
|
||||
h & hex;
|
||||
}
|
||||
|
||||
//Constexpr defined array with all directions used in battle
|
||||
static constexpr auto hexagonalDirections() {
|
||||
return std::array<EDir,6>{BattleHex::TOP_LEFT, BattleHex::TOP_RIGHT, BattleHex::RIGHT, BattleHex::BOTTOM_RIGHT, BattleHex::BOTTOM_LEFT, BattleHex::LEFT};
|
||||
}
|
||||
};
|
||||
|
||||
DLL_EXPORT std::ostream & operator<<(std::ostream & os, const BattleHex & hex);
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,43 +1,43 @@
|
||||
/*
|
||||
* Destination.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
|
||||
|
||||
#include "BattleHexArray.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
namespace battle
|
||||
{
|
||||
|
||||
class Unit;
|
||||
|
||||
class DLL_LINKAGE Destination
|
||||
{
|
||||
public:
|
||||
Destination();
|
||||
~Destination() = default;
|
||||
explicit Destination(const Unit * destination);
|
||||
explicit Destination(const BattleHex & destination);
|
||||
explicit Destination(const Unit * destination, const BattleHex & exactHex);
|
||||
|
||||
Destination(const Destination & other) = default;
|
||||
|
||||
Destination & operator=(const Destination & other) = default;
|
||||
|
||||
const Unit * unitValue;
|
||||
BattleHex hexValue;
|
||||
};
|
||||
|
||||
using Target = std::vector<Destination>;
|
||||
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* Destination.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
|
||||
|
||||
#include "BattleHexArray.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
namespace battle
|
||||
{
|
||||
|
||||
class Unit;
|
||||
|
||||
class DLL_LINKAGE Destination
|
||||
{
|
||||
public:
|
||||
Destination();
|
||||
~Destination() = default;
|
||||
explicit Destination(const Unit * destination);
|
||||
explicit Destination(const BattleHex & destination);
|
||||
explicit Destination(const Unit * destination, const BattleHex & exactHex);
|
||||
|
||||
Destination(const Destination & other) = default;
|
||||
|
||||
Destination & operator=(const Destination & other) = default;
|
||||
|
||||
const Unit * unitValue;
|
||||
BattleHex hexValue;
|
||||
};
|
||||
|
||||
using Target = std::vector<Destination>;
|
||||
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,89 +1,89 @@
|
||||
/*
|
||||
* IBattleInfoCallback.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
|
||||
|
||||
#include "GameConstants.h"
|
||||
#include "BattleHexArray.h"
|
||||
|
||||
#include <vcmi/Entity.h>
|
||||
|
||||
#define RETURN_IF_NOT_BATTLE(...) do { if(!duringBattle()) {logGlobal->error("%s called when no battle!", __FUNCTION__); return __VA_ARGS__; } } while (false)
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct CObstacleInstance;
|
||||
class BattleField;
|
||||
class IBattleInfo;
|
||||
|
||||
namespace battle
|
||||
{
|
||||
class IUnitInfo;
|
||||
class Unit;
|
||||
using Units = std::vector<const Unit *>;
|
||||
using UnitFilter = std::function<bool(const Unit *)>;
|
||||
}
|
||||
|
||||
struct DamageRange
|
||||
{
|
||||
int64_t min = 0;
|
||||
int64_t max = 0;
|
||||
};
|
||||
|
||||
struct DamageEstimation
|
||||
{
|
||||
DamageRange damage;
|
||||
DamageRange kills;
|
||||
};
|
||||
|
||||
#if SCRIPTING_ENABLED
|
||||
namespace scripting
|
||||
{
|
||||
class Pool;
|
||||
}
|
||||
#endif
|
||||
|
||||
class DLL_LINKAGE IBattleInfoCallback : public IConstBonusProvider
|
||||
{
|
||||
public:
|
||||
#if SCRIPTING_ENABLED
|
||||
virtual scripting::Pool * getContextPool() const = 0;
|
||||
#endif
|
||||
virtual ~IBattleInfoCallback() = default;
|
||||
|
||||
virtual const IBattleInfo * getBattle() const = 0;
|
||||
virtual std::optional<PlayerColor> getPlayerID() const = 0;
|
||||
|
||||
virtual TerrainId battleTerrainType() const = 0;
|
||||
virtual BattleField battleGetBattlefieldType() const = 0;
|
||||
|
||||
///return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw
|
||||
virtual std::optional<BattleSide> battleIsFinished() const = 0;
|
||||
|
||||
virtual si8 battleTacticDist() const = 0; //returns tactic distance in current tactics phase; 0 if not in tactics phase
|
||||
virtual BattleSide battleGetTacticsSide() const = 0; //returns which side is in tactics phase, undefined if none (?)
|
||||
|
||||
virtual uint32_t battleNextUnitId() const = 0;
|
||||
|
||||
virtual battle::Units battleGetUnitsIf(const battle::UnitFilter & predicate) const = 0;
|
||||
|
||||
virtual const battle::Unit * battleGetUnitByID(uint32_t ID) const = 0;
|
||||
virtual const battle::Unit * battleGetUnitByPos(BattleHex pos, bool onlyAlive = true) const = 0;
|
||||
|
||||
virtual const battle::Unit * battleActiveUnit() const = 0;
|
||||
|
||||
//blocking obstacles makes tile inaccessible, others cause special effects (like Land Mines, Moat, Quicksands)
|
||||
virtual std::vector<std::shared_ptr<const CObstacleInstance>> battleGetAllObstaclesOnPos(BattleHex tile, bool onlyBlocking = true) const = 0;
|
||||
virtual std::vector<std::shared_ptr<const CObstacleInstance>> getAllAffectedObstaclesByStack(const battle::Unit * unit, const BattleHexArray & passed) const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* IBattleInfoCallback.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
|
||||
|
||||
#include "GameConstants.h"
|
||||
#include "BattleHexArray.h"
|
||||
|
||||
#include <vcmi/Entity.h>
|
||||
|
||||
#define RETURN_IF_NOT_BATTLE(...) do { if(!duringBattle()) {logGlobal->error("%s called when no battle!", __FUNCTION__); return __VA_ARGS__; } } while (false)
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct CObstacleInstance;
|
||||
class BattleField;
|
||||
class IBattleInfo;
|
||||
|
||||
namespace battle
|
||||
{
|
||||
class IUnitInfo;
|
||||
class Unit;
|
||||
using Units = std::vector<const Unit *>;
|
||||
using UnitFilter = std::function<bool(const Unit *)>;
|
||||
}
|
||||
|
||||
struct DamageRange
|
||||
{
|
||||
int64_t min = 0;
|
||||
int64_t max = 0;
|
||||
};
|
||||
|
||||
struct DamageEstimation
|
||||
{
|
||||
DamageRange damage;
|
||||
DamageRange kills;
|
||||
};
|
||||
|
||||
#if SCRIPTING_ENABLED
|
||||
namespace scripting
|
||||
{
|
||||
class Pool;
|
||||
}
|
||||
#endif
|
||||
|
||||
class DLL_LINKAGE IBattleInfoCallback : public IConstBonusProvider
|
||||
{
|
||||
public:
|
||||
#if SCRIPTING_ENABLED
|
||||
virtual scripting::Pool * getContextPool() const = 0;
|
||||
#endif
|
||||
virtual ~IBattleInfoCallback() = default;
|
||||
|
||||
virtual const IBattleInfo * getBattle() const = 0;
|
||||
virtual std::optional<PlayerColor> getPlayerID() const = 0;
|
||||
|
||||
virtual TerrainId battleTerrainType() const = 0;
|
||||
virtual BattleField battleGetBattlefieldType() const = 0;
|
||||
|
||||
///return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw
|
||||
virtual std::optional<BattleSide> battleIsFinished() const = 0;
|
||||
|
||||
virtual si8 battleTacticDist() const = 0; //returns tactic distance in current tactics phase; 0 if not in tactics phase
|
||||
virtual BattleSide battleGetTacticsSide() const = 0; //returns which side is in tactics phase, undefined if none (?)
|
||||
|
||||
virtual uint32_t battleNextUnitId() const = 0;
|
||||
|
||||
virtual battle::Units battleGetUnitsIf(const battle::UnitFilter & predicate) const = 0;
|
||||
|
||||
virtual const battle::Unit * battleGetUnitByID(uint32_t ID) const = 0;
|
||||
virtual const battle::Unit * battleGetUnitByPos(BattleHex pos, bool onlyAlive = true) const = 0;
|
||||
|
||||
virtual const battle::Unit * battleActiveUnit() const = 0;
|
||||
|
||||
//blocking obstacles makes tile inaccessible, others cause special effects (like Land Mines, Moat, Quicksands)
|
||||
virtual std::vector<std::shared_ptr<const CObstacleInstance>> battleGetAllObstaclesOnPos(BattleHex tile, bool onlyBlocking = true) const = 0;
|
||||
virtual std::vector<std::shared_ptr<const CObstacleInstance>> getAllAffectedObstaclesByStack(const battle::Unit * unit, const BattleHexArray & passed) const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,89 +1,89 @@
|
||||
/*
|
||||
* ReachabilityInfo.cpp, 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "ReachabilityInfo.h"
|
||||
#include "Unit.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
ReachabilityInfo::Parameters::Parameters(const battle::Unit * Stack, BattleHex StartPosition):
|
||||
perspective(static_cast<BattleSide>(Stack->unitSide())),
|
||||
startPosition(StartPosition),
|
||||
doubleWide(Stack->doubleWide()),
|
||||
side(Stack->unitSide()),
|
||||
flying(Stack->hasBonusOfType(BonusType::FLYING))
|
||||
{
|
||||
knownAccessible = battle::Unit::getHexes(startPosition, doubleWide, side);
|
||||
}
|
||||
|
||||
ReachabilityInfo::ReachabilityInfo()
|
||||
{
|
||||
distances.fill(INFINITE_DIST);
|
||||
predecessors.fill(BattleHex::INVALID);
|
||||
}
|
||||
|
||||
bool ReachabilityInfo::isReachable(BattleHex hex) const
|
||||
{
|
||||
return distances[hex] < INFINITE_DIST;
|
||||
}
|
||||
|
||||
uint32_t ReachabilityInfo::distToNearestNeighbour(
|
||||
const BattleHexArray & targetHexes,
|
||||
BattleHex * chosenHex) const
|
||||
{
|
||||
uint32_t ret = 1000000;
|
||||
|
||||
for(auto targetHex : targetHexes)
|
||||
{
|
||||
for(auto & n : BattleHexArray::neighbouringTilesCache[targetHex])
|
||||
{
|
||||
if(distances[n] < ret)
|
||||
{
|
||||
ret = distances[n];
|
||||
if(chosenHex)
|
||||
*chosenHex = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t ReachabilityInfo::distToNearestNeighbour(
|
||||
const battle::Unit * attacker,
|
||||
const battle::Unit * defender,
|
||||
BattleHex * chosenHex) const
|
||||
{
|
||||
auto attackableHexes = defender->getHexes();
|
||||
|
||||
if(attacker->doubleWide())
|
||||
{
|
||||
if(defender->doubleWide())
|
||||
{
|
||||
// It can be back to back attack o==o or head to head =oo=.
|
||||
// In case of back-to-back the distance between heads (unit positions) may be up to 3 tiles
|
||||
attackableHexes.merge(battle::Unit::getHexes(defender->occupiedHex(), true, defender->unitSide()));
|
||||
}
|
||||
else
|
||||
{
|
||||
attackableHexes.merge(battle::Unit::getHexes(defender->getPosition(), true, defender->unitSide()));
|
||||
}
|
||||
}
|
||||
|
||||
vstd::erase_if(attackableHexes, [defender](BattleHex h) -> bool
|
||||
{
|
||||
return h.getY() != defender->getPosition().getY() || !h.isAvailable();
|
||||
});
|
||||
|
||||
return distToNearestNeighbour(attackableHexes, chosenHex);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* ReachabilityInfo.cpp, 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "ReachabilityInfo.h"
|
||||
#include "Unit.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
ReachabilityInfo::Parameters::Parameters(const battle::Unit * Stack, BattleHex StartPosition):
|
||||
perspective(static_cast<BattleSide>(Stack->unitSide())),
|
||||
startPosition(StartPosition),
|
||||
doubleWide(Stack->doubleWide()),
|
||||
side(Stack->unitSide()),
|
||||
flying(Stack->hasBonusOfType(BonusType::FLYING))
|
||||
{
|
||||
knownAccessible = battle::Unit::getHexes(startPosition, doubleWide, side);
|
||||
}
|
||||
|
||||
ReachabilityInfo::ReachabilityInfo()
|
||||
{
|
||||
distances.fill(INFINITE_DIST);
|
||||
predecessors.fill(BattleHex::INVALID);
|
||||
}
|
||||
|
||||
bool ReachabilityInfo::isReachable(BattleHex hex) const
|
||||
{
|
||||
return distances[hex] < INFINITE_DIST;
|
||||
}
|
||||
|
||||
uint32_t ReachabilityInfo::distToNearestNeighbour(
|
||||
const BattleHexArray & targetHexes,
|
||||
BattleHex * chosenHex) const
|
||||
{
|
||||
uint32_t ret = 1000000;
|
||||
|
||||
for(auto targetHex : targetHexes)
|
||||
{
|
||||
for(auto & n : BattleHexArray::neighbouringTilesCache[targetHex])
|
||||
{
|
||||
if(distances[n] < ret)
|
||||
{
|
||||
ret = distances[n];
|
||||
if(chosenHex)
|
||||
*chosenHex = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t ReachabilityInfo::distToNearestNeighbour(
|
||||
const battle::Unit * attacker,
|
||||
const battle::Unit * defender,
|
||||
BattleHex * chosenHex) const
|
||||
{
|
||||
auto attackableHexes = defender->getHexes();
|
||||
|
||||
if(attacker->doubleWide())
|
||||
{
|
||||
if(defender->doubleWide())
|
||||
{
|
||||
// It can be back to back attack o==o or head to head =oo=.
|
||||
// In case of back-to-back the distance between heads (unit positions) may be up to 3 tiles
|
||||
attackableHexes.merge(battle::Unit::getHexes(defender->occupiedHex(), true, defender->unitSide()));
|
||||
}
|
||||
else
|
||||
{
|
||||
attackableHexes.merge(battle::Unit::getHexes(defender->getPosition(), true, defender->unitSide()));
|
||||
}
|
||||
}
|
||||
|
||||
vstd::erase_if(attackableHexes, [defender](BattleHex h) -> bool
|
||||
{
|
||||
return h.getY() != defender->getPosition().getY() || !h.isAvailable();
|
||||
});
|
||||
|
||||
return distToNearestNeighbour(attackableHexes, chosenHex);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -220,8 +220,8 @@ ILimiter::EDecision UnitOnHexLimiter::limit(const BonusLimitationContext &contex
|
||||
return ILimiter::EDecision::DISCARD;
|
||||
|
||||
auto accept = false;
|
||||
for (const auto & hex : stack->getHexes())
|
||||
accept |= !!applicableHexes.count(hex);
|
||||
for (auto hex : stack->getHexes())
|
||||
accept |= applicableHexes.contains(hex);
|
||||
|
||||
return accept ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
||||
}
|
||||
@@ -236,7 +236,7 @@ JsonNode UnitOnHexLimiter::toJsonNode() const
|
||||
JsonNode root;
|
||||
|
||||
root["type"].String() = "UNIT_ON_HEXES";
|
||||
for(const auto & hex : applicableHexes)
|
||||
for(auto hex : applicableHexes)
|
||||
root["parameters"].Vector().emplace_back(hex);
|
||||
|
||||
return root;
|
||||
|
@@ -1,243 +1,243 @@
|
||||
/*
|
||||
* CGPathNode.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
|
||||
|
||||
#include "../GameConstants.h"
|
||||
#include "../int3.h"
|
||||
|
||||
#include <boost/heap/fibonacci_heap.hpp>
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CGHeroInstance;
|
||||
class CGObjectInstance;
|
||||
class CGameState;
|
||||
class CPathfinderHelper;
|
||||
struct TerrainTile;
|
||||
|
||||
template<typename N>
|
||||
struct DLL_LINKAGE NodeComparer
|
||||
{
|
||||
STRONG_INLINE
|
||||
bool operator()(const N * lhs, const N * rhs) const
|
||||
{
|
||||
return lhs->getCost() > rhs->getCost();
|
||||
}
|
||||
};
|
||||
|
||||
enum class EPathAccessibility : ui8
|
||||
{
|
||||
NOT_SET,
|
||||
ACCESSIBLE, //tile can be entered and passed
|
||||
VISITABLE, //tile can be entered as the last tile in path
|
||||
GUARDED, //tile can be entered, but is in zone of control of nearby monster (may also contain visitable object, if any)
|
||||
BLOCKVIS, //visitable from neighbouring tile but not passable
|
||||
FLYABLE, //can only be accessed in air layer
|
||||
BLOCKED //tile can be neither entered nor visited
|
||||
};
|
||||
|
||||
enum class EPathNodeAction : ui8
|
||||
{
|
||||
UNKNOWN,
|
||||
EMBARK,
|
||||
DISEMBARK,
|
||||
NORMAL,
|
||||
BATTLE,
|
||||
VISIT,
|
||||
BLOCKING_VISIT,
|
||||
TELEPORT_NORMAL,
|
||||
TELEPORT_BLOCKING_VISIT,
|
||||
TELEPORT_BATTLE
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE CGPathNode
|
||||
{
|
||||
using TFibHeap = boost::heap::fibonacci_heap<CGPathNode *, boost::heap::compare<NodeComparer<CGPathNode>>>;
|
||||
using ELayer = EPathfindingLayer;
|
||||
|
||||
TFibHeap::handle_type pqHandle;
|
||||
TFibHeap * pq;
|
||||
CGPathNode * theNodeBefore;
|
||||
|
||||
int3 coord; //coordinates
|
||||
ELayer layer;
|
||||
|
||||
float cost; //total cost of the path to this tile measured in turns with fractions
|
||||
int moveRemains; //remaining movement points after hero reaches the tile
|
||||
ui8 turns; //how many turns we have to wait before reaching the tile - 0 means current turn
|
||||
EPathAccessibility accessible;
|
||||
EPathNodeAction action;
|
||||
bool locked;
|
||||
|
||||
CGPathNode()
|
||||
: coord(-1),
|
||||
layer(ELayer::WRONG),
|
||||
pqHandle(nullptr)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
STRONG_INLINE
|
||||
void reset()
|
||||
{
|
||||
locked = false;
|
||||
accessible = EPathAccessibility::NOT_SET;
|
||||
moveRemains = 0;
|
||||
cost = std::numeric_limits<float>::max();
|
||||
turns = 255;
|
||||
theNodeBefore = nullptr;
|
||||
pq = nullptr;
|
||||
action = EPathNodeAction::UNKNOWN;
|
||||
}
|
||||
|
||||
STRONG_INLINE
|
||||
bool inPQ() const
|
||||
{
|
||||
return pq != nullptr;
|
||||
}
|
||||
|
||||
STRONG_INLINE
|
||||
float getCost() const
|
||||
{
|
||||
return cost;
|
||||
}
|
||||
|
||||
STRONG_INLINE
|
||||
void setCost(float value)
|
||||
{
|
||||
if(vstd::isAlmostEqual(value, cost))
|
||||
return;
|
||||
|
||||
bool getUpNode = value < cost;
|
||||
cost = value;
|
||||
// If the node is in the heap, update the heap.
|
||||
if(inPQ())
|
||||
{
|
||||
if(getUpNode)
|
||||
{
|
||||
pq->increase(this->pqHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
pq->decrease(this->pqHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STRONG_INLINE
|
||||
void update(const int3 & Coord, const ELayer Layer, const EPathAccessibility Accessible)
|
||||
{
|
||||
if(layer == ELayer::WRONG)
|
||||
{
|
||||
coord = Coord;
|
||||
layer = Layer;
|
||||
}
|
||||
else
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
accessible = Accessible;
|
||||
}
|
||||
|
||||
STRONG_INLINE
|
||||
bool reachable() const
|
||||
{
|
||||
return turns < 255;
|
||||
}
|
||||
|
||||
bool isTeleportAction() const
|
||||
{
|
||||
if (action != EPathNodeAction::TELEPORT_NORMAL &&
|
||||
action != EPathNodeAction::TELEPORT_BLOCKING_VISIT &&
|
||||
action != EPathNodeAction::TELEPORT_BATTLE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE CGPath
|
||||
{
|
||||
std::vector<CGPathNode> nodes; //just get node by node
|
||||
|
||||
/// Starting position of path, matches location of hero
|
||||
const CGPathNode & currNode() const;
|
||||
/// First node in path, this is where hero will move next
|
||||
const CGPathNode & nextNode() const;
|
||||
/// Last node in path, this is what hero wants to reach in the end
|
||||
const CGPathNode & lastNode() const;
|
||||
|
||||
int3 startPos() const; // start point
|
||||
int3 endPos() const; //destination point
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE CPathsInfo
|
||||
{
|
||||
using ELayer = EPathfindingLayer;
|
||||
|
||||
const CGHeroInstance * hero;
|
||||
int3 hpos;
|
||||
int3 sizes;
|
||||
boost::multi_array<CGPathNode, 4> nodes; //[layer][level][w][h]
|
||||
|
||||
CPathsInfo(const int3 & Sizes, const CGHeroInstance * hero_);
|
||||
~CPathsInfo();
|
||||
const CGPathNode * getPathInfo(const int3 & tile) const;
|
||||
bool getPath(CGPath & out, const int3 & dst) const;
|
||||
const CGPathNode * getNode(const int3 & coord) const;
|
||||
|
||||
STRONG_INLINE
|
||||
CGPathNode * getNode(const int3 & coord, const ELayer layer)
|
||||
{
|
||||
return &nodes[layer.getNum()][coord.z][coord.x][coord.y];
|
||||
}
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE PathNodeInfo
|
||||
{
|
||||
CGPathNode * node;
|
||||
const CGObjectInstance * nodeObject;
|
||||
const CGHeroInstance * nodeHero;
|
||||
const TerrainTile * tile;
|
||||
int3 coord;
|
||||
bool guarded;
|
||||
PlayerRelations objectRelations;
|
||||
PlayerRelations heroRelations;
|
||||
bool isInitialPosition;
|
||||
|
||||
PathNodeInfo();
|
||||
|
||||
virtual void setNode(CGameState * gs, CGPathNode * n);
|
||||
|
||||
void updateInfo(CPathfinderHelper * hlp, CGameState * gs);
|
||||
|
||||
bool isNodeObjectVisitable() const;
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE CDestinationNodeInfo : public PathNodeInfo
|
||||
{
|
||||
EPathNodeAction action;
|
||||
int turn;
|
||||
int movementLeft;
|
||||
float cost; //same as CGPathNode::cost
|
||||
bool blocked;
|
||||
bool isGuardianTile;
|
||||
|
||||
CDestinationNodeInfo();
|
||||
|
||||
void setNode(CGameState * gs, CGPathNode * n) override;
|
||||
|
||||
virtual bool isBetterWay() const;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* CGPathNode.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
|
||||
|
||||
#include "../GameConstants.h"
|
||||
#include "../int3.h"
|
||||
|
||||
#include <boost/heap/fibonacci_heap.hpp>
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CGHeroInstance;
|
||||
class CGObjectInstance;
|
||||
class CGameState;
|
||||
class CPathfinderHelper;
|
||||
struct TerrainTile;
|
||||
|
||||
template<typename N>
|
||||
struct DLL_LINKAGE NodeComparer
|
||||
{
|
||||
STRONG_INLINE
|
||||
bool operator()(const N * lhs, const N * rhs) const
|
||||
{
|
||||
return lhs->getCost() > rhs->getCost();
|
||||
}
|
||||
};
|
||||
|
||||
enum class EPathAccessibility : ui8
|
||||
{
|
||||
NOT_SET,
|
||||
ACCESSIBLE, //tile can be entered and passed
|
||||
VISITABLE, //tile can be entered as the last tile in path
|
||||
GUARDED, //tile can be entered, but is in zone of control of nearby monster (may also contain visitable object, if any)
|
||||
BLOCKVIS, //visitable from neighboring tile but not passable
|
||||
FLYABLE, //can only be accessed in air layer
|
||||
BLOCKED //tile can be neither entered nor visited
|
||||
};
|
||||
|
||||
enum class EPathNodeAction : ui8
|
||||
{
|
||||
UNKNOWN,
|
||||
EMBARK,
|
||||
DISEMBARK,
|
||||
NORMAL,
|
||||
BATTLE,
|
||||
VISIT,
|
||||
BLOCKING_VISIT,
|
||||
TELEPORT_NORMAL,
|
||||
TELEPORT_BLOCKING_VISIT,
|
||||
TELEPORT_BATTLE
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE CGPathNode
|
||||
{
|
||||
using TFibHeap = boost::heap::fibonacci_heap<CGPathNode *, boost::heap::compare<NodeComparer<CGPathNode>>>;
|
||||
using ELayer = EPathfindingLayer;
|
||||
|
||||
TFibHeap::handle_type pqHandle;
|
||||
TFibHeap * pq;
|
||||
CGPathNode * theNodeBefore;
|
||||
|
||||
int3 coord; //coordinates
|
||||
ELayer layer;
|
||||
|
||||
float cost; //total cost of the path to this tile measured in turns with fractions
|
||||
int moveRemains; //remaining movement points after hero reaches the tile
|
||||
ui8 turns; //how many turns we have to wait before reaching the tile - 0 means current turn
|
||||
EPathAccessibility accessible;
|
||||
EPathNodeAction action;
|
||||
bool locked;
|
||||
|
||||
CGPathNode()
|
||||
: coord(-1),
|
||||
layer(ELayer::WRONG),
|
||||
pqHandle(nullptr)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
STRONG_INLINE
|
||||
void reset()
|
||||
{
|
||||
locked = false;
|
||||
accessible = EPathAccessibility::NOT_SET;
|
||||
moveRemains = 0;
|
||||
cost = std::numeric_limits<float>::max();
|
||||
turns = 255;
|
||||
theNodeBefore = nullptr;
|
||||
pq = nullptr;
|
||||
action = EPathNodeAction::UNKNOWN;
|
||||
}
|
||||
|
||||
STRONG_INLINE
|
||||
bool inPQ() const
|
||||
{
|
||||
return pq != nullptr;
|
||||
}
|
||||
|
||||
STRONG_INLINE
|
||||
float getCost() const
|
||||
{
|
||||
return cost;
|
||||
}
|
||||
|
||||
STRONG_INLINE
|
||||
void setCost(float value)
|
||||
{
|
||||
if(vstd::isAlmostEqual(value, cost))
|
||||
return;
|
||||
|
||||
bool getUpNode = value < cost;
|
||||
cost = value;
|
||||
// If the node is in the heap, update the heap.
|
||||
if(inPQ())
|
||||
{
|
||||
if(getUpNode)
|
||||
{
|
||||
pq->increase(this->pqHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
pq->decrease(this->pqHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STRONG_INLINE
|
||||
void update(const int3 & Coord, const ELayer Layer, const EPathAccessibility Accessible)
|
||||
{
|
||||
if(layer == ELayer::WRONG)
|
||||
{
|
||||
coord = Coord;
|
||||
layer = Layer;
|
||||
}
|
||||
else
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
accessible = Accessible;
|
||||
}
|
||||
|
||||
STRONG_INLINE
|
||||
bool reachable() const
|
||||
{
|
||||
return turns < 255;
|
||||
}
|
||||
|
||||
bool isTeleportAction() const
|
||||
{
|
||||
if (action != EPathNodeAction::TELEPORT_NORMAL &&
|
||||
action != EPathNodeAction::TELEPORT_BLOCKING_VISIT &&
|
||||
action != EPathNodeAction::TELEPORT_BATTLE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE CGPath
|
||||
{
|
||||
std::vector<CGPathNode> nodes; //just get node by node
|
||||
|
||||
/// Starting position of path, matches location of hero
|
||||
const CGPathNode & currNode() const;
|
||||
/// First node in path, this is where hero will move next
|
||||
const CGPathNode & nextNode() const;
|
||||
/// Last node in path, this is what hero wants to reach in the end
|
||||
const CGPathNode & lastNode() const;
|
||||
|
||||
int3 startPos() const; // start point
|
||||
int3 endPos() const; //destination point
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE CPathsInfo
|
||||
{
|
||||
using ELayer = EPathfindingLayer;
|
||||
|
||||
const CGHeroInstance * hero;
|
||||
int3 hpos;
|
||||
int3 sizes;
|
||||
boost::multi_array<CGPathNode, 4> nodes; //[layer][level][w][h]
|
||||
|
||||
CPathsInfo(const int3 & Sizes, const CGHeroInstance * hero_);
|
||||
~CPathsInfo();
|
||||
const CGPathNode * getPathInfo(const int3 & tile) const;
|
||||
bool getPath(CGPath & out, const int3 & dst) const;
|
||||
const CGPathNode * getNode(const int3 & coord) const;
|
||||
|
||||
STRONG_INLINE
|
||||
CGPathNode * getNode(const int3 & coord, const ELayer layer)
|
||||
{
|
||||
return &nodes[layer.getNum()][coord.z][coord.x][coord.y];
|
||||
}
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE PathNodeInfo
|
||||
{
|
||||
CGPathNode * node;
|
||||
const CGObjectInstance * nodeObject;
|
||||
const CGHeroInstance * nodeHero;
|
||||
const TerrainTile * tile;
|
||||
int3 coord;
|
||||
bool guarded;
|
||||
PlayerRelations objectRelations;
|
||||
PlayerRelations heroRelations;
|
||||
bool isInitialPosition;
|
||||
|
||||
PathNodeInfo();
|
||||
|
||||
virtual void setNode(CGameState * gs, CGPathNode * n);
|
||||
|
||||
void updateInfo(CPathfinderHelper * hlp, CGameState * gs);
|
||||
|
||||
bool isNodeObjectVisitable() const;
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE CDestinationNodeInfo : public PathNodeInfo
|
||||
{
|
||||
EPathNodeAction action;
|
||||
int turn;
|
||||
int movementLeft;
|
||||
float cost; //same as CGPathNode::cost
|
||||
bool blocked;
|
||||
bool isGuardianTile;
|
||||
|
||||
CDestinationNodeInfo();
|
||||
|
||||
void setNode(CGameState * gs, CGPathNode * n) override;
|
||||
|
||||
virtual bool isBetterWay() const;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -117,6 +117,7 @@ Path Path::search(const Tileset & dst, bool straight, std::function<float(const
|
||||
return;
|
||||
|
||||
float movementCost = moveCostFunction(currentNode, pos);
|
||||
|
||||
float distance = distances[currentNode] + movementCost; //we prefer to use already free paths
|
||||
int bestDistanceSoFar = std::numeric_limits<int>::max();
|
||||
auto it = distances.find(pos);
|
||||
|
@@ -172,4 +172,4 @@ bool ObstaclePlacer::isProhibited(const rmg::Area & objArea) const
|
||||
return false;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -13,7 +13,6 @@
|
||||
#include "SerializerReflection.h"
|
||||
#include "ESerializationVersion.h"
|
||||
#include "../mapObjects/CGHeroInstance.h"
|
||||
#include "../battle/BattleHexArray.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@@ -443,19 +442,6 @@ public:
|
||||
load(data[key]);
|
||||
}
|
||||
}
|
||||
|
||||
//void load(BattleHexArray & data)
|
||||
//{
|
||||
// uint32_t length = readAndCheckLength();
|
||||
// data.clear();
|
||||
// BattleHex hex;
|
||||
// for(uint32_t i = 0; i < length; i++)
|
||||
// {
|
||||
// load(hex);
|
||||
// data.insert(hex);
|
||||
// }
|
||||
//}
|
||||
|
||||
void load(std::string &data)
|
||||
{
|
||||
if (hasFeature(Version::COMPACT_STRING_SERIALIZATION))
|
||||
|
@@ -15,7 +15,6 @@
|
||||
#include "ESerializationVersion.h"
|
||||
#include "Serializeable.h"
|
||||
#include "../mapObjects/CArmedInstance.h"
|
||||
#include "../battle/BattleHexArray.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
|
@@ -1,86 +1,86 @@
|
||||
/*
|
||||
* BattleSpellMechanics.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
|
||||
|
||||
#include "ISpellMechanics.h"
|
||||
|
||||
#include "effects/Effects.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct BattleSpellCast;
|
||||
|
||||
namespace spells
|
||||
{
|
||||
|
||||
class BattleSpellMechanics : public BaseMechanics
|
||||
{
|
||||
public:
|
||||
BattleSpellMechanics(const IBattleCast * event, std::shared_ptr<effects::Effects> effects_, std::shared_ptr<IReceptiveCheck> targetCondition_);
|
||||
virtual ~BattleSpellMechanics();
|
||||
|
||||
// TODO: ??? (what's the difference compared to cast?)
|
||||
void applyEffects(ServerCallback * server, const Target & targets, bool indirect, bool ignoreImmunity) const override;
|
||||
|
||||
/// Returns false if spell can not be cast at all, e.g. due to not having any possible target on battlefield
|
||||
bool canBeCast(Problem & problem) const override;
|
||||
|
||||
/// Returns false if spell can not be cast at specified target
|
||||
bool canBeCastAt(const Target & target, Problem & problem) const override;
|
||||
|
||||
// TODO: ??? (what's the difference compared to applyEffects?)
|
||||
void cast(ServerCallback * server, const Target & target) override final;
|
||||
// TODO: ??? (what's the difference compared to cast?)
|
||||
void castEval(ServerCallback * server, const Target & target) override final;
|
||||
|
||||
/// Returns list of affected stack using currently configured target
|
||||
std::vector<const CStack *> getAffectedStacks(const Target & target) const override final;
|
||||
|
||||
/// Returns list of target types that can be targeted by spell
|
||||
std::vector<AimType> getTargetTypes() const override final;
|
||||
|
||||
/// Returns vector of all possible destinations for specified aim type
|
||||
/// index - ???
|
||||
/// current - ???
|
||||
std::vector<Destination> getPossibleDestinations(size_t index, AimType aimType, const Target & current, bool fast) const override final;
|
||||
|
||||
/// Returns true if spell can be cast on unit
|
||||
bool isReceptive(const battle::Unit * target) const override;
|
||||
|
||||
/// Returns list of hexes that are affected by spell assuming cast at centralHex
|
||||
BattleHexArray rangeInHexes(BattleHex centralHex) const override;
|
||||
|
||||
const Spell * getSpell() const override;
|
||||
|
||||
bool counteringSelector(const Bonus * bonus) const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<effects::Effects> effects;
|
||||
std::shared_ptr<IReceptiveCheck> targetCondition;
|
||||
|
||||
std::vector<const battle::Unit *> affectedUnits;
|
||||
effects::Effects::EffectsToApply effectsToApply;
|
||||
|
||||
void beforeCast(BattleSpellCast & sc, vstd::RNG & rng, const Target & target);
|
||||
|
||||
std::set<const battle::Unit *> collectTargets() const;
|
||||
|
||||
void doRemoveEffects(ServerCallback * server, const std::vector<const battle::Unit *> & targets, const CSelector & selector);
|
||||
|
||||
BattleHexArray spellRangeInHexes(BattleHex centralHex) const;
|
||||
|
||||
Target transformSpellTarget(const Target & aimPoint) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* BattleSpellMechanics.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
|
||||
|
||||
#include "ISpellMechanics.h"
|
||||
|
||||
#include "effects/Effects.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct BattleSpellCast;
|
||||
|
||||
namespace spells
|
||||
{
|
||||
|
||||
class BattleSpellMechanics : public BaseMechanics
|
||||
{
|
||||
public:
|
||||
BattleSpellMechanics(const IBattleCast * event, std::shared_ptr<effects::Effects> effects_, std::shared_ptr<IReceptiveCheck> targetCondition_);
|
||||
virtual ~BattleSpellMechanics();
|
||||
|
||||
// TODO: ??? (what's the difference compared to cast?)
|
||||
void applyEffects(ServerCallback * server, const Target & targets, bool indirect, bool ignoreImmunity) const override;
|
||||
|
||||
/// Returns false if spell can not be cast at all, e.g. due to not having any possible target on battlefield
|
||||
bool canBeCast(Problem & problem) const override;
|
||||
|
||||
/// Returns false if spell can not be cast at specified target
|
||||
bool canBeCastAt(const Target & target, Problem & problem) const override;
|
||||
|
||||
// TODO: ??? (what's the difference compared to applyEffects?)
|
||||
void cast(ServerCallback * server, const Target & target) override final;
|
||||
// TODO: ??? (what's the difference compared to cast?)
|
||||
void castEval(ServerCallback * server, const Target & target) override final;
|
||||
|
||||
/// Returns list of affected stack using currently configured target
|
||||
std::vector<const CStack *> getAffectedStacks(const Target & target) const override final;
|
||||
|
||||
/// Returns list of target types that can be targeted by spell
|
||||
std::vector<AimType> getTargetTypes() const override final;
|
||||
|
||||
/// Returns vector of all possible destinations for specified aim type
|
||||
/// index - ???
|
||||
/// current - ???
|
||||
std::vector<Destination> getPossibleDestinations(size_t index, AimType aimType, const Target & current, bool fast) const override final;
|
||||
|
||||
/// Returns true if spell can be cast on unit
|
||||
bool isReceptive(const battle::Unit * target) const override;
|
||||
|
||||
/// Returns list of hexes that are affected by spell assuming cast at centralHex
|
||||
BattleHexArray rangeInHexes(BattleHex centralHex) const override;
|
||||
|
||||
const Spell * getSpell() const override;
|
||||
|
||||
bool counteringSelector(const Bonus * bonus) const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<effects::Effects> effects;
|
||||
std::shared_ptr<IReceptiveCheck> targetCondition;
|
||||
|
||||
std::vector<const battle::Unit *> affectedUnits;
|
||||
effects::Effects::EffectsToApply effectsToApply;
|
||||
|
||||
void beforeCast(BattleSpellCast & sc, vstd::RNG & rng, const Target & target);
|
||||
|
||||
std::set<const battle::Unit *> collectTargets() const;
|
||||
|
||||
void doRemoveEffects(ServerCallback * server, const std::vector<const battle::Unit *> & targets, const CSelector & selector);
|
||||
|
||||
BattleHexArray spellRangeInHexes(BattleHex centralHex) const;
|
||||
|
||||
Target transformSpellTarget(const Target & aimPoint) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,368 +1,368 @@
|
||||
/*
|
||||
* ISpellMechanics.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
|
||||
|
||||
#include <vcmi/spells/Magic.h>
|
||||
#include <vcmi/ServerCallback.h>
|
||||
|
||||
#include "../battle/Destination.h"
|
||||
#include "../int3.h"
|
||||
#include "../GameConstants.h"
|
||||
#include "../bonuses/Bonus.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct Query;
|
||||
class IBattleState;
|
||||
class CreatureService;
|
||||
class CMap;
|
||||
class CGameInfoCallback;
|
||||
class CBattleInfoCallback;
|
||||
class JsonNode;
|
||||
class CStack;
|
||||
class CGObjectInstance;
|
||||
class CGHeroInstance;
|
||||
|
||||
namespace spells
|
||||
{
|
||||
class Service;
|
||||
}
|
||||
|
||||
namespace vstd
|
||||
{
|
||||
class RNG;
|
||||
}
|
||||
|
||||
#if SCRIPTING_ENABLED
|
||||
namespace scripting
|
||||
{
|
||||
class Service;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
///callback to be provided by server
|
||||
class DLL_LINKAGE SpellCastEnvironment : public ServerCallback
|
||||
{
|
||||
public:
|
||||
virtual ~SpellCastEnvironment() = default;
|
||||
|
||||
virtual const CMap * getMap() const = 0;
|
||||
virtual const CGameInfoCallback * getCb() const = 0;
|
||||
|
||||
virtual void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) = 0;
|
||||
virtual bool moveHero(ObjectInstanceID hid, int3 dst, EMovementMode mode) = 0; //TODO: remove
|
||||
|
||||
virtual void genericQuery(Query * request, PlayerColor color, std::function<void(std::optional<int32_t>)> callback) = 0;//TODO: type safety on query, use generic query packet when implemented
|
||||
};
|
||||
|
||||
namespace spells
|
||||
{
|
||||
|
||||
class DLL_LINKAGE IBattleCast
|
||||
{
|
||||
public:
|
||||
using Value = int32_t;
|
||||
using Value64 = int64_t;
|
||||
|
||||
using OptionalValue = std::optional<Value>;
|
||||
using OptionalValue64 = std::optional<Value64>;
|
||||
|
||||
virtual const CSpell * getSpell() const = 0;
|
||||
virtual Mode getMode() const = 0;
|
||||
virtual const Caster * getCaster() const = 0;
|
||||
virtual const CBattleInfoCallback * getBattle() const = 0;
|
||||
|
||||
virtual OptionalValue getSpellLevel() const = 0;
|
||||
|
||||
virtual OptionalValue getEffectPower() const = 0;
|
||||
virtual OptionalValue getEffectDuration() const = 0;
|
||||
|
||||
virtual OptionalValue64 getEffectValue() const = 0;
|
||||
|
||||
virtual boost::logic::tribool isSmart() const = 0;
|
||||
virtual boost::logic::tribool isMassive() const = 0;
|
||||
};
|
||||
|
||||
///all parameters of particular cast event
|
||||
class DLL_LINKAGE BattleCast : public IBattleCast
|
||||
{
|
||||
public:
|
||||
boost::logic::tribool smart;
|
||||
boost::logic::tribool massive;
|
||||
|
||||
//normal constructor
|
||||
BattleCast(const CBattleInfoCallback * cb_, const Caster * caster_, const Mode mode_, const CSpell * spell_);
|
||||
|
||||
//magic mirror constructor
|
||||
BattleCast(const BattleCast & orig, const Caster * caster_);
|
||||
|
||||
virtual ~BattleCast();
|
||||
|
||||
///IBattleCast
|
||||
const CSpell * getSpell() const override;
|
||||
Mode getMode() const override;
|
||||
const Caster * getCaster() const override;
|
||||
const CBattleInfoCallback * getBattle() const override;
|
||||
|
||||
OptionalValue getSpellLevel() const override;
|
||||
|
||||
OptionalValue getEffectPower() const override;
|
||||
OptionalValue getEffectDuration() const override;
|
||||
|
||||
OptionalValue64 getEffectValue() const override;
|
||||
|
||||
boost::logic::tribool isSmart() const override;
|
||||
boost::logic::tribool isMassive() const override;
|
||||
|
||||
void setSpellLevel(Value value);
|
||||
|
||||
void setEffectPower(Value value);
|
||||
void setEffectDuration(Value value);
|
||||
|
||||
void setEffectValue(Value64 value);
|
||||
|
||||
///only apply effects to specified targets
|
||||
void applyEffects(ServerCallback * server, const Target & target, bool indirect = false, bool ignoreImmunity = false) const;
|
||||
|
||||
///normal cast
|
||||
void cast(ServerCallback * server, Target target);
|
||||
|
||||
///cast evaluation
|
||||
void castEval(ServerCallback * server, Target target);
|
||||
|
||||
///cast with silent check for permitted cast
|
||||
bool castIfPossible(ServerCallback * server, Target target);
|
||||
|
||||
std::vector<Target> findPotentialTargets(bool fast = false) const;
|
||||
|
||||
private:
|
||||
///spell school level
|
||||
OptionalValue magicSkillLevel;
|
||||
|
||||
///actual spell-power affecting effect values
|
||||
OptionalValue effectPower;
|
||||
///actual spell-power affecting effect duration
|
||||
OptionalValue effectDuration;
|
||||
|
||||
///for Archangel-like casting
|
||||
OptionalValue64 effectValue;
|
||||
|
||||
Mode mode;
|
||||
const CSpell * spell;
|
||||
const CBattleInfoCallback * cb;
|
||||
const Caster * caster;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE ISpellMechanicsFactory
|
||||
{
|
||||
public:
|
||||
virtual ~ISpellMechanicsFactory();
|
||||
|
||||
virtual std::unique_ptr<Mechanics> create(const IBattleCast * event) const = 0;
|
||||
|
||||
static std::unique_ptr<ISpellMechanicsFactory> get(const CSpell * s);
|
||||
|
||||
protected:
|
||||
const CSpell * spell;
|
||||
|
||||
ISpellMechanicsFactory(const CSpell * s);
|
||||
};
|
||||
|
||||
class DLL_LINKAGE Mechanics
|
||||
{
|
||||
public:
|
||||
virtual ~Mechanics();
|
||||
|
||||
virtual bool adaptProblem(ESpellCastProblem source, Problem & target) const = 0;
|
||||
virtual bool adaptGenericProblem(Problem & target) const = 0;
|
||||
|
||||
virtual BattleHexArray rangeInHexes(BattleHex centralHex) const = 0;
|
||||
virtual std::vector<const CStack *> getAffectedStacks(const Target & target) const = 0;
|
||||
|
||||
virtual bool canBeCast(Problem & problem) const = 0;
|
||||
virtual bool canBeCastAt(const Target & target, Problem & problem) const = 0;
|
||||
|
||||
virtual void applyEffects(ServerCallback * server, const Target & targets, bool indirect, bool ignoreImmunity) const = 0;
|
||||
|
||||
virtual void cast(ServerCallback * server, const Target & target) = 0;
|
||||
|
||||
virtual void castEval(ServerCallback * server, const Target & target) = 0;
|
||||
|
||||
virtual bool isReceptive(const battle::Unit * target) const = 0;
|
||||
|
||||
virtual std::vector<AimType> getTargetTypes() const = 0;
|
||||
|
||||
virtual std::vector<Destination> getPossibleDestinations(size_t index, AimType aimType, const Target & current, bool fast = false) const = 0;
|
||||
|
||||
virtual const Spell * getSpell() const = 0;
|
||||
|
||||
//Cast event facade
|
||||
|
||||
virtual IBattleCast::Value getEffectLevel() const = 0;
|
||||
virtual IBattleCast::Value getRangeLevel() const = 0;
|
||||
|
||||
virtual IBattleCast::Value getEffectPower() const = 0;
|
||||
virtual IBattleCast::Value getEffectDuration() const = 0;
|
||||
|
||||
virtual IBattleCast::Value64 getEffectValue() const = 0;
|
||||
|
||||
virtual PlayerColor getCasterColor() const = 0;
|
||||
|
||||
//Spell facade
|
||||
virtual int32_t getSpellIndex() const = 0;
|
||||
virtual SpellID getSpellId() const = 0;
|
||||
virtual std::string getSpellName() const = 0;
|
||||
virtual int32_t getSpellLevel() const = 0;
|
||||
|
||||
virtual bool isSmart() const = 0;
|
||||
virtual bool isMassive() const = 0;
|
||||
virtual bool alwaysHitFirstTarget() const = 0;
|
||||
virtual bool requiresClearTiles() const = 0;
|
||||
|
||||
virtual bool isNegativeSpell() const = 0;
|
||||
virtual bool isPositiveSpell() const = 0;
|
||||
virtual bool isMagicalEffect() const = 0;
|
||||
|
||||
virtual int64_t adjustEffectValue(const battle::Unit * target) const = 0;
|
||||
virtual int64_t applySpellBonus(int64_t value, const battle::Unit * target) const = 0;
|
||||
virtual int64_t applySpecificSpellBonus(int64_t value) const = 0;
|
||||
virtual int64_t calculateRawEffectValue(int32_t basePowerMultiplier, int32_t levelPowerMultiplier) const = 0;
|
||||
|
||||
//Battle facade
|
||||
virtual bool ownerMatches(const battle::Unit * unit) const = 0;
|
||||
virtual bool ownerMatches(const battle::Unit * unit, const boost::logic::tribool positivness) const = 0;
|
||||
|
||||
//Global environment facade
|
||||
virtual const CreatureService * creatures() const = 0;
|
||||
#if SCRIPTING_ENABLED
|
||||
virtual const scripting::Service * scripts() const = 0;
|
||||
#endif
|
||||
virtual const Service * spells() const = 0;
|
||||
|
||||
virtual const CBattleInfoCallback * battle() const = 0;
|
||||
|
||||
const Caster * caster;
|
||||
|
||||
BattleSide casterSide;
|
||||
|
||||
protected:
|
||||
Mechanics();
|
||||
};
|
||||
|
||||
class DLL_LINKAGE BaseMechanics : public Mechanics
|
||||
{
|
||||
public:
|
||||
virtual ~BaseMechanics();
|
||||
|
||||
bool adaptProblem(ESpellCastProblem source, Problem & target) const override;
|
||||
bool adaptGenericProblem(Problem & target) const override;
|
||||
|
||||
int32_t getSpellIndex() const override;
|
||||
SpellID getSpellId() const override;
|
||||
std::string getSpellName() const override;
|
||||
int32_t getSpellLevel() const override;
|
||||
|
||||
IBattleCast::Value getEffectLevel() const override;
|
||||
IBattleCast::Value getRangeLevel() const override;
|
||||
|
||||
IBattleCast::Value getEffectPower() const override;
|
||||
IBattleCast::Value getEffectDuration() const override;
|
||||
|
||||
IBattleCast::Value64 getEffectValue() const override;
|
||||
|
||||
PlayerColor getCasterColor() const override;
|
||||
|
||||
bool isSmart() const override;
|
||||
bool isMassive() const override;
|
||||
bool requiresClearTiles() const override;
|
||||
bool alwaysHitFirstTarget() const override;
|
||||
|
||||
bool isNegativeSpell() const override;
|
||||
bool isPositiveSpell() const override;
|
||||
bool isMagicalEffect() const override;
|
||||
|
||||
int64_t adjustEffectValue(const battle::Unit * target) const override;
|
||||
int64_t applySpellBonus(int64_t value, const battle::Unit * target) const override;
|
||||
int64_t applySpecificSpellBonus(int64_t value) const override;
|
||||
int64_t calculateRawEffectValue(int32_t basePowerMultiplier, int32_t levelPowerMultiplier) const override;
|
||||
|
||||
bool ownerMatches(const battle::Unit * unit) const override;
|
||||
bool ownerMatches(const battle::Unit * unit, const boost::logic::tribool positivness) const override;
|
||||
|
||||
std::vector<AimType> getTargetTypes() const override;
|
||||
|
||||
const CreatureService * creatures() const override;
|
||||
#if SCRIPTING_ENABLED
|
||||
const scripting::Service * scripts() const override;
|
||||
#endif
|
||||
const Service * spells() const override;
|
||||
|
||||
const CBattleInfoCallback * battle() const override;
|
||||
|
||||
protected:
|
||||
const CSpell * owner;
|
||||
Mode mode;
|
||||
|
||||
BaseMechanics(const IBattleCast * event);
|
||||
|
||||
private:
|
||||
IBattleCast::Value rangeLevel;
|
||||
IBattleCast::Value effectLevel;
|
||||
|
||||
///actual spell-power affecting effect values
|
||||
IBattleCast::Value effectPower;
|
||||
///actual spell-power affecting effect duration
|
||||
IBattleCast::Value effectDuration;
|
||||
|
||||
///raw damage/heal amount
|
||||
IBattleCast::Value64 effectValue;
|
||||
|
||||
boost::logic::tribool smart;
|
||||
boost::logic::tribool massive;
|
||||
|
||||
const CBattleInfoCallback * cb;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE IReceptiveCheck
|
||||
{
|
||||
public:
|
||||
virtual ~IReceptiveCheck() = default;
|
||||
|
||||
virtual bool isReceptive(const Mechanics * m, const battle::Unit * target) const = 0;
|
||||
};
|
||||
|
||||
}// namespace spells
|
||||
|
||||
class DLL_LINKAGE AdventureSpellCastParameters
|
||||
{
|
||||
public:
|
||||
const spells::Caster * caster;
|
||||
int3 pos;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE IAdventureSpellMechanics
|
||||
{
|
||||
public:
|
||||
IAdventureSpellMechanics(const CSpell * s);
|
||||
virtual ~IAdventureSpellMechanics() = default;
|
||||
|
||||
virtual bool canBeCast(spells::Problem & problem, const CGameInfoCallback * cb, const spells::Caster * caster) const = 0;
|
||||
virtual bool canBeCastAt(spells::Problem & problem, const CGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const = 0;
|
||||
|
||||
virtual bool adventureCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const = 0;
|
||||
|
||||
static std::unique_ptr<IAdventureSpellMechanics> createMechanics(const CSpell * s);
|
||||
protected:
|
||||
const CSpell * owner;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* ISpellMechanics.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
|
||||
|
||||
#include <vcmi/spells/Magic.h>
|
||||
#include <vcmi/ServerCallback.h>
|
||||
|
||||
#include "../battle/Destination.h"
|
||||
#include "../int3.h"
|
||||
#include "../GameConstants.h"
|
||||
#include "../bonuses/Bonus.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct Query;
|
||||
class IBattleState;
|
||||
class CreatureService;
|
||||
class CMap;
|
||||
class CGameInfoCallback;
|
||||
class CBattleInfoCallback;
|
||||
class JsonNode;
|
||||
class CStack;
|
||||
class CGObjectInstance;
|
||||
class CGHeroInstance;
|
||||
|
||||
namespace spells
|
||||
{
|
||||
class Service;
|
||||
}
|
||||
|
||||
namespace vstd
|
||||
{
|
||||
class RNG;
|
||||
}
|
||||
|
||||
#if SCRIPTING_ENABLED
|
||||
namespace scripting
|
||||
{
|
||||
class Service;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
///callback to be provided by server
|
||||
class DLL_LINKAGE SpellCastEnvironment : public ServerCallback
|
||||
{
|
||||
public:
|
||||
virtual ~SpellCastEnvironment() = default;
|
||||
|
||||
virtual const CMap * getMap() const = 0;
|
||||
virtual const CGameInfoCallback * getCb() const = 0;
|
||||
|
||||
virtual void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) = 0;
|
||||
virtual bool moveHero(ObjectInstanceID hid, int3 dst, EMovementMode mode) = 0; //TODO: remove
|
||||
|
||||
virtual void genericQuery(Query * request, PlayerColor color, std::function<void(std::optional<int32_t>)> callback) = 0;//TODO: type safety on query, use generic query packet when implemented
|
||||
};
|
||||
|
||||
namespace spells
|
||||
{
|
||||
|
||||
class DLL_LINKAGE IBattleCast
|
||||
{
|
||||
public:
|
||||
using Value = int32_t;
|
||||
using Value64 = int64_t;
|
||||
|
||||
using OptionalValue = std::optional<Value>;
|
||||
using OptionalValue64 = std::optional<Value64>;
|
||||
|
||||
virtual const CSpell * getSpell() const = 0;
|
||||
virtual Mode getMode() const = 0;
|
||||
virtual const Caster * getCaster() const = 0;
|
||||
virtual const CBattleInfoCallback * getBattle() const = 0;
|
||||
|
||||
virtual OptionalValue getSpellLevel() const = 0;
|
||||
|
||||
virtual OptionalValue getEffectPower() const = 0;
|
||||
virtual OptionalValue getEffectDuration() const = 0;
|
||||
|
||||
virtual OptionalValue64 getEffectValue() const = 0;
|
||||
|
||||
virtual boost::logic::tribool isSmart() const = 0;
|
||||
virtual boost::logic::tribool isMassive() const = 0;
|
||||
};
|
||||
|
||||
///all parameters of particular cast event
|
||||
class DLL_LINKAGE BattleCast : public IBattleCast
|
||||
{
|
||||
public:
|
||||
boost::logic::tribool smart;
|
||||
boost::logic::tribool massive;
|
||||
|
||||
//normal constructor
|
||||
BattleCast(const CBattleInfoCallback * cb_, const Caster * caster_, const Mode mode_, const CSpell * spell_);
|
||||
|
||||
//magic mirror constructor
|
||||
BattleCast(const BattleCast & orig, const Caster * caster_);
|
||||
|
||||
virtual ~BattleCast();
|
||||
|
||||
///IBattleCast
|
||||
const CSpell * getSpell() const override;
|
||||
Mode getMode() const override;
|
||||
const Caster * getCaster() const override;
|
||||
const CBattleInfoCallback * getBattle() const override;
|
||||
|
||||
OptionalValue getSpellLevel() const override;
|
||||
|
||||
OptionalValue getEffectPower() const override;
|
||||
OptionalValue getEffectDuration() const override;
|
||||
|
||||
OptionalValue64 getEffectValue() const override;
|
||||
|
||||
boost::logic::tribool isSmart() const override;
|
||||
boost::logic::tribool isMassive() const override;
|
||||
|
||||
void setSpellLevel(Value value);
|
||||
|
||||
void setEffectPower(Value value);
|
||||
void setEffectDuration(Value value);
|
||||
|
||||
void setEffectValue(Value64 value);
|
||||
|
||||
///only apply effects to specified targets
|
||||
void applyEffects(ServerCallback * server, const Target & target, bool indirect = false, bool ignoreImmunity = false) const;
|
||||
|
||||
///normal cast
|
||||
void cast(ServerCallback * server, Target target);
|
||||
|
||||
///cast evaluation
|
||||
void castEval(ServerCallback * server, Target target);
|
||||
|
||||
///cast with silent check for permitted cast
|
||||
bool castIfPossible(ServerCallback * server, Target target);
|
||||
|
||||
std::vector<Target> findPotentialTargets(bool fast = false) const;
|
||||
|
||||
private:
|
||||
///spell school level
|
||||
OptionalValue magicSkillLevel;
|
||||
|
||||
///actual spell-power affecting effect values
|
||||
OptionalValue effectPower;
|
||||
///actual spell-power affecting effect duration
|
||||
OptionalValue effectDuration;
|
||||
|
||||
///for Archangel-like casting
|
||||
OptionalValue64 effectValue;
|
||||
|
||||
Mode mode;
|
||||
const CSpell * spell;
|
||||
const CBattleInfoCallback * cb;
|
||||
const Caster * caster;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE ISpellMechanicsFactory
|
||||
{
|
||||
public:
|
||||
virtual ~ISpellMechanicsFactory();
|
||||
|
||||
virtual std::unique_ptr<Mechanics> create(const IBattleCast * event) const = 0;
|
||||
|
||||
static std::unique_ptr<ISpellMechanicsFactory> get(const CSpell * s);
|
||||
|
||||
protected:
|
||||
const CSpell * spell;
|
||||
|
||||
ISpellMechanicsFactory(const CSpell * s);
|
||||
};
|
||||
|
||||
class DLL_LINKAGE Mechanics
|
||||
{
|
||||
public:
|
||||
virtual ~Mechanics();
|
||||
|
||||
virtual bool adaptProblem(ESpellCastProblem source, Problem & target) const = 0;
|
||||
virtual bool adaptGenericProblem(Problem & target) const = 0;
|
||||
|
||||
virtual BattleHexArray rangeInHexes(BattleHex centralHex) const = 0;
|
||||
virtual std::vector<const CStack *> getAffectedStacks(const Target & target) const = 0;
|
||||
|
||||
virtual bool canBeCast(Problem & problem) const = 0;
|
||||
virtual bool canBeCastAt(const Target & target, Problem & problem) const = 0;
|
||||
|
||||
virtual void applyEffects(ServerCallback * server, const Target & targets, bool indirect, bool ignoreImmunity) const = 0;
|
||||
|
||||
virtual void cast(ServerCallback * server, const Target & target) = 0;
|
||||
|
||||
virtual void castEval(ServerCallback * server, const Target & target) = 0;
|
||||
|
||||
virtual bool isReceptive(const battle::Unit * target) const = 0;
|
||||
|
||||
virtual std::vector<AimType> getTargetTypes() const = 0;
|
||||
|
||||
virtual std::vector<Destination> getPossibleDestinations(size_t index, AimType aimType, const Target & current, bool fast = false) const = 0;
|
||||
|
||||
virtual const Spell * getSpell() const = 0;
|
||||
|
||||
//Cast event facade
|
||||
|
||||
virtual IBattleCast::Value getEffectLevel() const = 0;
|
||||
virtual IBattleCast::Value getRangeLevel() const = 0;
|
||||
|
||||
virtual IBattleCast::Value getEffectPower() const = 0;
|
||||
virtual IBattleCast::Value getEffectDuration() const = 0;
|
||||
|
||||
virtual IBattleCast::Value64 getEffectValue() const = 0;
|
||||
|
||||
virtual PlayerColor getCasterColor() const = 0;
|
||||
|
||||
//Spell facade
|
||||
virtual int32_t getSpellIndex() const = 0;
|
||||
virtual SpellID getSpellId() const = 0;
|
||||
virtual std::string getSpellName() const = 0;
|
||||
virtual int32_t getSpellLevel() const = 0;
|
||||
|
||||
virtual bool isSmart() const = 0;
|
||||
virtual bool isMassive() const = 0;
|
||||
virtual bool alwaysHitFirstTarget() const = 0;
|
||||
virtual bool requiresClearTiles() const = 0;
|
||||
|
||||
virtual bool isNegativeSpell() const = 0;
|
||||
virtual bool isPositiveSpell() const = 0;
|
||||
virtual bool isMagicalEffect() const = 0;
|
||||
|
||||
virtual int64_t adjustEffectValue(const battle::Unit * target) const = 0;
|
||||
virtual int64_t applySpellBonus(int64_t value, const battle::Unit * target) const = 0;
|
||||
virtual int64_t applySpecificSpellBonus(int64_t value) const = 0;
|
||||
virtual int64_t calculateRawEffectValue(int32_t basePowerMultiplier, int32_t levelPowerMultiplier) const = 0;
|
||||
|
||||
//Battle facade
|
||||
virtual bool ownerMatches(const battle::Unit * unit) const = 0;
|
||||
virtual bool ownerMatches(const battle::Unit * unit, const boost::logic::tribool positivness) const = 0;
|
||||
|
||||
//Global environment facade
|
||||
virtual const CreatureService * creatures() const = 0;
|
||||
#if SCRIPTING_ENABLED
|
||||
virtual const scripting::Service * scripts() const = 0;
|
||||
#endif
|
||||
virtual const Service * spells() const = 0;
|
||||
|
||||
virtual const CBattleInfoCallback * battle() const = 0;
|
||||
|
||||
const Caster * caster;
|
||||
|
||||
BattleSide casterSide;
|
||||
|
||||
protected:
|
||||
Mechanics();
|
||||
};
|
||||
|
||||
class DLL_LINKAGE BaseMechanics : public Mechanics
|
||||
{
|
||||
public:
|
||||
virtual ~BaseMechanics();
|
||||
|
||||
bool adaptProblem(ESpellCastProblem source, Problem & target) const override;
|
||||
bool adaptGenericProblem(Problem & target) const override;
|
||||
|
||||
int32_t getSpellIndex() const override;
|
||||
SpellID getSpellId() const override;
|
||||
std::string getSpellName() const override;
|
||||
int32_t getSpellLevel() const override;
|
||||
|
||||
IBattleCast::Value getEffectLevel() const override;
|
||||
IBattleCast::Value getRangeLevel() const override;
|
||||
|
||||
IBattleCast::Value getEffectPower() const override;
|
||||
IBattleCast::Value getEffectDuration() const override;
|
||||
|
||||
IBattleCast::Value64 getEffectValue() const override;
|
||||
|
||||
PlayerColor getCasterColor() const override;
|
||||
|
||||
bool isSmart() const override;
|
||||
bool isMassive() const override;
|
||||
bool requiresClearTiles() const override;
|
||||
bool alwaysHitFirstTarget() const override;
|
||||
|
||||
bool isNegativeSpell() const override;
|
||||
bool isPositiveSpell() const override;
|
||||
bool isMagicalEffect() const override;
|
||||
|
||||
int64_t adjustEffectValue(const battle::Unit * target) const override;
|
||||
int64_t applySpellBonus(int64_t value, const battle::Unit * target) const override;
|
||||
int64_t applySpecificSpellBonus(int64_t value) const override;
|
||||
int64_t calculateRawEffectValue(int32_t basePowerMultiplier, int32_t levelPowerMultiplier) const override;
|
||||
|
||||
bool ownerMatches(const battle::Unit * unit) const override;
|
||||
bool ownerMatches(const battle::Unit * unit, const boost::logic::tribool positivness) const override;
|
||||
|
||||
std::vector<AimType> getTargetTypes() const override;
|
||||
|
||||
const CreatureService * creatures() const override;
|
||||
#if SCRIPTING_ENABLED
|
||||
const scripting::Service * scripts() const override;
|
||||
#endif
|
||||
const Service * spells() const override;
|
||||
|
||||
const CBattleInfoCallback * battle() const override;
|
||||
|
||||
protected:
|
||||
const CSpell * owner;
|
||||
Mode mode;
|
||||
|
||||
BaseMechanics(const IBattleCast * event);
|
||||
|
||||
private:
|
||||
IBattleCast::Value rangeLevel;
|
||||
IBattleCast::Value effectLevel;
|
||||
|
||||
///actual spell-power affecting effect values
|
||||
IBattleCast::Value effectPower;
|
||||
///actual spell-power affecting effect duration
|
||||
IBattleCast::Value effectDuration;
|
||||
|
||||
///raw damage/heal amount
|
||||
IBattleCast::Value64 effectValue;
|
||||
|
||||
boost::logic::tribool smart;
|
||||
boost::logic::tribool massive;
|
||||
|
||||
const CBattleInfoCallback * cb;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE IReceptiveCheck
|
||||
{
|
||||
public:
|
||||
virtual ~IReceptiveCheck() = default;
|
||||
|
||||
virtual bool isReceptive(const Mechanics * m, const battle::Unit * target) const = 0;
|
||||
};
|
||||
|
||||
}// namespace spells
|
||||
|
||||
class DLL_LINKAGE AdventureSpellCastParameters
|
||||
{
|
||||
public:
|
||||
const spells::Caster * caster;
|
||||
int3 pos;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE IAdventureSpellMechanics
|
||||
{
|
||||
public:
|
||||
IAdventureSpellMechanics(const CSpell * s);
|
||||
virtual ~IAdventureSpellMechanics() = default;
|
||||
|
||||
virtual bool canBeCast(spells::Problem & problem, const CGameInfoCallback * cb, const spells::Caster * caster) const = 0;
|
||||
virtual bool canBeCastAt(spells::Problem & problem, const CGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const = 0;
|
||||
|
||||
virtual bool adventureCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const = 0;
|
||||
|
||||
static std::unique_ptr<IAdventureSpellMechanics> createMechanics(const CSpell * s);
|
||||
protected:
|
||||
const CSpell * owner;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,83 +1,83 @@
|
||||
/*
|
||||
* Effect.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
|
||||
|
||||
#include <vcmi/spells/Magic.h>
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct BattleHex;
|
||||
class BattleHexArray;
|
||||
class CBattleInfoCallback;
|
||||
class JsonSerializeFormat;
|
||||
class ServerCallback;
|
||||
|
||||
namespace vstd
|
||||
{
|
||||
class RNG;
|
||||
}
|
||||
|
||||
namespace spells
|
||||
{
|
||||
using EffectTarget = Target;
|
||||
|
||||
namespace effects
|
||||
{
|
||||
using RNG = vstd::RNG;
|
||||
class Effects;
|
||||
class Effect;
|
||||
class Registry;
|
||||
|
||||
using TargetType = spells::AimType;
|
||||
|
||||
class DLL_LINKAGE Effect
|
||||
{
|
||||
public:
|
||||
bool indirect = false;
|
||||
bool optional = false;
|
||||
|
||||
std::string name;
|
||||
|
||||
virtual ~Effect() = default; //Required for child classes
|
||||
|
||||
// TODO: document me
|
||||
virtual void adjustTargetTypes(std::vector<TargetType> & types) const = 0;
|
||||
|
||||
/// Generates list of hexes affected by spell, if spell were to cast at specified target
|
||||
virtual void adjustAffectedHexes(BattleHexArray & hexes, const Mechanics * m, const Target & spellTarget) const = 0;
|
||||
|
||||
/// Returns whether effect has any valid targets on the battlefield
|
||||
virtual bool applicable(Problem & problem, const Mechanics * m) const;
|
||||
|
||||
/// Returns whether effect is valid and can be applied onto selected target
|
||||
virtual bool applicable(Problem & problem, const Mechanics * m, const EffectTarget & target) const;
|
||||
|
||||
virtual void apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const = 0;
|
||||
|
||||
/// Processes input target and generates subset-result that contains only valid targets
|
||||
virtual EffectTarget filterTarget(const Mechanics * m, const EffectTarget & target) const = 0;
|
||||
|
||||
// TODO: document me
|
||||
virtual EffectTarget transformTarget(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const = 0;
|
||||
|
||||
/// Serializes (or deserializes) parameters of Effect
|
||||
void serializeJson(JsonSerializeFormat & handler);
|
||||
|
||||
static std::shared_ptr<Effect> create(const Registry * registry, const std::string & type);
|
||||
|
||||
protected:
|
||||
virtual void serializeJsonEffect(JsonSerializeFormat & handler) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* Effect.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
|
||||
|
||||
#include <vcmi/spells/Magic.h>
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct BattleHex;
|
||||
class BattleHexArray;
|
||||
class CBattleInfoCallback;
|
||||
class JsonSerializeFormat;
|
||||
class ServerCallback;
|
||||
|
||||
namespace vstd
|
||||
{
|
||||
class RNG;
|
||||
}
|
||||
|
||||
namespace spells
|
||||
{
|
||||
using EffectTarget = Target;
|
||||
|
||||
namespace effects
|
||||
{
|
||||
using RNG = vstd::RNG;
|
||||
class Effects;
|
||||
class Effect;
|
||||
class Registry;
|
||||
|
||||
using TargetType = spells::AimType;
|
||||
|
||||
class DLL_LINKAGE Effect
|
||||
{
|
||||
public:
|
||||
bool indirect = false;
|
||||
bool optional = false;
|
||||
|
||||
std::string name;
|
||||
|
||||
virtual ~Effect() = default; //Required for child classes
|
||||
|
||||
// TODO: document me
|
||||
virtual void adjustTargetTypes(std::vector<TargetType> & types) const = 0;
|
||||
|
||||
/// Generates list of hexes affected by spell, if spell were to cast at specified target
|
||||
virtual void adjustAffectedHexes(BattleHexArray & hexes, const Mechanics * m, const Target & spellTarget) const = 0;
|
||||
|
||||
/// Returns whether effect has any valid targets on the battlefield
|
||||
virtual bool applicable(Problem & problem, const Mechanics * m) const;
|
||||
|
||||
/// Returns whether effect is valid and can be applied onto selected target
|
||||
virtual bool applicable(Problem & problem, const Mechanics * m, const EffectTarget & target) const;
|
||||
|
||||
virtual void apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const = 0;
|
||||
|
||||
/// Processes input target and generates subset-result that contains only valid targets
|
||||
virtual EffectTarget filterTarget(const Mechanics * m, const EffectTarget & target) const = 0;
|
||||
|
||||
// TODO: document me
|
||||
virtual EffectTarget transformTarget(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const = 0;
|
||||
|
||||
/// Serializes (or deserializes) parameters of Effect
|
||||
void serializeJson(JsonSerializeFormat & handler);
|
||||
|
||||
static std::shared_ptr<Effect> create(const Registry * registry, const std::string & type);
|
||||
|
||||
protected:
|
||||
virtual void serializeJsonEffect(JsonSerializeFormat & handler) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,52 +1,52 @@
|
||||
/*
|
||||
* LocationEffect.cpp, 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
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
|
||||
#include "LocationEffect.h"
|
||||
#include "../ISpellMechanics.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
void LocationEffect::adjustTargetTypes(std::vector<TargetType> & types) const
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LocationEffect::adjustAffectedHexes(BattleHexArray & hexes, const Mechanics * m, const Target & spellTarget) const
|
||||
{
|
||||
for(const auto & destnation : spellTarget)
|
||||
hexes.insert(destnation.hexValue);
|
||||
}
|
||||
|
||||
EffectTarget LocationEffect::filterTarget(const Mechanics * m, const EffectTarget & target) const
|
||||
{
|
||||
EffectTarget res;
|
||||
vstd::copy_if(target, std::back_inserter(res), [](const Destination & d)
|
||||
{
|
||||
return !d.unitValue && (d.hexValue.isValid());
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
EffectTarget LocationEffect::transformTarget(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const
|
||||
{
|
||||
//by default effect covers exactly spell range
|
||||
return EffectTarget(spellTarget);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* LocationEffect.cpp, 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
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
|
||||
#include "LocationEffect.h"
|
||||
#include "../ISpellMechanics.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
void LocationEffect::adjustTargetTypes(std::vector<TargetType> & types) const
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LocationEffect::adjustAffectedHexes(BattleHexArray & hexes, const Mechanics * m, const Target & spellTarget) const
|
||||
{
|
||||
for(const auto & destnation : spellTarget)
|
||||
hexes.insert(destnation.hexValue);
|
||||
}
|
||||
|
||||
EffectTarget LocationEffect::filterTarget(const Mechanics * m, const EffectTarget & target) const
|
||||
{
|
||||
EffectTarget res;
|
||||
vstd::copy_if(target, std::back_inserter(res), [](const Destination & d)
|
||||
{
|
||||
return !d.unitValue && (d.hexValue.isValid());
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
EffectTarget LocationEffect::transformTarget(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const
|
||||
{
|
||||
//by default effect covers exactly spell range
|
||||
return EffectTarget(spellTarget);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,41 +1,41 @@
|
||||
/*
|
||||
* LocationEffect.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
|
||||
|
||||
#include "Effect.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
class LocationEffect : public Effect
|
||||
{
|
||||
public:
|
||||
void adjustTargetTypes(std::vector<TargetType> & types) const override;
|
||||
|
||||
void adjustAffectedHexes(BattleHexArray & hexes, const Mechanics * m, const Target & spellTarget) const override;
|
||||
|
||||
EffectTarget filterTarget(const Mechanics * m, const EffectTarget & target) const override;
|
||||
|
||||
EffectTarget transformTarget(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const override;
|
||||
protected:
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* LocationEffect.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
|
||||
|
||||
#include "Effect.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
class LocationEffect : public Effect
|
||||
{
|
||||
public:
|
||||
void adjustTargetTypes(std::vector<TargetType> & types) const override;
|
||||
|
||||
void adjustAffectedHexes(BattleHexArray & hexes, const Mechanics * m, const Target & spellTarget) const override;
|
||||
|
||||
EffectTarget filterTarget(const Mechanics * m, const EffectTarget & target) const override;
|
||||
|
||||
EffectTarget transformTarget(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const override;
|
||||
protected:
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,43 +1,43 @@
|
||||
/*
|
||||
* Moat.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
|
||||
|
||||
#include "Obstacle.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct Bonus;
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
class Moat : public Obstacle
|
||||
{
|
||||
private:
|
||||
ObstacleSideOptions sideOptions; //Defender only
|
||||
std::vector<BattleHexArray> moatHexes; //Determine number of moat patches and hexes
|
||||
std::vector<std::shared_ptr<Bonus>> bonus; //For battle-wide bonuses
|
||||
bool dispellable; //For Tower landmines
|
||||
int moatDamage; // Minimal moat damage
|
||||
public:
|
||||
void apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const override;
|
||||
protected:
|
||||
void serializeJsonEffect(JsonSerializeFormat & handler) override;
|
||||
void placeObstacles(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const override;
|
||||
void convertBonus(const Mechanics * m, std::vector<Bonus> & converted) const;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* Moat.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
|
||||
|
||||
#include "Obstacle.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct Bonus;
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
class Moat : public Obstacle
|
||||
{
|
||||
private:
|
||||
ObstacleSideOptions sideOptions; //Defender only
|
||||
std::vector<BattleHexArray> moatHexes; //Determine number of moat patches and hexes
|
||||
std::vector<std::shared_ptr<Bonus>> bonus; //For battle-wide bonuses
|
||||
bool dispellable; //For Tower landmines
|
||||
int moatDamage; // Minimal moat damage
|
||||
public:
|
||||
void apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const override;
|
||||
protected:
|
||||
void serializeJsonEffect(JsonSerializeFormat & handler) override;
|
||||
void placeObstacles(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const override;
|
||||
void convertBonus(const Mechanics * m, std::vector<Bonus> & converted) const;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,78 +1,78 @@
|
||||
/*
|
||||
* Obstacle.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
|
||||
|
||||
#include "LocationEffect.h"
|
||||
#include "../../GameConstants.h"
|
||||
#include "../../battle/BattleHexArray.h"
|
||||
#include "../../battle/CObstacleInstance.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
class ObstacleSideOptions
|
||||
{
|
||||
public:
|
||||
using RelativeShape = std::vector<std::vector<BattleHex::EDir>>;
|
||||
|
||||
RelativeShape shape; //shape of single obstacle relative to obstacle position
|
||||
RelativeShape range; //position of obstacles relative to effect destination
|
||||
|
||||
AudioPath appearSound;
|
||||
AnimationPath appearAnimation;
|
||||
AnimationPath animation;
|
||||
|
||||
int offsetY = 0;
|
||||
|
||||
void serializeJson(JsonSerializeFormat & handler);
|
||||
};
|
||||
|
||||
class Obstacle : public LocationEffect
|
||||
{
|
||||
public:
|
||||
void adjustAffectedHexes(BattleHexArray & hexes, const Mechanics * m, const Target & spellTarget) const override;
|
||||
|
||||
bool applicable(Problem & problem, const Mechanics * m) const override;
|
||||
bool applicable(Problem & problem, const Mechanics * m, const EffectTarget & target) const override;
|
||||
|
||||
EffectTarget transformTarget(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const override;
|
||||
|
||||
void apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const override;
|
||||
|
||||
protected:
|
||||
void serializeJsonEffect(JsonSerializeFormat & handler) override;
|
||||
virtual void placeObstacles(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const;
|
||||
|
||||
bool hidden = false;
|
||||
bool trigger = false;
|
||||
bool trap = false;
|
||||
bool removeOnTrigger = false;
|
||||
bool hideNative = false;
|
||||
SpellID triggerAbility;
|
||||
private:
|
||||
int32_t patchCount = 0; //random patches to place, for massive spells should be >= 1, for non-massive ones if >= 1, then place only this number inside a target (like H5 landMine)
|
||||
bool passable = false;
|
||||
int32_t turnsRemaining = -1;
|
||||
|
||||
BattleSideArray<ObstacleSideOptions> sideOptions;
|
||||
|
||||
static bool isHexAvailable(const CBattleInfoCallback * cb, const BattleHex & hex, const bool mustBeClear);
|
||||
static bool noRoomToPlace(Problem & problem, const Mechanics * m);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* Obstacle.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
|
||||
|
||||
#include "LocationEffect.h"
|
||||
#include "../../GameConstants.h"
|
||||
#include "../../battle/BattleHexArray.h"
|
||||
#include "../../battle/CObstacleInstance.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
class ObstacleSideOptions
|
||||
{
|
||||
public:
|
||||
using RelativeShape = std::vector<std::vector<BattleHex::EDir>>;
|
||||
|
||||
RelativeShape shape; //shape of single obstacle relative to obstacle position
|
||||
RelativeShape range; //position of obstacles relative to effect destination
|
||||
|
||||
AudioPath appearSound;
|
||||
AnimationPath appearAnimation;
|
||||
AnimationPath animation;
|
||||
|
||||
int offsetY = 0;
|
||||
|
||||
void serializeJson(JsonSerializeFormat & handler);
|
||||
};
|
||||
|
||||
class Obstacle : public LocationEffect
|
||||
{
|
||||
public:
|
||||
void adjustAffectedHexes(BattleHexArray & hexes, const Mechanics * m, const Target & spellTarget) const override;
|
||||
|
||||
bool applicable(Problem & problem, const Mechanics * m) const override;
|
||||
bool applicable(Problem & problem, const Mechanics * m, const EffectTarget & target) const override;
|
||||
|
||||
EffectTarget transformTarget(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const override;
|
||||
|
||||
void apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const override;
|
||||
|
||||
protected:
|
||||
void serializeJsonEffect(JsonSerializeFormat & handler) override;
|
||||
virtual void placeObstacles(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const;
|
||||
|
||||
bool hidden = false;
|
||||
bool trigger = false;
|
||||
bool trap = false;
|
||||
bool removeOnTrigger = false;
|
||||
bool hideNative = false;
|
||||
SpellID triggerAbility;
|
||||
private:
|
||||
int32_t patchCount = 0; //random patches to place, for massive spells should be >= 1, for non-massive ones if >= 1, then place only this number inside a target (like H5 landMine)
|
||||
bool passable = false;
|
||||
int32_t turnsRemaining = -1;
|
||||
|
||||
BattleSideArray<ObstacleSideOptions> sideOptions;
|
||||
|
||||
static bool isHexAvailable(const CBattleInfoCallback * cb, const BattleHex & hex, const bool mustBeClear);
|
||||
static bool noRoomToPlace(Problem & problem, const Mechanics * m);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,55 +1,55 @@
|
||||
/*
|
||||
* Summon.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
|
||||
|
||||
#include "Effect.h"
|
||||
#include "../../GameConstants.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
class Summon : public Effect
|
||||
{
|
||||
public:
|
||||
void adjustAffectedHexes(BattleHexArray & hexes, const Mechanics * m, const Target & spellTarget) const override;
|
||||
void adjustTargetTypes(std::vector<TargetType> & types) const override;
|
||||
|
||||
bool applicable(Problem & problem, const Mechanics * m) const override;
|
||||
|
||||
void apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const override;
|
||||
|
||||
EffectTarget filterTarget(const Mechanics * m, const EffectTarget & target) const override;
|
||||
|
||||
EffectTarget transformTarget(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const override;
|
||||
|
||||
protected:
|
||||
void serializeJsonEffect(JsonSerializeFormat & handler) override final;
|
||||
|
||||
private:
|
||||
int32_t summonedCreatureAmount(const Mechanics * m) const;
|
||||
int32_t summonedCreatureHealth(const Mechanics * m, const battle::Unit * unit) const;
|
||||
|
||||
CreatureID creature;
|
||||
|
||||
bool permanent = false;
|
||||
bool exclusive = true;
|
||||
bool summonByHealth = false;
|
||||
bool summonSameUnit = false;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* Summon.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
|
||||
|
||||
#include "Effect.h"
|
||||
#include "../../GameConstants.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
class Summon : public Effect
|
||||
{
|
||||
public:
|
||||
void adjustAffectedHexes(BattleHexArray & hexes, const Mechanics * m, const Target & spellTarget) const override;
|
||||
void adjustTargetTypes(std::vector<TargetType> & types) const override;
|
||||
|
||||
bool applicable(Problem & problem, const Mechanics * m) const override;
|
||||
|
||||
void apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const override;
|
||||
|
||||
EffectTarget filterTarget(const Mechanics * m, const EffectTarget & target) const override;
|
||||
|
||||
EffectTarget transformTarget(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const override;
|
||||
|
||||
protected:
|
||||
void serializeJsonEffect(JsonSerializeFormat & handler) override final;
|
||||
|
||||
private:
|
||||
int32_t summonedCreatureAmount(const Mechanics * m) const;
|
||||
int32_t summonedCreatureHealth(const Mechanics * m, const battle::Unit * unit) const;
|
||||
|
||||
CreatureID creature;
|
||||
|
||||
bool permanent = false;
|
||||
bool exclusive = true;
|
||||
bool summonByHealth = false;
|
||||
bool summonSameUnit = false;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,61 +1,61 @@
|
||||
/*
|
||||
* UnitEffect.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
|
||||
|
||||
#include "Effect.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
class UnitEffect : public Effect
|
||||
{
|
||||
public:
|
||||
void adjustTargetTypes(std::vector<TargetType> & types) const override;
|
||||
|
||||
void adjustAffectedHexes(BattleHexArray & hexes, const Mechanics * m, const Target & spellTarget) const override;
|
||||
|
||||
bool applicable(Problem & problem, const Mechanics * m) const override;
|
||||
bool applicable(Problem & problem, const Mechanics * m, const EffectTarget & target) const override;
|
||||
|
||||
EffectTarget filterTarget(const Mechanics * m, const EffectTarget & target) const override;
|
||||
|
||||
EffectTarget transformTarget(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const override;
|
||||
|
||||
bool getStackFilter(const Mechanics * m, bool alwaysSmart, const battle::Unit * s) const;
|
||||
|
||||
virtual bool eraseByImmunityFilter(const Mechanics * m, const battle::Unit * s) const;
|
||||
|
||||
protected:
|
||||
int32_t chainLength = 0;
|
||||
double chainFactor = 0.0;
|
||||
|
||||
virtual bool isReceptive(const Mechanics * m, const battle::Unit * unit) const;
|
||||
virtual bool isSmartTarget(const Mechanics * m, const battle::Unit * unit, bool alwaysSmart) const;
|
||||
virtual bool isValidTarget(const Mechanics * m, const battle::Unit * unit) const;
|
||||
|
||||
void serializeJsonEffect(JsonSerializeFormat & handler) override final;
|
||||
virtual void serializeJsonUnitEffect(JsonSerializeFormat & handler) = 0;
|
||||
|
||||
private:
|
||||
bool ignoreImmunity = false;
|
||||
|
||||
EffectTarget transformTargetByRange(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const;
|
||||
EffectTarget transformTargetByChain(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
/*
|
||||
* UnitEffect.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
|
||||
|
||||
#include "Effect.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
class UnitEffect : public Effect
|
||||
{
|
||||
public:
|
||||
void adjustTargetTypes(std::vector<TargetType> & types) const override;
|
||||
|
||||
void adjustAffectedHexes(BattleHexArray & hexes, const Mechanics * m, const Target & spellTarget) const override;
|
||||
|
||||
bool applicable(Problem & problem, const Mechanics * m) const override;
|
||||
bool applicable(Problem & problem, const Mechanics * m, const EffectTarget & target) const override;
|
||||
|
||||
EffectTarget filterTarget(const Mechanics * m, const EffectTarget & target) const override;
|
||||
|
||||
EffectTarget transformTarget(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const override;
|
||||
|
||||
bool getStackFilter(const Mechanics * m, bool alwaysSmart, const battle::Unit * s) const;
|
||||
|
||||
virtual bool eraseByImmunityFilter(const Mechanics * m, const battle::Unit * s) const;
|
||||
|
||||
protected:
|
||||
int32_t chainLength = 0;
|
||||
double chainFactor = 0.0;
|
||||
|
||||
virtual bool isReceptive(const Mechanics * m, const battle::Unit * unit) const;
|
||||
virtual bool isSmartTarget(const Mechanics * m, const battle::Unit * unit, bool alwaysSmart) const;
|
||||
virtual bool isValidTarget(const Mechanics * m, const battle::Unit * unit) const;
|
||||
|
||||
void serializeJsonEffect(JsonSerializeFormat & handler) override final;
|
||||
virtual void serializeJsonUnitEffect(JsonSerializeFormat & handler) = 0;
|
||||
|
||||
private:
|
||||
bool ignoreImmunity = false;
|
||||
|
||||
EffectTarget transformTargetByRange(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const;
|
||||
EffectTarget transformTargetByChain(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -1,62 +1,62 @@
|
||||
/*
|
||||
* BattleFlowProcessor.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
|
||||
|
||||
#include "../lib/battle/BattleSide.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class CStack;
|
||||
struct BattleHex;
|
||||
class BattleHexArray;
|
||||
class BattleAction;
|
||||
class CBattleInfoCallback;
|
||||
struct CObstacleInstance;
|
||||
namespace battle
|
||||
{
|
||||
class Unit;
|
||||
}
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class CGameHandler;
|
||||
class BattleProcessor;
|
||||
|
||||
/// Controls flow of battles - battle startup actions and switching to next stack or next round after actions
|
||||
class BattleFlowProcessor : boost::noncopyable
|
||||
{
|
||||
BattleProcessor * owner;
|
||||
CGameHandler * gameHandler;
|
||||
|
||||
const CStack * getNextStack(const CBattleInfoCallback & battle);
|
||||
|
||||
bool rollGoodMorale(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
bool tryMakeAutomaticAction(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
|
||||
void summonGuardiansHelper(const CBattleInfoCallback & battle, BattleHexArray & output, const BattleHex & targetPosition, BattleSide side, bool targetIsTwoHex);
|
||||
void trySummonGuardians(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
void tryPlaceMoats(const CBattleInfoCallback & battle);
|
||||
void castOpeningSpells(const CBattleInfoCallback & battle);
|
||||
void activateNextStack(const CBattleInfoCallback & battle);
|
||||
void startNextRound(const CBattleInfoCallback & battle, bool isFirstRound);
|
||||
|
||||
void stackEnchantedTrigger(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
void removeObstacle(const CBattleInfoCallback & battle, const CObstacleInstance & obstacle);
|
||||
void stackTurnTrigger(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
void setActiveStack(const CBattleInfoCallback & battle, const battle::Unit * stack);
|
||||
|
||||
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)
|
||||
|
||||
public:
|
||||
explicit BattleFlowProcessor(BattleProcessor * owner, CGameHandler * newGameHandler);
|
||||
|
||||
void onBattleStarted(const CBattleInfoCallback & battle);
|
||||
void onTacticsEnded(const CBattleInfoCallback & battle);
|
||||
void onActionMade(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
};
|
||||
/*
|
||||
* BattleFlowProcessor.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
|
||||
|
||||
#include "../lib/battle/BattleSide.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class CStack;
|
||||
struct BattleHex;
|
||||
class BattleHexArray;
|
||||
class BattleAction;
|
||||
class CBattleInfoCallback;
|
||||
struct CObstacleInstance;
|
||||
namespace battle
|
||||
{
|
||||
class Unit;
|
||||
}
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class CGameHandler;
|
||||
class BattleProcessor;
|
||||
|
||||
/// Controls flow of battles - battle startup actions and switching to next stack or next round after actions
|
||||
class BattleFlowProcessor : boost::noncopyable
|
||||
{
|
||||
BattleProcessor * owner;
|
||||
CGameHandler * gameHandler;
|
||||
|
||||
const CStack * getNextStack(const CBattleInfoCallback & battle);
|
||||
|
||||
bool rollGoodMorale(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
bool tryMakeAutomaticAction(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
|
||||
void summonGuardiansHelper(const CBattleInfoCallback & battle, BattleHexArray & output, const BattleHex & targetPosition, BattleSide side, bool targetIsTwoHex);
|
||||
void trySummonGuardians(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
void tryPlaceMoats(const CBattleInfoCallback & battle);
|
||||
void castOpeningSpells(const CBattleInfoCallback & battle);
|
||||
void activateNextStack(const CBattleInfoCallback & battle);
|
||||
void startNextRound(const CBattleInfoCallback & battle, bool isFirstRound);
|
||||
|
||||
void stackEnchantedTrigger(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
void removeObstacle(const CBattleInfoCallback & battle, const CObstacleInstance & obstacle);
|
||||
void stackTurnTrigger(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
void setActiveStack(const CBattleInfoCallback & battle, const battle::Unit * stack);
|
||||
|
||||
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)
|
||||
|
||||
public:
|
||||
explicit BattleFlowProcessor(BattleProcessor * owner, CGameHandler * newGameHandler);
|
||||
|
||||
void onBattleStarted(const CBattleInfoCallback & battle);
|
||||
void onTacticsEnded(const CBattleInfoCallback & battle);
|
||||
void onActionMade(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
};
|
||||
|
Reference in New Issue
Block a user