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 "../../lib/CCreatureHandler.h"
|
||||
|
||||
CBattleCallback * cbc;
|
||||
CPlayerBattleCallback * cbc;
|
||||
|
||||
CStupidAI::CStupidAI(void)
|
||||
: side(-1), cb(NULL)
|
||||
@ -19,7 +19,7 @@ CStupidAI::~CStupidAI(void)
|
||||
print("destroyed");
|
||||
}
|
||||
|
||||
void CStupidAI::init( CBattleCallback * CB )
|
||||
void CStupidAI::init( CPlayerBattleCallback * CB )
|
||||
{
|
||||
print("init called, saving ptr to IBattleCallback");
|
||||
cbc = cb = CB;
|
||||
@ -60,7 +60,7 @@ bool isMoreProfitable(const EnemyInfo &ei1, const EnemyInfo& ei2)
|
||||
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;
|
||||
BOOST_FOREACH(BattleHex n, hex.neighbouringTiles())
|
||||
@ -76,7 +76,7 @@ int distToNearestNeighbour(BattleHex hex, const std::vector<int> & dists, Battle
|
||||
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);
|
||||
}
|
||||
@ -97,9 +97,9 @@ static bool willSecondHexBlockMoreEnemyShooters(const BattleHex &h1, const Battl
|
||||
BattleAction CStupidAI::activeStack( const CStack * stack )
|
||||
{
|
||||
//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<int> dists = cb->battleGetDistances(stack);
|
||||
auto dists = cb->battleGetDistances(stack);
|
||||
std::vector<EnemyInfo> enemiesShootable, enemiesReachable, enemiesUnreachable;
|
||||
|
||||
if(stack->type->idNumber == 145) //catapult
|
||||
@ -246,33 +246,66 @@ void CStupidAI::print(const std::string &text) const
|
||||
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;
|
||||
BattleHex predecessors[GameConstants::BFIELD_SIZE];
|
||||
std::vector<int> dists = cb->battleGetDistances(stack, hex);
|
||||
if(distToNearestNeighbour(hex, dists, &realDest) > GameConstants::BFIELD_SIZE)
|
||||
assert(destination.isValid());
|
||||
auto avHexes = cb->battleGetAvailableHexes(stack, false);
|
||||
auto reachability = cb->getReachability(stack);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
dists = cb->battleGetDistances(stack, realDest, predecessors);
|
||||
std::vector<BattleHex> avHexes = cb->battleGetAvailableHexes(stack, false);
|
||||
vstd::erase_if(destNeighbours, [&](BattleHex hex){ return !reachability.accessibility.accessible(hex, stack); });
|
||||
|
||||
if(!avHexes.size())
|
||||
if(!avHexes.size() || !destNeighbours.size()) //we are blocked or dest is blocked
|
||||
{
|
||||
print("goTowards: Stack cannot move! That's " + stack->nodeName());
|
||||
return BattleAction::makeDefend(stack);
|
||||
}
|
||||
|
||||
while(1)
|
||||
if(stack->hasBonusOfType(Bonus::FLYING))
|
||||
{
|
||||
assert(realDest.isValid());
|
||||
if(vstd::contains(avHexes, hex))
|
||||
return BattleAction::makeMove(stack, hex);
|
||||
// Flying stack doesn't go hex by hex, so we can't backtrack using predecessors.
|
||||
// We just check all available hexes and pick the one closest to the target.
|
||||
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
|
||||
{
|
||||
int side;
|
||||
CBattleCallback *cb;
|
||||
CPlayerBattleCallback *cb;
|
||||
|
||||
void print(const std::string &text) const;
|
||||
public:
|
||||
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 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
|
||||
|
@ -174,13 +174,6 @@ void removeDuplicates(std::vector<T> &vec)
|
||||
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
|
||||
{
|
||||
boost::function<void()> foo;
|
||||
@ -1711,7 +1704,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
cb->moveHero(*h, CGHeroInstance::convertPosition(endpos, true));
|
||||
waitTillFree(); //movement may cause battle or blocking dialog
|
||||
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);
|
||||
//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);
|
||||
}
|
||||
|
||||
if(h->tempOwner == playerID) //we could have lost hero after last move
|
||||
if(h) //we could have lost hero after last move
|
||||
{
|
||||
cb->recalculatePaths();
|
||||
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;
|
||||
name = h->name;
|
||||
|
||||
hid = H->subID;
|
||||
hid = H->id;
|
||||
// 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
|
||||
//
|
||||
//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);
|
||||
|
||||
if(h)
|
||||
{
|
||||
assert(cb->getObj(h->id));
|
||||
assert(h->tempOwner == ai->playerID);
|
||||
auto obj = cb->getObj(hid);
|
||||
const bool owned = obj && obj->tempOwner == ai->playerID;
|
||||
|
||||
if(doWeExpectNull && !owned)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(obj);
|
||||
assert(owned);
|
||||
}
|
||||
}
|
||||
|
||||
return h;
|
||||
|
@ -78,17 +78,15 @@ public:
|
||||
|
||||
struct CPack;
|
||||
|
||||
class CBattleCallback : public IBattleCallback, public CBattleInfoCallback
|
||||
class CBattleCallback : public IBattleCallback, public CPlayerBattleCallback
|
||||
{
|
||||
private:
|
||||
CBattleCallback(CGameState *GS, int Player, CClient *C);
|
||||
|
||||
protected:
|
||||
int sendRequest(const CPack *request); //returns requestID (that'll be matched to requestID in PackageApplied)
|
||||
CClient *cl;
|
||||
//virtual bool hasAccess(int playerId) const;
|
||||
|
||||
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
|
||||
bool battleMakeTacticAction(BattleAction * action) OVERRIDE; // performs tactic phase actions
|
||||
|
||||
|
58
Global.h
58
Global.h
@ -44,17 +44,10 @@
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
//#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <numeric>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
//The only available version is 3, as of Boost 1.50
|
||||
#define BOOST_FILESYSTEM_VERSION 3
|
||||
@ -72,8 +65,10 @@
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/logic/tribool.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/range/algorithm.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
@ -172,7 +167,14 @@ namespace vstd
|
||||
template <typename Container, typename Item>
|
||||
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
|
||||
@ -201,7 +203,7 @@ namespace vstd
|
||||
int find_pos(const Container & c, const T2 &s)
|
||||
{
|
||||
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)
|
||||
return i;
|
||||
return -1;
|
||||
@ -343,11 +345,39 @@ namespace vstd
|
||||
{
|
||||
assert(r.size());
|
||||
index %= r.size();
|
||||
// auto itr = std::begin(r); //not available in gcc-4.5
|
||||
auto itr = r.begin();
|
||||
auto itr = boost::begin(r);
|
||||
std::advance(itr, index);
|
||||
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;
|
||||
|
@ -141,7 +141,7 @@ CAttackAnimation::CAttackAnimation(CBattleInterface *_owner, const CStack *attac
|
||||
|
||||
assert(attackingStack && "attackingStack is NULL in CBattleAttack::CBattleAttack !\n");
|
||||
bool isCatapultAttack = attackingStack->hasBonusOfType(Bonus::CATAPULT)
|
||||
&& owner->curInt->cb->battleGetWallUnderHex(_dest) >= 0;
|
||||
&& owner->curInt->cb->battleHexToWallPart(_dest) >= 0;
|
||||
|
||||
assert(attackedStack || isCatapultAttack);
|
||||
attackingStackPosBeforeReturn = attackingStack->position;
|
||||
|
@ -1252,16 +1252,35 @@ void CBattleInterface::bSpellf()
|
||||
|
||||
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;
|
||||
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);
|
||||
CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), myHero, curInt);
|
||||
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()
|
||||
@ -1495,11 +1514,11 @@ bool CBattleInterface::isCatapultAttackable(BattleHex hex) const
|
||||
if(!siegeH || tacticsMode)
|
||||
return false;
|
||||
|
||||
int wallUnder = curInt->cb->battleGetWallUnderHex(hex);
|
||||
int wallUnder = curInt->cb->battleHexToWallPart(hex);
|
||||
if(wallUnder == -1)
|
||||
return false;
|
||||
|
||||
return curInt->cb->battleGetWallState(wallUnder) < 3;
|
||||
return curInt->cb->battleGetWallState(wallUnder) < EWallState::DESTROYED;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
//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);
|
||||
bFlee->block(!curInt->cb->battleCanFlee());
|
||||
bSurrender->block(curInt->cb->battleGetSurrenderCost() < 0);
|
||||
@ -3484,6 +3505,25 @@ Point CBattleInterface::whereToBlitObstacleImage(SDL_Surface *image, const CObst
|
||||
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"};
|
||||
|
||||
CBattleInterface::SiegeHelper::SiegeHelper(const CGTownInstance *siegeTown, const CBattleInterface * _owner)
|
||||
|
@ -45,6 +45,7 @@ class CCreatureAnimation;
|
||||
struct ProjectileInfo;
|
||||
class CClickableHex;
|
||||
struct BattleHex;
|
||||
struct InfoAboutHero;
|
||||
|
||||
/// Class which manages the locked hex fields that are blocked e.g. by obstacles
|
||||
class CBattleObstacle
|
||||
@ -284,6 +285,9 @@ public:
|
||||
BattleHex fromWhichHexAttack(BattleHex myNumber);
|
||||
void obstaclePlaced(const CObstacleInstance & oi);
|
||||
|
||||
const CGHeroInstance * currentHero() const;
|
||||
InfoAboutHero enemyHero() const;
|
||||
|
||||
friend class CPlayerInterface;
|
||||
friend class CAdventureMapButton;
|
||||
friend class CInGameConsole;
|
||||
|
@ -616,7 +616,7 @@ void CClickableHex::clickRight(tribool down, bool previousState)
|
||||
void CStackQueue::update()
|
||||
{
|
||||
stacksSorted.clear();
|
||||
owner->curInt->cb->getStackQueue(stacksSorted, QUEUE_SIZE);
|
||||
owner->curInt->cb->battleGetStackQueue(stacksSorted, QUEUE_SIZE);
|
||||
for (int i = 0; i < QUEUE_SIZE ; 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
|
||||
{
|
||||
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;
|
||||
case ESpellCastProblem::SPELL_LEVEL_LIMIT_EXCEEDED:
|
||||
{
|
||||
std::string text = CGI->generaltexth->allTexts[541], caster = owner->myHero->name;
|
||||
text = boost::str(boost::format(text) % caster);
|
||||
owner->myInt->showInfoDialog(text);
|
||||
//Recanter's Cloak or similar effect. Try to retrieve bonus
|
||||
const Bonus *b = owner->myHero->getBonus(Selector::type(Bonus::BLOCK_MAGIC_ABOVE));
|
||||
//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;
|
||||
case ESpellCastProblem::NO_APPROPRIATE_TARGET:
|
||||
|
@ -117,7 +117,7 @@ void CClient::waitForMoveAndSend(int color)
|
||||
try
|
||||
{
|
||||
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);
|
||||
sendRequest(&temp_action, color);
|
||||
return;
|
||||
@ -381,13 +381,14 @@ void CClient::newGame( CConnection *con, StartInfo *si )
|
||||
battleints[color] = playerint[color];
|
||||
|
||||
playerint[color]->init(cb.get());
|
||||
callbacks[color] = cb;
|
||||
battleCallbacks[color] = callbacks[color] = cb;
|
||||
}
|
||||
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]->init(cbc);
|
||||
battleints[color]->init(cbc.get());
|
||||
}
|
||||
}
|
||||
|
||||
@ -399,7 +400,9 @@ void CClient::newGame( CConnection *con, StartInfo *si )
|
||||
battleints[254] = playerint[254] = p;
|
||||
privilagedBattleEventReceivers.push_back(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);
|
||||
}
|
||||
else
|
||||
@ -554,6 +557,15 @@ void CClient::stopConnection()
|
||||
|
||||
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;
|
||||
if(vstd::contains(playerint, info->sides[0]) && playerint[info->sides[0]]->human)
|
||||
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()
|
||||
{
|
||||
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 )
|
||||
|
@ -114,6 +114,7 @@ class CClient : public IGameCallback
|
||||
public:
|
||||
CCallback *cb;
|
||||
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<IBattleEventsReceiver*> privilagedBattleEventReceivers; //scripting modules, spectator interfaces
|
||||
std::map<ui8,CGameInterface *> playerint;
|
||||
@ -225,4 +226,5 @@ public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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 )
|
||||
{
|
||||
CStack * activated = GS(cl)->curB->getStack(stack);
|
||||
const CStack * activated = GS(cl)->curB->battleGetStackByID(stack);
|
||||
int playerToCall = -1; //player that will move activated stack
|
||||
if( activated->hasBonusOfType(Bonus::HYPNOTIZED) )
|
||||
{
|
||||
@ -616,11 +616,12 @@ void BattleObstaclePlaced::applyCl(CClient * cl)
|
||||
void BattleResult::applyFirstCl( CClient *cl )
|
||||
{
|
||||
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleEnd,this);
|
||||
cl->battleFinished();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -248,7 +248,6 @@
|
||||
<ClCompile Include="CPlayerInterface.cpp" />
|
||||
<ClCompile Include="CPreGame.cpp" />
|
||||
<ClCompile Include="CQuestLog.cpp" />
|
||||
<ClCompile Include="CSndHandler.cpp" />
|
||||
<ClCompile Include="CSpellWindow.cpp" />
|
||||
<ClCompile Include="CVideoHandler.cpp" />
|
||||
<ClCompile Include="Graphics.cpp" />
|
||||
@ -289,12 +288,10 @@
|
||||
<ClInclude Include="CKingdomInterface.h" />
|
||||
<ClInclude Include="Client.h" />
|
||||
<ClInclude Include="CMessage.h" />
|
||||
<ClInclude Include="CMusicBase.h" />
|
||||
<ClInclude Include="CMusicHandler.h" />
|
||||
<ClInclude Include="CPlayerInterface.h" />
|
||||
<ClInclude Include="CPreGame.h" />
|
||||
<ClInclude Include="CQuestLog.h" />
|
||||
<ClInclude Include="CSndHandler.h" />
|
||||
<ClInclude Include="CSoundBase.h" />
|
||||
<ClInclude Include="CSpellWindow.h" />
|
||||
<ClInclude Include="CVideoHandler.h" />
|
||||
@ -315,7 +312,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\ChangeLog" />
|
||||
<None Include="ClassDiagram21.cd" />
|
||||
<None Include="vcmi.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -46,28 +46,23 @@
|
||||
<ClInclude Include="BattleInterface\CBattleInterfaceClasses.h" />
|
||||
<ClInclude Include="BattleInterface\CCreatureAnimation.h" />
|
||||
<ClInclude Include="CAdvmapInterface.h" />
|
||||
<ClInclude Include="..\hch\CArtHandler.h" />
|
||||
<ClInclude Include="CAnimation.h" />
|
||||
<ClInclude Include="CBitmapHandler.h" />
|
||||
<ClInclude Include="..\hch\CBuildingHandler.h" />
|
||||
<ClInclude Include="..\CCallback.h" />
|
||||
<ClInclude Include="CCastleInterface.h" />
|
||||
<ClInclude Include="CConfigHandler.h" />
|
||||
<ClInclude Include="CCreatureWindow.h" />
|
||||
<ClInclude Include="CDefHandler.h" />
|
||||
<ClInclude Include="CGameInfo.h" />
|
||||
<ClInclude Include="..\hch\CHeroHandler.h" />
|
||||
<ClInclude Include="CHeroWindow.h" />
|
||||
<ClInclude Include="CKingdomInterface.h" />
|
||||
<ClInclude Include="Client.h" />
|
||||
<ClInclude Include="CMessage.h" />
|
||||
<ClInclude Include="..\hch\CObjectHandler.h" />
|
||||
<ClInclude Include="CMusicHandler.h" />
|
||||
<ClInclude Include="CPlayerInterface.h" />
|
||||
<ClInclude Include="CPreGame.h" />
|
||||
<ClInclude Include="CSoundBase.h" />
|
||||
<ClInclude Include="CSpellWindow.h" />
|
||||
<ClInclude Include="..\hch\CVideoHandler.h" />
|
||||
<ClInclude Include="CVideoHandler.h" />
|
||||
<ClInclude Include="FontBase.h" />
|
||||
<ClInclude Include="FunctionList.h" />
|
||||
@ -86,6 +81,7 @@
|
||||
<ClCompile Include="CQuestLog.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="mapHandler.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="VCMI_client.rc" />
|
||||
@ -94,6 +90,7 @@
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\ChangeLog" />
|
||||
<None Include="vcmi.ico" />
|
||||
</ItemGroup>
|
||||
</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;
|
||||
}
|
||||
|
||||
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))
|
||||
&& (tile%GameConstants::BFIELD_WIDTH != 0) )
|
||||
ret.push_back(BattleHex(tile));
|
||||
if(tile.isAvailable())
|
||||
ret.push_back(tile);
|
||||
}
|
||||
|
||||
bool BattleHex::isAvailable() const
|
||||
|
@ -108,7 +108,7 @@ struct DLL_LINKAGE BattleHex
|
||||
{
|
||||
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
|
||||
};
|
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 "ConstTransitivePtr.h"
|
||||
#include "GameConstants.h"
|
||||
#include "CBattleCallback.h"
|
||||
|
||||
/*
|
||||
* BattleState.h, part of VCMI engine
|
||||
@ -28,10 +29,11 @@ class CStackInstance;
|
||||
struct BattleStackAttacked;
|
||||
|
||||
|
||||
|
||||
//only for use in BattleInfo
|
||||
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)
|
||||
{
|
||||
@ -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
|
||||
si32 round, activeStack, selectedStack;
|
||||
@ -81,82 +75,62 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode
|
||||
h & static_cast<CBonusSystemNode&>(*this);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
BattleInfo();
|
||||
~BattleInfo(){};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//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);
|
||||
const CStack * getStackT(BattleHex tileID, bool onlyAlive = true) const;
|
||||
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
|
||||
CStack * getStack(int stackID, bool onlyAlive = true);
|
||||
|
||||
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
|
||||
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
|
||||
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::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)
|
||||
//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, 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)
|
||||
|
||||
bool isObstacleVisibleForSide(const CObstacleInstance &obstacle, ui8 side) const;
|
||||
//bool isObstacleVisibleForSide(const CObstacleInstance &obstacle, ui8 side) 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;
|
||||
|
||||
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)
|
||||
std::set<CStack*> getAttackedCreatures(const CSpell * s, int skillLevel, ui8 attackerOwner, BattleHex destinationTile); //calculates stack affected by given spell
|
||||
void getPotentiallyAttackableHexes(AttackableTiles &at, const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos); //hexes around target that could be attacked in melee
|
||||
std::set<CStack*> getAttackedCreatures(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID); //calculates range of multi-hex attacks
|
||||
std::set<BattleHex> getAttackedHexes(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID); //calculates range of multi-hex attacks
|
||||
std::set<CStack*> getAdjacentCreatures (const CStack * stack) const;
|
||||
using CBattleInfoCallback::getAttackedCreatures;
|
||||
std::set<const CStack*> getAttackedCreatures(const CSpell * s, int skillLevel, ui8 attackerOwner, BattleHex destinationTile); //calculates stack affected by given spell
|
||||
//void getPotentiallyAttackableHexes(AttackableTiles &at, const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos); //hexes around target that could be attacked in melee
|
||||
//std::set<CStack*> getAttackedCreatures(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID); //calculates range of multi-hex attacks
|
||||
//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);
|
||||
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
|
||||
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
|
||||
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)
|
||||
//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 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(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
|
||||
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
|
||||
|
||||
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 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 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 );
|
||||
bool isInTacticRange( BattleHex dest ) const;
|
||||
int getSurrenderingCost(int player) const;
|
||||
bool hasNativeStack(ui8 side) const;
|
||||
//bool hasNativeStack(ui8 side) const;
|
||||
|
||||
int theOtherPlayer(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
|
||||
{
|
||||
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 baseAmount;
|
||||
@ -226,7 +200,10 @@ public:
|
||||
|
||||
bool doubleWide() const;
|
||||
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(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
|
||||
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);
|
||||
}
|
||||
}
|
||||
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->valType = valType;
|
||||
added->limiter.reset(limiter);
|
||||
if(type == Bonus::MORALE || type == Bonus::LUCK)
|
||||
added->description = artifacts[aid]->Name() + (val > 0 ? " +" : " ") + boost::lexical_cast<std::string>(val);
|
||||
else
|
||||
added->description = artifacts[aid]->Name();
|
||||
artifacts[aid]->addNewBonus(added);
|
||||
added->limiter = limiter;
|
||||
return 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->valType = Bonus::BASE_NUMBER;
|
||||
added->propagator.reset(propagator);
|
||||
if(type == Bonus::MORALE || type == Bonus::LUCK)
|
||||
added->description = artifacts[aid]->Name() + (val > 0 ? " +" : " ") + boost::lexical_cast<std::string>(val);
|
||||
else
|
||||
added->description = artifacts[aid]->Name();
|
||||
artifacts[aid]->addNewBonus(added);
|
||||
added->propagator = propagator;
|
||||
return 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*/)
|
||||
{
|
||||
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_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)
|
||||
ART_PRIM_SKILL(7,0,+2); //Centaur Axe
|
||||
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(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(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(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_WALL_PENALTY, 0, 0, 0, new HasAnotherBonusLimiter(Bonus::SHOOTER));
|
||||
giveArtBonus(91,Bonus::NO_DISTANCE_PENALTY,0, 0, 0, shooterOnlyLimiter);//Golden Bow
|
||||
giveArtBonus(91,Bonus::NO_WALL_PENALTY, 0, 0, 0, shooterOnlyLimiter);
|
||||
giveArtBonus(92,Bonus::SPELL_IMMUNITY,0,35);//Sphere of Permanence
|
||||
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(99,Bonus::STACKS_SPEED,+2);//Cape of Velocity
|
||||
|
||||
giveArtBonus(100,Bonus::SPELL_IMMUNITY,0,59);//Pendant of Dispassion
|
||||
giveArtBonus(101,Bonus::SPELL_IMMUNITY,0,62);//Pendant of Second Sight
|
||||
giveArtBonus(102,Bonus::SPELL_IMMUNITY,0,42);//Pendant of Holiness
|
||||
giveArtBonus(103,Bonus::SPELL_IMMUNITY,0,24);//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(105,Bonus::SPELL_IMMUNITY,0,60);//Pendant of Free Will
|
||||
giveArtBonus(106,Bonus::SPELL_IMMUNITY,0,17);//Pendant of Negativity
|
||||
giveArtBonus(107,Bonus::SPELL_IMMUNITY,0,61);//Pendant of Total Recall
|
||||
giveArtBonus(100,Bonus::SPELL_IMMUNITY,0,Spells::BERSERK);//Pendant of Dispassion
|
||||
giveArtBonus(101,Bonus::SPELL_IMMUNITY,0,Spells::BLIND);//Pendant of Second Sight
|
||||
giveArtBonus(102,Bonus::SPELL_IMMUNITY,0,Spells::CURSE);//Pendant of Holiness
|
||||
giveArtBonus(103,Bonus::SPELL_IMMUNITY,0,Spells::DEATH_RIPPLE);//Pendant of Life
|
||||
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,Spells::HYPNOTIZE);//Pendant of Free Will
|
||||
giveArtBonus(106,Bonus::SPELL_IMMUNITY,0,Spells::LIGHTNING_BOLT);//Pendant of Negativity
|
||||
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::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(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
|
||||
giveArtBonus(120,Bonus::CREATURE_GROWTH,+3,3, new CPropagatorNodeType(CBonusSystemNode::TOWN_AND_VISITOR)); //Torso of Legion
|
||||
giveArtBonus(121,Bonus::CREATURE_GROWTH,+2,4, new CPropagatorNodeType(CBonusSystemNode::TOWN_AND_VISITOR)); //Arms of Legion
|
||||
giveArtBonus(122,Bonus::CREATURE_GROWTH,+1,5, new CPropagatorNodeType(CBonusSystemNode::TOWN_AND_VISITOR)); //Head of Legion
|
||||
|
||||
//Town will receive bonus if hero is visiting town or stays in its garrison.
|
||||
giveArtBonus(118,Bonus::CREATURE_GROWTH,+5,1, visitedTownPropagator); //Legs of Legion
|
||||
giveArtBonus(119,Bonus::CREATURE_GROWTH,+4,2, visitedTownPropagator); //Loins 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
|
||||
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,1, Bonus::INDEPENDENT_MAX);
|
||||
|
||||
giveArtBonus(124,Bonus::SPELLS_OF_LEVEL,3,1); //Spellbinder's Hat
|
||||
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(124, Bonus::SPELLS_OF_LEVEL,3,1); //Spellbinder's Hat
|
||||
giveArtBonus(125, Bonus::ENEMY_CANT_ESCAPE,0); //Shackles of War
|
||||
giveArtBonus(126, Bonus::BLOCK_ALL_MAGIC, 0, -1, battleWidePropagator);//Orb of Inhibition
|
||||
|
||||
//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::DEFENSE, 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, dragonNatureLimiter);
|
||||
|
||||
//Armageddon's Blade
|
||||
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
|
||||
|
||||
// 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
|
||||
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);
|
||||
|
||||
//Bow of the Sharpshooter
|
||||
giveArtBonus(137, Bonus::NO_DISTANCE_PENALTY, 0, 0, 0, new HasAnotherBonusLimiter(Bonus::SHOOTER));
|
||||
giveArtBonus(137, Bonus::NO_WALL_PENALTY, 0, 0, 0, new HasAnotherBonusLimiter(Bonus::SHOOTER));
|
||||
giveArtBonus(137, Bonus::FREE_SHOOTING, 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, shooterOnlyLimiter);
|
||||
giveArtBonus(137, Bonus::FREE_SHOOTING, 0, 0, 0, shooterOnlyLimiter);
|
||||
|
||||
//Wizard's Well
|
||||
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::POISON, 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
|
||||
giveArtBonus(143, Bonus::STACK_HEALTH, +100, -1, Bonus::PERCENT_TO_BASE);
|
||||
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
|
||||
{
|
||||
enum
|
||||
@ -181,8 +189,9 @@ public:
|
||||
|
||||
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, IPropagator* propagator, 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, shared_ptr<IPropagator> propagator, int additionalinfo = 0);
|
||||
void giveArtBonus(int aid, Bonus *bonus);
|
||||
public:
|
||||
std::vector<CArtifact*> treasures, minors, majors, relics;
|
||||
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;
|
||||
class CCallback;
|
||||
class CBattleCallback;
|
||||
class CPlayerBattleCallback;
|
||||
class ICallback;
|
||||
class CGlobalAI;
|
||||
struct Component;
|
||||
@ -61,7 +61,7 @@ public:
|
||||
std::string dllName;
|
||||
|
||||
virtual ~CBattleGameInterface() {};
|
||||
virtual void init(CBattleCallback * CB){};
|
||||
virtual void init(CPlayerBattleCallback * CB){};
|
||||
|
||||
//battle call-ins
|
||||
virtual BattleAction activeStack(const CStack * stack)=0; //called when it's turn of that stack
|
||||
@ -115,7 +115,7 @@ public:
|
||||
|
||||
std::string battleAIName;
|
||||
CBattleGameInterface *battleAI;
|
||||
CBattleCallback *cbc;
|
||||
CPlayerBattleCallback *cbc;
|
||||
|
||||
//battle interface
|
||||
virtual BattleAction activeStack(const CStack * stack);
|
||||
|
@ -256,6 +256,10 @@ bool CSpell::isRisingSpell() const
|
||||
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)
|
||||
{
|
||||
int3 diff = pos - center;
|
||||
|
@ -22,7 +22,7 @@ class DLL_LINKAGE CSpell
|
||||
public:
|
||||
enum ETargetType {NO_TARGET, CREATURE, CREATURE_EXPERT_MASSIVE, OBSTACLE};
|
||||
enum ESpellPositiveness {NEGATIVE = -1, NEUTRAL = 0, POSITIVE = 1};
|
||||
ui32 id;
|
||||
TSpell id;
|
||||
std::string name;
|
||||
std::string abbName; //abbreviated name
|
||||
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 isNegative() const;
|
||||
bool isRisingSpell() const;
|
||||
bool isDamageSpell() const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
|
@ -161,11 +161,11 @@ void CLodArchiveLoader::initSNDArchive(CFileInputStream & fileStream)
|
||||
SoundEntryBlock sndEntry = sndEntries[i];
|
||||
ArchiveEntry entry;
|
||||
|
||||
//for some reason entries in snd have format NAME\0WAV\0\0\0....
|
||||
//we need to replace first \0 with dot and trim line
|
||||
//for some reason entries in snd have format NAME\0WAVRUBBISH....
|
||||
//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.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.resize(entry.name.find_first_of('\0'));
|
||||
|
||||
entry.offset = SDL_SwapLE32(sndEntry.offset);
|
||||
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,
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
enum
|
||||
@ -224,6 +248,17 @@ namespace Obj
|
||||
};
|
||||
}
|
||||
|
||||
namespace SecSkillLevel
|
||||
{
|
||||
enum SecSkillLevel
|
||||
{
|
||||
NONE,
|
||||
BASIC,
|
||||
ADVANCED,
|
||||
EXPERT
|
||||
};
|
||||
}
|
||||
|
||||
//follows ERM BI (battle image) format
|
||||
namespace BattlefieldBI
|
||||
{
|
||||
|
@ -134,10 +134,26 @@ int BonusList::totalValue() const
|
||||
|
||||
if(hasIndepMin && hasIndepMax)
|
||||
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)
|
||||
vstd::amax(valFirst, indepMax);
|
||||
{
|
||||
if(notIndepBonuses)
|
||||
vstd::amax(valFirst, indepMax);
|
||||
else
|
||||
valFirst = indepMax;
|
||||
}
|
||||
if (hasIndepMin)
|
||||
vstd::amin(valFirst, indepMin);
|
||||
{
|
||||
if(notIndepBonuses)
|
||||
vstd::amin(valFirst, indepMin);
|
||||
else
|
||||
valFirst = indepMin;
|
||||
}
|
||||
|
||||
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_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(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(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) \
|
||||
@ -626,7 +628,8 @@ public:
|
||||
}
|
||||
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;
|
||||
|
||||
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 ()
|
||||
{
|
||||
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);
|
||||
//if there is a battle
|
||||
if(gs->curB)
|
||||
return gs->curB->getSpellCost(sp, caster);
|
||||
return gs->curB->battleGetSpellCost(sp, caster);
|
||||
|
||||
//if there is no battle
|
||||
return caster->getSpellCost(sp);
|
||||
@ -784,7 +373,7 @@ bool CGameInfoCallback::getTownInfo( const CGObjectInstance *town, InfoAboutTown
|
||||
//TODO vision support
|
||||
if(town->ID == GameConstants::TOWNI_TYPE)
|
||||
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);
|
||||
else
|
||||
return false;
|
||||
|
@ -3,10 +3,10 @@
|
||||
|
||||
#include "BattleHex.h"
|
||||
#include "../client/FunctionList.h"
|
||||
#include "CObstacleInstance.h"
|
||||
#include "ResourceSet.h"
|
||||
#include "int3.h"
|
||||
#include "GameConstants.h"
|
||||
#include "CBattleCallback.h"
|
||||
|
||||
/*
|
||||
* IGameCallback.h, part of VCMI engine
|
||||
@ -59,85 +59,6 @@ struct TeamState;
|
||||
struct QuestInfo;
|
||||
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
|
||||
{
|
||||
|
@ -1113,6 +1113,7 @@ void BattleStackMoved::applyGs( CGameState *gs )
|
||||
DLL_LINKAGE void BattleStackAttacked::applyGs( CGameState *gs )
|
||||
{
|
||||
CStack * at = gs->curB->getStack(stackAttacked);
|
||||
assert(at);
|
||||
at->count = newAmount;
|
||||
at->firstHPleft = newHP;
|
||||
|
||||
@ -1334,16 +1335,13 @@ DLL_LINKAGE void StacksHealedOrResurrected::applyGs( CGameState *gs )
|
||||
CStack * changedStack = gs->curB->getStack(healedStacks[g].stackID, false);
|
||||
|
||||
//checking if we resurrect a stack that is under a living stack
|
||||
std::vector<BattleHex> access = gs->curB->getAccessibility(changedStack, true);
|
||||
bool acc[GameConstants::BFIELD_SIZE];
|
||||
for(int h=0; h<GameConstants::BFIELD_SIZE; ++h)
|
||||
acc[h] = false;
|
||||
for(int h=0; h<access.size(); ++h)
|
||||
acc[access[h]] = true;
|
||||
if(!changedStack->alive() && !gs->curB->isAccessible(changedStack->position, acc,
|
||||
changedStack->doubleWide(), changedStack->attackerOwned,
|
||||
changedStack->hasBonusOfType(Bonus::FLYING), true))
|
||||
auto accessibility = gs->curB->getAccesibility();
|
||||
|
||||
if(!changedStack->alive() && !accessibility.accessible(changedStack->position, changedStack))
|
||||
{
|
||||
tlog1 << "Cannot resurrect " << changedStack->nodeName() << " because hex " << changedStack->position << " is occupied!\n";
|
||||
return; //position is already occupied
|
||||
}
|
||||
|
||||
//applying changes
|
||||
bool resurrected = !changedStack->alive(); //indicates if stack is resurrected or just healed
|
||||
|
@ -1,8 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <climits>
|
||||
|
||||
typedef si32 TResource;
|
||||
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="CCreatureSet.cpp" />
|
||||
<ClCompile Include="CDefObjInfoHandler.cpp" />
|
||||
<ClCompile Include="CFileUtility.cpp" />
|
||||
<ClCompile Include="CGameInterface.cpp" />
|
||||
<ClCompile Include="CGameState.cpp" />
|
||||
<ClCompile Include="CGeneralTextHandler.cpp" />
|
||||
<ClCompile Include="CHeroHandler.cpp" />
|
||||
<ClCompile Include="CLodHandler.cpp" />
|
||||
<ClCompile Include="CLogger.cpp" />
|
||||
<ClCompile Include="CMapInfo.cpp" />
|
||||
<ClCompile Include="CModHandler.cpp" />
|
||||
<ClCompile Include="CObjectHandler.cpp" />
|
||||
<ClCompile Include="CObstacleInstance.cpp" />
|
||||
<ClCompile Include="Connection.cpp" />
|
||||
@ -245,15 +244,15 @@
|
||||
<ClCompile Include="CThreadHelper.cpp" />
|
||||
<ClCompile Include="CTownHandler.cpp" />
|
||||
<ClCompile Include="Filesystem\CBinaryReader.cpp" />
|
||||
<ClCompile Include="Filesystem\CCompressedStream.cpp" />
|
||||
<ClCompile Include="Filesystem\CFileInfo.cpp" />
|
||||
<ClCompile Include="Filesystem\CFileInputStream.cpp" />
|
||||
<ClCompile Include="Filesystem\CFilesystemLoader.cpp" />
|
||||
<ClCompile Include="Filesystem\CLodArchiveLoader.cpp" />
|
||||
<ClCompile Include="Filesystem\CLodStream.cpp" />
|
||||
<ClCompile Include="Filesystem\CMemoryStream.cpp" />
|
||||
<ClCompile Include="Filesystem\CResourceLoader.cpp" />
|
||||
<ClCompile Include="Filesystem\ISimpleResourceLoader.cpp" />
|
||||
<ClCompile Include="HeroBonus.cpp" />
|
||||
<ClCompile Include="CBattleCallback.cpp" />
|
||||
<ClCompile Include="IGameCallback.cpp" />
|
||||
<ClCompile Include="JsonNode.cpp" />
|
||||
<ClCompile Include="map.cpp" />
|
||||
@ -283,14 +282,13 @@
|
||||
<ClInclude Include="CCreatureHandler.h" />
|
||||
<ClInclude Include="CCreatureSet.h" />
|
||||
<ClInclude Include="CDefObjInfoHandler.h" />
|
||||
<ClInclude Include="CFileUtility.h" />
|
||||
<ClInclude Include="CGameInterface.h" />
|
||||
<ClInclude Include="CGameState.h" />
|
||||
<ClInclude Include="CGeneralTextHandler.h" />
|
||||
<ClInclude Include="CHeroHandler.h" />
|
||||
<ClInclude Include="CLodHandler.h" />
|
||||
<ClInclude Include="CLogger.h" />
|
||||
<ClInclude Include="CMapInfo.h" />
|
||||
<ClInclude Include="CModHandler.h" />
|
||||
<ClInclude Include="CObjectHandler.h" />
|
||||
<ClInclude Include="CObstacleInstance.h" />
|
||||
<ClInclude Include="CondSh.h" />
|
||||
@ -302,17 +300,18 @@
|
||||
<ClInclude Include="CThreadHelper.h" />
|
||||
<ClInclude Include="CTownHandler.h" />
|
||||
<ClInclude Include="Filesystem\CBinaryReader.h" />
|
||||
<ClInclude Include="Filesystem\CCompressedStream.h" />
|
||||
<ClInclude Include="Filesystem\CFileInfo.h" />
|
||||
<ClInclude Include="Filesystem\CFileInputStream.h" />
|
||||
<ClInclude Include="Filesystem\CFilesystemLoader.h" />
|
||||
<ClInclude Include="Filesystem\CInputStream.h" />
|
||||
<ClInclude Include="Filesystem\CLodArchiveLoader.h" />
|
||||
<ClInclude Include="Filesystem\CLodStream.h" />
|
||||
<ClInclude Include="Filesystem\CMemoryStream.h" />
|
||||
<ClInclude Include="Filesystem\CResourceLoader.h" />
|
||||
<ClInclude Include="Filesystem\ISimpleResourceLoader.h" />
|
||||
<ClInclude Include="GameConstants.h" />
|
||||
<ClInclude Include="HeroBonus.h" />
|
||||
<ClInclude Include="CBattleCallback.h" />
|
||||
<ClInclude Include="IGameCallback.h" />
|
||||
<ClInclude Include="IGameEventsReceiver.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;
|
||||
std::vector<ui32> arts; //display them in window
|
||||
|
||||
//TODO: display loot in window
|
||||
if (result < BattleResult::SURRENDER && winnerHero)
|
||||
if (result == BattleResult::NORMAL && winnerHero)
|
||||
{
|
||||
if (loserHero)
|
||||
{
|
||||
@ -542,7 +541,7 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
|
||||
MoveArtifact ma;
|
||||
ma.src = ArtifactLocation (loserHero, artSlot.first);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
sendAndApply(&resultsApplied);
|
||||
setBattle(nullptr);
|
||||
|
||||
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
|
||||
{
|
||||
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
|
||||
|
||||
BOOST_FOREACH(CStack * stack, attackedCreatures)
|
||||
BOOST_FOREACH(const CStack * stack, attackedCreatures)
|
||||
{
|
||||
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().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
|
||||
|
||||
BOOST_FOREACH(CStack * stack, attackedCreatures)
|
||||
BOOST_FOREACH(const CStack * stack, attackedCreatures)
|
||||
{
|
||||
if (stack != def) //do not hit same stack twice
|
||||
{
|
||||
@ -924,8 +924,8 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
CStack *curStack = gs->curB->getStack(stack),
|
||||
*stackAtEnd = gs->curB->getStackT(dest);
|
||||
const CStack *curStack = gs->curB->battleGetStackByID(stack),
|
||||
*stackAtEnd = gs->curB->battleGetStackByPos(dest);
|
||||
|
||||
assert(curStack);
|
||||
assert(dest < GameConstants::BFIELD_SIZE);
|
||||
@ -936,50 +936,30 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
||||
}
|
||||
|
||||
//initing necessary tables
|
||||
bool accessibility[GameConstants::BFIELD_SIZE];
|
||||
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;
|
||||
}
|
||||
auto accessibility = getAccesibility();
|
||||
|
||||
//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(accessibility[dest+1])
|
||||
if(accessibility.accessible(dest+1, curStack))
|
||||
dest += BattleHex::RIGHT;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(accessibility[dest-1])
|
||||
if(accessibility.accessible(dest-1, curStack))
|
||||
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;
|
||||
|
||||
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
|
||||
// return false;
|
||||
|
||||
std::pair< std::vector<BattleHex>, int > path = gs->curB->getPath(curStack->position, dest, accessibilityWithOccupyable, curStack->hasBonusOfType(Bonus::FLYING), curStack->doubleWide(), curStack->attackerOwned);
|
||||
|
||||
std::pair< std::vector<BattleHex>, int > path = gs->curB->getPath(curStack->position, dest, curStack);
|
||||
|
||||
ret = path.second;
|
||||
|
||||
@ -3220,6 +3200,40 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
tlog1 << "\tMaking action of type " << ba.actionType << std::endl;
|
||||
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)
|
||||
{
|
||||
case BattleAction::END_TACTIC_PHASE: //wait
|
||||
@ -3267,7 +3281,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
case BattleAction::SURRENDER:
|
||||
{
|
||||
int player = gs->curB->sides[ba.side];
|
||||
int cost = gs->curB->getSurrenderingCost(player);
|
||||
int cost = gs->curB->battleGetSurrenderCost(player);
|
||||
if(cost < 0)
|
||||
complain("Cannot surrender!");
|
||||
else if(getResource(player, Res::GOLD) < cost)
|
||||
@ -3284,10 +3298,10 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
{
|
||||
StartAction start_action(ba);
|
||||
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);
|
||||
CStack *curStack = gs->curB->getStack(ba.stackNumber),
|
||||
*stackAtEnd = gs->curB->getStackT(ba.additionalInfo);
|
||||
const CStack *curStack = gs->curB->battleGetStackByID(ba.stackNumber),
|
||||
*stackAtEnd = gs->curB->battleGetStackByPos(ba.additionalInfo);
|
||||
|
||||
if(!curStack || !stackAtEnd)
|
||||
{
|
||||
@ -3295,6 +3309,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
break;
|
||||
}
|
||||
|
||||
tlog5 << curStack->nodeName() << " will attack " << stackAtEnd->nodeName() << std::endl;
|
||||
|
||||
if(curStack->position != ba.destinationTile //we wasn't able to reach destination tile
|
||||
&& !(curStack->doubleWide()
|
||||
&& ( curStack->position == ba.destinationTile + (curStack->attackerOwned ? +1 : -1 ) )
|
||||
@ -3341,7 +3357,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
|
||||
//counterattack
|
||||
if(!curStack->hasBonusOfType(Bonus::BLOCKS_RETALIATION)
|
||||
&& stackAtEnd->ableToRetaliate())
|
||||
&& stackAtEnd->ableToRetaliate()
|
||||
&& curStack->alive()) //attacker may have died (fire shield)
|
||||
{
|
||||
BattleAttack bat;
|
||||
prepareAttack(bat, stackAtEnd, curStack, 0, curStack->position);
|
||||
@ -3374,8 +3391,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
}
|
||||
case BattleAction::SHOOT: //shoot
|
||||
{
|
||||
CStack *curStack = gs->curB->getStack(ba.stackNumber),
|
||||
*destStack= gs->curB->getStackT(ba.destinationTile);
|
||||
const CStack *curStack = gs->curB->battleGetStackByID(ba.stackNumber),
|
||||
*destStack= gs->curB->battleGetStackByPos(ba.destinationTile);
|
||||
if( !gs->curB->battleCanShoot(curStack, ba.destinationTile) )
|
||||
break;
|
||||
|
||||
@ -3423,7 +3440,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
const CGHeroInstance * attackingHero = gs->curB->heroes[ba.side];
|
||||
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)
|
||||
{
|
||||
complain("catapult tried to attack non-catapultable hex!");
|
||||
@ -3524,8 +3541,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
StartAction start_action(ba);
|
||||
sendAndApply(&start_action);
|
||||
const CGHeroInstance * attackingHero = gs->curB->heroes[ba.side];
|
||||
CStack *healer = gs->curB->getStack(ba.stackNumber),
|
||||
*destStack = gs->curB->getStackT(ba.destinationTile);
|
||||
const CStack *healer = gs->curB->battleGetStackByID(ba.stackNumber),
|
||||
*destStack = gs->curB->battleGetStackByPos(ba.destinationTile);
|
||||
|
||||
if(healer == NULL || destStack == NULL || !healer->hasBonusOfType(Bonus::HEALER))
|
||||
{
|
||||
@ -3567,8 +3584,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
StartAction start_action(ba);
|
||||
sendAndApply(&start_action);
|
||||
|
||||
CStack *summoner = gs->curB->getStack(ba.stackNumber),
|
||||
*destStack = gs->curB->getStackT(ba.destinationTile, false);
|
||||
const CStack *summoner = gs->curB->battleGetStackByID(ba.stackNumber),
|
||||
*destStack = gs->curB->battleGetStackByPos(ba.destinationTile, false);
|
||||
|
||||
BattleStackAdded bsa;
|
||||
bsa.attacker = summoner->attackerOwned;
|
||||
@ -3603,7 +3620,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
StartAction start_action(ba);
|
||||
sendAndApply(&start_action);
|
||||
|
||||
CStack * stack = gs->curB->getStack(ba.stackNumber);
|
||||
const CStack * stack = gs->curB->battleGetStackByID(ba.stackNumber);
|
||||
int spellID = ba.additionalInfo;
|
||||
BattleHex destination(ba.destinationTile);
|
||||
|
||||
@ -3852,7 +3869,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
||||
|
||||
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
|
||||
{
|
||||
@ -3869,18 +3886,18 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
||||
}
|
||||
|
||||
//calculating affected creatures for all spells
|
||||
std::set<CStack*> attackedCres;
|
||||
std::set<const CStack*> attackedCres;
|
||||
if (mode != ECastingMode::ENCHANTER_CASTING)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
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((!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);
|
||||
|
||||
//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
|
||||
continue;
|
||||
@ -3976,7 +3993,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
||||
}
|
||||
}
|
||||
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
|
||||
continue;
|
||||
@ -4067,7 +4084,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
||||
bonus = caster->getBonus(Selector::typeSubtype(Bonus::SPECIAL_PECULIAR_ENCHANT, spellID));
|
||||
|
||||
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
|
||||
continue;
|
||||
@ -4154,7 +4171,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
||||
StacksHealedOrResurrected shr;
|
||||
shr.lifeDrain = (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
|
||||
|| (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);
|
||||
}
|
||||
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;
|
||||
shr.healedStacks.push_back(hi);
|
||||
}
|
||||
@ -4227,7 +4244,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
||||
break;
|
||||
case Spells::CLONE:
|
||||
{
|
||||
CStack * clonedStack = NULL;
|
||||
const CStack * clonedStack = NULL;
|
||||
if (attackedCres.size())
|
||||
clonedStack = *attackedCres.begin();
|
||||
if (!clonedStack)
|
||||
@ -4270,7 +4287,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
||||
break;
|
||||
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
|
||||
{
|
||||
@ -4291,7 +4308,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
||||
break;
|
||||
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;
|
||||
bsa.flags |= BattleStackAttacked::EFFECT;
|
||||
@ -4323,7 +4340,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
||||
//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
|
||||
{
|
||||
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);
|
||||
if(mirrorChance > rand()%100)
|
||||
@ -4388,7 +4405,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
|
||||
ECastingMode::HERO_CASTING, NULL, ba.selectedStack);
|
||||
|
||||
sendAndApply(&end_action);
|
||||
if( !gs->curB->getStack(gs->curB->activeStack, false)->alive() )
|
||||
if( !gs->curB->battleGetStackByID(gs->curB->activeStack, false)->alive() )
|
||||
{
|
||||
battleMadeAction.setn(true);
|
||||
}
|
||||
@ -4426,11 +4443,11 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
|
||||
{
|
||||
bool unbind = true;
|
||||
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)
|
||||
{
|
||||
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 (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
|
||||
int damage = -1;
|
||||
@ -4552,7 +4569,7 @@ void CGameHandler::handleDamageFromObstacle(const CObstacleInstance &obstacle, C
|
||||
else if(obstacle.obstacleType == CObstacleInstance::LAND_MINE)
|
||||
{
|
||||
//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;
|
||||
|
||||
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
|
||||
{
|
||||
oneOfAttacked = gs->curB->getStack(bat.bsa[g].stackAttacked);
|
||||
oneOfAttacked = gs->curB->battleGetStackByID(bat.bsa[g].stackAttacked);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -5206,13 +5223,13 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta
|
||||
|
||||
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?
|
||||
}
|
||||
|
||||
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
|
||||
return;
|
||||
attackCasting(bat, Bonus::SPELL_AFTER_ATTACK, attacker);
|
||||
@ -5241,7 +5258,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
|
||||
if (staredCreatures)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -5255,7 +5272,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
|
||||
}
|
||||
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,
|
||||
acidDamage * attacker->count, ECastingMode::AFTER_ATTACK_CASTING, attacker);
|
||||
}
|
||||
@ -5716,6 +5733,7 @@ bool CGameHandler::swapStacks(const StackLocation &sl1, const StackLocation &sl2
|
||||
|
||||
void CGameHandler::runBattle()
|
||||
{
|
||||
setBattle(gs->curB);
|
||||
assert(gs->curB);
|
||||
//TODO: pre-tactic stuff, call scripts etc.
|
||||
|
||||
|
@ -201,7 +201,7 @@ public:
|
||||
int usedSpellPower, ECastingMode::ECastingMode mode, const CStack * stack, si32 selectedStack = -1);
|
||||
bool makeCustomAction(BattleAction &ba);
|
||||
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);
|
||||
bool queryReply( ui32 qid, ui32 answer, 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)
|
||||
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;
|
||||
|
||||
return gh->makeBattleAction(ba);
|
||||
@ -262,9 +262,10 @@ bool MakeCustomAction::applyGh( CGameHandler *gh )
|
||||
const BattleInfo *b = GS(gh)->curB;
|
||||
if(!b) 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(gh->connections[active->owner] != c) ERROR_AND_RETURN;
|
||||
if(ba.actionType != BattleAction::HERO_SPELL) ERROR_AND_RETURN;
|
||||
return gh->makeCustomAction(ba);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user