mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
* New files for lib: CBattleCallback.cpp and CBattleCallback.h
* Updated MSVC project files * Filesystem: My version of .SND archive does not have \0 after WAV extension. Fixed (though hardcoded 3-char extension length). * New bonus types: BLOCK_MAGIC_ABOVE for blocking casting spells above given level and BLOCK_ALL_MAGIC for blocking all magic. * Heavy rewrite of battle callbacks. Fixed some minor bugs. Code reusage between lib/client/server (removed proxy calls). Better access control and support for various perspectives. * Fixed #1031 * Fixed Orb of Inhibition and Recanter's Cloak (they were incorrectly implemented). Fixed #97. * Fleeing hero won't lose artifacts. Spellbook won't be captured. Fixed #980. * Fixed crash when attacking stack dies before counterattack (ie. because of Fire Shield) * Server does some basic checks if action requests during battle are valid * Minor stuff.
This commit is contained in:
parent
2dd9d943c9
commit
d390113c23
@ -5,7 +5,7 @@
|
|||||||
#include "../../CCallback.h"
|
#include "../../CCallback.h"
|
||||||
#include "../../lib/CCreatureHandler.h"
|
#include "../../lib/CCreatureHandler.h"
|
||||||
|
|
||||||
CBattleCallback * cbc;
|
CPlayerBattleCallback * cbc;
|
||||||
|
|
||||||
CStupidAI::CStupidAI(void)
|
CStupidAI::CStupidAI(void)
|
||||||
: side(-1), cb(NULL)
|
: side(-1), cb(NULL)
|
||||||
@ -19,7 +19,7 @@ CStupidAI::~CStupidAI(void)
|
|||||||
print("destroyed");
|
print("destroyed");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CStupidAI::init( CBattleCallback * CB )
|
void CStupidAI::init( CPlayerBattleCallback * CB )
|
||||||
{
|
{
|
||||||
print("init called, saving ptr to IBattleCallback");
|
print("init called, saving ptr to IBattleCallback");
|
||||||
cbc = cb = CB;
|
cbc = cb = CB;
|
||||||
@ -60,7 +60,7 @@ bool isMoreProfitable(const EnemyInfo &ei1, const EnemyInfo& ei2)
|
|||||||
return (ei1.adi-ei1.adr) < (ei2.adi - ei2.adr);
|
return (ei1.adi-ei1.adr) < (ei2.adi - ei2.adr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int distToNearestNeighbour(BattleHex hex, const std::vector<int> & dists, BattleHex *chosenHex = NULL)
|
int distToNearestNeighbour(BattleHex hex, const ReachabilityInfo::TDistances& dists, BattleHex *chosenHex = NULL)
|
||||||
{
|
{
|
||||||
int ret = 1000000;
|
int ret = 1000000;
|
||||||
BOOST_FOREACH(BattleHex n, hex.neighbouringTiles())
|
BOOST_FOREACH(BattleHex n, hex.neighbouringTiles())
|
||||||
@ -76,7 +76,7 @@ int distToNearestNeighbour(BattleHex hex, const std::vector<int> & dists, Battle
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isCloser(const EnemyInfo & ei1, const EnemyInfo & ei2, const std::vector<int> & dists)
|
bool isCloser(const EnemyInfo & ei1, const EnemyInfo & ei2, const ReachabilityInfo::TDistances & dists)
|
||||||
{
|
{
|
||||||
return distToNearestNeighbour(ei1.s->position, dists) < distToNearestNeighbour(ei2.s->position, dists);
|
return distToNearestNeighbour(ei1.s->position, dists) < distToNearestNeighbour(ei2.s->position, dists);
|
||||||
}
|
}
|
||||||
@ -97,9 +97,9 @@ static bool willSecondHexBlockMoreEnemyShooters(const BattleHex &h1, const Battl
|
|||||||
BattleAction CStupidAI::activeStack( const CStack * stack )
|
BattleAction CStupidAI::activeStack( const CStack * stack )
|
||||||
{
|
{
|
||||||
//boost::this_thread::sleep(boost::posix_time::seconds(2));
|
//boost::this_thread::sleep(boost::posix_time::seconds(2));
|
||||||
print("activeStack called");
|
print("activeStack called for " + stack->nodeName());
|
||||||
std::vector<BattleHex> avHexes = cb->battleGetAvailableHexes(stack, false);
|
std::vector<BattleHex> avHexes = cb->battleGetAvailableHexes(stack, false);
|
||||||
std::vector<int> dists = cb->battleGetDistances(stack);
|
auto dists = cb->battleGetDistances(stack);
|
||||||
std::vector<EnemyInfo> enemiesShootable, enemiesReachable, enemiesUnreachable;
|
std::vector<EnemyInfo> enemiesShootable, enemiesReachable, enemiesUnreachable;
|
||||||
|
|
||||||
if(stack->type->idNumber == 145) //catapult
|
if(stack->type->idNumber == 145) //catapult
|
||||||
@ -246,33 +246,66 @@ void CStupidAI::print(const std::string &text) const
|
|||||||
tlog6 << "CStupidAI [" << this <<"]: " << text << std::endl;
|
tlog6 << "CStupidAI [" << this <<"]: " << text << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
BattleAction CStupidAI::goTowards(const CStack * stack, BattleHex hex)
|
BattleAction CStupidAI::goTowards(const CStack * stack, BattleHex destination)
|
||||||
{
|
{
|
||||||
BattleHex realDest = hex;
|
assert(destination.isValid());
|
||||||
BattleHex predecessors[GameConstants::BFIELD_SIZE];
|
auto avHexes = cb->battleGetAvailableHexes(stack, false);
|
||||||
std::vector<int> dists = cb->battleGetDistances(stack, hex);
|
auto reachability = cb->getReachability(stack);
|
||||||
if(distToNearestNeighbour(hex, dists, &realDest) > GameConstants::BFIELD_SIZE)
|
|
||||||
|
if(vstd::contains(avHexes, destination))
|
||||||
|
return BattleAction::makeMove(stack, destination);
|
||||||
|
|
||||||
|
auto destNeighbours = destination.neighbouringTiles();
|
||||||
|
if(vstd::contains_if(destNeighbours, [&](BattleHex n) { return stack->coversPos(destination); }))
|
||||||
{
|
{
|
||||||
print("goTowards: Cannot reach");
|
tlog3 << "Warning: already standing on neighbouring tile!" << std::endl;
|
||||||
|
//We shouldn't even be here...
|
||||||
return BattleAction::makeDefend(stack);
|
return BattleAction::makeDefend(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
dists = cb->battleGetDistances(stack, realDest, predecessors);
|
vstd::erase_if(destNeighbours, [&](BattleHex hex){ return !reachability.accessibility.accessible(hex, stack); });
|
||||||
std::vector<BattleHex> avHexes = cb->battleGetAvailableHexes(stack, false);
|
|
||||||
|
|
||||||
if(!avHexes.size())
|
if(!avHexes.size() || !destNeighbours.size()) //we are blocked or dest is blocked
|
||||||
{
|
{
|
||||||
print("goTowards: Stack cannot move! That's " + stack->nodeName());
|
print("goTowards: Stack cannot move! That's " + stack->nodeName());
|
||||||
return BattleAction::makeDefend(stack);
|
return BattleAction::makeDefend(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
while(1)
|
if(stack->hasBonusOfType(Bonus::FLYING))
|
||||||
{
|
{
|
||||||
assert(realDest.isValid());
|
// Flying stack doesn't go hex by hex, so we can't backtrack using predecessors.
|
||||||
if(vstd::contains(avHexes, hex))
|
// We just check all available hexes and pick the one closest to the target.
|
||||||
return BattleAction::makeMove(stack, hex);
|
auto distToDestNeighbour = [&](BattleHex hex) -> int
|
||||||
|
{
|
||||||
|
auto nearestNeighbourToHex = vstd::minElementByFun(destNeighbours, [&](BattleHex a)
|
||||||
|
{
|
||||||
|
return BattleHex::getDistance(a, hex);
|
||||||
|
});
|
||||||
|
|
||||||
hex = predecessors[hex];
|
return BattleHex::getDistance(*nearestNeighbourToHex, hex);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto nearestAvailableHex = vstd::minElementByFun(avHexes, distToDestNeighbour);
|
||||||
|
return BattleAction::makeMove(stack, *nearestAvailableHex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BattleHex bestNeighbor = destination;
|
||||||
|
if(distToNearestNeighbour(destination, reachability.distances, &bestNeighbor) > GameConstants::BFIELD_SIZE)
|
||||||
|
{
|
||||||
|
print("goTowards: Cannot reach");
|
||||||
|
return BattleAction::makeDefend(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
BattleHex currentDest = bestNeighbor;
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
assert(currentDest.isValid());
|
||||||
|
if(vstd::contains(avHexes, currentDest))
|
||||||
|
return BattleAction::makeMove(stack, currentDest);
|
||||||
|
|
||||||
|
currentDest = reachability.predecessors[currentDest];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,14 +5,14 @@
|
|||||||
class CStupidAI : public CBattleGameInterface
|
class CStupidAI : public CBattleGameInterface
|
||||||
{
|
{
|
||||||
int side;
|
int side;
|
||||||
CBattleCallback *cb;
|
CPlayerBattleCallback *cb;
|
||||||
|
|
||||||
void print(const std::string &text) const;
|
void print(const std::string &text) const;
|
||||||
public:
|
public:
|
||||||
CStupidAI(void);
|
CStupidAI(void);
|
||||||
~CStupidAI(void);
|
~CStupidAI(void);
|
||||||
|
|
||||||
void init(CBattleCallback * CB) OVERRIDE;
|
void init(CPlayerBattleCallback * CB) OVERRIDE;
|
||||||
void actionFinished(const BattleAction *action) OVERRIDE;//occurs AFTER every action taken by any stack or by the hero
|
void actionFinished(const BattleAction *action) OVERRIDE;//occurs AFTER every action taken by any stack or by the hero
|
||||||
void actionStarted(const BattleAction *action) OVERRIDE;//occurs BEFORE every action taken by any stack or by the hero
|
void actionStarted(const BattleAction *action) OVERRIDE;//occurs BEFORE every action taken by any stack or by the hero
|
||||||
BattleAction activeStack(const CStack * stack) OVERRIDE; //called when it's turn of that stack
|
BattleAction activeStack(const CStack * stack) OVERRIDE; //called when it's turn of that stack
|
||||||
|
@ -174,13 +174,6 @@ void removeDuplicates(std::vector<T> &vec)
|
|||||||
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
|
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename Range, typename Predicate>
|
|
||||||
void erase_if(Range &vec, Predicate pred)
|
|
||||||
{
|
|
||||||
vec.erase(boost::remove_if(vec, pred),vec.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AtScopeExit
|
struct AtScopeExit
|
||||||
{
|
{
|
||||||
boost::function<void()> foo;
|
boost::function<void()> foo;
|
||||||
@ -1711,7 +1704,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
|||||||
cb->moveHero(*h, CGHeroInstance::convertPosition(endpos, true));
|
cb->moveHero(*h, CGHeroInstance::convertPosition(endpos, true));
|
||||||
waitTillFree(); //movement may cause battle or blocking dialog
|
waitTillFree(); //movement may cause battle or blocking dialog
|
||||||
boost::this_thread::interruption_point();
|
boost::this_thread::interruption_point();
|
||||||
if(h->tempOwner != playerID) //we lost hero - remove all tasks assigned to him/her
|
if(!h) //we lost hero - remove all tasks assigned to him/her
|
||||||
{
|
{
|
||||||
lostHero(h);
|
lostHero(h);
|
||||||
//we need to throw, otherwise hero will be assigned to sth again
|
//we need to throw, otherwise hero will be assigned to sth again
|
||||||
@ -1727,7 +1720,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
|||||||
performObjectInteraction (visitedObject, h);
|
performObjectInteraction (visitedObject, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(h->tempOwner == playerID) //we could have lost hero after last move
|
if(h) //we could have lost hero after last move
|
||||||
{
|
{
|
||||||
cb->recalculatePaths();
|
cb->recalculatePaths();
|
||||||
if (startHpos == h->visitablePos() && !ret) //we didn't move and didn't reach the target
|
if (startHpos == h->visitablePos() && !ret) //we didn't move and didn't reach the target
|
||||||
@ -3616,7 +3609,7 @@ HeroPtr::HeroPtr(const CGHeroInstance *H)
|
|||||||
h = H;
|
h = H;
|
||||||
name = h->name;
|
name = h->name;
|
||||||
|
|
||||||
hid = H->subID;
|
hid = H->id;
|
||||||
// infosCount[ai->playerID][hid]++;
|
// infosCount[ai->playerID][hid]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3641,12 +3634,23 @@ const CGHeroInstance * HeroPtr::get(bool doWeExpectNull /*= false*/) const
|
|||||||
{
|
{
|
||||||
//TODO? check if these all assertions every time we get info about hero affect efficiency
|
//TODO? check if these all assertions every time we get info about hero affect efficiency
|
||||||
//
|
//
|
||||||
//behave terribly when attempting unauthorised access to hero that is not ours (or was lost)
|
//behave terribly when attempting unauthorized access to hero that is not ours (or was lost)
|
||||||
assert(doWeExpectNull || h);
|
assert(doWeExpectNull || h);
|
||||||
|
|
||||||
if(h)
|
if(h)
|
||||||
{
|
{
|
||||||
assert(cb->getObj(h->id));
|
auto obj = cb->getObj(hid);
|
||||||
assert(h->tempOwner == ai->playerID);
|
const bool owned = obj && obj->tempOwner == ai->playerID;
|
||||||
|
|
||||||
|
if(doWeExpectNull && !owned)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(obj);
|
||||||
|
assert(owned);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return h;
|
return h;
|
||||||
|
@ -78,17 +78,15 @@ public:
|
|||||||
|
|
||||||
struct CPack;
|
struct CPack;
|
||||||
|
|
||||||
class CBattleCallback : public IBattleCallback, public CBattleInfoCallback
|
class CBattleCallback : public IBattleCallback, public CPlayerBattleCallback
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
CBattleCallback(CGameState *GS, int Player, CClient *C);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int sendRequest(const CPack *request); //returns requestID (that'll be matched to requestID in PackageApplied)
|
int sendRequest(const CPack *request); //returns requestID (that'll be matched to requestID in PackageApplied)
|
||||||
CClient *cl;
|
CClient *cl;
|
||||||
//virtual bool hasAccess(int playerId) const;
|
//virtual bool hasAccess(int playerId) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
CBattleCallback(CGameState *GS, int Player, CClient *C);
|
||||||
int battleMakeAction(BattleAction* action) OVERRIDE;//for casting spells by hero - DO NOT use it for moving active stack
|
int battleMakeAction(BattleAction* action) OVERRIDE;//for casting spells by hero - DO NOT use it for moving active stack
|
||||||
bool battleMakeTacticAction(BattleAction * action) OVERRIDE; // performs tactic phase actions
|
bool battleMakeTacticAction(BattleAction * action) OVERRIDE; // performs tactic phase actions
|
||||||
|
|
||||||
|
58
Global.h
58
Global.h
@ -44,17 +44,10 @@
|
|||||||
#include <queue>
|
#include <queue>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
//#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <numeric>
|
#include <vector>
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <iomanip>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <memory>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
//The only available version is 3, as of Boost 1.50
|
//The only available version is 3, as of Boost 1.50
|
||||||
#define BOOST_FILESYSTEM_VERSION 3
|
#define BOOST_FILESYSTEM_VERSION 3
|
||||||
@ -72,8 +65,10 @@
|
|||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <boost/logic/tribool.hpp>
|
#include <boost/logic/tribool.hpp>
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
#include <boost/range/algorithm.hpp>
|
#include <boost/range/algorithm.hpp>
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
|
#include <boost/unordered_map.hpp>
|
||||||
#include <boost/unordered_set.hpp>
|
#include <boost/unordered_set.hpp>
|
||||||
#include <boost/unordered_map.hpp>
|
#include <boost/unordered_map.hpp>
|
||||||
#include <boost/variant.hpp>
|
#include <boost/variant.hpp>
|
||||||
@ -172,7 +167,14 @@ namespace vstd
|
|||||||
template <typename Container, typename Item>
|
template <typename Container, typename Item>
|
||||||
bool contains(const Container & c, const Item &i)
|
bool contains(const Container & c, const Item &i)
|
||||||
{
|
{
|
||||||
return std::find(c.begin(),c.end(),i) != c.end();
|
return std::find(boost::begin(c), boost::end(c),i) != boost::end(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
//returns true if container c contains item i
|
||||||
|
template <typename Container, typename Pred>
|
||||||
|
bool contains_if(const Container & c, Pred p)
|
||||||
|
{
|
||||||
|
return std::find_if(boost::begin(c), boost::end(c), p) != boost::end(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
//returns true if map c contains item i
|
//returns true if map c contains item i
|
||||||
@ -201,7 +203,7 @@ namespace vstd
|
|||||||
int find_pos(const Container & c, const T2 &s)
|
int find_pos(const Container & c, const T2 &s)
|
||||||
{
|
{
|
||||||
size_t i=0;
|
size_t i=0;
|
||||||
for (auto iter = c.begin(); iter != c.end(); iter++, i++)
|
for (auto iter = boost::begin(c); iter != boost::end(c); iter++, i++)
|
||||||
if(*iter == s)
|
if(*iter == s)
|
||||||
return i;
|
return i;
|
||||||
return -1;
|
return -1;
|
||||||
@ -343,11 +345,39 @@ namespace vstd
|
|||||||
{
|
{
|
||||||
assert(r.size());
|
assert(r.size());
|
||||||
index %= r.size();
|
index %= r.size();
|
||||||
// auto itr = std::begin(r); //not available in gcc-4.5
|
auto itr = boost::begin(r);
|
||||||
auto itr = r.begin();
|
|
||||||
std::advance(itr, index);
|
std::advance(itr, index);
|
||||||
return *itr;
|
return *itr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Range, typename Predicate>
|
||||||
|
void erase_if(Range &vec, Predicate pred)
|
||||||
|
{
|
||||||
|
vec.erase(boost::remove_if(vec, pred),vec.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename InputRange, typename OutputIterator, typename Predicate>
|
||||||
|
OutputIterator copy_if(const InputRange &input, OutputIterator result, Predicate pred)
|
||||||
|
{
|
||||||
|
return std::copy_if(boost::const_begin(input), boost::end(input), result, pred);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Container>
|
||||||
|
std::insert_iterator<Container> set_inserter(Container &c)
|
||||||
|
{
|
||||||
|
return std::inserter(c, c.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Retuns iterator to the element for which the value of ValueFunction is minimal
|
||||||
|
template<class ForwardRange, class ValueFunction>
|
||||||
|
auto minElementByFun(const ForwardRange& rng, ValueFunction vf) -> decltype(boost::begin(rng))
|
||||||
|
{
|
||||||
|
typedef decltype(*boost::begin(rng)) ElemType;
|
||||||
|
return boost::min_element(rng, [&] (const ElemType &lhs, const ElemType &rhs) -> bool
|
||||||
|
{
|
||||||
|
return vf(lhs) < vf(rhs);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using std::shared_ptr;
|
using std::shared_ptr;
|
||||||
|
@ -141,7 +141,7 @@ CAttackAnimation::CAttackAnimation(CBattleInterface *_owner, const CStack *attac
|
|||||||
|
|
||||||
assert(attackingStack && "attackingStack is NULL in CBattleAttack::CBattleAttack !\n");
|
assert(attackingStack && "attackingStack is NULL in CBattleAttack::CBattleAttack !\n");
|
||||||
bool isCatapultAttack = attackingStack->hasBonusOfType(Bonus::CATAPULT)
|
bool isCatapultAttack = attackingStack->hasBonusOfType(Bonus::CATAPULT)
|
||||||
&& owner->curInt->cb->battleGetWallUnderHex(_dest) >= 0;
|
&& owner->curInt->cb->battleHexToWallPart(_dest) >= 0;
|
||||||
|
|
||||||
assert(attackedStack || isCatapultAttack);
|
assert(attackedStack || isCatapultAttack);
|
||||||
attackingStackPosBeforeReturn = attackingStack->position;
|
attackingStackPosBeforeReturn = attackingStack->position;
|
||||||
|
@ -1252,16 +1252,35 @@ void CBattleInterface::bSpellf()
|
|||||||
|
|
||||||
CCS->curh->changeGraphic(0,0);
|
CCS->curh->changeGraphic(0,0);
|
||||||
|
|
||||||
if ( myTurn && curInt->cb->battleCanCastSpell())
|
if(!myTurn)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto myHero = currentHero();
|
||||||
|
ESpellCastProblem::ESpellCastProblem spellCastProblem;
|
||||||
|
if (curInt->cb->battleCanCastSpell(&spellCastProblem))
|
||||||
{
|
{
|
||||||
const CGHeroInstance * chi = NULL;
|
CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), myHero, curInt);
|
||||||
if(attackingHeroInstance->tempOwner == curInt->playerID)
|
|
||||||
chi = attackingHeroInstance;
|
|
||||||
else
|
|
||||||
chi = defendingHeroInstance;
|
|
||||||
CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), chi, curInt);
|
|
||||||
GH.pushInt(spellWindow);
|
GH.pushInt(spellWindow);
|
||||||
}
|
}
|
||||||
|
else if(spellCastProblem == ESpellCastProblem::MAGIC_IS_BLOCKED)
|
||||||
|
{
|
||||||
|
//Handle Orb of Inhibition-like effects -> we want to display dialog with info, why casting is impossible
|
||||||
|
auto blockingBonus = currentHero()->getBonus(Selector::type(Bonus::BLOCK_ALL_MAGIC));
|
||||||
|
if(!blockingBonus)
|
||||||
|
return;;
|
||||||
|
|
||||||
|
if(blockingBonus->source == Bonus::ARTIFACT)
|
||||||
|
{
|
||||||
|
const int artID = blockingBonus->sid;
|
||||||
|
//If we have artifact, put name of our hero. Otherwise assume it's the enemy.
|
||||||
|
//TODO check who *really* is source of bonus
|
||||||
|
std::string heroName = myHero->hasArt(artID) ? myHero->name : enemyHero().name;
|
||||||
|
|
||||||
|
//%s wields the %s, an ancient artifact which creates a p dead to all magic.
|
||||||
|
LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[683])
|
||||||
|
% heroName % CGI->arth->artifacts[artID]->Name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBattleInterface::bWaitf()
|
void CBattleInterface::bWaitf()
|
||||||
@ -1495,11 +1514,11 @@ bool CBattleInterface::isCatapultAttackable(BattleHex hex) const
|
|||||||
if(!siegeH || tacticsMode)
|
if(!siegeH || tacticsMode)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int wallUnder = curInt->cb->battleGetWallUnderHex(hex);
|
int wallUnder = curInt->cb->battleHexToWallPart(hex);
|
||||||
if(wallUnder == -1)
|
if(wallUnder == -1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return curInt->cb->battleGetWallState(wallUnder) < 3;
|
return curInt->cb->battleGetWallState(wallUnder) < EWallState::DESTROYED;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CGHeroInstance * CBattleInterface::getActiveHero()
|
const CGHeroInstance * CBattleInterface::getActiveHero()
|
||||||
@ -1985,7 +2004,9 @@ void CBattleInterface::activateStack()
|
|||||||
bWait->block(vstd::contains(s->state, EBattleStackState::WAITING)); //block waiting button if stack has been already waiting
|
bWait->block(vstd::contains(s->state, EBattleStackState::WAITING)); //block waiting button if stack has been already waiting
|
||||||
|
|
||||||
//block cast spell button if hero doesn't have a spellbook
|
//block cast spell button if hero doesn't have a spellbook
|
||||||
bSpell->block(!curInt->cb->battleCanCastSpell());
|
ESpellCastProblem::ESpellCastProblem spellcastingProblem;
|
||||||
|
bool canCastSpells = curInt->cb->battleCanCastSpell(&spellcastingProblem);
|
||||||
|
bSpell->block(!canCastSpells && spellcastingProblem != ESpellCastProblem::MAGIC_IS_BLOCKED); //if magic is blocked, we leave button active, so the message can be displayed (cf bug #97)
|
||||||
bSurrender->block((curInt == attackerInt ? defendingHeroInstance : attackingHeroInstance) == NULL);
|
bSurrender->block((curInt == attackerInt ? defendingHeroInstance : attackingHeroInstance) == NULL);
|
||||||
bFlee->block(!curInt->cb->battleCanFlee());
|
bFlee->block(!curInt->cb->battleCanFlee());
|
||||||
bSurrender->block(curInt->cb->battleGetSurrenderCost() < 0);
|
bSurrender->block(curInt->cb->battleGetSurrenderCost() < 0);
|
||||||
@ -3484,6 +3505,25 @@ Point CBattleInterface::whereToBlitObstacleImage(SDL_Surface *image, const CObst
|
|||||||
return r.topLeft();
|
return r.topLeft();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CGHeroInstance * CBattleInterface::currentHero() const
|
||||||
|
{
|
||||||
|
if(attackingHeroInstance->tempOwner == curInt->playerID)
|
||||||
|
return attackingHeroInstance;
|
||||||
|
else
|
||||||
|
return defendingHeroInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoAboutHero CBattleInterface::enemyHero() const
|
||||||
|
{
|
||||||
|
InfoAboutHero ret;
|
||||||
|
if(attackingHeroInstance->tempOwner == curInt->playerID)
|
||||||
|
curInt->cb->getHeroInfo(defendingHeroInstance, ret);
|
||||||
|
else
|
||||||
|
curInt->cb->getHeroInfo(attackingHeroInstance, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
std::string CBattleInterface::SiegeHelper::townTypeInfixes[GameConstants::F_NUMBER] = {"CS", "RM", "TW", "IN", "NC", "DN", "ST", "FR", "EL"};
|
std::string CBattleInterface::SiegeHelper::townTypeInfixes[GameConstants::F_NUMBER] = {"CS", "RM", "TW", "IN", "NC", "DN", "ST", "FR", "EL"};
|
||||||
|
|
||||||
CBattleInterface::SiegeHelper::SiegeHelper(const CGTownInstance *siegeTown, const CBattleInterface * _owner)
|
CBattleInterface::SiegeHelper::SiegeHelper(const CGTownInstance *siegeTown, const CBattleInterface * _owner)
|
||||||
|
@ -45,6 +45,7 @@ class CCreatureAnimation;
|
|||||||
struct ProjectileInfo;
|
struct ProjectileInfo;
|
||||||
class CClickableHex;
|
class CClickableHex;
|
||||||
struct BattleHex;
|
struct BattleHex;
|
||||||
|
struct InfoAboutHero;
|
||||||
|
|
||||||
/// Class which manages the locked hex fields that are blocked e.g. by obstacles
|
/// Class which manages the locked hex fields that are blocked e.g. by obstacles
|
||||||
class CBattleObstacle
|
class CBattleObstacle
|
||||||
@ -284,6 +285,9 @@ public:
|
|||||||
BattleHex fromWhichHexAttack(BattleHex myNumber);
|
BattleHex fromWhichHexAttack(BattleHex myNumber);
|
||||||
void obstaclePlaced(const CObstacleInstance & oi);
|
void obstaclePlaced(const CObstacleInstance & oi);
|
||||||
|
|
||||||
|
const CGHeroInstance * currentHero() const;
|
||||||
|
InfoAboutHero enemyHero() const;
|
||||||
|
|
||||||
friend class CPlayerInterface;
|
friend class CPlayerInterface;
|
||||||
friend class CAdventureMapButton;
|
friend class CAdventureMapButton;
|
||||||
friend class CInGameConsole;
|
friend class CInGameConsole;
|
||||||
|
@ -616,7 +616,7 @@ void CClickableHex::clickRight(tribool down, bool previousState)
|
|||||||
void CStackQueue::update()
|
void CStackQueue::update()
|
||||||
{
|
{
|
||||||
stacksSorted.clear();
|
stacksSorted.clear();
|
||||||
owner->curInt->cb->getStackQueue(stacksSorted, QUEUE_SIZE);
|
owner->curInt->cb->battleGetStackQueue(stacksSorted, QUEUE_SIZE);
|
||||||
for (int i = 0; i < QUEUE_SIZE ; i++)
|
for (int i = 0; i < QUEUE_SIZE ; i++)
|
||||||
{
|
{
|
||||||
stackBoxes[i]->setStack(stacksSorted[i]);
|
stackBoxes[i]->setStack(stacksSorted[i]);
|
||||||
|
@ -892,7 +892,7 @@ void CPlayerInterface::battleAttack(const BattleAttack *ba)
|
|||||||
if (!i->isSecondary()) //display projectile only for primary target
|
if (!i->isSecondary()) //display projectile only for primary target
|
||||||
{
|
{
|
||||||
const CStack * attacked = cb->battleGetStackByID(i->stackAttacked);
|
const CStack * attacked = cb->battleGetStackByID(i->stackAttacked);
|
||||||
battleInt->stackAttacking(attacker, cb->battleGetPos(i->stackAttacked), attacked, true);
|
battleInt->stackAttacking(attacker, attacked->position, attacked, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -654,9 +654,24 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
|
|||||||
break;
|
break;
|
||||||
case ESpellCastProblem::SPELL_LEVEL_LIMIT_EXCEEDED:
|
case ESpellCastProblem::SPELL_LEVEL_LIMIT_EXCEEDED:
|
||||||
{
|
{
|
||||||
std::string text = CGI->generaltexth->allTexts[541], caster = owner->myHero->name;
|
//Recanter's Cloak or similar effect. Try to retrieve bonus
|
||||||
text = boost::str(boost::format(text) % caster);
|
const Bonus *b = owner->myHero->getBonus(Selector::type(Bonus::BLOCK_MAGIC_ABOVE));
|
||||||
owner->myInt->showInfoDialog(text);
|
//TODO what about other values and non-artifact sources?
|
||||||
|
if(b && b->val == 2 && b->source == Bonus::ARTIFACT)
|
||||||
|
{
|
||||||
|
std::string artName = CGI->arth->artifacts[b->sid]->Name();
|
||||||
|
//The %s prevents %s from casting 3rd level or higher spells.
|
||||||
|
owner->myInt->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[536])
|
||||||
|
% artName % owner->myHero->name));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// General message:
|
||||||
|
// %s recites the incantations but they seem to have no effect.
|
||||||
|
std::string text = CGI->generaltexth->allTexts[541], caster = owner->myHero->name;
|
||||||
|
text = boost::str(boost::format(text) % caster);
|
||||||
|
owner->myInt->showInfoDialog(text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ESpellCastProblem::NO_APPROPRIATE_TARGET:
|
case ESpellCastProblem::NO_APPROPRIATE_TARGET:
|
||||||
|
@ -117,7 +117,7 @@ void CClient::waitForMoveAndSend(int color)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
assert(vstd::contains(battleints, color));
|
assert(vstd::contains(battleints, color));
|
||||||
BattleAction ba = battleints[color]->activeStack(gs->curB->getStack(gs->curB->activeStack, false));
|
BattleAction ba = battleints[color]->activeStack(gs->curB->battleGetStackByID(gs->curB->activeStack, false));
|
||||||
MakeAction temp_action(ba);
|
MakeAction temp_action(ba);
|
||||||
sendRequest(&temp_action, color);
|
sendRequest(&temp_action, color);
|
||||||
return;
|
return;
|
||||||
@ -381,13 +381,14 @@ void CClient::newGame( CConnection *con, StartInfo *si )
|
|||||||
battleints[color] = playerint[color];
|
battleints[color] = playerint[color];
|
||||||
|
|
||||||
playerint[color]->init(cb.get());
|
playerint[color]->init(cb.get());
|
||||||
callbacks[color] = cb;
|
battleCallbacks[color] = callbacks[color] = cb;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CBattleCallback * cbc = new CBattleCallback(gs, color, this);
|
auto cbc = make_shared<CBattleCallback>(gs, color, this);
|
||||||
|
battleCallbacks[color] = cbc;
|
||||||
battleints[color] = CDynLibHandler::getNewBattleAI("StupidAI");
|
battleints[color] = CDynLibHandler::getNewBattleAI("StupidAI");
|
||||||
battleints[color]->init(cbc);
|
battleints[color]->init(cbc.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,7 +400,9 @@ void CClient::newGame( CConnection *con, StartInfo *si )
|
|||||||
battleints[254] = playerint[254] = p;
|
battleints[254] = playerint[254] = p;
|
||||||
privilagedBattleEventReceivers.push_back(p);
|
privilagedBattleEventReceivers.push_back(p);
|
||||||
GH.curInt = p;
|
GH.curInt = p;
|
||||||
p->init(new CCallback(gs, -1, this));
|
auto cb = make_shared<CCallback>(gs, -1, this);
|
||||||
|
battleCallbacks[-1] = callbacks[-1] = cb;
|
||||||
|
p->init(cb.get());
|
||||||
battleStarted(gs->curB);
|
battleStarted(gs->curB);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -554,6 +557,15 @@ void CClient::stopConnection()
|
|||||||
|
|
||||||
void CClient::battleStarted(const BattleInfo * info)
|
void CClient::battleStarted(const BattleInfo * info)
|
||||||
{
|
{
|
||||||
|
BOOST_FOREACH(auto &battleCb, battleCallbacks)
|
||||||
|
{
|
||||||
|
if(vstd::contains(info->sides, battleCb.first) || battleCb.first >= GameConstants::PLAYER_LIMIT)
|
||||||
|
battleCb.second->setBattle(info);
|
||||||
|
}
|
||||||
|
// BOOST_FOREACH(ui8 side, info->sides)
|
||||||
|
// if(battleCallbacks.count(side))
|
||||||
|
// battleCallbacks[side]->setBattle(info);
|
||||||
|
|
||||||
CPlayerInterface * att, * def;
|
CPlayerInterface * att, * def;
|
||||||
if(vstd::contains(playerint, info->sides[0]) && playerint[info->sides[0]]->human)
|
if(vstd::contains(playerint, info->sides[0]) && playerint[info->sides[0]]->human)
|
||||||
att = static_cast<CPlayerInterface*>( playerint[info->sides[0]] );
|
att = static_cast<CPlayerInterface*>( playerint[info->sides[0]] );
|
||||||
@ -586,10 +598,19 @@ void CClient::battleStarted(const BattleInfo * info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CClient::battleFinished()
|
||||||
|
{
|
||||||
|
BOOST_FOREACH(ui8 side, gs->curB->sides)
|
||||||
|
if(battleCallbacks.count(side))
|
||||||
|
battleCallbacks[side]->setBattle(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
void CClient::loadNeutralBattleAI()
|
void CClient::loadNeutralBattleAI()
|
||||||
{
|
{
|
||||||
battleints[255] = CDynLibHandler::getNewBattleAI(settings["server"]["neutralAI"].String());
|
battleints[255] = CDynLibHandler::getNewBattleAI(settings["server"]["neutralAI"].String());
|
||||||
battleints[255]->init(new CBattleCallback(gs, 255, this));
|
auto cbc = make_shared<CBattleCallback>(gs, 255, this);
|
||||||
|
battleCallbacks[255] = cbc;
|
||||||
|
battleints[255]->init(cbc.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::commitPackage( CPackForClient *pack )
|
void CClient::commitPackage( CPackForClient *pack )
|
||||||
|
@ -114,6 +114,7 @@ class CClient : public IGameCallback
|
|||||||
public:
|
public:
|
||||||
CCallback *cb;
|
CCallback *cb;
|
||||||
std::map<ui8,shared_ptr<CCallback> > callbacks; //callbacks given to player interfaces
|
std::map<ui8,shared_ptr<CCallback> > callbacks; //callbacks given to player interfaces
|
||||||
|
std::map<ui8,shared_ptr<CBattleCallback> > battleCallbacks; //callbacks given to player interfaces
|
||||||
std::vector<IGameEventsReceiver*> privilagedGameEventReceivers; //scripting modules, spectator interfaces
|
std::vector<IGameEventsReceiver*> privilagedGameEventReceivers; //scripting modules, spectator interfaces
|
||||||
std::vector<IBattleEventsReceiver*> privilagedBattleEventReceivers; //scripting modules, spectator interfaces
|
std::vector<IBattleEventsReceiver*> privilagedBattleEventReceivers; //scripting modules, spectator interfaces
|
||||||
std::map<ui8,CGameInterface *> playerint;
|
std::map<ui8,CGameInterface *> playerint;
|
||||||
@ -225,4 +226,5 @@ public:
|
|||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version);
|
template <typename Handler> void serialize(Handler &h, const int version);
|
||||||
|
void battleFinished();
|
||||||
};
|
};
|
||||||
|
@ -589,7 +589,7 @@ void BattleNextRound::applyCl( CClient *cl )
|
|||||||
|
|
||||||
void BattleSetActiveStack::applyCl( CClient *cl )
|
void BattleSetActiveStack::applyCl( CClient *cl )
|
||||||
{
|
{
|
||||||
CStack * activated = GS(cl)->curB->getStack(stack);
|
const CStack * activated = GS(cl)->curB->battleGetStackByID(stack);
|
||||||
int playerToCall = -1; //player that will move activated stack
|
int playerToCall = -1; //player that will move activated stack
|
||||||
if( activated->hasBonusOfType(Bonus::HYPNOTIZED) )
|
if( activated->hasBonusOfType(Bonus::HYPNOTIZED) )
|
||||||
{
|
{
|
||||||
@ -616,11 +616,12 @@ void BattleObstaclePlaced::applyCl(CClient * cl)
|
|||||||
void BattleResult::applyFirstCl( CClient *cl )
|
void BattleResult::applyFirstCl( CClient *cl )
|
||||||
{
|
{
|
||||||
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleEnd,this);
|
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleEnd,this);
|
||||||
|
cl->battleFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BattleStackMoved::applyFirstCl( CClient *cl )
|
void BattleStackMoved::applyFirstCl( CClient *cl )
|
||||||
{
|
{
|
||||||
const CStack * movedStack = GS(cl)->curB->getStack(stack);
|
const CStack * movedStack = GS(cl)->curB->battleGetStackByID(stack);
|
||||||
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleStackMoved,movedStack,tilesToMove,distance);
|
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleStackMoved,movedStack,tilesToMove,distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +248,6 @@
|
|||||||
<ClCompile Include="CPlayerInterface.cpp" />
|
<ClCompile Include="CPlayerInterface.cpp" />
|
||||||
<ClCompile Include="CPreGame.cpp" />
|
<ClCompile Include="CPreGame.cpp" />
|
||||||
<ClCompile Include="CQuestLog.cpp" />
|
<ClCompile Include="CQuestLog.cpp" />
|
||||||
<ClCompile Include="CSndHandler.cpp" />
|
|
||||||
<ClCompile Include="CSpellWindow.cpp" />
|
<ClCompile Include="CSpellWindow.cpp" />
|
||||||
<ClCompile Include="CVideoHandler.cpp" />
|
<ClCompile Include="CVideoHandler.cpp" />
|
||||||
<ClCompile Include="Graphics.cpp" />
|
<ClCompile Include="Graphics.cpp" />
|
||||||
@ -289,12 +288,10 @@
|
|||||||
<ClInclude Include="CKingdomInterface.h" />
|
<ClInclude Include="CKingdomInterface.h" />
|
||||||
<ClInclude Include="Client.h" />
|
<ClInclude Include="Client.h" />
|
||||||
<ClInclude Include="CMessage.h" />
|
<ClInclude Include="CMessage.h" />
|
||||||
<ClInclude Include="CMusicBase.h" />
|
|
||||||
<ClInclude Include="CMusicHandler.h" />
|
<ClInclude Include="CMusicHandler.h" />
|
||||||
<ClInclude Include="CPlayerInterface.h" />
|
<ClInclude Include="CPlayerInterface.h" />
|
||||||
<ClInclude Include="CPreGame.h" />
|
<ClInclude Include="CPreGame.h" />
|
||||||
<ClInclude Include="CQuestLog.h" />
|
<ClInclude Include="CQuestLog.h" />
|
||||||
<ClInclude Include="CSndHandler.h" />
|
|
||||||
<ClInclude Include="CSoundBase.h" />
|
<ClInclude Include="CSoundBase.h" />
|
||||||
<ClInclude Include="CSpellWindow.h" />
|
<ClInclude Include="CSpellWindow.h" />
|
||||||
<ClInclude Include="CVideoHandler.h" />
|
<ClInclude Include="CVideoHandler.h" />
|
||||||
@ -315,7 +312,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\ChangeLog" />
|
<None Include="..\ChangeLog" />
|
||||||
<None Include="ClassDiagram21.cd" />
|
|
||||||
<None Include="vcmi.ico" />
|
<None Include="vcmi.ico" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -46,28 +46,23 @@
|
|||||||
<ClInclude Include="BattleInterface\CBattleInterfaceClasses.h" />
|
<ClInclude Include="BattleInterface\CBattleInterfaceClasses.h" />
|
||||||
<ClInclude Include="BattleInterface\CCreatureAnimation.h" />
|
<ClInclude Include="BattleInterface\CCreatureAnimation.h" />
|
||||||
<ClInclude Include="CAdvmapInterface.h" />
|
<ClInclude Include="CAdvmapInterface.h" />
|
||||||
<ClInclude Include="..\hch\CArtHandler.h" />
|
|
||||||
<ClInclude Include="CAnimation.h" />
|
<ClInclude Include="CAnimation.h" />
|
||||||
<ClInclude Include="CBitmapHandler.h" />
|
<ClInclude Include="CBitmapHandler.h" />
|
||||||
<ClInclude Include="..\hch\CBuildingHandler.h" />
|
|
||||||
<ClInclude Include="..\CCallback.h" />
|
<ClInclude Include="..\CCallback.h" />
|
||||||
<ClInclude Include="CCastleInterface.h" />
|
<ClInclude Include="CCastleInterface.h" />
|
||||||
<ClInclude Include="CConfigHandler.h" />
|
<ClInclude Include="CConfigHandler.h" />
|
||||||
<ClInclude Include="CCreatureWindow.h" />
|
<ClInclude Include="CCreatureWindow.h" />
|
||||||
<ClInclude Include="CDefHandler.h" />
|
<ClInclude Include="CDefHandler.h" />
|
||||||
<ClInclude Include="CGameInfo.h" />
|
<ClInclude Include="CGameInfo.h" />
|
||||||
<ClInclude Include="..\hch\CHeroHandler.h" />
|
|
||||||
<ClInclude Include="CHeroWindow.h" />
|
<ClInclude Include="CHeroWindow.h" />
|
||||||
<ClInclude Include="CKingdomInterface.h" />
|
<ClInclude Include="CKingdomInterface.h" />
|
||||||
<ClInclude Include="Client.h" />
|
<ClInclude Include="Client.h" />
|
||||||
<ClInclude Include="CMessage.h" />
|
<ClInclude Include="CMessage.h" />
|
||||||
<ClInclude Include="..\hch\CObjectHandler.h" />
|
|
||||||
<ClInclude Include="CMusicHandler.h" />
|
<ClInclude Include="CMusicHandler.h" />
|
||||||
<ClInclude Include="CPlayerInterface.h" />
|
<ClInclude Include="CPlayerInterface.h" />
|
||||||
<ClInclude Include="CPreGame.h" />
|
<ClInclude Include="CPreGame.h" />
|
||||||
<ClInclude Include="CSoundBase.h" />
|
<ClInclude Include="CSoundBase.h" />
|
||||||
<ClInclude Include="CSpellWindow.h" />
|
<ClInclude Include="CSpellWindow.h" />
|
||||||
<ClInclude Include="..\hch\CVideoHandler.h" />
|
|
||||||
<ClInclude Include="CVideoHandler.h" />
|
<ClInclude Include="CVideoHandler.h" />
|
||||||
<ClInclude Include="FontBase.h" />
|
<ClInclude Include="FontBase.h" />
|
||||||
<ClInclude Include="FunctionList.h" />
|
<ClInclude Include="FunctionList.h" />
|
||||||
@ -86,6 +81,7 @@
|
|||||||
<ClCompile Include="CQuestLog.cpp">
|
<ClCompile Include="CQuestLog.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClInclude Include="mapHandler.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="VCMI_client.rc" />
|
<ResourceCompile Include="VCMI_client.rc" />
|
||||||
@ -94,6 +90,7 @@
|
|||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<None Include="..\ChangeLog" />
|
||||||
<None Include="vcmi.ico" />
|
<None Include="vcmi.ico" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -84,11 +84,10 @@ char BattleHex::getDistance(BattleHex hex1, BattleHex hex2)
|
|||||||
return std::max(xDst, yDst) + std::min(xDst, yDst) - (yDst + (yDst + xDst < 2 ? 0 : 1))/2;
|
return std::max(xDst, yDst) + std::min(xDst, yDst) - (yDst + (yDst + xDst < 2 ? 0 : 1))/2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BattleHex::checkAndPush(int tile, std::vector<BattleHex> & ret)
|
void BattleHex::checkAndPush(BattleHex tile, std::vector<BattleHex> & ret)
|
||||||
{
|
{
|
||||||
if( tile>=0 && tile<GameConstants::BFIELD_SIZE && (tile%GameConstants::BFIELD_WIDTH != (GameConstants::BFIELD_WIDTH - 1))
|
if(tile.isAvailable())
|
||||||
&& (tile%GameConstants::BFIELD_WIDTH != 0) )
|
ret.push_back(tile);
|
||||||
ret.push_back(BattleHex(tile));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BattleHex::isAvailable() const
|
bool BattleHex::isAvailable() const
|
||||||
|
@ -108,7 +108,7 @@ struct DLL_LINKAGE BattleHex
|
|||||||
{
|
{
|
||||||
h & hex;
|
h & hex;
|
||||||
}
|
}
|
||||||
static void checkAndPush(int tile, std::vector<BattleHex> & ret);
|
static void checkAndPush(BattleHex tile, std::vector<BattleHex> & ret);
|
||||||
|
|
||||||
bool isAvailable() const; //valid position not in first or last column
|
bool isAvailable() const; //valid position not in first or last column
|
||||||
};
|
};
|
1850
lib/BattleState.cpp
1850
lib/BattleState.cpp
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,7 @@
|
|||||||
#include "CObstacleInstance.h"
|
#include "CObstacleInstance.h"
|
||||||
#include "ConstTransitivePtr.h"
|
#include "ConstTransitivePtr.h"
|
||||||
#include "GameConstants.h"
|
#include "GameConstants.h"
|
||||||
|
#include "CBattleCallback.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BattleState.h, part of VCMI engine
|
* BattleState.h, part of VCMI engine
|
||||||
@ -28,10 +29,11 @@ class CStackInstance;
|
|||||||
struct BattleStackAttacked;
|
struct BattleStackAttacked;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//only for use in BattleInfo
|
//only for use in BattleInfo
|
||||||
struct DLL_LINKAGE SiegeInfo
|
struct DLL_LINKAGE SiegeInfo
|
||||||
{
|
{
|
||||||
ui8 wallState[8]; //[0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; 1 - intact, 2 - damaged, 3 - destroyed
|
ui8 wallState[EWallParts::PARTS_COUNT];
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
@ -39,17 +41,9 @@ struct DLL_LINKAGE SiegeInfo
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DLL_LINKAGE AttackableTiles
|
|
||||||
{
|
|
||||||
std::set<BattleHex> hostileCreaturePositions;
|
|
||||||
std::set<BattleHex> friendlyCreaturePositions; //for Dragon Breath
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
|
||||||
{
|
|
||||||
h & hostileCreaturePositions & friendlyCreaturePositions;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DLL_LINKAGE BattleInfo : public CBonusSystemNode
|
|
||||||
|
struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallback
|
||||||
{
|
{
|
||||||
ui8 sides[2]; //sides[0] - attacker, sides[1] - defender
|
ui8 sides[2]; //sides[0] - attacker, sides[1] - defender
|
||||||
si32 round, activeStack, selectedStack;
|
si32 round, activeStack, selectedStack;
|
||||||
@ -81,82 +75,62 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode
|
|||||||
h & static_cast<CBonusSystemNode&>(*this);
|
h & static_cast<CBonusSystemNode&>(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
BattleInfo();
|
||||||
|
~BattleInfo(){};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
//void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const;
|
//void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const;
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
const CStack *getStackIf(boost::function<bool(const CStack*)> pred) const;
|
|
||||||
const CStack * getNextStack() const; //which stack will have turn after current one
|
|
||||||
void getStackQueue(std::vector<const CStack *> &out, int howMany, int turn = 0, int lastMoved = -1) const; //returns stack in order of their movement action
|
|
||||||
CStack * getStack(int stackID, bool onlyAlive = true);
|
|
||||||
const CStack * getStack(int stackID, bool onlyAlive = true) const;
|
|
||||||
CStack * getStackT(BattleHex tileID, bool onlyAlive = true);
|
CStack * getStackT(BattleHex tileID, bool onlyAlive = true);
|
||||||
const CStack * getStackT(BattleHex tileID, bool onlyAlive = true) const;
|
CStack * getStack(int stackID, bool onlyAlive = true);
|
||||||
void getAccessibilityMap(bool *accessibility, bool twoHex, bool attackerOwned, bool addOccupiable, std::set<BattleHex> & occupyable, bool flying, const CStack* stackToOmmit = NULL) const; //send pointer to at least 187 allocated bytes
|
|
||||||
static bool isAccessible(BattleHex hex, bool * accessibility, bool twoHex, bool attackerOwned, bool flying, bool lastPos); //helper for makeBFS
|
const CStack * getNextStack() const; //which stack will have turn after current one
|
||||||
|
//void getStackQueue(std::vector<const CStack *> &out, int howMany, int turn = 0, int lastMoved = -1) const; //returns stack in order of their movement action
|
||||||
|
|
||||||
|
//void getAccessibilityMap(bool *accessibility, bool twoHex, bool attackerOwned, bool addOccupiable, std::set<BattleHex> & occupyable, bool flying, const CStack* stackToOmmit = NULL) const; //send pointer to at least 187 allocated bytes
|
||||||
|
//static bool isAccessible(BattleHex hex, bool * accessibility, bool twoHex, bool attackerOwned, bool flying, bool lastPos); //helper for makeBFS
|
||||||
BattleHex getClosestTile (bool attackerOwned, int initialPos, std::set<BattleHex> & possibilities) const; //TODO: vector or set? copying one to another is bad
|
BattleHex getClosestTile (bool attackerOwned, int initialPos, std::set<BattleHex> & possibilities) const; //TODO: vector or set? copying one to another is bad
|
||||||
int getAvaliableHex(TCreature creID, bool attackerOwned, int initialPos = -1) const; //find place for summon / clone effects
|
int getAvaliableHex(TCreature creID, bool attackerOwned, int initialPos = -1) const; //find place for summon / clone effects
|
||||||
void makeBFS(BattleHex start, bool*accessibility, BattleHex *predecessor, int *dists, bool twoHex, bool attackerOwned, bool flying, bool fillPredecessors) const; //*accessibility must be prepared bool[187] array; last two pointers must point to the at least 187-elements int arrays - there is written result
|
//void makeBFS(BattleHex start, bool*accessibility, BattleHex *predecessor, int *dists, bool twoHex, bool attackerOwned, bool flying, bool fillPredecessors) const; //*accessibility must be prepared bool[187] array; last two pointers must point to the at least 187-elements int arrays - there is written result
|
||||||
std::pair< std::vector<BattleHex>, int > getPath(BattleHex start, BattleHex dest, bool*accessibility, bool flyingCreature, bool twoHex, bool attackerOwned); //returned value: pair<path, length>; length may be different than number of elements in path since flying vreatures jump between distant hexes
|
std::pair< std::vector<BattleHex>, int > getPath(BattleHex start, BattleHex dest, const CStack *stack); //returned value: pair<path, length>; length may be different than number of elements in path since flying vreatures jump between distant hexes
|
||||||
std::vector<BattleHex> getAccessibility(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = NULL, bool forPassingBy = false) const; //returns vector of accessible tiles (taking into account the creature range)
|
//std::vector<BattleHex> getAccessibility(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = NULL, bool forPassingBy = false) const; //returns vector of accessible tiles (taking into account the creature range)
|
||||||
|
|
||||||
bool isObstacleVisibleForSide(const CObstacleInstance &obstacle, ui8 side) const;
|
//bool isObstacleVisibleForSide(const CObstacleInstance &obstacle, ui8 side) const;
|
||||||
shared_ptr<CObstacleInstance> getObstacleOnTile(BattleHex tile) const;
|
shared_ptr<CObstacleInstance> getObstacleOnTile(BattleHex tile) const;
|
||||||
bool isStackBlocked(const CStack * stack) const; //returns true if there is neighboring enemy stack
|
|
||||||
std::set<BattleHex> getStoppers(bool whichSidePerspective) const;
|
std::set<BattleHex> getStoppers(bool whichSidePerspective) const;
|
||||||
|
|
||||||
ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky, bool deathBlow, bool ballistaDoubleDmg); //charge - number of hexes travelled before attack (for champion's jousting)
|
ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky, bool deathBlow, bool ballistaDoubleDmg); //charge - number of hexes travelled before attack (for champion's jousting)
|
||||||
TDmgRange calculateDmgRange(const CStack* attacker, const CStack* defender, TQuantity attackerCount, TQuantity defenderCount, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky, bool deathBlow, bool ballistaDoubleDmg) const; //charge - number of hexes travelled before attack (for champion's jousting); returns pair <min dmg, max dmg>
|
|
||||||
TDmgRange calculateDmgRange(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky, bool deathBlow, bool ballistaDoubleDmg) const; //charge - number of hexes travelled before attack (for champion's jousting); returns pair <min dmg, max dmg>
|
|
||||||
void calculateCasualties(std::map<ui32,si32> *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount)
|
void calculateCasualties(std::map<ui32,si32> *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount)
|
||||||
std::set<CStack*> getAttackedCreatures(const CSpell * s, int skillLevel, ui8 attackerOwner, BattleHex destinationTile); //calculates stack affected by given spell
|
using CBattleInfoCallback::getAttackedCreatures;
|
||||||
void getPotentiallyAttackableHexes(AttackableTiles &at, const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos); //hexes around target that could be attacked in melee
|
std::set<const CStack*> getAttackedCreatures(const CSpell * s, int skillLevel, ui8 attackerOwner, BattleHex destinationTile); //calculates stack affected by given spell
|
||||||
std::set<CStack*> getAttackedCreatures(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID); //calculates range of multi-hex attacks
|
//void getPotentiallyAttackableHexes(AttackableTiles &at, const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos); //hexes around target that could be attacked in melee
|
||||||
std::set<BattleHex> getAttackedHexes(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID); //calculates range of multi-hex attacks
|
//std::set<CStack*> getAttackedCreatures(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID); //calculates range of multi-hex attacks
|
||||||
std::set<CStack*> getAdjacentCreatures (const CStack * stack) const;
|
//std::set<BattleHex> getAttackedHexes(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID); //calculates range of multi-hex attacks
|
||||||
static int calculateSpellDuration(const CSpell * spell, const CGHeroInstance * caster, int usedSpellPower);
|
static int calculateSpellDuration(const CSpell * spell, const CGHeroInstance * caster, int usedSpellPower);
|
||||||
CStack * generateNewStack(const CStackInstance &base, bool attackerOwned, int slot, BattleHex position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
|
CStack * generateNewStack(const CStackInstance &base, bool attackerOwned, int slot, BattleHex position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
|
||||||
CStack * generateNewStack(const CStackBasicDescriptor &base, bool attackerOwned, int slot, BattleHex position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
|
CStack * generateNewStack(const CStackBasicDescriptor &base, bool attackerOwned, int slot, BattleHex position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
|
||||||
int getIdForNewStack() const; //suggest a currently unused ID that'd suitable for generating a new stack
|
int getIdForNewStack() const; //suggest a currently unused ID that'd suitable for generating a new stack
|
||||||
ui32 getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //returns cost of given spell
|
//std::pair<const CStack *, BattleHex> getNearestStack(const CStack * closest, boost::logic::tribool attackerOwned) const; //if attackerOwned is indetermnate, returened stack is of any owner; hex is the number of hex we should be looking from; returns (nerarest creature, predecessorHex)
|
||||||
int hexToWallPart(BattleHex hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
|
||||||
int lineToWallHex(int line) const; //returns hex with wall in given line
|
|
||||||
std::pair<const CStack *, BattleHex> getNearestStack(const CStack * closest, boost::logic::tribool attackerOwned) const; //if attackerOwned is indetermnate, returened stack is of any owner; hex is the number of hex we should be looking from; returns (nerarest creature, predecessorHex)
|
|
||||||
ui32 calculateSpellBonus(ui32 baseDamage, const CSpell * sp, const CGHeroInstance * caster, const CStack * affectedCreature) const;
|
ui32 calculateSpellBonus(ui32 baseDamage, const CSpell * sp, const CGHeroInstance * caster, const CStack * affectedCreature) const;
|
||||||
ui32 calculateSpellDmg(const CSpell * sp, const CGHeroInstance * caster, const CStack * affectedCreature, int spellSchoolLevel, int usedSpellPower) const; //calculates damage inflicted by spell
|
ui32 calculateSpellDmg(const CSpell * sp, const CGHeroInstance * caster, const CStack * affectedCreature, int spellSchoolLevel, int usedSpellPower) const; //calculates damage inflicted by spell
|
||||||
ui32 calculateHealedHP(const CGHeroInstance * caster, const CSpell * spell, const CStack * stack, const CStack * sacrificedStack = NULL) const;
|
ui32 calculateHealedHP(const CGHeroInstance * caster, const CSpell * spell, const CStack * stack, const CStack * sacrificedStack = NULL) const;
|
||||||
ui32 calculateHealedHP(int healedHealth, const CSpell * spell, const CStack * stack) const; //for Archangel
|
ui32 calculateHealedHP(int healedHealth, const CSpell * spell, const CStack * stack) const; //for Archangel
|
||||||
ui32 calculateHealedHP(const CSpell * spell, int usedSpellPower, int spellSchoolLevel, const CStack * stack) const; //unused
|
ui32 calculateHealedHP(const CSpell * spell, int usedSpellPower, int spellSchoolLevel, const CStack * stack) const; //unused
|
||||||
bool resurrects(TSpell spellid) const; //TODO: move it to spellHandler?
|
bool resurrects(TSpell spellid) const; //TODO: move it to spellHandler?
|
||||||
si8 hasDistancePenalty(const CStack * stackID, BattleHex destHex) const; //determines if given stack has distance penalty shooting given pos
|
|
||||||
si8 sameSideOfWall(int pos1, int pos2) const; //determines if given positions are on the same side of wall
|
|
||||||
si8 hasWallPenalty(const CStack * stack, BattleHex destHex) const; //determines if given stack has wall penalty shooting given pos
|
|
||||||
si8 canTeleportTo(const CStack * stack, BattleHex destHex, int telportLevel) const; //determines if given stack can teleport to given place
|
|
||||||
bool battleCanShoot(const CStack * stack, BattleHex dest) const; //determines if stack with given ID shoot at the selected destination
|
|
||||||
const CGHeroInstance * getHero(int player) const; //returns fighting hero that belongs to given player
|
const CGHeroInstance * getHero(int player) const; //returns fighting hero that belongs to given player
|
||||||
|
|
||||||
ESpellCastProblem::ESpellCastProblem battleCanCastSpell(int player, ECastingMode::ECastingMode mode) const; //returns true if there are no general issues preventing from casting a spell
|
|
||||||
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(int player, const CSpell * spell, ECastingMode::ECastingMode mode) const; //checks if given player can cast given spell
|
|
||||||
ESpellCastProblem::ESpellCastProblem battleIsImmune(const CGHeroInstance * caster, const CSpell * spell, ECastingMode::ECastingMode mode, BattleHex dest) const; //checks for creature immunity / anything that prevent casting *at given hex* - doesn't take into acount general problems such as not having spellbook or mana points etc.
|
|
||||||
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpellHere(int player, const CSpell * spell, ECastingMode::ECastingMode mode, BattleHex dest) const; //checks if given player can cast given spell at given tile in given mode
|
|
||||||
bool battleTestElementalImmunity(const CStack * subject, const CSpell * spell, Bonus::BonusType element, bool damageSpell) const;
|
|
||||||
TSpell getRandomBeneficialSpell(const CStack * subject) const;
|
|
||||||
TSpell getRandomCastedSpell(const CStack * caster) const; //called at the beginning of turn for Faerie Dragon
|
|
||||||
|
|
||||||
std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHeroInstance * caster, const CGHeroInstance * hero2, const std::set<CStack*> affectedCreatures, int casterSideOwner, ECastingMode::ECastingMode mode, int usedSpellPower, int spellLevel) const;
|
std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHeroInstance * caster, const CGHeroInstance * hero2, const std::set<const CStack*> affectedCreatures, int casterSideOwner, ECastingMode::ECastingMode mode, int usedSpellPower, int spellLevel) const;
|
||||||
|
|
||||||
|
|
||||||
bool battleCanFlee(int player) const; //returns true if player can flee from the battle
|
|
||||||
const CStack * battleGetStack(BattleHex pos, bool onlyAlive); //returns stack at given tile
|
const CStack * battleGetStack(BattleHex pos, bool onlyAlive); //returns stack at given tile
|
||||||
const CGHeroInstance * battleGetOwner(const CStack * stack) const; //returns hero that owns given stack; NULL if none
|
const CGHeroInstance * battleGetOwner(const CStack * stack) const; //returns hero that owns given stack; NULL if none
|
||||||
si8 battleMinSpellLevel() const; //calculates minimum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, 0 is returned
|
|
||||||
void localInit();
|
void localInit();
|
||||||
|
|
||||||
void localInitStack(CStack * s);
|
void localInitStack(CStack * s);
|
||||||
static BattleInfo * setupBattle( int3 tile, int terrain, int battlefieldType, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town );
|
static BattleInfo * setupBattle( int3 tile, int terrain, int battlefieldType, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town );
|
||||||
bool isInTacticRange( BattleHex dest ) const;
|
//bool hasNativeStack(ui8 side) const;
|
||||||
int getSurrenderingCost(int player) const;
|
|
||||||
bool hasNativeStack(ui8 side) const;
|
|
||||||
|
|
||||||
int theOtherPlayer(int player) const;
|
int theOtherPlayer(int player) const;
|
||||||
ui8 whatSide(int player) const;
|
ui8 whatSide(int player) const;
|
||||||
@ -168,7 +142,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode
|
|||||||
class DLL_LINKAGE CStack : public CBonusSystemNode, public CStackBasicDescriptor
|
class DLL_LINKAGE CStack : public CBonusSystemNode, public CStackBasicDescriptor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const CStackInstance *base;
|
const CStackInstance *base; //garrison slot from which stack originates (NULL for war machines, summoned cres, etc)
|
||||||
|
|
||||||
ui32 ID; //unique ID of stack
|
ui32 ID; //unique ID of stack
|
||||||
ui32 baseAmount;
|
ui32 baseAmount;
|
||||||
@ -226,7 +200,10 @@ public:
|
|||||||
|
|
||||||
bool doubleWide() const;
|
bool doubleWide() const;
|
||||||
BattleHex occupiedHex() const; //returns number of occupied hex (not the position) if stack is double wide; otherwise -1
|
BattleHex occupiedHex() const; //returns number of occupied hex (not the position) if stack is double wide; otherwise -1
|
||||||
|
BattleHex occupiedHex(BattleHex assumedPos) const; //returns number of occupied hex (not the position) if stack is double wide and would stand on assumedPos; otherwise -1
|
||||||
std::vector<BattleHex> getHexes() const; //up to two occupied hexes, starting from front
|
std::vector<BattleHex> getHexes() const; //up to two occupied hexes, starting from front
|
||||||
|
std::vector<BattleHex> getHexes(BattleHex assumedPos) const; //up to two occupied hexes, starting from front
|
||||||
|
static std::vector<BattleHex> getHexes(BattleHex assumedPos, bool twoHex, bool AttackerOwned); //up to two occupied hexes, starting from front
|
||||||
bool coversPos(BattleHex position) const; //checks also if unit is double-wide
|
bool coversPos(BattleHex position) const; //checks also if unit is double-wide
|
||||||
std::vector<BattleHex> getSurroundingHexes(BattleHex attackerPos = BattleHex::INVALID) const; // get six or 8 surrounding hexes depending on creature size
|
std::vector<BattleHex> getSurroundingHexes(BattleHex attackerPos = BattleHex::INVALID) const; // get six or 8 surrounding hexes depending on creature size
|
||||||
|
|
||||||
|
@ -526,31 +526,46 @@ void CArtHandler::getAllowedArts(std::vector<ConstTransitivePtr<CArtifact> > &ou
|
|||||||
out.push_back(art);
|
out.push_back(art);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void CArtHandler::giveArtBonus( int aid, Bonus::BonusType type, int val, int subtype, int valType, ILimiter * limiter, int additionalInfo)
|
|
||||||
|
Bonus *createBonus(Bonus::BonusType type, int val, int subtype, int valType, shared_ptr<ILimiter> limiter = nullptr, int additionalInfo = 0)
|
||||||
{
|
{
|
||||||
Bonus *added = new Bonus(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,aid,subtype);
|
Bonus *added = new Bonus(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,-1,subtype);
|
||||||
added->additionalInfo = additionalInfo;
|
added->additionalInfo = additionalInfo;
|
||||||
added->valType = valType;
|
added->valType = valType;
|
||||||
added->limiter.reset(limiter);
|
added->limiter = limiter;
|
||||||
if(type == Bonus::MORALE || type == Bonus::LUCK)
|
return added;
|
||||||
added->description = artifacts[aid]->Name() + (val > 0 ? " +" : " ") + boost::lexical_cast<std::string>(val);
|
|
||||||
else
|
|
||||||
added->description = artifacts[aid]->Name();
|
|
||||||
artifacts[aid]->addNewBonus(added);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CArtHandler::giveArtBonus(int aid, Bonus::BonusType type, int val, int subtype, IPropagator* propagator /*= NULL*/, int additionalInfo)
|
Bonus *createBonus(Bonus::BonusType type, int val, int subtype, shared_ptr<IPropagator> propagator = nullptr, int additionalInfo = 0)
|
||||||
{
|
{
|
||||||
Bonus *added = new Bonus(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,aid,subtype);
|
Bonus *added = new Bonus(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,-1,subtype);
|
||||||
added->additionalInfo = additionalInfo;
|
added->additionalInfo = additionalInfo;
|
||||||
added->valType = Bonus::BASE_NUMBER;
|
added->valType = Bonus::BASE_NUMBER;
|
||||||
added->propagator.reset(propagator);
|
added->propagator = propagator;
|
||||||
if(type == Bonus::MORALE || type == Bonus::LUCK)
|
return added;
|
||||||
added->description = artifacts[aid]->Name() + (val > 0 ? " +" : " ") + boost::lexical_cast<std::string>(val);
|
|
||||||
else
|
|
||||||
added->description = artifacts[aid]->Name();
|
|
||||||
artifacts[aid]->addNewBonus(added);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CArtHandler::giveArtBonus( int aid, Bonus::BonusType type, int val, int subtype, int valType, shared_ptr<ILimiter> limiter, int additionalInfo)
|
||||||
|
{
|
||||||
|
giveArtBonus(aid, createBonus(type, val, subtype, valType, limiter, additionalInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CArtHandler::giveArtBonus(int aid, Bonus::BonusType type, int val, int subtype, shared_ptr<IPropagator> propagator /*= NULL*/, int additionalInfo)
|
||||||
|
{
|
||||||
|
giveArtBonus(aid, createBonus(type, val, subtype, propagator, additionalInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CArtHandler::giveArtBonus(int aid, Bonus *bonus)
|
||||||
|
{
|
||||||
|
bonus->sid = aid;
|
||||||
|
if(bonus->subtype == Bonus::MORALE || bonus->type == Bonus::LUCK)
|
||||||
|
bonus->description = artifacts[aid]->Name() + (bonus->val > 0 ? " +" : " ") + boost::lexical_cast<std::string>(bonus->val);
|
||||||
|
else
|
||||||
|
bonus->description = artifacts[aid]->Name();
|
||||||
|
|
||||||
|
artifacts[aid]->addNewBonus(bonus);
|
||||||
|
}
|
||||||
|
|
||||||
void CArtHandler::makeItCreatureArt (int aid, bool onlyCreature /*=true*/)
|
void CArtHandler::makeItCreatureArt (int aid, bool onlyCreature /*=true*/)
|
||||||
{
|
{
|
||||||
CArtifact *a = artifacts[aid];
|
CArtifact *a = artifacts[aid];
|
||||||
@ -584,6 +599,13 @@ void CArtHandler::addBonuses()
|
|||||||
#define ART_ATTACK_AND_DEFENSE(ID, val) ART_PRIM_SKILL(ID,0,val); ART_PRIM_SKILL(ID,1,val)
|
#define ART_ATTACK_AND_DEFENSE(ID, val) ART_PRIM_SKILL(ID,0,val); ART_PRIM_SKILL(ID,1,val)
|
||||||
#define ART_POWER_AND_KNOWLEDGE(ID, val) ART_PRIM_SKILL(ID,2,val); ART_PRIM_SKILL(ID,3,val)
|
#define ART_POWER_AND_KNOWLEDGE(ID, val) ART_PRIM_SKILL(ID,2,val); ART_PRIM_SKILL(ID,3,val)
|
||||||
|
|
||||||
|
//Propagators/limiters used more than once
|
||||||
|
auto battleWidePropagator = make_shared<CPropagatorNodeType>(CBonusSystemNode::BATTLE);
|
||||||
|
auto visitedTownPropagator = make_shared<CPropagatorNodeType>(CBonusSystemNode::TOWN_AND_VISITOR);
|
||||||
|
|
||||||
|
auto shooterOnlyLimiter = make_shared<HasAnotherBonusLimiter>(Bonus::SHOOTER);
|
||||||
|
auto dragonNatureLimiter = make_shared<HasAnotherBonusLimiter>(Bonus::DRAGON_NATURE);
|
||||||
|
|
||||||
//Attack bonus artifacts (Weapons)
|
//Attack bonus artifacts (Weapons)
|
||||||
ART_PRIM_SKILL(7,0,+2); //Centaur Axe
|
ART_PRIM_SKILL(7,0,+2); //Centaur Axe
|
||||||
ART_PRIM_SKILL(8,0,+3); //Blackshard of the Dead Knight
|
ART_PRIM_SKILL(8,0,+3); //Blackshard of the Dead Knight
|
||||||
@ -697,7 +719,7 @@ void CArtHandler::addBonuses()
|
|||||||
giveArtBonus(81,Bonus::FIRE_SPELL_DMG_PREMY,+50);//Orb of Tempestuous Fire
|
giveArtBonus(81,Bonus::FIRE_SPELL_DMG_PREMY,+50);//Orb of Tempestuous Fire
|
||||||
giveArtBonus(82,Bonus::WATER_SPELL_DMG_PREMY,+50);//Orb of Driving Rain
|
giveArtBonus(82,Bonus::WATER_SPELL_DMG_PREMY,+50);//Orb of Driving Rain
|
||||||
|
|
||||||
giveArtBonus(83,Bonus::LEVEL_SPELL_IMMUNITY,3,-1,Bonus::INDEPENDENT_MAX);//Recanter's Cloak
|
giveArtBonus(83,createBonus(Bonus::BLOCK_MAGIC_ABOVE, 2, -1, Bonus::INDEPENDENT_MIN)->addPropagator(battleWidePropagator));//Recanter's Cloak
|
||||||
giveArtBonus(84,Bonus::BLOCK_MORALE,0);//Spirit of Oppression
|
giveArtBonus(84,Bonus::BLOCK_MORALE,0);//Spirit of Oppression
|
||||||
giveArtBonus(85,Bonus::BLOCK_LUCK,0);//Hourglass of the Evil Hour
|
giveArtBonus(85,Bonus::BLOCK_LUCK,0);//Hourglass of the Evil Hour
|
||||||
|
|
||||||
@ -707,8 +729,8 @@ void CArtHandler::addBonuses()
|
|||||||
giveArtBonus(89,Bonus::EARTH_SPELLS,0);//Tome of Earth Magic
|
giveArtBonus(89,Bonus::EARTH_SPELLS,0);//Tome of Earth Magic
|
||||||
|
|
||||||
giveArtBonus(90,Bonus::WATER_WALKING, 0, 1);//Boots of Levitation
|
giveArtBonus(90,Bonus::WATER_WALKING, 0, 1);//Boots of Levitation
|
||||||
giveArtBonus(91,Bonus::NO_DISTANCE_PENALTY,0, 0, 0, new HasAnotherBonusLimiter(Bonus::SHOOTER));//Golden Bow
|
giveArtBonus(91,Bonus::NO_DISTANCE_PENALTY,0, 0, 0, shooterOnlyLimiter);//Golden Bow
|
||||||
giveArtBonus(91,Bonus::NO_WALL_PENALTY, 0, 0, 0, new HasAnotherBonusLimiter(Bonus::SHOOTER));
|
giveArtBonus(91,Bonus::NO_WALL_PENALTY, 0, 0, 0, shooterOnlyLimiter);
|
||||||
giveArtBonus(92,Bonus::SPELL_IMMUNITY,0,35);//Sphere of Permanence
|
giveArtBonus(92,Bonus::SPELL_IMMUNITY,0,35);//Sphere of Permanence
|
||||||
giveArtBonus(93,Bonus::NEGATE_ALL_NATURAL_IMMUNITIES,0);//Orb of Vulnerability
|
giveArtBonus(93,Bonus::NEGATE_ALL_NATURAL_IMMUNITIES,0);//Orb of Vulnerability
|
||||||
|
|
||||||
@ -720,14 +742,15 @@ void CArtHandler::addBonuses()
|
|||||||
giveArtBonus(98,Bonus::LAND_MOVEMENT,+600);//Boots of Speed
|
giveArtBonus(98,Bonus::LAND_MOVEMENT,+600);//Boots of Speed
|
||||||
giveArtBonus(99,Bonus::STACKS_SPEED,+2);//Cape of Velocity
|
giveArtBonus(99,Bonus::STACKS_SPEED,+2);//Cape of Velocity
|
||||||
|
|
||||||
giveArtBonus(100,Bonus::SPELL_IMMUNITY,0,59);//Pendant of Dispassion
|
giveArtBonus(100,Bonus::SPELL_IMMUNITY,0,Spells::BERSERK);//Pendant of Dispassion
|
||||||
giveArtBonus(101,Bonus::SPELL_IMMUNITY,0,62);//Pendant of Second Sight
|
giveArtBonus(101,Bonus::SPELL_IMMUNITY,0,Spells::BLIND);//Pendant of Second Sight
|
||||||
giveArtBonus(102,Bonus::SPELL_IMMUNITY,0,42);//Pendant of Holiness
|
giveArtBonus(102,Bonus::SPELL_IMMUNITY,0,Spells::CURSE);//Pendant of Holiness
|
||||||
giveArtBonus(103,Bonus::SPELL_IMMUNITY,0,24);//Pendant of Life
|
giveArtBonus(103,Bonus::SPELL_IMMUNITY,0,Spells::DEATH_RIPPLE);//Pendant of Life
|
||||||
giveArtBonus(104,Bonus::SPELL_IMMUNITY,0,25, 1, new HasAnotherBonusLimiter(Bonus::UNDEAD));//Pendant of Death does not display info for living stacks
|
giveArtBonus(104,Bonus::SPELL_IMMUNITY,0,Spells::DESTROY_UNDEAD, 1, make_shared<HasAnotherBonusLimiter>(Bonus::UNDEAD));//Pendant of Death does not display info for living stacks
|
||||||
giveArtBonus(105,Bonus::SPELL_IMMUNITY,0,60);//Pendant of Free Will
|
giveArtBonus(105,Bonus::SPELL_IMMUNITY,0,Spells::HYPNOTIZE);//Pendant of Free Will
|
||||||
giveArtBonus(106,Bonus::SPELL_IMMUNITY,0,17);//Pendant of Negativity
|
giveArtBonus(106,Bonus::SPELL_IMMUNITY,0,Spells::LIGHTNING_BOLT);//Pendant of Negativity
|
||||||
giveArtBonus(107,Bonus::SPELL_IMMUNITY,0,61);//Pendant of Total Recall
|
giveArtBonus(106,Bonus::SPELL_IMMUNITY,0,Spells::CHAIN_LIGHTNING);//Pendant of Negativity
|
||||||
|
giveArtBonus(107,Bonus::SPELL_IMMUNITY,0,Spells::FORGETFULNESS);//Pendant of Total Recall
|
||||||
giveArtBonus(108,Bonus::MORALE,+3);//Pendant of Courage
|
giveArtBonus(108,Bonus::MORALE,+3);//Pendant of Courage
|
||||||
giveArtBonus(108,Bonus::LUCK,+3);//Pendant of Courage
|
giveArtBonus(108,Bonus::LUCK,+3);//Pendant of Courage
|
||||||
|
|
||||||
@ -741,11 +764,13 @@ void CArtHandler::addBonuses()
|
|||||||
giveArtBonus(116,Bonus::GENERATE_RESOURCE,+750, Res::GOLD); //Endless Bag of Gold
|
giveArtBonus(116,Bonus::GENERATE_RESOURCE,+750, Res::GOLD); //Endless Bag of Gold
|
||||||
giveArtBonus(117,Bonus::GENERATE_RESOURCE,+500, Res::GOLD); //Endless Purse of Gold
|
giveArtBonus(117,Bonus::GENERATE_RESOURCE,+500, Res::GOLD); //Endless Purse of Gold
|
||||||
|
|
||||||
giveArtBonus(118,Bonus::CREATURE_GROWTH,+5,1, new CPropagatorNodeType(CBonusSystemNode::TOWN_AND_VISITOR)); //Legs of Legion
|
|
||||||
giveArtBonus(119,Bonus::CREATURE_GROWTH,+4,2, new CPropagatorNodeType(CBonusSystemNode::TOWN_AND_VISITOR)); //Loins of Legion
|
//Town will receive bonus if hero is visiting town or stays in its garrison.
|
||||||
giveArtBonus(120,Bonus::CREATURE_GROWTH,+3,3, new CPropagatorNodeType(CBonusSystemNode::TOWN_AND_VISITOR)); //Torso of Legion
|
giveArtBonus(118,Bonus::CREATURE_GROWTH,+5,1, visitedTownPropagator); //Legs of Legion
|
||||||
giveArtBonus(121,Bonus::CREATURE_GROWTH,+2,4, new CPropagatorNodeType(CBonusSystemNode::TOWN_AND_VISITOR)); //Arms of Legion
|
giveArtBonus(119,Bonus::CREATURE_GROWTH,+4,2, visitedTownPropagator); //Loins of Legion
|
||||||
giveArtBonus(122,Bonus::CREATURE_GROWTH,+1,5, new CPropagatorNodeType(CBonusSystemNode::TOWN_AND_VISITOR)); //Head of Legion
|
giveArtBonus(120,Bonus::CREATURE_GROWTH,+3,3, visitedTownPropagator); //Torso of Legion
|
||||||
|
giveArtBonus(121,Bonus::CREATURE_GROWTH,+2,4, visitedTownPropagator); //Arms of Legion
|
||||||
|
giveArtBonus(122,Bonus::CREATURE_GROWTH,+1,5, visitedTownPropagator); //Head of Legion
|
||||||
|
|
||||||
//Sea Captain's Hat
|
//Sea Captain's Hat
|
||||||
giveArtBonus(123,Bonus::WHIRLPOOL_PROTECTION,0);
|
giveArtBonus(123,Bonus::WHIRLPOOL_PROTECTION,0);
|
||||||
@ -753,13 +778,13 @@ void CArtHandler::addBonuses()
|
|||||||
giveArtBonus(123,Bonus::SPELL,3,0, Bonus::INDEPENDENT_MAX);
|
giveArtBonus(123,Bonus::SPELL,3,0, Bonus::INDEPENDENT_MAX);
|
||||||
giveArtBonus(123,Bonus::SPELL,3,1, Bonus::INDEPENDENT_MAX);
|
giveArtBonus(123,Bonus::SPELL,3,1, Bonus::INDEPENDENT_MAX);
|
||||||
|
|
||||||
giveArtBonus(124,Bonus::SPELLS_OF_LEVEL,3,1); //Spellbinder's Hat
|
giveArtBonus(124, Bonus::SPELLS_OF_LEVEL,3,1); //Spellbinder's Hat
|
||||||
giveArtBonus(125,Bonus::ENEMY_CANT_ESCAPE,0); //Shackles of War
|
giveArtBonus(125, Bonus::ENEMY_CANT_ESCAPE,0); //Shackles of War
|
||||||
giveArtBonus(126,Bonus::LEVEL_SPELL_IMMUNITY,GameConstants::SPELL_LEVELS,-1,Bonus::INDEPENDENT_MAX);//Orb of Inhibition
|
giveArtBonus(126, Bonus::BLOCK_ALL_MAGIC, 0, -1, battleWidePropagator);//Orb of Inhibition
|
||||||
|
|
||||||
//vial of dragon blood
|
//vial of dragon blood
|
||||||
giveArtBonus(127, Bonus::PRIMARY_SKILL, +5, PrimarySkill::ATTACK, Bonus::BASE_NUMBER, new HasAnotherBonusLimiter(Bonus::DRAGON_NATURE));
|
giveArtBonus(127, Bonus::PRIMARY_SKILL, +5, PrimarySkill::ATTACK, Bonus::BASE_NUMBER, dragonNatureLimiter);
|
||||||
giveArtBonus(127, Bonus::PRIMARY_SKILL, +5, PrimarySkill::DEFENSE, Bonus::BASE_NUMBER, new HasAnotherBonusLimiter(Bonus::DRAGON_NATURE));
|
giveArtBonus(127, Bonus::PRIMARY_SKILL, +5, PrimarySkill::DEFENSE, Bonus::BASE_NUMBER, dragonNatureLimiter);
|
||||||
|
|
||||||
//Armageddon's Blade
|
//Armageddon's Blade
|
||||||
giveArtBonus(128, Bonus::SPELL, 3, 26, Bonus::INDEPENDENT_MAX);
|
giveArtBonus(128, Bonus::SPELL, 3, 26, Bonus::INDEPENDENT_MAX);
|
||||||
@ -786,7 +811,7 @@ void CArtHandler::addBonuses()
|
|||||||
giveArtBonus(132, Bonus::OPENING_BATTLE_SPELL, 50, 52); // Misfortune
|
giveArtBonus(132, Bonus::OPENING_BATTLE_SPELL, 50, 52); // Misfortune
|
||||||
|
|
||||||
// Statue of Legion - gives only 50% growth
|
// Statue of Legion - gives only 50% growth
|
||||||
giveArtBonus(133, Bonus::CREATURE_GROWTH_PERCENT, 50, -1, new CPropagatorNodeType(CBonusSystemNode::PLAYER));
|
giveArtBonus(133, Bonus::CREATURE_GROWTH_PERCENT, 50, -1, make_shared<CPropagatorNodeType>(CBonusSystemNode::PLAYER));
|
||||||
|
|
||||||
//Power of the Dragon Father
|
//Power of the Dragon Father
|
||||||
giveArtBonus(134, Bonus::LEVEL_SPELL_IMMUNITY, 4, -1, Bonus::INDEPENDENT_MAX);
|
giveArtBonus(134, Bonus::LEVEL_SPELL_IMMUNITY, 4, -1, Bonus::INDEPENDENT_MAX);
|
||||||
@ -798,9 +823,9 @@ void CArtHandler::addBonuses()
|
|||||||
giveArtBonus(136, Bonus::FREE_SHIP_BOARDING, 0);
|
giveArtBonus(136, Bonus::FREE_SHIP_BOARDING, 0);
|
||||||
|
|
||||||
//Bow of the Sharpshooter
|
//Bow of the Sharpshooter
|
||||||
giveArtBonus(137, Bonus::NO_DISTANCE_PENALTY, 0, 0, 0, new HasAnotherBonusLimiter(Bonus::SHOOTER));
|
giveArtBonus(137, Bonus::NO_DISTANCE_PENALTY, 0, 0, 0, shooterOnlyLimiter);
|
||||||
giveArtBonus(137, Bonus::NO_WALL_PENALTY, 0, 0, 0, new HasAnotherBonusLimiter(Bonus::SHOOTER));
|
giveArtBonus(137, Bonus::NO_WALL_PENALTY, 0, 0, 0, shooterOnlyLimiter);
|
||||||
giveArtBonus(137, Bonus::FREE_SHOOTING, 0, 0, 0, new HasAnotherBonusLimiter(Bonus::SHOOTER));
|
giveArtBonus(137, Bonus::FREE_SHOOTING, 0, 0, 0, shooterOnlyLimiter);
|
||||||
|
|
||||||
//Wizard's Well
|
//Wizard's Well
|
||||||
giveArtBonus(138, Bonus::FULL_MANA_REGENERATION, 0);
|
giveArtBonus(138, Bonus::FULL_MANA_REGENERATION, 0);
|
||||||
@ -844,7 +869,7 @@ void CArtHandler::addBonuses()
|
|||||||
giveArtBonus(142, Bonus::SPELL_AFTER_ATTACK, 50, Spells::BERSERK, NULL, 1);
|
giveArtBonus(142, Bonus::SPELL_AFTER_ATTACK, 50, Spells::BERSERK, NULL, 1);
|
||||||
giveArtBonus(142, Bonus::SPELL_AFTER_ATTACK, 50, Spells::POISON, NULL, 1);
|
giveArtBonus(142, Bonus::SPELL_AFTER_ATTACK, 50, Spells::POISON, NULL, 1);
|
||||||
giveArtBonus(142, Bonus::SPELL_AFTER_ATTACK, 50, Spells::DISRUPTING_RAY, NULL, 1);
|
giveArtBonus(142, Bonus::SPELL_AFTER_ATTACK, 50, Spells::DISRUPTING_RAY, NULL, 1);
|
||||||
artifacts[142].get()->setDescription ("Tripple shots, tripple attack, casts various spells during attack, attacks have range of Inferno, no distance penalty, catapult");
|
artifacts[142].get()->setDescription ("Triple shots, triple attack, casts various spells during attack, attacks have range of Inferno, no distance penalty, catapult");
|
||||||
//Monster's Power
|
//Monster's Power
|
||||||
giveArtBonus(143, Bonus::STACK_HEALTH, +100, -1, Bonus::PERCENT_TO_BASE);
|
giveArtBonus(143, Bonus::STACK_HEALTH, +100, -1, Bonus::PERCENT_TO_BASE);
|
||||||
giveArtBonus(143, Bonus::CREATURE_DAMAGE, +100, 2, Bonus::PERCENT_TO_ALL);
|
giveArtBonus(143, Bonus::CREATURE_DAMAGE, +100, 2, Bonus::PERCENT_TO_ALL);
|
||||||
|
@ -34,6 +34,14 @@ namespace ArtifactPosition
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace ArtifactId
|
||||||
|
{
|
||||||
|
enum ArtifactId
|
||||||
|
{
|
||||||
|
SPELLBOOK = 17
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
namespace ArtBearer
|
namespace ArtBearer
|
||||||
{
|
{
|
||||||
enum
|
enum
|
||||||
@ -181,8 +189,9 @@ public:
|
|||||||
|
|
||||||
class DLL_LINKAGE CArtHandler //handles artifacts
|
class DLL_LINKAGE CArtHandler //handles artifacts
|
||||||
{
|
{
|
||||||
void giveArtBonus(int aid, Bonus::BonusType type, int val, int subtype = -1, int valType = Bonus::BASE_NUMBER, ILimiter * limiter = NULL, int additionalinfo = 0);
|
void giveArtBonus(int aid, Bonus::BonusType type, int val, int subtype = -1, int valType = Bonus::BASE_NUMBER, shared_ptr<ILimiter> limiter = NULL, int additionalinfo = 0);
|
||||||
void giveArtBonus(int aid, Bonus::BonusType type, int val, int subtype, IPropagator* propagator, int additionalinfo = 0);
|
void giveArtBonus(int aid, Bonus::BonusType type, int val, int subtype, shared_ptr<IPropagator> propagator, int additionalinfo = 0);
|
||||||
|
void giveArtBonus(int aid, Bonus *bonus);
|
||||||
public:
|
public:
|
||||||
std::vector<CArtifact*> treasures, minors, majors, relics;
|
std::vector<CArtifact*> treasures, minors, majors, relics;
|
||||||
std::vector< ConstTransitivePtr<CArtifact> > artifacts;
|
std::vector< ConstTransitivePtr<CArtifact> > artifacts;
|
||||||
|
2021
lib/CBattleCallback.cpp
Normal file
2021
lib/CBattleCallback.cpp
Normal file
File diff suppressed because it is too large
Load Diff
269
lib/CBattleCallback.h
Normal file
269
lib/CBattleCallback.h
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "BattleHex.h"
|
||||||
|
|
||||||
|
class CGameState;
|
||||||
|
class CGTownInstance;
|
||||||
|
class CGHeroInstance;
|
||||||
|
class CStack;
|
||||||
|
class CSpell;
|
||||||
|
struct BattleInfo;
|
||||||
|
struct CObstacleInstance;
|
||||||
|
|
||||||
|
namespace boost
|
||||||
|
{class shared_mutex;}
|
||||||
|
|
||||||
|
namespace BattleSide
|
||||||
|
{
|
||||||
|
enum {ATTACKER = 0, DEFENDER = 1};
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef std::vector<const CStack*> TStacks;
|
||||||
|
|
||||||
|
class CBattleInfoEssentials;
|
||||||
|
|
||||||
|
//Basic class for various callbacks (interfaces called by players to get info about game and so forth)
|
||||||
|
class DLL_LINKAGE CCallbackBase
|
||||||
|
{
|
||||||
|
const BattleInfo *battle; //battle to which the player is engaged, NULL if none or not applicable
|
||||||
|
|
||||||
|
const BattleInfo * getBattle() const
|
||||||
|
{
|
||||||
|
return battle;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CGameState *gs;
|
||||||
|
int player; // -1 gives access to all information, otherwise callback provides only information "visible" for player
|
||||||
|
|
||||||
|
CCallbackBase(CGameState *GS, int Player)
|
||||||
|
: gs(GS), player(Player)
|
||||||
|
{}
|
||||||
|
CCallbackBase()
|
||||||
|
: gs(NULL), player(-1)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void setBattle(const BattleInfo *B);
|
||||||
|
bool duringBattle() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
boost::shared_mutex &getGsMutex(); //just return a reference to mutex, does not lock nor anything
|
||||||
|
|
||||||
|
friend class CBattleInfoEssentials;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct DLL_LINKAGE AttackableTiles
|
||||||
|
{
|
||||||
|
std::set<BattleHex> hostileCreaturePositions;
|
||||||
|
std::set<BattleHex> friendlyCreaturePositions; //for Dragon Breath
|
||||||
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
|
{
|
||||||
|
h & hostileCreaturePositions & friendlyCreaturePositions;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Accessibility is property of hex in battle. It doesn't depend on stack, side's perspective and so on.
|
||||||
|
namespace EAccessibility
|
||||||
|
{
|
||||||
|
enum EAccessibility
|
||||||
|
{
|
||||||
|
ACCESSIBLE,
|
||||||
|
ALIVE_STACK,
|
||||||
|
OBSTACLE,
|
||||||
|
DESTRUCTIBLE_WALL,
|
||||||
|
GATE, //sieges -> gate opens only for defender stacks
|
||||||
|
UNAVAILABLE, //indestructible wall parts, special battlefields (like boat-to-boat)
|
||||||
|
SIDE_COLUMN //used for first and last columns of hexes that are unavailable but wat machines can stand there
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef std::array<EAccessibility::EAccessibility, GameConstants::BFIELD_SIZE> TAccessibilityArray;
|
||||||
|
|
||||||
|
struct DLL_LINKAGE AccessibilityInfo : TAccessibilityArray
|
||||||
|
{
|
||||||
|
bool occupiable(const CStack *stack, BattleHex tile) const;
|
||||||
|
bool accessible(BattleHex tile, const CStack *stack) const; //checks for both tiles if stack is double wide
|
||||||
|
bool accessible(BattleHex tile, bool doubleWide, bool attackerOwned) const; //checks for both tiles if stack is double wide
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace BattlePerspective
|
||||||
|
{
|
||||||
|
enum BattlePerspective
|
||||||
|
{
|
||||||
|
INVALID = -2,
|
||||||
|
ALL_KNOWING = -1,
|
||||||
|
LEFT_SIDE,
|
||||||
|
RIGHT_SIDE
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reachability info is result of BFS calculation. It's dependant on stack (it's owner, whether it's flying),
|
||||||
|
// startPosition and perpective.
|
||||||
|
struct DLL_LINKAGE ReachabilityInfo
|
||||||
|
{
|
||||||
|
typedef std::array<int, GameConstants::BFIELD_SIZE> TDistances;
|
||||||
|
typedef std::array<BattleHex, GameConstants::BFIELD_SIZE> TPredecessors;
|
||||||
|
|
||||||
|
static const int INFINITE_DIST = 1000000;
|
||||||
|
|
||||||
|
struct DLL_LINKAGE Parameters
|
||||||
|
{
|
||||||
|
const CStack *stack; //stack for which calculation is mage => not required (kept for debugging mostly), following variables are enough
|
||||||
|
|
||||||
|
bool attackerOwned;
|
||||||
|
bool doubleWide;
|
||||||
|
bool flying;
|
||||||
|
|
||||||
|
BattleHex startPosition; //assumed position of stack
|
||||||
|
BattlePerspective::BattlePerspective perspective; //some obstacles (eg. quicksands) may be invisible for some side
|
||||||
|
|
||||||
|
Parameters();
|
||||||
|
Parameters(const CStack *Stack);
|
||||||
|
};
|
||||||
|
|
||||||
|
Parameters params;
|
||||||
|
AccessibilityInfo accessibility;
|
||||||
|
TDistances distances;
|
||||||
|
TPredecessors predecessors;
|
||||||
|
|
||||||
|
ReachabilityInfo()
|
||||||
|
{
|
||||||
|
distances.fill(INFINITE_DIST);
|
||||||
|
predecessors.fill(BattleHex::INVALID);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isReachable(BattleHex hex) const
|
||||||
|
{
|
||||||
|
return predecessors[hex].isValid();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DLL_LINKAGE CBattleInfoEssentials : public virtual CCallbackBase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
bool battleDoWeKnowAbout(ui8 side) const;
|
||||||
|
public:
|
||||||
|
enum EStackOwnership
|
||||||
|
{
|
||||||
|
ONLY_MINE, ONLY_ENEMY, MINE_AND_ENEMY
|
||||||
|
};
|
||||||
|
|
||||||
|
BattlePerspective::BattlePerspective battleGetMySide() const;
|
||||||
|
|
||||||
|
ui8 battleTerrainType() const;
|
||||||
|
int battleGetBattlefieldType() const; // 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines 8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields 15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog 21. "favourable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship
|
||||||
|
std::vector<shared_ptr<const CObstacleInstance> > battleGetAllObstacles(boost::optional<BattlePerspective::BattlePerspective> perspective = boost::none) const; //returns all obstacles on the battlefield
|
||||||
|
TStacks battleGetAllStacks() const; //returns all stacks, alive or dead or undead or mechanical :)
|
||||||
|
bool battleHasNativeStack(ui8 side) const;
|
||||||
|
ui8 battleGetWallState(int partOfWall) const; //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
|
||||||
|
int battleGetMoatDmg() const; //what dmg unit will suffer if ending turn in the moat
|
||||||
|
const CGTownInstance * battleGetDefendedTown() const; //returns defended town if current battle is a siege, NULL instead
|
||||||
|
const CStack *battleActiveStack() const;
|
||||||
|
si8 battleTacticDist() const; //returns tactic distance in current tactics phase; 0 if not in tactics phase
|
||||||
|
si8 battleGetTacticsSide() const; //returns which side is in tactics phase, undefined if none (?)
|
||||||
|
bool battleCanFlee(int player) const;
|
||||||
|
bool battleCanSurrender(int player) const;
|
||||||
|
ui8 playerToSide(int player) const;
|
||||||
|
ui8 battleGetSiegeLevel() const; //returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle
|
||||||
|
bool battleHasHero(ui8 side) const;
|
||||||
|
int battleCastSpells(ui8 side) const; //how many spells has given side casted
|
||||||
|
const CGHeroInstance * battleGetFightingHero(ui8 side) const;
|
||||||
|
|
||||||
|
//helpers
|
||||||
|
TStacks battleAliveStacks() const;
|
||||||
|
TStacks battleAliveStacks(ui8 side) const;
|
||||||
|
const CStack * battleGetStackByID(int ID, bool onlyAlive = true) const; //returns stack info by given ID
|
||||||
|
bool battleIsObstacleVisibleForSide(const CObstacleInstance & coi, BattlePerspective::BattlePerspective side) const;
|
||||||
|
//ESpellCastProblem::ESpellCastProblem battleCanCastSpell(int player, ECastingMode::ECastingMode mode) const; //Checks if player is able to cast spells (at all) at the moment
|
||||||
|
};
|
||||||
|
|
||||||
|
class DLL_LINKAGE CBattleInfoCallback : public virtual CBattleInfoEssentials
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum ERandomSpell
|
||||||
|
{
|
||||||
|
RANDOM_GENIE, RANDOM_AIMED
|
||||||
|
};
|
||||||
|
|
||||||
|
//battle
|
||||||
|
shared_ptr<const CObstacleInstance> battleGetObstacleOnPos(BattleHex tile, bool onlyBlocking = true) const; //blocking obstacles makes tile inaccessible, others cause special effects (like Land Mines, Moat, Quicksands)
|
||||||
|
const CStack * battleGetStackByPos(BattleHex pos, bool onlyAlive = true) const; //returns stack info by given pos
|
||||||
|
void battleGetStackQueue(std::vector<const CStack *> &out, const int howMany, const int turn = 0, int lastMoved = -1) const;
|
||||||
|
void battleGetStackCountOutsideHexes(bool *ac) const; // returns hexes which when in front of a stack cause us to move the amount box back
|
||||||
|
|
||||||
|
//void getStackQueue( std::vector<const CStack *> &out, int howMany ) const; //returns vector of stack in order of their move sequence
|
||||||
|
std::vector<BattleHex> battleGetAvailableHexes(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = NULL) const; //returns numbers of hexes reachable by creature with id ID
|
||||||
|
|
||||||
|
int battleGetSurrenderCost(int Player) const; //returns cost of surrendering battle, -1 if surrendering is not possible
|
||||||
|
ReachabilityInfo::TDistances battleGetDistances(const CStack * stack, BattleHex hex = BattleHex::INVALID, BattleHex * predecessors = NULL) const; //returns vector of distances to [dest hex number]
|
||||||
|
std::set<BattleHex> battleGetAttackedHexes(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID) const;
|
||||||
|
bool battleCanShoot(const CStack * stack, BattleHex dest) const; //determines if stack with given ID shoot at the selected destination
|
||||||
|
bool battleIsStackBlocked(const CStack * stack) const; //returns true if there is neighboring enemy stack
|
||||||
|
std::set<const CStack*> batteAdjacentCreatures (const CStack * stack) const;
|
||||||
|
|
||||||
|
TDmgRange calculateDmgRange(const CStack* attacker, const CStack* defender, TQuantity attackerCount, bool shooting, ui8 charge, bool lucky, bool deathBlow, bool ballistaDoubleDmg) const; //charge - number of hexes travelled before attack (for champion's jousting); returns pair <min dmg, max dmg>
|
||||||
|
TDmgRange calculateDmgRange(const CStack* attacker, const CStack* defender, bool shooting, ui8 charge, bool lucky, bool deathBlow, bool ballistaDoubleDmg) const; //charge - number of hexes travelled before attack (for champion's jousting); returns pair <min dmg, max dmg>
|
||||||
|
|
||||||
|
//hextowallpart //int battleGetWallUnderHex(BattleHex hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
||||||
|
std::pair<ui32, ui32> battleEstimateDamage(const CStack * attacker, const CStack * defender, std::pair<ui32, ui32> * retaliationDmg = NULL) const; //estimates damage dealt by attacker to defender; it may be not precise especially when stack has randomly working bonuses; returns pair <min dmg, max dmg>
|
||||||
|
si8 battleHasDistancePenalty( const CStack * stack, BattleHex destHex ) const;
|
||||||
|
si8 battleHasWallPenalty(const CStack * stack, BattleHex destHex) const; //checks if given stack has wall penalty
|
||||||
|
EWallParts::EWallParts battleHexToWallPart(BattleHex hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
||||||
|
|
||||||
|
//*** MAGIC
|
||||||
|
si8 battleMaxSpellLevel() const; //calculates minimum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, 0 is returned
|
||||||
|
ui32 battleGetSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //returns cost of given spell
|
||||||
|
ESpellCastProblem::ESpellCastProblem battleCanCastSpell(int player, ECastingMode::ECastingMode mode) const; //returns true if there are no general issues preventing from casting a spell
|
||||||
|
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(int player, const CSpell * spell, ECastingMode::ECastingMode mode) const; //checks if given player can cast given spell
|
||||||
|
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpellHere(int player, const CSpell * spell, ECastingMode::ECastingMode mode, BattleHex dest) const; //checks if given player can cast given spell at given tile in given mode
|
||||||
|
ESpellCastProblem::ESpellCastProblem battleCanCreatureCastThisSpell(const CSpell * spell, BattleHex destination) const; //determines if creature can cast a spell here
|
||||||
|
|
||||||
|
si32 battleGetRandomStackSpell(const CStack * stack, ERandomSpell mode) const;
|
||||||
|
TSpell getRandomBeneficialSpell(const CStack * subject) const;
|
||||||
|
TSpell getRandomCastedSpell(const CStack * caster) const; //called at the beginning of turn for Faerie Dragon
|
||||||
|
|
||||||
|
//checks for creature immunity / anything that prevent casting *at given hex* - doesn't take into acount general problems such as not having spellbook or mana points etc.
|
||||||
|
ESpellCastProblem::ESpellCastProblem battleIsImmune(const CGHeroInstance * caster, const CSpell * spell, ECastingMode::ECastingMode mode, BattleHex dest) const;
|
||||||
|
|
||||||
|
|
||||||
|
const CStack * getStackIf(boost::function<bool(const CStack*)> pred) const;
|
||||||
|
|
||||||
|
si8 battleHasShootingPenalty(const CStack * stack, BattleHex destHex)
|
||||||
|
{
|
||||||
|
return battleHasDistancePenalty(stack, destHex) || battleHasWallPenalty(stack, destHex);
|
||||||
|
}
|
||||||
|
si8 battleCanTeleportTo(const CStack * stack, BattleHex destHex, int telportLevel) const; //checks if teleportation of given stack to given position can take place
|
||||||
|
|
||||||
|
|
||||||
|
//convenience methods using the ones above
|
||||||
|
bool isInTacticRange( BattleHex dest ) const;
|
||||||
|
si8 battleGetTacticDist() const; //returns tactic distance for calling player or 0 if this player is not in tactic phase (for ALL_KNOWING actual distance for tactic side)
|
||||||
|
|
||||||
|
AttackableTiles getPotentiallyAttackableHexes(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos) const;
|
||||||
|
std::set<const CStack*> getAttackedCreatures(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID) const; //calculates range of multi-hex attacks
|
||||||
|
|
||||||
|
ReachabilityInfo getReachability(const CStack *stack) const;
|
||||||
|
ReachabilityInfo getReachability(const ReachabilityInfo::Parameters ¶ms) const;
|
||||||
|
AccessibilityInfo getAccesibility() const;
|
||||||
|
std::pair<const CStack *, BattleHex> getNearestStack(const CStack * closest, boost::logic::tribool attackerOwned) const;
|
||||||
|
protected:
|
||||||
|
ReachabilityInfo getFlyingReachability(const ReachabilityInfo::Parameters params) const;
|
||||||
|
ReachabilityInfo makeBFS(const AccessibilityInfo &accessibility, const ReachabilityInfo::Parameters params) const;
|
||||||
|
ReachabilityInfo makeBFS(const CStack *stack) const; //uses default parameters -> stack position and owner's perspective
|
||||||
|
std::set<BattleHex> getStoppers(BattlePerspective::BattlePerspective whichSidePerspective) const; //get hexes with stopping obstacles (quicksands)
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class DLL_LINKAGE CPlayerBattleCallback : public CBattleInfoCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool battleCanFlee() const; //returns true if caller can flee from the battle
|
||||||
|
TStacks battleGetStacks(EStackOwnership whose = MINE_AND_ENEMY, bool onlyAlive = true) const; //returns stacks on battlefield
|
||||||
|
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell) const; //determines if given spell can be casted (and returns problem description)
|
||||||
|
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell, BattleHex destination) const; //if hero can cast spell here
|
||||||
|
ESpellCastProblem::ESpellCastProblem battleCanCreatureCastThisSpell(const CSpell * spell, BattleHex destination) const; //determines if creature can cast a spell here
|
||||||
|
int battleGetSurrenderCost() const; //returns cost of surrendering battle, -1 if surrendering is not possible
|
||||||
|
|
||||||
|
bool battleCanCastSpell(ESpellCastProblem::ESpellCastProblem *outProblem = nullptr) const; //returns true, if caller can cast a spell. If not, if pointer is given via arg, the reason will be written.
|
||||||
|
};
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
using namespace boost::logic;
|
using namespace boost::logic;
|
||||||
class CCallback;
|
class CCallback;
|
||||||
class CBattleCallback;
|
class CPlayerBattleCallback;
|
||||||
class ICallback;
|
class ICallback;
|
||||||
class CGlobalAI;
|
class CGlobalAI;
|
||||||
struct Component;
|
struct Component;
|
||||||
@ -61,7 +61,7 @@ public:
|
|||||||
std::string dllName;
|
std::string dllName;
|
||||||
|
|
||||||
virtual ~CBattleGameInterface() {};
|
virtual ~CBattleGameInterface() {};
|
||||||
virtual void init(CBattleCallback * CB){};
|
virtual void init(CPlayerBattleCallback * CB){};
|
||||||
|
|
||||||
//battle call-ins
|
//battle call-ins
|
||||||
virtual BattleAction activeStack(const CStack * stack)=0; //called when it's turn of that stack
|
virtual BattleAction activeStack(const CStack * stack)=0; //called when it's turn of that stack
|
||||||
@ -115,7 +115,7 @@ public:
|
|||||||
|
|
||||||
std::string battleAIName;
|
std::string battleAIName;
|
||||||
CBattleGameInterface *battleAI;
|
CBattleGameInterface *battleAI;
|
||||||
CBattleCallback *cbc;
|
CPlayerBattleCallback *cbc;
|
||||||
|
|
||||||
//battle interface
|
//battle interface
|
||||||
virtual BattleAction activeStack(const CStack * stack);
|
virtual BattleAction activeStack(const CStack * stack);
|
||||||
|
@ -256,6 +256,10 @@ bool CSpell::isRisingSpell() const
|
|||||||
return vstd::contains(VLC->spellh->risingSpells, id);
|
return vstd::contains(VLC->spellh->risingSpells, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CSpell::isDamageSpell() const
|
||||||
|
{
|
||||||
|
return vstd::contains(VLC->spellh->damageSpells, id);
|
||||||
|
}
|
||||||
bool DLL_LINKAGE isInScreenRange(const int3 ¢er, const int3 &pos)
|
bool DLL_LINKAGE isInScreenRange(const int3 ¢er, const int3 &pos)
|
||||||
{
|
{
|
||||||
int3 diff = pos - center;
|
int3 diff = pos - center;
|
||||||
|
@ -22,7 +22,7 @@ class DLL_LINKAGE CSpell
|
|||||||
public:
|
public:
|
||||||
enum ETargetType {NO_TARGET, CREATURE, CREATURE_EXPERT_MASSIVE, OBSTACLE};
|
enum ETargetType {NO_TARGET, CREATURE, CREATURE_EXPERT_MASSIVE, OBSTACLE};
|
||||||
enum ESpellPositiveness {NEGATIVE = -1, NEUTRAL = 0, POSITIVE = 1};
|
enum ESpellPositiveness {NEGATIVE = -1, NEUTRAL = 0, POSITIVE = 1};
|
||||||
ui32 id;
|
TSpell id;
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string abbName; //abbreviated name
|
std::string abbName; //abbreviated name
|
||||||
std::vector<std::string> descriptions; //descriptions of spell for skill levels: 0 - none, 1 - basic, etc
|
std::vector<std::string> descriptions; //descriptions of spell for skill levels: 0 - none, 1 - basic, etc
|
||||||
@ -48,6 +48,7 @@ public:
|
|||||||
bool isPositive() const;
|
bool isPositive() const;
|
||||||
bool isNegative() const;
|
bool isNegative() const;
|
||||||
bool isRisingSpell() const;
|
bool isRisingSpell() const;
|
||||||
|
bool isDamageSpell() const;
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
|
@ -161,11 +161,11 @@ void CLodArchiveLoader::initSNDArchive(CFileInputStream & fileStream)
|
|||||||
SoundEntryBlock sndEntry = sndEntries[i];
|
SoundEntryBlock sndEntry = sndEntries[i];
|
||||||
ArchiveEntry entry;
|
ArchiveEntry entry;
|
||||||
|
|
||||||
//for some reason entries in snd have format NAME\0WAV\0\0\0....
|
//for some reason entries in snd have format NAME\0WAVRUBBISH....
|
||||||
//we need to replace first \0 with dot and trim line
|
//we need to replace first \0 with dot and take the 3 chars with extension (and drop the rest)
|
||||||
entry.name = std::string(sndEntry.filename, 40);
|
entry.name = std::string(sndEntry.filename, 40);
|
||||||
|
entry.name.resize(entry.name.find_first_of('\0') + 4); //+4 because we take dot and 3-char extension
|
||||||
entry.name[entry.name.find_first_of('\0')] = '.';
|
entry.name[entry.name.find_first_of('\0')] = '.';
|
||||||
entry.name.resize(entry.name.find_first_of('\0'));
|
|
||||||
|
|
||||||
entry.offset = SDL_SwapLE32(sndEntry.offset);
|
entry.offset = SDL_SwapLE32(sndEntry.offset);
|
||||||
entry.realSize = SDL_SwapLE32(sndEntry.size);
|
entry.realSize = SDL_SwapLE32(sndEntry.size);
|
||||||
|
@ -140,7 +140,9 @@ namespace ESpellCastProblem
|
|||||||
OK, NO_HERO_TO_CAST_SPELL, ALREADY_CASTED_THIS_TURN, NO_SPELLBOOK, ANOTHER_ELEMENTAL_SUMMONED,
|
OK, NO_HERO_TO_CAST_SPELL, ALREADY_CASTED_THIS_TURN, NO_SPELLBOOK, ANOTHER_ELEMENTAL_SUMMONED,
|
||||||
HERO_DOESNT_KNOW_SPELL, NOT_ENOUGH_MANA, ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL,
|
HERO_DOESNT_KNOW_SPELL, NOT_ENOUGH_MANA, ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL,
|
||||||
SECOND_HEROS_SPELL_IMMUNITY, SPELL_LEVEL_LIMIT_EXCEEDED, NO_SPELLS_TO_DISPEL,
|
SECOND_HEROS_SPELL_IMMUNITY, SPELL_LEVEL_LIMIT_EXCEEDED, NO_SPELLS_TO_DISPEL,
|
||||||
NO_APPROPRIATE_TARGET, STACK_IMMUNE_TO_SPELL, WRONG_SPELL_TARGET, ONGOING_TACTIC_PHASE
|
NO_APPROPRIATE_TARGET, STACK_IMMUNE_TO_SPELL, WRONG_SPELL_TARGET, ONGOING_TACTIC_PHASE,
|
||||||
|
MAGIC_IS_BLOCKED, //For Orb of Inhibition and similar - no casting at all
|
||||||
|
INVALID
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,6 +174,28 @@ namespace ECommander
|
|||||||
const int MAX_SKILL_LEVEL = 5;
|
const int MAX_SKILL_LEVEL = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace EWallParts
|
||||||
|
{
|
||||||
|
enum EWallParts
|
||||||
|
{
|
||||||
|
INDESTRUCTIBLE_PART = -2, INVALID = -1,
|
||||||
|
KEEP = 0, BOTTOM_TOWER, BOTTOM_WALL, BELOW_GATE, OVER_GATE, UPPER_WAL, UPPER_TOWER, GATE,
|
||||||
|
|
||||||
|
PARTS_COUNT
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace EWallState
|
||||||
|
{
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
NONE, //no wall
|
||||||
|
INTACT,
|
||||||
|
DAMAGED,
|
||||||
|
DESTROYED
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
namespace Obj
|
namespace Obj
|
||||||
{
|
{
|
||||||
enum
|
enum
|
||||||
@ -224,6 +248,17 @@ namespace Obj
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace SecSkillLevel
|
||||||
|
{
|
||||||
|
enum SecSkillLevel
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
BASIC,
|
||||||
|
ADVANCED,
|
||||||
|
EXPERT
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
//follows ERM BI (battle image) format
|
//follows ERM BI (battle image) format
|
||||||
namespace BattlefieldBI
|
namespace BattlefieldBI
|
||||||
{
|
{
|
||||||
|
@ -134,10 +134,26 @@ int BonusList::totalValue() const
|
|||||||
|
|
||||||
if(hasIndepMin && hasIndepMax)
|
if(hasIndepMin && hasIndepMax)
|
||||||
assert(indepMin < indepMax);
|
assert(indepMin < indepMax);
|
||||||
|
|
||||||
|
const int notIndepBonuses = boost::count_if(bonuses, [](const Bonus *b)
|
||||||
|
{
|
||||||
|
return b->valType != Bonus::INDEPENDENT_MAX && b->valType != Bonus::INDEPENDENT_MIN;
|
||||||
|
});
|
||||||
|
|
||||||
if (hasIndepMax)
|
if (hasIndepMax)
|
||||||
vstd::amax(valFirst, indepMax);
|
{
|
||||||
|
if(notIndepBonuses)
|
||||||
|
vstd::amax(valFirst, indepMax);
|
||||||
|
else
|
||||||
|
valFirst = indepMax;
|
||||||
|
}
|
||||||
if (hasIndepMin)
|
if (hasIndepMin)
|
||||||
vstd::amin(valFirst, indepMin);
|
{
|
||||||
|
if(notIndepBonuses)
|
||||||
|
vstd::amin(valFirst, indepMin);
|
||||||
|
else
|
||||||
|
valFirst = indepMin;
|
||||||
|
}
|
||||||
|
|
||||||
return valFirst;
|
return valFirst;
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,8 @@ typedef boost::function<bool(const Bonus*)> CSelector;
|
|||||||
BONUS_NAME(SPELL_BEFORE_ATTACK) /* subtype - spell id, value - chance %, additional info % 1000 - level, (additional info)/1000 -> [0 - all attacks, 1 - shot only, 2 - melee only*/ \
|
BONUS_NAME(SPELL_BEFORE_ATTACK) /* subtype - spell id, value - chance %, additional info % 1000 - level, (additional info)/1000 -> [0 - all attacks, 1 - shot only, 2 - melee only*/ \
|
||||||
BONUS_NAME(SPELL_RESISTANCE_AURA) /*eg. unicorns, value - resistance bonus in % for adjacent creatures*/ \
|
BONUS_NAME(SPELL_RESISTANCE_AURA) /*eg. unicorns, value - resistance bonus in % for adjacent creatures*/ \
|
||||||
BONUS_NAME(LEVEL_SPELL_IMMUNITY) /*creature is immune to all spell with level below or equal to value of this bonus*/ \
|
BONUS_NAME(LEVEL_SPELL_IMMUNITY) /*creature is immune to all spell with level below or equal to value of this bonus*/ \
|
||||||
|
BONUS_NAME(BLOCK_MAGIC_ABOVE) /*blocks casting spells of the level > value */ \
|
||||||
|
BONUS_NAME(BLOCK_ALL_MAGIC) /*blocks casting spells of the level > value */ \
|
||||||
BONUS_NAME(TWO_HEX_ATTACK_BREATH) /*eg. dragons*/ \
|
BONUS_NAME(TWO_HEX_ATTACK_BREATH) /*eg. dragons*/ \
|
||||||
BONUS_NAME(SPELL_DAMAGE_REDUCTION) /*eg. golems; value - reduction in %, subtype - spell school; -1 - all, 0 - air, 1 - fire, 2 - water, 3 - earth*/ \
|
BONUS_NAME(SPELL_DAMAGE_REDUCTION) /*eg. golems; value - reduction in %, subtype - spell school; -1 - all, 0 - air, 1 - fire, 2 - water, 3 - earth*/ \
|
||||||
BONUS_NAME(NO_WALL_PENALTY) \
|
BONUS_NAME(NO_WALL_PENALTY) \
|
||||||
@ -626,7 +628,8 @@ public:
|
|||||||
}
|
}
|
||||||
enum ENodeTypes
|
enum ENodeTypes
|
||||||
{
|
{
|
||||||
UNKNOWN, STACK_INSTANCE, STACK_BATTLE, SPECIALITY, ARTIFACT, CREATURE, ARTIFACT_INSTANCE, HERO, PLAYER, TEAM, TOWN_AND_VISITOR
|
UNKNOWN, STACK_INSTANCE, STACK_BATTLE, SPECIALITY, ARTIFACT, CREATURE, ARTIFACT_INSTANCE, HERO, PLAYER, TEAM,
|
||||||
|
TOWN_AND_VISITOR, BATTLE
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,417 +34,6 @@
|
|||||||
|
|
||||||
extern boost::rand48 ran;
|
extern boost::rand48 ran;
|
||||||
|
|
||||||
boost::shared_mutex& CCallbackBase::getGsMutex()
|
|
||||||
{
|
|
||||||
return *gs->mx;
|
|
||||||
}
|
|
||||||
|
|
||||||
si8 CBattleInfoCallback::battleHasDistancePenalty( const CStack * stack, BattleHex destHex )
|
|
||||||
{
|
|
||||||
return gs->curB->hasDistancePenalty(stack, destHex);
|
|
||||||
}
|
|
||||||
|
|
||||||
si8 CBattleInfoCallback::battleHasWallPenalty( const CStack * stack, BattleHex destHex )
|
|
||||||
{
|
|
||||||
return gs->curB->hasWallPenalty(stack, destHex);
|
|
||||||
}
|
|
||||||
|
|
||||||
si8 CBattleInfoCallback::battleCanTeleportTo(const CStack * stack, BattleHex destHex, int telportLevel)
|
|
||||||
{
|
|
||||||
return gs->curB->canTeleportTo(stack, destHex, telportLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<int> CBattleInfoCallback::battleGetDistances(const CStack * stack, BattleHex hex /*= BattleHex::INVALID*/, BattleHex * predecessors /*= NULL*/)
|
|
||||||
{
|
|
||||||
// FIXME - This method is broken, hex argument is not used. However AI depends on that wrong behaviour.
|
|
||||||
|
|
||||||
if(!hex.isValid())
|
|
||||||
hex = stack->position;
|
|
||||||
|
|
||||||
std::vector<int> ret(GameConstants::BFIELD_SIZE, -1); //fill initial ret with -1's
|
|
||||||
|
|
||||||
if(!hex.isValid()) //stack has bad position? probably castle turret, return initial values (they can't move)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
bool ac[GameConstants::BFIELD_SIZE] = {0};
|
|
||||||
std::set<BattleHex> occupyable;
|
|
||||||
gs->curB->getAccessibilityMap(ac, stack->doubleWide(), stack->attackerOwned, false, occupyable, stack->hasBonusOfType(Bonus::FLYING), stack);
|
|
||||||
BattleHex pr[GameConstants::BFIELD_SIZE];
|
|
||||||
int dist[GameConstants::BFIELD_SIZE];
|
|
||||||
gs->curB->makeBFS(stack->position, ac, pr, dist, stack->doubleWide(), stack->attackerOwned, stack->hasBonusOfType(Bonus::FLYING), false);
|
|
||||||
|
|
||||||
for(int i=0; i<GameConstants::BFIELD_SIZE; ++i)
|
|
||||||
{
|
|
||||||
if(pr[i] != -1)
|
|
||||||
ret[i] = dist[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(predecessors)
|
|
||||||
{
|
|
||||||
memcpy(predecessors, pr, GameConstants::BFIELD_SIZE * sizeof(BattleHex));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
std::set<BattleHex> CBattleInfoCallback::battleGetAttackedHexes(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos /*= BattleHex::INVALID*/)
|
|
||||||
{
|
|
||||||
if(!gs->curB)
|
|
||||||
{
|
|
||||||
|
|
||||||
tlog1 << "battleGetAttackedHexes called when there is no battle!\n";
|
|
||||||
std::set<BattleHex> set;
|
|
||||||
return set;
|
|
||||||
}
|
|
||||||
|
|
||||||
return gs->curB->getAttackedHexes(attacker, destinationTile, attackerPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell( const CSpell * spell )
|
|
||||||
{
|
|
||||||
if(!gs->curB)
|
|
||||||
{
|
|
||||||
|
|
||||||
tlog1 << "battleCanCastThisSpell called when there is no battle!\n";
|
|
||||||
return ESpellCastProblem::NO_HERO_TO_CAST_SPELL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return gs->curB->battleCanCastThisSpell(player, spell, ECastingMode::HERO_CASTING);
|
|
||||||
}
|
|
||||||
|
|
||||||
ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell(const CSpell * spell, BattleHex destination)
|
|
||||||
{
|
|
||||||
if(!gs->curB)
|
|
||||||
{
|
|
||||||
|
|
||||||
tlog1 << "battleCanCastThisSpell called when there is no battle!\n";
|
|
||||||
return ESpellCastProblem::NO_HERO_TO_CAST_SPELL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return gs->curB->battleCanCastThisSpellHere(player, spell, ECastingMode::HERO_CASTING, destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCreatureCastThisSpell(const CSpell * spell, BattleHex destination)
|
|
||||||
{
|
|
||||||
if(!gs->curB)
|
|
||||||
{
|
|
||||||
|
|
||||||
tlog1 << "battleCanCastThisSpell called when there is no battle!\n";
|
|
||||||
return ESpellCastProblem::NO_HERO_TO_CAST_SPELL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return gs->curB->battleCanCastThisSpellHere(player, spell, ECastingMode::CREATURE_ACTIVE_CASTING, destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
si32 CBattleInfoCallback::battleGetRandomStackSpell(const CStack * stack, ERandomSpell mode)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case RANDOM_GENIE:
|
|
||||||
return gs->curB->getRandomBeneficialSpell(stack); //target
|
|
||||||
break;
|
|
||||||
case RANDOM_AIMED:
|
|
||||||
return gs->curB->getRandomCastedSpell(stack); //caster
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
tlog1 << "Incorrect mode of battleGetRandomSpell (" << mode <<")\n";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
si8 CBattleInfoCallback::battleGetTacticDist()
|
|
||||||
{
|
|
||||||
if (!gs->curB)
|
|
||||||
{
|
|
||||||
tlog1 << "battleGetTacticDist called when no battle!\n";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gs->curB->sides[gs->curB->tacticsSide] == player)
|
|
||||||
{
|
|
||||||
return gs->curB->tacticDistance;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ui8 CBattleInfoCallback::battleGetMySide()
|
|
||||||
{
|
|
||||||
if (!gs->curB)
|
|
||||||
{
|
|
||||||
tlog1 << "battleGetMySide called when no battle!\n";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return gs->curB->sides[1] == player;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CBattleInfoCallback::battleGetSurrenderCost()
|
|
||||||
{
|
|
||||||
if (!gs->curB)
|
|
||||||
{
|
|
||||||
tlog1 << "battleGetSurrenderCost called when no battle!\n";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return gs->curB->getSurrenderingCost(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
int CBattleInfoCallback::battleGetBattlefieldType()
|
|
||||||
{
|
|
||||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
|
||||||
//return gs->battleGetBattlefieldType();
|
|
||||||
|
|
||||||
if(!gs->curB)
|
|
||||||
{
|
|
||||||
tlog2<<"battleGetBattlefieldType called when there is no battle!"<<std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return gs->curB->battlefieldType;
|
|
||||||
}
|
|
||||||
|
|
||||||
// int CBattleInfoCallback::battleGetObstaclesAtTile(BattleHex tile) //returns bitfield
|
|
||||||
// {
|
|
||||||
// //TODO - write
|
|
||||||
// return -1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
std::vector<shared_ptr<const CObstacleInstance> > CBattleInfoCallback::battleGetAllObstacles()
|
|
||||||
{
|
|
||||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
|
||||||
std::vector<shared_ptr<const CObstacleInstance> > ret;
|
|
||||||
if(gs->curB)
|
|
||||||
{
|
|
||||||
BOOST_FOREACH(auto oi, gs->curB->obstacles)
|
|
||||||
{
|
|
||||||
if(player < 0 || gs->curB->isObstacleVisibleForSide(*oi, battleGetMySide()))
|
|
||||||
ret.push_back(oi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CStack* CBattleInfoCallback::battleGetStackByID(int ID, bool onlyAlive)
|
|
||||||
{
|
|
||||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
|
||||||
if(!gs->curB) return NULL;
|
|
||||||
return gs->curB->getStack(ID, onlyAlive);
|
|
||||||
}
|
|
||||||
|
|
||||||
const CStack* CBattleInfoCallback::battleGetStackByPos(BattleHex pos, bool onlyAlive)
|
|
||||||
{
|
|
||||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
|
||||||
return gs->curB->battleGetStack(pos, onlyAlive);
|
|
||||||
}
|
|
||||||
|
|
||||||
BattleHex CBattleInfoCallback::battleGetPos(int stack)
|
|
||||||
{
|
|
||||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
|
||||||
if(!gs->curB)
|
|
||||||
{
|
|
||||||
tlog2<<"battleGetPos called when there is no battle!"<<std::endl;
|
|
||||||
return BattleHex::INVALID;
|
|
||||||
}
|
|
||||||
for(size_t g=0; g<gs->curB->stacks.size(); ++g)
|
|
||||||
{
|
|
||||||
if(gs->curB->stacks[g]->ID == stack)
|
|
||||||
return gs->curB->stacks[g]->position;
|
|
||||||
}
|
|
||||||
return BattleHex::INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
TStacks CBattleInfoCallback::battleGetStacks(EStackOwnership whose /*= MINE_AND_ENEMY*/, bool onlyAlive /*= true*/)
|
|
||||||
{
|
|
||||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
|
||||||
TStacks ret;
|
|
||||||
if(!gs->curB) //there is no battle
|
|
||||||
{
|
|
||||||
tlog2<<"battleGetStacks called when there is no battle!"<<std::endl;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_FOREACH(const CStack *s, gs->curB->stacks)
|
|
||||||
{
|
|
||||||
bool ownerMatches = (whose == MINE_AND_ENEMY) || (whose == ONLY_MINE && s->owner == player) || (whose == ONLY_ENEMY && s->owner != player);
|
|
||||||
bool alivenessMatches = s->alive() || !onlyAlive;
|
|
||||||
if(ownerMatches && alivenessMatches)
|
|
||||||
ret.push_back(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CBattleInfoCallback::getStackQueue( std::vector<const CStack *> &out, int howMany )
|
|
||||||
{
|
|
||||||
if(!gs->curB)
|
|
||||||
{
|
|
||||||
tlog2 << "battleGetStackQueue called when there is not battle!" << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
gs->curB->getStackQueue(out, howMany);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CBattleInfoCallback::battleGetStackCountOutsideHexes(bool *ac)
|
|
||||||
{
|
|
||||||
if(!gs->curB)
|
|
||||||
{
|
|
||||||
tlog2<<"battleGetAvailableHexes called when there is no battle!"<<std::endl;
|
|
||||||
for (int i = 0; i < GameConstants::BFIELD_SIZE; ++i) ac[i] = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
std::set<BattleHex> ignored;
|
|
||||||
gs->curB->getAccessibilityMap(ac, false /*ignored*/, false, false, ignored, false /*ignored*/, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<BattleHex> CBattleInfoCallback::battleGetAvailableHexes(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable)
|
|
||||||
{
|
|
||||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
|
||||||
if(!gs->curB)
|
|
||||||
{
|
|
||||||
tlog2<<"battleGetAvailableHexes called when there is no battle!"<<std::endl;
|
|
||||||
return std::vector<BattleHex>();
|
|
||||||
}
|
|
||||||
return gs->curB->getAccessibility(stack, addOccupiable, attackable);
|
|
||||||
//return gs->battleGetRange(ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CBattleInfoCallback::battleCanShoot(const CStack * stack, BattleHex dest)
|
|
||||||
{
|
|
||||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
|
||||||
|
|
||||||
if(!gs->curB) return false;
|
|
||||||
|
|
||||||
return gs->curB->battleCanShoot(stack, dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CBattleInfoCallback::battleCanCastSpell()
|
|
||||||
{
|
|
||||||
if(!gs->curB) //there is no battle
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return gs->curB->battleCanCastSpell(player, ECastingMode::HERO_CASTING) == ESpellCastProblem::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CBattleInfoCallback::battleCanFlee()
|
|
||||||
{
|
|
||||||
return gs->curB->battleCanFlee(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
const CGTownInstance *CBattleInfoCallback::battleGetDefendedTown()
|
|
||||||
{
|
|
||||||
if(!gs->curB || gs->curB->town == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return gs->curB->town;
|
|
||||||
}
|
|
||||||
|
|
||||||
ui8 CBattleInfoCallback::battleGetWallState(int partOfWall)
|
|
||||||
{
|
|
||||||
if(!gs->curB || gs->curB->siege == 0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return gs->curB->si.wallState[partOfWall];
|
|
||||||
}
|
|
||||||
|
|
||||||
int CBattleInfoCallback::battleGetWallUnderHex(BattleHex hex)
|
|
||||||
{
|
|
||||||
if(!gs->curB || gs->curB->siege == 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return gs->curB->hexToWallPart(hex);
|
|
||||||
}
|
|
||||||
|
|
||||||
TDmgRange CBattleInfoCallback::battleEstimateDamage(const CStack * attacker, const CStack * defender, TDmgRange * retaliationDmg)
|
|
||||||
{
|
|
||||||
if(!gs->curB)
|
|
||||||
return std::make_pair(0, 0);
|
|
||||||
|
|
||||||
const CGHeroInstance * attackerHero, * defenderHero;
|
|
||||||
bool shooting = battleCanShoot(attacker, defender->position);
|
|
||||||
|
|
||||||
if(gs->curB->sides[0] == attacker->owner)
|
|
||||||
{
|
|
||||||
attackerHero = gs->curB->heroes[0];
|
|
||||||
defenderHero = gs->curB->heroes[1];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
attackerHero = gs->curB->heroes[1];
|
|
||||||
defenderHero = gs->curB->heroes[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
TDmgRange ret = gs->curB->calculateDmgRange(attacker, defender, attackerHero, defenderHero, shooting, 0, false, false, false);
|
|
||||||
|
|
||||||
if(retaliationDmg)
|
|
||||||
{
|
|
||||||
if(shooting)
|
|
||||||
{
|
|
||||||
retaliationDmg->first = retaliationDmg->second = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ui32 TDmgRange::* pairElems[] = {&TDmgRange::first, &TDmgRange::second};
|
|
||||||
for (int i=0; i<2; ++i)
|
|
||||||
{
|
|
||||||
BattleStackAttacked bsa;
|
|
||||||
bsa.damageAmount = ret.*pairElems[i];
|
|
||||||
retaliationDmg->*pairElems[!i] = gs->curB->calculateDmgRange(defender, attacker, bsa.newAmount, attacker->count, attackerHero, defenderHero, false, 0, false, false, false).*pairElems[!i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ui8 CBattleInfoCallback::battleGetSiegeLevel()
|
|
||||||
{
|
|
||||||
if(!gs->curB)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return gs->curB->siege;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CGHeroInstance * CBattleInfoCallback::battleGetFightingHero(ui8 side) const
|
|
||||||
{
|
|
||||||
if(!gs->curB)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
//TODO: this method should not exist... you shouldn't be able to get info about enemy hero
|
|
||||||
return gs->curB->heroes[side];
|
|
||||||
}
|
|
||||||
|
|
||||||
shared_ptr<const CObstacleInstance> CBattleInfoCallback::battleGetObstacleOnPos(BattleHex tile, bool onlyBlocking /*= true*/)
|
|
||||||
{
|
|
||||||
if(!gs->curB)
|
|
||||||
return shared_ptr<const CObstacleInstance>();
|
|
||||||
|
|
||||||
BOOST_FOREACH(auto &obs, battleGetAllObstacles())
|
|
||||||
{
|
|
||||||
if(vstd::contains(obs->getBlockedTiles(), tile)
|
|
||||||
|| (!onlyBlocking && vstd::contains(obs->getAffectedTiles(), tile)))
|
|
||||||
{
|
|
||||||
return obs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return shared_ptr<const CObstacleInstance>();
|
|
||||||
}
|
|
||||||
|
|
||||||
int CBattleInfoCallback::battleGetMoatDmg()
|
|
||||||
{
|
|
||||||
if(!gs->curB || !gs->curB->town)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
//TODO move to config file
|
|
||||||
static const int dmgs[] = {70, 70, -1,
|
|
||||||
90, 70, 90,
|
|
||||||
70, 90, 70};
|
|
||||||
if(gs->curB->town->subID < ARRAY_COUNT(dmgs))
|
|
||||||
return dmgs[gs->curB->town->subID];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CGameState * CPrivilagedInfoCallback::gameState ()
|
CGameState * CPrivilagedInfoCallback::gameState ()
|
||||||
{
|
{
|
||||||
return gs;
|
return gs;
|
||||||
@ -729,7 +318,7 @@ int CGameInfoCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * ca
|
|||||||
ERROR_RET_VAL_IF(!canGetFullInfo(caster), "Cannot get info about caster!", -1);
|
ERROR_RET_VAL_IF(!canGetFullInfo(caster), "Cannot get info about caster!", -1);
|
||||||
//if there is a battle
|
//if there is a battle
|
||||||
if(gs->curB)
|
if(gs->curB)
|
||||||
return gs->curB->getSpellCost(sp, caster);
|
return gs->curB->battleGetSpellCost(sp, caster);
|
||||||
|
|
||||||
//if there is no battle
|
//if there is no battle
|
||||||
return caster->getSpellCost(sp);
|
return caster->getSpellCost(sp);
|
||||||
@ -784,7 +373,7 @@ bool CGameInfoCallback::getTownInfo( const CGObjectInstance *town, InfoAboutTown
|
|||||||
//TODO vision support
|
//TODO vision support
|
||||||
if(town->ID == GameConstants::TOWNI_TYPE)
|
if(town->ID == GameConstants::TOWNI_TYPE)
|
||||||
dest.initFromTown(static_cast<const CGTownInstance *>(town), detailed);
|
dest.initFromTown(static_cast<const CGTownInstance *>(town), detailed);
|
||||||
else if(town->ID == 33 || town->ID == 219)
|
else if(town->ID == Obj::GARRISON || town->ID == Obj::GARRISON2)
|
||||||
dest.initFromArmy(static_cast<const CArmedInstance *>(town), detailed);
|
dest.initFromArmy(static_cast<const CArmedInstance *>(town), detailed);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
#include "BattleHex.h"
|
#include "BattleHex.h"
|
||||||
#include "../client/FunctionList.h"
|
#include "../client/FunctionList.h"
|
||||||
#include "CObstacleInstance.h"
|
|
||||||
#include "ResourceSet.h"
|
#include "ResourceSet.h"
|
||||||
#include "int3.h"
|
#include "int3.h"
|
||||||
#include "GameConstants.h"
|
#include "GameConstants.h"
|
||||||
|
#include "CBattleCallback.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IGameCallback.h, part of VCMI engine
|
* IGameCallback.h, part of VCMI engine
|
||||||
@ -59,85 +59,6 @@ struct TeamState;
|
|||||||
struct QuestInfo;
|
struct QuestInfo;
|
||||||
class CGCreature;
|
class CGCreature;
|
||||||
|
|
||||||
typedef std::vector<const CStack*> TStacks;
|
|
||||||
|
|
||||||
namespace boost
|
|
||||||
{class shared_mutex;}
|
|
||||||
|
|
||||||
class DLL_LINKAGE CCallbackBase
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
CGameState *gs;
|
|
||||||
int player; // -1 gives access to all information, otherwise limited to knowledge of given player
|
|
||||||
|
|
||||||
CCallbackBase(CGameState *GS, int Player)
|
|
||||||
: gs(GS), player(Player)
|
|
||||||
{}
|
|
||||||
CCallbackBase()
|
|
||||||
: gs(NULL), player(-1)
|
|
||||||
{}
|
|
||||||
|
|
||||||
public:
|
|
||||||
boost::shared_mutex &getGsMutex(); //just return a reference to mutex, does not lock nor anything
|
|
||||||
};
|
|
||||||
|
|
||||||
class DLL_LINKAGE CBattleInfoCallback : public virtual CCallbackBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum EStackOwnership
|
|
||||||
{
|
|
||||||
ONLY_MINE, ONLY_ENEMY, MINE_AND_ENEMY
|
|
||||||
};
|
|
||||||
enum ERandomSpell
|
|
||||||
{
|
|
||||||
RANDOM_GENIE, RANDOM_AIMED
|
|
||||||
};
|
|
||||||
|
|
||||||
//battle
|
|
||||||
int battleGetBattlefieldType(); // 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines 8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields 15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog 21. "favourable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship
|
|
||||||
//int battleGetObstaclesAtTile(BattleHex tile); //returns bitfield
|
|
||||||
shared_ptr<const CObstacleInstance> battleGetObstacleOnPos(BattleHex tile, bool onlyBlocking = true);
|
|
||||||
std::vector<shared_ptr<const CObstacleInstance> > battleGetAllObstacles(); //returns all obstacles on the battlefield
|
|
||||||
const CStack * battleGetStackByID(int ID, bool onlyAlive = true); //returns stack info by given ID
|
|
||||||
const CStack * battleGetStackByPos(BattleHex pos, bool onlyAlive = true); //returns stack info by given pos
|
|
||||||
BattleHex battleGetPos(int stack); //returns position (tile ID) of stack
|
|
||||||
TStacks battleGetStacks(EStackOwnership whose = MINE_AND_ENEMY, bool onlyAlive = true); //returns stacks on battlefield
|
|
||||||
void getStackQueue( std::vector<const CStack *> &out, int howMany ); //returns vector of stack in order of their move sequence
|
|
||||||
void battleGetStackCountOutsideHexes(bool *ac); // returns hexes which when in front of a stack cause us to move the amount box back
|
|
||||||
std::vector<BattleHex> battleGetAvailableHexes(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = NULL); //returns numbers of hexes reachable by creature with id ID
|
|
||||||
std::vector<int> battleGetDistances(const CStack * stack, BattleHex hex = BattleHex::INVALID, BattleHex * predecessors = NULL); //returns vector of distances to [dest hex number]
|
|
||||||
std::set<BattleHex> battleGetAttackedHexes(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID);
|
|
||||||
bool battleCanShoot(const CStack * stack, BattleHex dest); //returns true if unit with id ID can shoot to dest
|
|
||||||
bool battleCanCastSpell(); //returns true, if caller can cast a spell
|
|
||||||
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell); //determines if given spell can be casted (and returns problem description)
|
|
||||||
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell, BattleHex destination); //if hero can cast spell here
|
|
||||||
ESpellCastProblem::ESpellCastProblem battleCanCreatureCastThisSpell(const CSpell * spell, BattleHex destination); //determines if creature can cast a spell here
|
|
||||||
si32 battleGetRandomStackSpell(const CStack * stack, ERandomSpell mode);
|
|
||||||
bool battleCanFlee(); //returns true if caller can flee from the battle
|
|
||||||
int battleGetSurrenderCost(); //returns cost of surrendering battle, -1 if surrendering is not possible
|
|
||||||
const CGTownInstance * battleGetDefendedTown(); //returns defended town if current battle is a siege, NULL instead
|
|
||||||
ui8 battleGetWallState(int partOfWall); //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
|
|
||||||
int battleGetWallUnderHex(BattleHex hex); //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
|
||||||
std::pair<ui32, ui32> battleEstimateDamage(const CStack * attacker, const CStack * defender, std::pair<ui32, ui32> * retaliationDmg = NULL); //estimates damage dealt by attacker to defender; it may be not precise especially when stack has randomly working bonuses; returns pair <min dmg, max dmg>
|
|
||||||
ui8 battleGetSiegeLevel(); //returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle
|
|
||||||
const CGHeroInstance * battleGetFightingHero(ui8 side) const; //returns hero corresponding to given side (0 - attacker, 1 - defender)
|
|
||||||
si8 battleHasDistancePenalty(const CStack * stack, BattleHex destHex); //checks if given stack has distance penalty
|
|
||||||
si8 battleHasWallPenalty(const CStack * stack, BattleHex destHex); //checks if given stack has wall penalty
|
|
||||||
si8 battleHasShootingPenalty(const CStack * stack, BattleHex destHex)
|
|
||||||
{
|
|
||||||
return battleHasDistancePenalty(stack, destHex) || battleHasWallPenalty(stack, destHex);
|
|
||||||
}
|
|
||||||
si8 battleCanTeleportTo(const CStack * stack, BattleHex destHex, int telportLevel); //checks if teleportation of given stack to given position can take place
|
|
||||||
si8 battleGetTacticDist(); //returns tactic distance for calling player or 0 if player is not in tactic phase
|
|
||||||
ui8 battleGetMySide(); //return side of player in battle (attacker/defender)
|
|
||||||
int battleGetMoatDmg(); //what dmg unit will suffer if ending turn in the moat
|
|
||||||
|
|
||||||
//convenience methods using the ones above
|
|
||||||
TStacks battleGetAllStacks() //returns all stacks, alive or dead or undead or mechanical :)
|
|
||||||
{
|
|
||||||
return battleGetStacks(MINE_AND_ENEMY, false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class DLL_LINKAGE CGameInfoCallback : public virtual CCallbackBase
|
class DLL_LINKAGE CGameInfoCallback : public virtual CCallbackBase
|
||||||
{
|
{
|
||||||
|
@ -1113,6 +1113,7 @@ void BattleStackMoved::applyGs( CGameState *gs )
|
|||||||
DLL_LINKAGE void BattleStackAttacked::applyGs( CGameState *gs )
|
DLL_LINKAGE void BattleStackAttacked::applyGs( CGameState *gs )
|
||||||
{
|
{
|
||||||
CStack * at = gs->curB->getStack(stackAttacked);
|
CStack * at = gs->curB->getStack(stackAttacked);
|
||||||
|
assert(at);
|
||||||
at->count = newAmount;
|
at->count = newAmount;
|
||||||
at->firstHPleft = newHP;
|
at->firstHPleft = newHP;
|
||||||
|
|
||||||
@ -1334,16 +1335,13 @@ DLL_LINKAGE void StacksHealedOrResurrected::applyGs( CGameState *gs )
|
|||||||
CStack * changedStack = gs->curB->getStack(healedStacks[g].stackID, false);
|
CStack * changedStack = gs->curB->getStack(healedStacks[g].stackID, false);
|
||||||
|
|
||||||
//checking if we resurrect a stack that is under a living stack
|
//checking if we resurrect a stack that is under a living stack
|
||||||
std::vector<BattleHex> access = gs->curB->getAccessibility(changedStack, true);
|
auto accessibility = gs->curB->getAccesibility();
|
||||||
bool acc[GameConstants::BFIELD_SIZE];
|
|
||||||
for(int h=0; h<GameConstants::BFIELD_SIZE; ++h)
|
if(!changedStack->alive() && !accessibility.accessible(changedStack->position, changedStack))
|
||||||
acc[h] = false;
|
{
|
||||||
for(int h=0; h<access.size(); ++h)
|
tlog1 << "Cannot resurrect " << changedStack->nodeName() << " because hex " << changedStack->position << " is occupied!\n";
|
||||||
acc[access[h]] = true;
|
|
||||||
if(!changedStack->alive() && !gs->curB->isAccessible(changedStack->position, acc,
|
|
||||||
changedStack->doubleWide(), changedStack->attackerOwned,
|
|
||||||
changedStack->hasBonusOfType(Bonus::FLYING), true))
|
|
||||||
return; //position is already occupied
|
return; //position is already occupied
|
||||||
|
}
|
||||||
|
|
||||||
//applying changes
|
//applying changes
|
||||||
bool resurrected = !changedStack->alive(); //indicates if stack is resurrected or just healed
|
bool resurrected = !changedStack->alive(); //indicates if stack is resurrected or just healed
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
#include <climits>
|
|
||||||
|
|
||||||
typedef si32 TResource;
|
typedef si32 TResource;
|
||||||
typedef si64 TResourceCap; //to avoid overflow when adding integers. Signed values are easier to control.
|
typedef si64 TResourceCap; //to avoid overflow when adding integers. Signed values are easier to control.
|
||||||
|
|
||||||
|
@ -230,14 +230,13 @@
|
|||||||
<ClCompile Include="CCreatureHandler.cpp" />
|
<ClCompile Include="CCreatureHandler.cpp" />
|
||||||
<ClCompile Include="CCreatureSet.cpp" />
|
<ClCompile Include="CCreatureSet.cpp" />
|
||||||
<ClCompile Include="CDefObjInfoHandler.cpp" />
|
<ClCompile Include="CDefObjInfoHandler.cpp" />
|
||||||
<ClCompile Include="CFileUtility.cpp" />
|
|
||||||
<ClCompile Include="CGameInterface.cpp" />
|
<ClCompile Include="CGameInterface.cpp" />
|
||||||
<ClCompile Include="CGameState.cpp" />
|
<ClCompile Include="CGameState.cpp" />
|
||||||
<ClCompile Include="CGeneralTextHandler.cpp" />
|
<ClCompile Include="CGeneralTextHandler.cpp" />
|
||||||
<ClCompile Include="CHeroHandler.cpp" />
|
<ClCompile Include="CHeroHandler.cpp" />
|
||||||
<ClCompile Include="CLodHandler.cpp" />
|
|
||||||
<ClCompile Include="CLogger.cpp" />
|
<ClCompile Include="CLogger.cpp" />
|
||||||
<ClCompile Include="CMapInfo.cpp" />
|
<ClCompile Include="CMapInfo.cpp" />
|
||||||
|
<ClCompile Include="CModHandler.cpp" />
|
||||||
<ClCompile Include="CObjectHandler.cpp" />
|
<ClCompile Include="CObjectHandler.cpp" />
|
||||||
<ClCompile Include="CObstacleInstance.cpp" />
|
<ClCompile Include="CObstacleInstance.cpp" />
|
||||||
<ClCompile Include="Connection.cpp" />
|
<ClCompile Include="Connection.cpp" />
|
||||||
@ -245,15 +244,15 @@
|
|||||||
<ClCompile Include="CThreadHelper.cpp" />
|
<ClCompile Include="CThreadHelper.cpp" />
|
||||||
<ClCompile Include="CTownHandler.cpp" />
|
<ClCompile Include="CTownHandler.cpp" />
|
||||||
<ClCompile Include="Filesystem\CBinaryReader.cpp" />
|
<ClCompile Include="Filesystem\CBinaryReader.cpp" />
|
||||||
|
<ClCompile Include="Filesystem\CCompressedStream.cpp" />
|
||||||
<ClCompile Include="Filesystem\CFileInfo.cpp" />
|
<ClCompile Include="Filesystem\CFileInfo.cpp" />
|
||||||
<ClCompile Include="Filesystem\CFileInputStream.cpp" />
|
<ClCompile Include="Filesystem\CFileInputStream.cpp" />
|
||||||
<ClCompile Include="Filesystem\CFilesystemLoader.cpp" />
|
<ClCompile Include="Filesystem\CFilesystemLoader.cpp" />
|
||||||
<ClCompile Include="Filesystem\CLodArchiveLoader.cpp" />
|
<ClCompile Include="Filesystem\CLodArchiveLoader.cpp" />
|
||||||
<ClCompile Include="Filesystem\CLodStream.cpp" />
|
|
||||||
<ClCompile Include="Filesystem\CMemoryStream.cpp" />
|
<ClCompile Include="Filesystem\CMemoryStream.cpp" />
|
||||||
<ClCompile Include="Filesystem\CResourceLoader.cpp" />
|
<ClCompile Include="Filesystem\CResourceLoader.cpp" />
|
||||||
<ClCompile Include="Filesystem\ISimpleResourceLoader.cpp" />
|
|
||||||
<ClCompile Include="HeroBonus.cpp" />
|
<ClCompile Include="HeroBonus.cpp" />
|
||||||
|
<ClCompile Include="CBattleCallback.cpp" />
|
||||||
<ClCompile Include="IGameCallback.cpp" />
|
<ClCompile Include="IGameCallback.cpp" />
|
||||||
<ClCompile Include="JsonNode.cpp" />
|
<ClCompile Include="JsonNode.cpp" />
|
||||||
<ClCompile Include="map.cpp" />
|
<ClCompile Include="map.cpp" />
|
||||||
@ -283,14 +282,13 @@
|
|||||||
<ClInclude Include="CCreatureHandler.h" />
|
<ClInclude Include="CCreatureHandler.h" />
|
||||||
<ClInclude Include="CCreatureSet.h" />
|
<ClInclude Include="CCreatureSet.h" />
|
||||||
<ClInclude Include="CDefObjInfoHandler.h" />
|
<ClInclude Include="CDefObjInfoHandler.h" />
|
||||||
<ClInclude Include="CFileUtility.h" />
|
|
||||||
<ClInclude Include="CGameInterface.h" />
|
<ClInclude Include="CGameInterface.h" />
|
||||||
<ClInclude Include="CGameState.h" />
|
<ClInclude Include="CGameState.h" />
|
||||||
<ClInclude Include="CGeneralTextHandler.h" />
|
<ClInclude Include="CGeneralTextHandler.h" />
|
||||||
<ClInclude Include="CHeroHandler.h" />
|
<ClInclude Include="CHeroHandler.h" />
|
||||||
<ClInclude Include="CLodHandler.h" />
|
|
||||||
<ClInclude Include="CLogger.h" />
|
<ClInclude Include="CLogger.h" />
|
||||||
<ClInclude Include="CMapInfo.h" />
|
<ClInclude Include="CMapInfo.h" />
|
||||||
|
<ClInclude Include="CModHandler.h" />
|
||||||
<ClInclude Include="CObjectHandler.h" />
|
<ClInclude Include="CObjectHandler.h" />
|
||||||
<ClInclude Include="CObstacleInstance.h" />
|
<ClInclude Include="CObstacleInstance.h" />
|
||||||
<ClInclude Include="CondSh.h" />
|
<ClInclude Include="CondSh.h" />
|
||||||
@ -302,17 +300,18 @@
|
|||||||
<ClInclude Include="CThreadHelper.h" />
|
<ClInclude Include="CThreadHelper.h" />
|
||||||
<ClInclude Include="CTownHandler.h" />
|
<ClInclude Include="CTownHandler.h" />
|
||||||
<ClInclude Include="Filesystem\CBinaryReader.h" />
|
<ClInclude Include="Filesystem\CBinaryReader.h" />
|
||||||
|
<ClInclude Include="Filesystem\CCompressedStream.h" />
|
||||||
<ClInclude Include="Filesystem\CFileInfo.h" />
|
<ClInclude Include="Filesystem\CFileInfo.h" />
|
||||||
<ClInclude Include="Filesystem\CFileInputStream.h" />
|
<ClInclude Include="Filesystem\CFileInputStream.h" />
|
||||||
<ClInclude Include="Filesystem\CFilesystemLoader.h" />
|
<ClInclude Include="Filesystem\CFilesystemLoader.h" />
|
||||||
<ClInclude Include="Filesystem\CInputStream.h" />
|
<ClInclude Include="Filesystem\CInputStream.h" />
|
||||||
<ClInclude Include="Filesystem\CLodArchiveLoader.h" />
|
<ClInclude Include="Filesystem\CLodArchiveLoader.h" />
|
||||||
<ClInclude Include="Filesystem\CLodStream.h" />
|
|
||||||
<ClInclude Include="Filesystem\CMemoryStream.h" />
|
<ClInclude Include="Filesystem\CMemoryStream.h" />
|
||||||
<ClInclude Include="Filesystem\CResourceLoader.h" />
|
<ClInclude Include="Filesystem\CResourceLoader.h" />
|
||||||
<ClInclude Include="Filesystem\ISimpleResourceLoader.h" />
|
<ClInclude Include="Filesystem\ISimpleResourceLoader.h" />
|
||||||
<ClInclude Include="GameConstants.h" />
|
<ClInclude Include="GameConstants.h" />
|
||||||
<ClInclude Include="HeroBonus.h" />
|
<ClInclude Include="HeroBonus.h" />
|
||||||
|
<ClInclude Include="CBattleCallback.h" />
|
||||||
<ClInclude Include="IGameCallback.h" />
|
<ClInclude Include="IGameCallback.h" />
|
||||||
<ClInclude Include="IGameEventsReceiver.h" />
|
<ClInclude Include="IGameEventsReceiver.h" />
|
||||||
<ClInclude Include="int3.h" />
|
<ClInclude Include="int3.h" />
|
||||||
|
@ -531,8 +531,7 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
|
|||||||
ConstTransitivePtr <CGHeroInstance> loserHero = battleResult.data->winner != 0 ? hero1 : hero2;
|
ConstTransitivePtr <CGHeroInstance> loserHero = battleResult.data->winner != 0 ? hero1 : hero2;
|
||||||
std::vector<ui32> arts; //display them in window
|
std::vector<ui32> arts; //display them in window
|
||||||
|
|
||||||
//TODO: display loot in window
|
if (result == BattleResult::NORMAL && winnerHero)
|
||||||
if (result < BattleResult::SURRENDER && winnerHero)
|
|
||||||
{
|
{
|
||||||
if (loserHero)
|
if (loserHero)
|
||||||
{
|
{
|
||||||
@ -542,7 +541,7 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
|
|||||||
MoveArtifact ma;
|
MoveArtifact ma;
|
||||||
ma.src = ArtifactLocation (loserHero, artSlot.first);
|
ma.src = ArtifactLocation (loserHero, artSlot.first);
|
||||||
const CArtifactInstance * art = ma.src.getArt();
|
const CArtifactInstance * art = ma.src.getArt();
|
||||||
if (art && !art->artType->isBig()) // don't move war machines or locked arts (spellbook)
|
if (art && !art->artType->isBig() && art->id != ArtifactId::SPELLBOOK) // don't move war machines or locked arts (spellbook)
|
||||||
{
|
{
|
||||||
arts.push_back (art->artType->id);
|
arts.push_back (art->artType->id);
|
||||||
ma.dst = ArtifactLocation (winnerHero, art->firstAvailableSlot(winnerHero));
|
ma.dst = ArtifactLocation (winnerHero, art->firstAvailableSlot(winnerHero));
|
||||||
@ -692,6 +691,7 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
|
|||||||
addToSlot(StackLocation(winnerHero, necroSlot), raisedStack.type, raisedStack.count);
|
addToSlot(StackLocation(winnerHero, necroSlot), raisedStack.type, raisedStack.count);
|
||||||
}
|
}
|
||||||
sendAndApply(&resultsApplied);
|
sendAndApply(&resultsApplied);
|
||||||
|
setBattle(nullptr);
|
||||||
|
|
||||||
if(duel)
|
if(duel)
|
||||||
{
|
{
|
||||||
@ -775,10 +775,10 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
|
|||||||
|
|
||||||
if (!bat.shot()) //multiple-hex attack - only in meele
|
if (!bat.shot()) //multiple-hex attack - only in meele
|
||||||
{
|
{
|
||||||
std::set<CStack*> attackedCreatures = gs->curB->getAttackedCreatures(att, targetHex);
|
std::set<const CStack*> attackedCreatures = gs->curB->getAttackedCreatures(att, targetHex);
|
||||||
//TODO: get exact attacked hex for defender
|
//TODO: get exact attacked hex for defender
|
||||||
|
|
||||||
BOOST_FOREACH(CStack * stack, attackedCreatures)
|
BOOST_FOREACH(const CStack * stack, attackedCreatures)
|
||||||
{
|
{
|
||||||
if (stack != def) //do not hit same stack twice
|
if (stack != def) //do not hit same stack twice
|
||||||
{
|
{
|
||||||
@ -793,10 +793,10 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
|
|||||||
bat.bsa.front().flags |= BattleStackAttacked::EFFECT;
|
bat.bsa.front().flags |= BattleStackAttacked::EFFECT;
|
||||||
bat.bsa.front().effect = VLC->spellh->spells[bonus->subtype]->mainEffectAnim; //hopefully it does not interfere with any other effect?
|
bat.bsa.front().effect = VLC->spellh->spells[bonus->subtype]->mainEffectAnim; //hopefully it does not interfere with any other effect?
|
||||||
|
|
||||||
std::set<CStack*> attackedCreatures = gs->curB->getAttackedCreatures(VLC->spellh->spells[bonus->subtype], bonus->val, att->owner, targetHex);
|
std::set<const CStack*> attackedCreatures = gs->curB->getAttackedCreatures(VLC->spellh->spells[bonus->subtype], bonus->val, att->owner, targetHex);
|
||||||
//TODO: get exact attacked hex for defender
|
//TODO: get exact attacked hex for defender
|
||||||
|
|
||||||
BOOST_FOREACH(CStack * stack, attackedCreatures)
|
BOOST_FOREACH(const CStack * stack, attackedCreatures)
|
||||||
{
|
{
|
||||||
if (stack != def) //do not hit same stack twice
|
if (stack != def) //do not hit same stack twice
|
||||||
{
|
{
|
||||||
@ -924,8 +924,8 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
CStack *curStack = gs->curB->getStack(stack),
|
const CStack *curStack = gs->curB->battleGetStackByID(stack),
|
||||||
*stackAtEnd = gs->curB->getStackT(dest);
|
*stackAtEnd = gs->curB->battleGetStackByPos(dest);
|
||||||
|
|
||||||
assert(curStack);
|
assert(curStack);
|
||||||
assert(dest < GameConstants::BFIELD_SIZE);
|
assert(dest < GameConstants::BFIELD_SIZE);
|
||||||
@ -936,50 +936,30 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//initing necessary tables
|
//initing necessary tables
|
||||||
bool accessibility[GameConstants::BFIELD_SIZE];
|
auto accessibility = getAccesibility();
|
||||||
std::vector<BattleHex> accessible = gs->curB->getAccessibility(curStack, false, NULL, true);
|
|
||||||
for(int b=0; b<GameConstants::BFIELD_SIZE; ++b)
|
|
||||||
{
|
|
||||||
accessibility[b] = false;
|
|
||||||
}
|
|
||||||
for(int g=0; g<accessible.size(); ++g)
|
|
||||||
{
|
|
||||||
accessibility[accessible[g]] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//shifting destination (if we have double wide stack and we can occupy dest but not be exactly there)
|
//shifting destination (if we have double wide stack and we can occupy dest but not be exactly there)
|
||||||
if(!stackAtEnd && curStack->doubleWide() && !accessibility[dest])
|
if(!stackAtEnd && curStack->doubleWide() && !accessibility.accessible(dest, curStack))
|
||||||
{
|
{
|
||||||
if(curStack->attackerOwned)
|
if(curStack->attackerOwned)
|
||||||
{
|
{
|
||||||
if(accessibility[dest+1])
|
if(accessibility.accessible(dest+1, curStack))
|
||||||
dest += BattleHex::RIGHT;
|
dest += BattleHex::RIGHT;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(accessibility[dest-1])
|
if(accessibility.accessible(dest-1, curStack))
|
||||||
dest += BattleHex::LEFT;
|
dest += BattleHex::LEFT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if((stackAtEnd && stackAtEnd!=curStack && stackAtEnd->alive()) || !accessibility[dest])
|
if((stackAtEnd && stackAtEnd!=curStack && stackAtEnd->alive()) || !accessibility.accessible(dest, curStack))
|
||||||
|
{
|
||||||
|
complain("Given destination is not accessible!");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bool accessibilityWithOccupyable[GameConstants::BFIELD_SIZE];
|
|
||||||
std::vector<BattleHex> accOc = gs->curB->getAccessibility(curStack, true, NULL, true);
|
|
||||||
for(int b=0; b<GameConstants::BFIELD_SIZE; ++b)
|
|
||||||
{
|
|
||||||
accessibilityWithOccupyable[b] = false;
|
|
||||||
}
|
|
||||||
for(int g=0; g<accOc.size(); ++g)
|
|
||||||
{
|
|
||||||
accessibilityWithOccupyable[accOc[g]] = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//if(dists[dest] > curStack->creature->speed && !(stackAtEnd && dists[dest] == curStack->creature->speed+1)) //we can attack a stack if we can go to adjacent hex
|
std::pair< std::vector<BattleHex>, int > path = gs->curB->getPath(curStack->position, dest, curStack);
|
||||||
// return false;
|
|
||||||
|
|
||||||
std::pair< std::vector<BattleHex>, int > path = gs->curB->getPath(curStack->position, dest, accessibilityWithOccupyable, curStack->hasBonusOfType(Bonus::FLYING), curStack->doubleWide(), curStack->attackerOwned);
|
|
||||||
|
|
||||||
ret = path.second;
|
ret = path.second;
|
||||||
|
|
||||||
@ -3220,6 +3200,40 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
tlog1 << "\tMaking action of type " << ba.actionType << std::endl;
|
tlog1 << "\tMaking action of type " << ba.actionType << std::endl;
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
|
|
||||||
|
|
||||||
|
const CStack *stack = battleGetStackByID(ba.stackNumber); //may be nullptr if action is not about stack
|
||||||
|
const bool isAboutActiveStack = stack && (stack == battleActiveStack());
|
||||||
|
|
||||||
|
switch(ba.actionType)
|
||||||
|
{
|
||||||
|
case BattleAction::WALK: //walk
|
||||||
|
case BattleAction::DEFEND: //defend
|
||||||
|
case BattleAction::WAIT: //wait
|
||||||
|
case BattleAction::WALK_AND_ATTACK: //walk or attack
|
||||||
|
case BattleAction::SHOOT: //shoot
|
||||||
|
case BattleAction::CATAPULT: //catapult
|
||||||
|
case BattleAction::STACK_HEAL: //healing with First Aid Tent
|
||||||
|
case BattleAction::DAEMON_SUMMONING:
|
||||||
|
case BattleAction::MONSTER_SPELL:
|
||||||
|
|
||||||
|
if(!stack)
|
||||||
|
{
|
||||||
|
complain("No such stack!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!stack->alive())
|
||||||
|
{
|
||||||
|
complain("This stack is dead: " + stack->nodeName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!isAboutActiveStack)
|
||||||
|
{
|
||||||
|
complain("Action has to be about active stack!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
switch(ba.actionType)
|
switch(ba.actionType)
|
||||||
{
|
{
|
||||||
case BattleAction::END_TACTIC_PHASE: //wait
|
case BattleAction::END_TACTIC_PHASE: //wait
|
||||||
@ -3267,7 +3281,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
case BattleAction::SURRENDER:
|
case BattleAction::SURRENDER:
|
||||||
{
|
{
|
||||||
int player = gs->curB->sides[ba.side];
|
int player = gs->curB->sides[ba.side];
|
||||||
int cost = gs->curB->getSurrenderingCost(player);
|
int cost = gs->curB->battleGetSurrenderCost(player);
|
||||||
if(cost < 0)
|
if(cost < 0)
|
||||||
complain("Cannot surrender!");
|
complain("Cannot surrender!");
|
||||||
else if(getResource(player, Res::GOLD) < cost)
|
else if(getResource(player, Res::GOLD) < cost)
|
||||||
@ -3284,10 +3298,10 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
{
|
{
|
||||||
StartAction start_action(ba);
|
StartAction start_action(ba);
|
||||||
sendAndApply(&start_action); //start movement and attack
|
sendAndApply(&start_action); //start movement and attack
|
||||||
int startingPos = gs->curB->getStack(ba.stackNumber)->position;
|
int startingPos = gs->curB->battleGetStackByID(ba.stackNumber)->position;
|
||||||
int distance = moveStack(ba.stackNumber, ba.destinationTile);
|
int distance = moveStack(ba.stackNumber, ba.destinationTile);
|
||||||
CStack *curStack = gs->curB->getStack(ba.stackNumber),
|
const CStack *curStack = gs->curB->battleGetStackByID(ba.stackNumber),
|
||||||
*stackAtEnd = gs->curB->getStackT(ba.additionalInfo);
|
*stackAtEnd = gs->curB->battleGetStackByPos(ba.additionalInfo);
|
||||||
|
|
||||||
if(!curStack || !stackAtEnd)
|
if(!curStack || !stackAtEnd)
|
||||||
{
|
{
|
||||||
@ -3295,6 +3309,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tlog5 << curStack->nodeName() << " will attack " << stackAtEnd->nodeName() << std::endl;
|
||||||
|
|
||||||
if(curStack->position != ba.destinationTile //we wasn't able to reach destination tile
|
if(curStack->position != ba.destinationTile //we wasn't able to reach destination tile
|
||||||
&& !(curStack->doubleWide()
|
&& !(curStack->doubleWide()
|
||||||
&& ( curStack->position == ba.destinationTile + (curStack->attackerOwned ? +1 : -1 ) )
|
&& ( curStack->position == ba.destinationTile + (curStack->attackerOwned ? +1 : -1 ) )
|
||||||
@ -3341,7 +3357,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
|
|
||||||
//counterattack
|
//counterattack
|
||||||
if(!curStack->hasBonusOfType(Bonus::BLOCKS_RETALIATION)
|
if(!curStack->hasBonusOfType(Bonus::BLOCKS_RETALIATION)
|
||||||
&& stackAtEnd->ableToRetaliate())
|
&& stackAtEnd->ableToRetaliate()
|
||||||
|
&& curStack->alive()) //attacker may have died (fire shield)
|
||||||
{
|
{
|
||||||
BattleAttack bat;
|
BattleAttack bat;
|
||||||
prepareAttack(bat, stackAtEnd, curStack, 0, curStack->position);
|
prepareAttack(bat, stackAtEnd, curStack, 0, curStack->position);
|
||||||
@ -3374,8 +3391,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
}
|
}
|
||||||
case BattleAction::SHOOT: //shoot
|
case BattleAction::SHOOT: //shoot
|
||||||
{
|
{
|
||||||
CStack *curStack = gs->curB->getStack(ba.stackNumber),
|
const CStack *curStack = gs->curB->battleGetStackByID(ba.stackNumber),
|
||||||
*destStack= gs->curB->getStackT(ba.destinationTile);
|
*destStack= gs->curB->battleGetStackByPos(ba.destinationTile);
|
||||||
if( !gs->curB->battleCanShoot(curStack, ba.destinationTile) )
|
if( !gs->curB->battleCanShoot(curStack, ba.destinationTile) )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -3423,7 +3440,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
const CGHeroInstance * attackingHero = gs->curB->heroes[ba.side];
|
const CGHeroInstance * attackingHero = gs->curB->heroes[ba.side];
|
||||||
CHeroHandler::SBallisticsLevelInfo sbi = VLC->heroh->ballistics[attackingHero->getSecSkillLevel(CGHeroInstance::BALLISTICS)];
|
CHeroHandler::SBallisticsLevelInfo sbi = VLC->heroh->ballistics[attackingHero->getSecSkillLevel(CGHeroInstance::BALLISTICS)];
|
||||||
|
|
||||||
int attackedPart = gs->curB->hexToWallPart(ba.destinationTile);
|
int attackedPart = gs->curB->battleHexToWallPart(ba.destinationTile);
|
||||||
if(attackedPart < 0)
|
if(attackedPart < 0)
|
||||||
{
|
{
|
||||||
complain("catapult tried to attack non-catapultable hex!");
|
complain("catapult tried to attack non-catapultable hex!");
|
||||||
@ -3524,8 +3541,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
StartAction start_action(ba);
|
StartAction start_action(ba);
|
||||||
sendAndApply(&start_action);
|
sendAndApply(&start_action);
|
||||||
const CGHeroInstance * attackingHero = gs->curB->heroes[ba.side];
|
const CGHeroInstance * attackingHero = gs->curB->heroes[ba.side];
|
||||||
CStack *healer = gs->curB->getStack(ba.stackNumber),
|
const CStack *healer = gs->curB->battleGetStackByID(ba.stackNumber),
|
||||||
*destStack = gs->curB->getStackT(ba.destinationTile);
|
*destStack = gs->curB->battleGetStackByPos(ba.destinationTile);
|
||||||
|
|
||||||
if(healer == NULL || destStack == NULL || !healer->hasBonusOfType(Bonus::HEALER))
|
if(healer == NULL || destStack == NULL || !healer->hasBonusOfType(Bonus::HEALER))
|
||||||
{
|
{
|
||||||
@ -3567,8 +3584,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
StartAction start_action(ba);
|
StartAction start_action(ba);
|
||||||
sendAndApply(&start_action);
|
sendAndApply(&start_action);
|
||||||
|
|
||||||
CStack *summoner = gs->curB->getStack(ba.stackNumber),
|
const CStack *summoner = gs->curB->battleGetStackByID(ba.stackNumber),
|
||||||
*destStack = gs->curB->getStackT(ba.destinationTile, false);
|
*destStack = gs->curB->battleGetStackByPos(ba.destinationTile, false);
|
||||||
|
|
||||||
BattleStackAdded bsa;
|
BattleStackAdded bsa;
|
||||||
bsa.attacker = summoner->attackerOwned;
|
bsa.attacker = summoner->attackerOwned;
|
||||||
@ -3603,7 +3620,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
StartAction start_action(ba);
|
StartAction start_action(ba);
|
||||||
sendAndApply(&start_action);
|
sendAndApply(&start_action);
|
||||||
|
|
||||||
CStack * stack = gs->curB->getStack(ba.stackNumber);
|
const CStack * stack = gs->curB->battleGetStackByID(ba.stackNumber);
|
||||||
int spellID = ba.additionalInfo;
|
int spellID = ba.additionalInfo;
|
||||||
BattleHex destination(ba.destinationTile);
|
BattleHex destination(ba.destinationTile);
|
||||||
|
|
||||||
@ -3852,7 +3869,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
|||||||
|
|
||||||
if (caster) //calculate spell cost
|
if (caster) //calculate spell cost
|
||||||
{
|
{
|
||||||
sc.spellCost = gs->curB->getSpellCost(VLC->spellh->spells[spellID], caster);
|
sc.spellCost = gs->curB->battleGetSpellCost(VLC->spellh->spells[spellID], caster);
|
||||||
|
|
||||||
if (secHero && mode == ECastingMode::HERO_CASTING) //handle mana channel
|
if (secHero && mode == ECastingMode::HERO_CASTING) //handle mana channel
|
||||||
{
|
{
|
||||||
@ -3869,18 +3886,18 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
|||||||
}
|
}
|
||||||
|
|
||||||
//calculating affected creatures for all spells
|
//calculating affected creatures for all spells
|
||||||
std::set<CStack*> attackedCres;
|
std::set<const CStack*> attackedCres;
|
||||||
if (mode != ECastingMode::ENCHANTER_CASTING)
|
if (mode != ECastingMode::ENCHANTER_CASTING)
|
||||||
{
|
{
|
||||||
attackedCres = gs->curB->getAttackedCreatures(spell, spellLvl, casterColor, destination);
|
attackedCres = gs->curB->getAttackedCreatures(spell, spellLvl, casterColor, destination);
|
||||||
for(std::set<CStack*>::const_iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
for(std::set<const CStack*>::const_iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
||||||
{
|
{
|
||||||
sc.affectedCres.insert((*it)->ID);
|
sc.affectedCres.insert((*it)->ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else //enchanter - hit all possible stacks
|
else //enchanter - hit all possible stacks
|
||||||
{
|
{
|
||||||
BOOST_FOREACH (CStack * stack, gs->curB->stacks)
|
BOOST_FOREACH (const CStack * stack, gs->curB->stacks)
|
||||||
{
|
{
|
||||||
/*if it's non negative spell and our unit or non positive spell and hostile unit */
|
/*if it's non negative spell and our unit or non positive spell and hostile unit */
|
||||||
if((!spell->isNegative() && stack->owner == casterColor)
|
if((!spell->isNegative() && stack->owner == casterColor)
|
||||||
@ -3898,7 +3915,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
|||||||
sc.resisted = gs->curB->calculateResistedStacks(spell, caster, secHero, attackedCres, casterColor, mode, usedSpellPower, spellLvl);
|
sc.resisted = gs->curB->calculateResistedStacks(spell, caster, secHero, attackedCres, casterColor, mode, usedSpellPower, spellLvl);
|
||||||
|
|
||||||
//calculating dmg to display
|
//calculating dmg to display
|
||||||
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
for(std::set<const CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
||||||
{
|
{
|
||||||
if(vstd::contains(sc.resisted, (*it)->ID)) //this creature resisted the spell
|
if(vstd::contains(sc.resisted, (*it)->ID)) //this creature resisted the spell
|
||||||
continue;
|
continue;
|
||||||
@ -3976,7 +3993,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
int chainLightningModifier = 0;
|
int chainLightningModifier = 0;
|
||||||
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
for(auto it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
||||||
{
|
{
|
||||||
if(vstd::contains(sc.resisted, (*it)->ID)) //this creature resisted the spell
|
if(vstd::contains(sc.resisted, (*it)->ID)) //this creature resisted the spell
|
||||||
continue;
|
continue;
|
||||||
@ -4067,7 +4084,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
|||||||
bonus = caster->getBonus(Selector::typeSubtype(Bonus::SPECIAL_PECULIAR_ENCHANT, spellID));
|
bonus = caster->getBonus(Selector::typeSubtype(Bonus::SPECIAL_PECULIAR_ENCHANT, spellID));
|
||||||
|
|
||||||
si32 power = 0;
|
si32 power = 0;
|
||||||
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
for(auto it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
||||||
{
|
{
|
||||||
if(vstd::contains(sc.resisted, (*it)->ID)) //this creature resisted the spell
|
if(vstd::contains(sc.resisted, (*it)->ID)) //this creature resisted the spell
|
||||||
continue;
|
continue;
|
||||||
@ -4154,7 +4171,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
|||||||
StacksHealedOrResurrected shr;
|
StacksHealedOrResurrected shr;
|
||||||
shr.lifeDrain = (ui8)false;
|
shr.lifeDrain = (ui8)false;
|
||||||
shr.tentHealing = (ui8)false;
|
shr.tentHealing = (ui8)false;
|
||||||
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
for(auto it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
||||||
{
|
{
|
||||||
if(vstd::contains(sc.resisted, (*it)->ID) //this creature resisted the spell
|
if(vstd::contains(sc.resisted, (*it)->ID) //this creature resisted the spell
|
||||||
|| (spellID == Spells::ANIMATE_DEAD && !(*it)->hasBonusOfType(Bonus::UNDEAD)) //we try to cast animate dead on living stack
|
|| (spellID == Spells::ANIMATE_DEAD && !(*it)->hasBonusOfType(Bonus::UNDEAD)) //we try to cast animate dead on living stack
|
||||||
@ -4172,7 +4189,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
|||||||
hi.healedHP = gs->curB->calculateHealedHP(spell, usedSpellPower, spellLvl, *it);
|
hi.healedHP = gs->curB->calculateHealedHP(spell, usedSpellPower, spellLvl, *it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
hi.healedHP = gs->curB->calculateHealedHP(caster, spell, *it, gs->curB->getStack(selectedStack));
|
hi.healedHP = gs->curB->calculateHealedHP(caster, spell, *it, gs->curB->battleGetStackByID(selectedStack));
|
||||||
hi.lowLevelResurrection = spellLvl <= 1;
|
hi.lowLevelResurrection = spellLvl <= 1;
|
||||||
shr.healedStacks.push_back(hi);
|
shr.healedStacks.push_back(hi);
|
||||||
}
|
}
|
||||||
@ -4227,7 +4244,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
|||||||
break;
|
break;
|
||||||
case Spells::CLONE:
|
case Spells::CLONE:
|
||||||
{
|
{
|
||||||
CStack * clonedStack = NULL;
|
const CStack * clonedStack = NULL;
|
||||||
if (attackedCres.size())
|
if (attackedCres.size())
|
||||||
clonedStack = *attackedCres.begin();
|
clonedStack = *attackedCres.begin();
|
||||||
if (!clonedStack)
|
if (!clonedStack)
|
||||||
@ -4270,7 +4287,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
|||||||
break;
|
break;
|
||||||
case Spells::DEATH_STARE: //handled in a bit different way
|
case Spells::DEATH_STARE: //handled in a bit different way
|
||||||
{
|
{
|
||||||
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
for(auto it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
||||||
{
|
{
|
||||||
if((*it)->hasBonusOfType(Bonus::UNDEAD) || (*it)->hasBonusOfType(Bonus::NON_LIVING)) //this creature is immune
|
if((*it)->hasBonusOfType(Bonus::UNDEAD) || (*it)->hasBonusOfType(Bonus::NON_LIVING)) //this creature is immune
|
||||||
{
|
{
|
||||||
@ -4291,7 +4308,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
|||||||
break;
|
break;
|
||||||
case Spells::ACID_BREATH_DAMAGE: //new effect, separate from acid breath defense reduction
|
case Spells::ACID_BREATH_DAMAGE: //new effect, separate from acid breath defense reduction
|
||||||
{
|
{
|
||||||
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it) //no immunities
|
for(auto it = attackedCres.begin(); it != attackedCres.end(); ++it) //no immunities
|
||||||
{
|
{
|
||||||
BattleStackAttacked bsa;
|
BattleStackAttacked bsa;
|
||||||
bsa.flags |= BattleStackAttacked::EFFECT;
|
bsa.flags |= BattleStackAttacked::EFFECT;
|
||||||
@ -4323,7 +4340,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
|||||||
//Magic Mirror effect
|
//Magic Mirror effect
|
||||||
if (spell->isNegative() && mode != ECastingMode::MAGIC_MIRROR && spell->level && spell->range[0] == "0") //it is actual spell and can be reflected to single target, no recurrence
|
if (spell->isNegative() && mode != ECastingMode::MAGIC_MIRROR && spell->level && spell->range[0] == "0") //it is actual spell and can be reflected to single target, no recurrence
|
||||||
{
|
{
|
||||||
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
for(auto it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
||||||
{
|
{
|
||||||
int mirrorChance = (*it)->valOfBonuses(Bonus::MAGIC_MIRROR);
|
int mirrorChance = (*it)->valOfBonuses(Bonus::MAGIC_MIRROR);
|
||||||
if(mirrorChance > rand()%100)
|
if(mirrorChance > rand()%100)
|
||||||
@ -4388,7 +4405,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
|
|||||||
ECastingMode::HERO_CASTING, NULL, ba.selectedStack);
|
ECastingMode::HERO_CASTING, NULL, ba.selectedStack);
|
||||||
|
|
||||||
sendAndApply(&end_action);
|
sendAndApply(&end_action);
|
||||||
if( !gs->curB->getStack(gs->curB->activeStack, false)->alive() )
|
if( !gs->curB->battleGetStackByID(gs->curB->activeStack, false)->alive() )
|
||||||
{
|
{
|
||||||
battleMadeAction.setn(true);
|
battleMadeAction.setn(true);
|
||||||
}
|
}
|
||||||
@ -4426,11 +4443,11 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
|
|||||||
{
|
{
|
||||||
bool unbind = true;
|
bool unbind = true;
|
||||||
BonusList bl = *(st->getBonuses(Selector::type(Bonus::BIND_EFFECT)));
|
BonusList bl = *(st->getBonuses(Selector::type(Bonus::BIND_EFFECT)));
|
||||||
std::set<CStack*> stacks = gs->curB->getAdjacentCreatures(st);
|
std::set<const CStack*> stacks = gs->curB-> batteAdjacentCreatures(st);
|
||||||
|
|
||||||
BOOST_FOREACH(Bonus * b, bl)
|
BOOST_FOREACH(Bonus * b, bl)
|
||||||
{
|
{
|
||||||
const CStack * stack = gs->curB->getStack(b->additionalInfo); //binding stack must be alive and adjacent
|
const CStack * stack = gs->curB->battleGetStackByID(b->additionalInfo); //binding stack must be alive and adjacent
|
||||||
if (stack)
|
if (stack)
|
||||||
{
|
{
|
||||||
if (vstd::contains(stacks, stack)) //binding stack is still present
|
if (vstd::contains(stacks, stack)) //binding stack is still present
|
||||||
@ -4533,7 +4550,7 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::handleDamageFromObstacle(const CObstacleInstance &obstacle, CStack * curStack)
|
void CGameHandler::handleDamageFromObstacle(const CObstacleInstance &obstacle, const CStack * curStack)
|
||||||
{
|
{
|
||||||
//we want to determine following vars depending on obstacle type
|
//we want to determine following vars depending on obstacle type
|
||||||
int damage = -1;
|
int damage = -1;
|
||||||
@ -4552,7 +4569,7 @@ void CGameHandler::handleDamageFromObstacle(const CObstacleInstance &obstacle, C
|
|||||||
else if(obstacle.obstacleType == CObstacleInstance::LAND_MINE)
|
else if(obstacle.obstacleType == CObstacleInstance::LAND_MINE)
|
||||||
{
|
{
|
||||||
//You don't get hit by a Mine you can see.
|
//You don't get hit by a Mine you can see.
|
||||||
if(gs->curB->isObstacleVisibleForSide(obstacle, side))
|
if(gs->curB->battleIsObstacleVisibleForSide(obstacle, (BattlePerspective::BattlePerspective)side))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
oneTimeObstacle = true;
|
oneTimeObstacle = true;
|
||||||
@ -5168,7 +5185,7 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta
|
|||||||
{
|
{
|
||||||
if (bat.bsa[g].newAmount > 0 && !bat.bsa[g].isSecondary()) //apply effects only to first target stack if it's alive
|
if (bat.bsa[g].newAmount > 0 && !bat.bsa[g].isSecondary()) //apply effects only to first target stack if it's alive
|
||||||
{
|
{
|
||||||
oneOfAttacked = gs->curB->getStack(bat.bsa[g].stackAttacked);
|
oneOfAttacked = gs->curB->battleGetStackByID(bat.bsa[g].stackAttacked);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5206,13 +5223,13 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta
|
|||||||
|
|
||||||
void CGameHandler::handleAttackBeforeCasting (const BattleAttack & bat)
|
void CGameHandler::handleAttackBeforeCasting (const BattleAttack & bat)
|
||||||
{
|
{
|
||||||
const CStack * attacker = gs->curB->getStack(bat.stackAttacking);
|
const CStack * attacker = gs->curB->battleGetStackByID(bat.stackAttacking);
|
||||||
attackCasting(bat, Bonus::SPELL_BEFORE_ATTACK, attacker); //no detah stare / acid bretah needed?
|
attackCasting(bat, Bonus::SPELL_BEFORE_ATTACK, attacker); //no detah stare / acid bretah needed?
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
|
void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
|
||||||
{
|
{
|
||||||
const CStack * attacker = gs->curB->getStack(bat.stackAttacking);
|
const CStack * attacker = gs->curB->battleGetStackByID(bat.stackAttacking);
|
||||||
if (!attacker) //could be already dead
|
if (!attacker) //could be already dead
|
||||||
return;
|
return;
|
||||||
attackCasting(bat, Bonus::SPELL_AFTER_ATTACK, attacker);
|
attackCasting(bat, Bonus::SPELL_AFTER_ATTACK, attacker);
|
||||||
@ -5241,7 +5258,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
|
|||||||
if (staredCreatures)
|
if (staredCreatures)
|
||||||
{
|
{
|
||||||
if (bat.bsa.size() && bat.bsa[0].newAmount > 0) //TODO: death stare was not originally available for multiple-hex attacks, but...
|
if (bat.bsa.size() && bat.bsa[0].newAmount > 0) //TODO: death stare was not originally available for multiple-hex attacks, but...
|
||||||
handleSpellCasting(79, 0, gs->curB->getStack(bat.bsa[0].stackAttacked)->position,
|
handleSpellCasting(79, 0, gs->curB->battleGetStackByID(bat.bsa[0].stackAttacked)->position,
|
||||||
!attacker->attackerOwned, attacker->owner, NULL, NULL, staredCreatures, ECastingMode::AFTER_ATTACK_CASTING, attacker);
|
!attacker->attackerOwned, attacker->owner, NULL, NULL, staredCreatures, ECastingMode::AFTER_ATTACK_CASTING, attacker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5255,7 +5272,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
|
|||||||
}
|
}
|
||||||
if (acidDamage)
|
if (acidDamage)
|
||||||
{
|
{
|
||||||
handleSpellCasting(81, 0, gs->curB->getStack(bat.bsa[0].stackAttacked)->position,
|
handleSpellCasting(81, 0, gs->curB->battleGetStackByID(bat.bsa[0].stackAttacked)->position,
|
||||||
!attacker->attackerOwned, attacker->owner, NULL, NULL,
|
!attacker->attackerOwned, attacker->owner, NULL, NULL,
|
||||||
acidDamage * attacker->count, ECastingMode::AFTER_ATTACK_CASTING, attacker);
|
acidDamage * attacker->count, ECastingMode::AFTER_ATTACK_CASTING, attacker);
|
||||||
}
|
}
|
||||||
@ -5716,6 +5733,7 @@ bool CGameHandler::swapStacks(const StackLocation &sl1, const StackLocation &sl2
|
|||||||
|
|
||||||
void CGameHandler::runBattle()
|
void CGameHandler::runBattle()
|
||||||
{
|
{
|
||||||
|
setBattle(gs->curB);
|
||||||
assert(gs->curB);
|
assert(gs->curB);
|
||||||
//TODO: pre-tactic stuff, call scripts etc.
|
//TODO: pre-tactic stuff, call scripts etc.
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ public:
|
|||||||
int usedSpellPower, ECastingMode::ECastingMode mode, const CStack * stack, si32 selectedStack = -1);
|
int usedSpellPower, ECastingMode::ECastingMode mode, const CStack * stack, si32 selectedStack = -1);
|
||||||
bool makeCustomAction(BattleAction &ba);
|
bool makeCustomAction(BattleAction &ba);
|
||||||
void stackTurnTrigger(const CStack * stack);
|
void stackTurnTrigger(const CStack * stack);
|
||||||
void handleDamageFromObstacle(const CObstacleInstance &obstacle, CStack * curStack); //checks if obstacle is land mine and handles possible consequences
|
void handleDamageFromObstacle(const CObstacleInstance &obstacle, const CStack * curStack); //checks if obstacle is land mine and handles possible consequences
|
||||||
void removeObstacle(const CObstacleInstance &obstacle);
|
void removeObstacle(const CObstacleInstance &obstacle);
|
||||||
bool queryReply( ui32 qid, ui32 answer, ui8 player );
|
bool queryReply( ui32 qid, ui32 answer, ui8 player );
|
||||||
bool hireHero( const CGObjectInstance *obj, ui8 hid, ui8 player );
|
bool hireHero( const CGObjectInstance *obj, ui8 hid, ui8 player );
|
||||||
|
@ -251,7 +251,7 @@ bool MakeAction::applyGh( CGameHandler *gh )
|
|||||||
if(gh->connections[b->sides[b->tacticsSide]] != c)
|
if(gh->connections[b->sides[b->tacticsSide]] != c)
|
||||||
ERROR_AND_RETURN;
|
ERROR_AND_RETURN;
|
||||||
}
|
}
|
||||||
else if(gh->connections[b->getStack(b->activeStack)->owner] != c)
|
else if(gh->connections[b->battleGetStackByID(b->activeStack)->owner] != c)
|
||||||
ERROR_AND_RETURN;
|
ERROR_AND_RETURN;
|
||||||
|
|
||||||
return gh->makeBattleAction(ba);
|
return gh->makeBattleAction(ba);
|
||||||
@ -262,9 +262,10 @@ bool MakeCustomAction::applyGh( CGameHandler *gh )
|
|||||||
const BattleInfo *b = GS(gh)->curB;
|
const BattleInfo *b = GS(gh)->curB;
|
||||||
if(!b) ERROR_AND_RETURN;
|
if(!b) ERROR_AND_RETURN;
|
||||||
if(b->tacticDistance) ERROR_AND_RETURN;
|
if(b->tacticDistance) ERROR_AND_RETURN;
|
||||||
const CStack *active = GS(gh)->curB->getStack(GS(gh)->curB->activeStack);
|
const CStack *active = GS(gh)->curB->battleGetStackByID(GS(gh)->curB->activeStack);
|
||||||
if(!active) ERROR_AND_RETURN;
|
if(!active) ERROR_AND_RETURN;
|
||||||
if(gh->connections[active->owner] != c) ERROR_AND_RETURN;
|
if(gh->connections[active->owner] != c) ERROR_AND_RETURN;
|
||||||
|
if(ba.actionType != BattleAction::HERO_SPELL) ERROR_AND_RETURN;
|
||||||
return gh->makeCustomAction(ba);
|
return gh->makeCustomAction(ba);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user