mirror of
https://github.com/vcmi/vcmi.git
synced 2025-07-15 01:24:45 +02:00
- Partially fixed mantis #1065 (Gate with hex 95 can't be attacked)
- Fixed 'catapult tried to attack non-catapultable hex!' problem, now catapult attacks attackable wall parts only - Fixed problem that the server performed applying damage on a wall part twice - Added methods for checking what wall parts are attackable and if a wall part is potentially attackable - Added functionality to trace net packages - Added functionality to trace std::vectors - Added tracing for CatapultAttack(CPack) - Updated various toString methods to use {} instead of [] - Refactoring
This commit is contained in:
19
Global.h
19
Global.h
@ -226,14 +226,23 @@ template<typename T, size_t N> char (&_ArrayCountObj(const T (&)[N]))[N];
|
|||||||
/* VCMI standard library */
|
/* VCMI standard library */
|
||||||
/* ---------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------- */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
std::ostream &operator<<(std::ostream &out, const boost::optional<T> &opt)
|
std::ostream & operator<<(std::ostream & out, const boost::optional<T> & opt)
|
||||||
{
|
{
|
||||||
if(opt)
|
if(opt) return out << *opt;
|
||||||
return out << *opt;
|
else return out << "empty";
|
||||||
else
|
|
||||||
return out<< "empty";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::ostream & operator<<(std::ostream & out, const std::vector<T> & container)
|
||||||
|
{
|
||||||
|
out << "[";
|
||||||
|
for(auto it = container.begin(); it != container.end(); ++it)
|
||||||
|
{
|
||||||
|
out << *it;
|
||||||
|
if(std::prev(container.end()) != it) out << ", ";
|
||||||
|
}
|
||||||
|
return out << "]";
|
||||||
|
}
|
||||||
|
|
||||||
namespace vstd
|
namespace vstd
|
||||||
{
|
{
|
||||||
|
@ -1156,14 +1156,12 @@ bool CBattleInterface::isTileAttackable(const BattleHex & number) const
|
|||||||
|
|
||||||
bool CBattleInterface::isCatapultAttackable(BattleHex hex) const
|
bool CBattleInterface::isCatapultAttackable(BattleHex hex) const
|
||||||
{
|
{
|
||||||
if(!siegeH || tacticsMode)
|
if(!siegeH || tacticsMode) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
int wallUnder = curInt->cb->battleHexToWallPart(hex);
|
auto wallPart = curInt->cb->battleHexToWallPart(hex);
|
||||||
if(wallUnder < 0) //invalid or indestructible
|
if(!curInt->cb->isWallPartPotentiallyAttackable(wallPart)) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
auto state = curInt->cb->battleGetWallState(wallUnder);
|
auto state = curInt->cb->battleGetWallState(static_cast<int>(wallPart));
|
||||||
return state != EWallState::DESTROYED && state != EWallState::NONE;
|
return state != EWallState::DESTROYED && state != EWallState::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,6 +98,6 @@ std::ostream & operator<<(std::ostream & os, const BattleAction & ba)
|
|||||||
std::stringstream actionTypeStream;
|
std::stringstream actionTypeStream;
|
||||||
actionTypeStream << ba.actionType;
|
actionTypeStream << ba.actionType;
|
||||||
|
|
||||||
return os << boost::str(boost::format("[BattleAction: side '%d', stackNumber '%d', actionType '%s', destinationTile '%s', additionalInfo '%d', selectedStack '%d']")
|
return os << boost::str(boost::format("{BattleAction: side '%d', stackNumber '%d', actionType '%s', destinationTile '%s', additionalInfo '%d', selectedStack '%d'}")
|
||||||
% static_cast<int>(ba.side) % ba.stackNumber % actionTypeStream.str() % ba.destinationTile % ba.additionalInfo % ba.selectedStack);
|
% static_cast<int>(ba.side) % ba.stackNumber % actionTypeStream.str() % ba.destinationTile % ba.additionalInfo % ba.selectedStack);
|
||||||
}
|
}
|
||||||
|
@ -161,5 +161,5 @@ BattleHex BattleHex::getClosestTile(bool attackerOwned, BattleHex initialPos, st
|
|||||||
|
|
||||||
std::ostream & operator<<(std::ostream & os, const BattleHex & hex)
|
std::ostream & operator<<(std::ostream & os, const BattleHex & hex)
|
||||||
{
|
{
|
||||||
return os << boost::str(boost::format("[BattleHex: x '%d', y '%d', hex '%d']") % hex.getX() % hex.getY() % hex.hex);
|
return os << boost::str(boost::format("{BattleHex: x '%d', y '%d', hex '%d'}") % hex.getX() % hex.getY() % hex.hex);
|
||||||
}
|
}
|
||||||
|
@ -386,13 +386,13 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, ETerrainType terrain, BFieldTyp
|
|||||||
|
|
||||||
if (!town->hasBuilt(BuildingID::CITADEL))
|
if (!town->hasBuilt(BuildingID::CITADEL))
|
||||||
{
|
{
|
||||||
curB->si.wallState[EWallParts::KEEP] = EWallState::NONE;
|
curB->si.wallState[EWallPart::KEEP] = EWallState::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!town->hasBuilt(BuildingID::CASTLE))
|
if (!town->hasBuilt(BuildingID::CASTLE))
|
||||||
{
|
{
|
||||||
curB->si.wallState[EWallParts::UPPER_TOWER] = EWallState::NONE;
|
curB->si.wallState[EWallPart::UPPER_TOWER] = EWallState::NONE;
|
||||||
curB->si.wallState[EWallParts::BOTTOM_TOWER] = EWallState::NONE;
|
curB->si.wallState[EWallPart::BOTTOM_TOWER] = EWallState::NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ struct BattleStackAttacked;
|
|||||||
//only for use in BattleInfo
|
//only for use in BattleInfo
|
||||||
struct DLL_LINKAGE SiegeInfo
|
struct DLL_LINKAGE SiegeInfo
|
||||||
{
|
{
|
||||||
std::array<si8, EWallParts::PARTS_COUNT> wallState;
|
std::array<si8, EWallPart::PARTS_COUNT> wallState;
|
||||||
|
|
||||||
// return EWallState decreased by value of damage points
|
// return EWallState decreased by value of damage points
|
||||||
static EWallState::EWallState applyDamage(EWallState::EWallState state, unsigned int value)
|
static EWallState::EWallState applyDamage(EWallState::EWallState state, unsigned int value)
|
||||||
|
@ -54,38 +54,38 @@ namespace SiegeStuffThatShouldBeMovedToHandlers // <=== TODO
|
|||||||
return stackLeft != destLeft;
|
return stackLeft != destLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
//potentially attackable parts of wall
|
// parts of wall
|
||||||
static const std::pair<int, EWallParts::EWallParts> attackable[] =
|
static const std::pair<int, EWallPart::EWallPart> wallParts[] =
|
||||||
{
|
{
|
||||||
std::make_pair(50, EWallParts::KEEP),
|
std::make_pair(50, EWallPart::KEEP),
|
||||||
std::make_pair(183, EWallParts::BOTTOM_TOWER),
|
std::make_pair(183, EWallPart::BOTTOM_TOWER),
|
||||||
std::make_pair(182, EWallParts::BOTTOM_WALL),
|
std::make_pair(182, EWallPart::BOTTOM_WALL),
|
||||||
std::make_pair(130, EWallParts::BELOW_GATE),
|
std::make_pair(130, EWallPart::BELOW_GATE),
|
||||||
std::make_pair(62, EWallParts::OVER_GATE),
|
std::make_pair(62, EWallPart::OVER_GATE),
|
||||||
std::make_pair(29, EWallParts::UPPER_WALL),
|
std::make_pair(29, EWallPart::UPPER_WALL),
|
||||||
std::make_pair(12, EWallParts::UPPER_TOWER),
|
std::make_pair(12, EWallPart::UPPER_TOWER),
|
||||||
std::make_pair(95, EWallParts::GATE),
|
std::make_pair(95, EWallPart::INDESTRUCTIBLE_PART_OF_GATE),
|
||||||
std::make_pair(96, EWallParts::GATE),
|
std::make_pair(96, EWallPart::GATE),
|
||||||
std::make_pair(45, EWallParts::INDESTRUCTIBLE_PART),
|
std::make_pair(45, EWallPart::INDESTRUCTIBLE_PART),
|
||||||
std::make_pair(78, EWallParts::INDESTRUCTIBLE_PART),
|
std::make_pair(78, EWallPart::INDESTRUCTIBLE_PART),
|
||||||
std::make_pair(112, EWallParts::INDESTRUCTIBLE_PART),
|
std::make_pair(112, EWallPart::INDESTRUCTIBLE_PART),
|
||||||
std::make_pair(147, EWallParts::INDESTRUCTIBLE_PART)
|
std::make_pair(147, EWallPart::INDESTRUCTIBLE_PART)
|
||||||
};
|
};
|
||||||
|
|
||||||
static EWallParts::EWallParts hexToWallPart(BattleHex hex)
|
static EWallPart::EWallPart hexToWallPart(BattleHex hex)
|
||||||
{
|
{
|
||||||
for(auto & elem : attackable)
|
for(auto & elem : wallParts)
|
||||||
{
|
{
|
||||||
if(elem.first == hex)
|
if(elem.first == hex)
|
||||||
return elem.second;
|
return elem.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EWallParts::INVALID; //not found!
|
return EWallPart::INVALID; //not found!
|
||||||
}
|
}
|
||||||
|
|
||||||
static BattleHex WallPartToHex(EWallParts::EWallParts part)
|
static BattleHex WallPartToHex(EWallPart::EWallPart part)
|
||||||
{
|
{
|
||||||
for(auto & elem : attackable)
|
for(auto & elem : wallParts)
|
||||||
{
|
{
|
||||||
if(elem.second == part)
|
if(elem.second == part)
|
||||||
return elem.first;
|
return elem.first;
|
||||||
@ -425,7 +425,7 @@ si8 CBattleInfoEssentials::battleGetWallState(int partOfWall) const
|
|||||||
if(getBattle()->siege == CGTownInstance::NONE)
|
if(getBattle()->siege == CGTownInstance::NONE)
|
||||||
return EWallState::NONE;
|
return EWallState::NONE;
|
||||||
|
|
||||||
assert(partOfWall >= 0 && partOfWall < EWallParts::PARTS_COUNT);
|
assert(partOfWall >= 0 && partOfWall < EWallPart::PARTS_COUNT);
|
||||||
return getBattle()->si.wallState[partOfWall];
|
return getBattle()->si.wallState[partOfWall];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,8 +452,7 @@ si8 CBattleInfoCallback::battleHasWallPenalty(const IBonusBearer *bonusBearer, B
|
|||||||
if (shooterPosition > destHex && ((destHex % GameConstants::BFIELD_WIDTH - shooterPosition % GameConstants::BFIELD_WIDTH) < 2)) //shooting up high
|
if (shooterPosition > destHex && ((destHex % GameConstants::BFIELD_WIDTH - shooterPosition % GameConstants::BFIELD_WIDTH) < 2)) //shooting up high
|
||||||
row -= 2;
|
row -= 2;
|
||||||
const int wallPos = lineToWallHex(row);
|
const int wallPos = lineToWallHex(row);
|
||||||
if (battleHexToWallPart(wallPos) < 0) //wall still exists or is indestructible
|
if (!isWallPartPotentiallyAttackable(battleHexToWallPart(wallPos))) return true;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -1094,7 +1093,7 @@ AccessibilityInfo CBattleInfoCallback::getAccesibility() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
//gate -> should be before stacks
|
//gate -> should be before stacks
|
||||||
if(battleGetSiegeLevel() > 0 && battleGetWallState(EWallParts::GATE) != EWallState::DESTROYED)
|
if(battleGetSiegeLevel() > 0 && battleGetWallState(EWallPart::GATE) != EWallState::DESTROYED)
|
||||||
{
|
{
|
||||||
ret[95] = ret[96] = EAccessibility::GATE; //block gate's hexes
|
ret[95] = ret[96] = EAccessibility::GATE; //block gate's hexes
|
||||||
}
|
}
|
||||||
@ -1514,18 +1513,45 @@ si8 CBattleInfoCallback::battleHasDistancePenalty(const IBonusBearer *bonusBeare
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BattleHex CBattleInfoCallback::wallPartToBattleHex(EWallParts::EWallParts part) const
|
BattleHex CBattleInfoCallback::wallPartToBattleHex(EWallPart::EWallPart part) const
|
||||||
{
|
{
|
||||||
RETURN_IF_NOT_BATTLE(BattleHex::INVALID);
|
RETURN_IF_NOT_BATTLE(BattleHex::INVALID);
|
||||||
return WallPartToHex(part);
|
return WallPartToHex(part);
|
||||||
}
|
}
|
||||||
|
|
||||||
EWallParts::EWallParts CBattleInfoCallback::battleHexToWallPart(BattleHex hex) const
|
EWallPart::EWallPart CBattleInfoCallback::battleHexToWallPart(BattleHex hex) const
|
||||||
{
|
{
|
||||||
RETURN_IF_NOT_BATTLE(EWallParts::INVALID);
|
RETURN_IF_NOT_BATTLE(EWallPart::INVALID);
|
||||||
return hexToWallPart(hex);
|
return hexToWallPart(hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CBattleInfoCallback::isWallPartPotentiallyAttackable(EWallPart::EWallPart wallPart) const
|
||||||
|
{
|
||||||
|
RETURN_IF_NOT_BATTLE(false);
|
||||||
|
return wallPart != EWallPart::INDESTRUCTIBLE_PART && wallPart != EWallPart::INDESTRUCTIBLE_PART_OF_GATE &&
|
||||||
|
wallPart != EWallPart::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<BattleHex> CBattleInfoCallback::getAttackableBattleHexes() const
|
||||||
|
{
|
||||||
|
std::vector<BattleHex> attackableBattleHexes;
|
||||||
|
RETURN_IF_NOT_BATTLE(attackableBattleHexes);
|
||||||
|
|
||||||
|
for(auto & wallPartPair : wallParts)
|
||||||
|
{
|
||||||
|
if(isWallPartPotentiallyAttackable(wallPartPair.second))
|
||||||
|
{
|
||||||
|
auto wallState = static_cast<EWallState::EWallState>(battleGetWallState(static_cast<int>(wallPartPair.second)));
|
||||||
|
if(wallState == EWallState::INTACT || wallState == EWallState::DAMAGED)
|
||||||
|
{
|
||||||
|
attackableBattleHexes.push_back(BattleHex(wallPartPair.first));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return attackableBattleHexes;
|
||||||
|
}
|
||||||
|
|
||||||
ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleIsImmune(const CGHeroInstance * caster, const CSpell * spell, ECastingMode::ECastingMode mode, BattleHex dest) const
|
ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleIsImmune(const CGHeroInstance * caster, const CSpell * spell, ECastingMode::ECastingMode mode, BattleHex dest) const
|
||||||
{
|
{
|
||||||
RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID);
|
RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID);
|
||||||
|
@ -170,7 +170,6 @@ public:
|
|||||||
std::vector<shared_ptr<const CObstacleInstance> > battleGetAllObstacles(boost::optional<BattlePerspective::BattlePerspective> perspective = boost::none) const; //returns all obstacles on the battlefield
|
std::vector<shared_ptr<const CObstacleInstance> > battleGetAllObstacles(boost::optional<BattlePerspective::BattlePerspective> perspective = boost::none) const; //returns all obstacles on the battlefield
|
||||||
TStacks battleGetAllStacks(bool includeTurrets = false) const; //returns all stacks, alive or dead or undead or mechanical :)
|
TStacks battleGetAllStacks(bool includeTurrets = false) const; //returns all stacks, alive or dead or undead or mechanical :)
|
||||||
bool battleHasNativeStack(ui8 side) const;
|
bool battleHasNativeStack(ui8 side) const;
|
||||||
si8 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
|
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, nullptr instead
|
const CGTownInstance * battleGetDefendedTown() const; //returns defended town if current battle is a siege, nullptr instead
|
||||||
const CStack *battleActiveStack() const;
|
const CStack *battleActiveStack() const;
|
||||||
@ -186,6 +185,10 @@ public:
|
|||||||
const CArmedInstance * battleGetArmyObject(ui8 side) const;
|
const CArmedInstance * battleGetArmyObject(ui8 side) const;
|
||||||
InfoAboutHero battleGetHeroInfo(ui8 side) const;
|
InfoAboutHero battleGetHeroInfo(ui8 side) 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
|
||||||
|
si8 battleGetWallState(int partOfWall) const;
|
||||||
|
|
||||||
//helpers
|
//helpers
|
||||||
TStacks battleAliveStacks() const;
|
TStacks battleAliveStacks() const;
|
||||||
TStacks battleAliveStacks(ui8 side) const;
|
TStacks battleAliveStacks(ui8 side) const;
|
||||||
@ -251,8 +254,10 @@ public:
|
|||||||
si8 battleHasWallPenalty(const CStack * stack, BattleHex destHex) const; //checks if given stack has wall penalty
|
si8 battleHasWallPenalty(const CStack * stack, BattleHex destHex) const; //checks if given stack has wall penalty
|
||||||
si8 battleHasWallPenalty(const IBonusBearer *bonusBearer, BattleHex shooterPosition, BattleHex destHex) const; //checks if given stack has wall penalty
|
si8 battleHasWallPenalty(const IBonusBearer *bonusBearer, BattleHex shooterPosition, BattleHex destHex) const; //checks if given stack has wall penalty
|
||||||
|
|
||||||
BattleHex wallPartToBattleHex(EWallParts::EWallParts part) const;
|
BattleHex wallPartToBattleHex(EWallPart::EWallPart part) const;
|
||||||
EWallParts::EWallParts battleHexToWallPart(BattleHex hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
EWallPart::EWallPart battleHexToWallPart(BattleHex hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
||||||
|
bool isWallPartPotentiallyAttackable(EWallPart::EWallPart wallPart) const; // returns true if the wall part is potentially attackable (independent of wall state), false if not
|
||||||
|
std::vector<BattleHex> getAttackableBattleHexes() const;
|
||||||
|
|
||||||
//*** MAGIC
|
//*** 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
|
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
|
||||||
|
@ -224,7 +224,7 @@ CPack * CConnection::retreivePack()
|
|||||||
boost::unique_lock<boost::mutex> lock(*rmx);
|
boost::unique_lock<boost::mutex> lock(*rmx);
|
||||||
logNetwork->traceStream() << "Listening... ";
|
logNetwork->traceStream() << "Listening... ";
|
||||||
*this >> ret;
|
*this >> ret;
|
||||||
logNetwork->traceStream() << "\treceived server message of type " << typeid(*ret).name();
|
logNetwork->traceStream() << "\treceived server message of type " << typeid(*ret).name() << ", data: " << ret;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,13 +439,13 @@ namespace ECommander
|
|||||||
const int MAX_SKILL_LEVEL = 5;
|
const int MAX_SKILL_LEVEL = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace EWallParts
|
namespace EWallPart
|
||||||
{
|
{
|
||||||
enum EWallParts
|
enum EWallPart
|
||||||
{
|
{
|
||||||
INDESTRUCTIBLE_PART = -2, INVALID = -1,
|
INDESTRUCTIBLE_PART_OF_GATE = -3, INDESTRUCTIBLE_PART = -2, INVALID = -1,
|
||||||
KEEP = 0, BOTTOM_TOWER, BOTTOM_WALL, BELOW_GATE, OVER_GATE, UPPER_WALL, UPPER_TOWER, GATE,
|
KEEP = 0, BOTTOM_TOWER, BOTTOM_WALL, BELOW_GATE, OVER_GATE, UPPER_WALL, UPPER_TOWER, GATE,
|
||||||
PARTS_COUNT
|
PARTS_COUNT /* This constant SHOULD always stay as the last item in the enum. */
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,10 +48,12 @@ struct CPack
|
|||||||
{
|
{
|
||||||
logNetwork->errorStream() << "CPack serialized... this should not happen!";
|
logNetwork->errorStream() << "CPack serialized... this should not happen!";
|
||||||
}
|
}
|
||||||
void applyGs(CGameState *gs)
|
void applyGs(CGameState *gs) { }
|
||||||
{};
|
virtual std::string toString() const { return boost::str(boost::format("{CPack: type '%d'}") % type); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::ostream & operator<<(std::ostream & out, const CPack * pack);
|
||||||
|
|
||||||
struct CPackForClient : public CPack
|
struct CPackForClient : public CPack
|
||||||
{
|
{
|
||||||
CPackForClient(){type = 1;};
|
CPackForClient(){type = 1;};
|
||||||
@ -1678,6 +1680,8 @@ struct CatapultAttack : public CPackForClient //3015
|
|||||||
ui8 attackedPart;
|
ui8 attackedPart;
|
||||||
ui8 damageDealt;
|
ui8 damageDealt;
|
||||||
|
|
||||||
|
DLL_LINKAGE std::string toString() const;
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & destinationTile & attackedPart & damageDealt;
|
h & destinationTile & attackedPart & damageDealt;
|
||||||
@ -1688,9 +1692,9 @@ struct CatapultAttack : public CPackForClient //3015
|
|||||||
|
|
||||||
DLL_LINKAGE void applyGs(CGameState *gs);
|
DLL_LINKAGE void applyGs(CGameState *gs);
|
||||||
void applyCl(CClient *cl);
|
void applyCl(CClient *cl);
|
||||||
|
DLL_LINKAGE std::string toString() const override;
|
||||||
|
|
||||||
std::vector< AttackInfo > attackedParts;
|
std::vector< AttackInfo > attackedParts;
|
||||||
|
|
||||||
int attacker; //if -1, then a spell caused this
|
int attacker; //if -1, then a spell caused this
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
@ -1699,6 +1703,8 @@ struct CatapultAttack : public CPackForClient //3015
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DLL_LINKAGE std::ostream & operator<<(std::ostream & out, const CatapultAttack::AttackInfo & attackInfo);
|
||||||
|
|
||||||
struct BattleStacksRemoved : public CPackForClient //3016
|
struct BattleStacksRemoved : public CPackForClient //3016
|
||||||
{
|
{
|
||||||
BattleStacksRemoved(){type = 3016;}
|
BattleStacksRemoved(){type = 3016;}
|
||||||
|
@ -35,6 +35,11 @@
|
|||||||
#undef max
|
#undef max
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
std::ostream & operator<<(std::ostream & out, const CPack * pack)
|
||||||
|
{
|
||||||
|
return out << pack->toString();
|
||||||
|
}
|
||||||
|
|
||||||
DLL_LINKAGE void SetResource::applyGs( CGameState *gs )
|
DLL_LINKAGE void SetResource::applyGs( CGameState *gs )
|
||||||
{
|
{
|
||||||
assert(player < PlayerColor::PLAYER_LIMIT);
|
assert(player < PlayerColor::PLAYER_LIMIT);
|
||||||
@ -1508,6 +1513,22 @@ DLL_LINKAGE void CatapultAttack::applyGs( CGameState *gs )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DLL_LINKAGE std::string CatapultAttack::AttackInfo::toString() const
|
||||||
|
{
|
||||||
|
return boost::str(boost::format("{AttackInfo: destinationTile '%d', attackedPart '%d', damageDealt '%d'}")
|
||||||
|
% destinationTile % static_cast<int>(attackedPart) % static_cast<int>(damageDealt));
|
||||||
|
}
|
||||||
|
|
||||||
|
DLL_LINKAGE std::ostream & operator<<(std::ostream & out, const CatapultAttack::AttackInfo & attackInfo)
|
||||||
|
{
|
||||||
|
return out << attackInfo.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
DLL_LINKAGE std::string CatapultAttack::toString() const
|
||||||
|
{
|
||||||
|
return boost::str(boost::format("{CatapultAttack: attackedParts '%s', attacker '%d'}") % attackedParts % attacker);
|
||||||
|
}
|
||||||
|
|
||||||
DLL_LINKAGE void BattleStacksRemoved::applyGs( CGameState *gs )
|
DLL_LINKAGE void BattleStacksRemoved::applyGs( CGameState *gs )
|
||||||
{
|
{
|
||||||
if(!gs->curB)
|
if(!gs->curB)
|
||||||
|
@ -3476,21 +3476,21 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
}
|
}
|
||||||
case Battle::CATAPULT:
|
case Battle::CATAPULT:
|
||||||
{
|
{
|
||||||
auto getCatapultHitChance = [&](EWallParts::EWallParts part, const CHeroHandler::SBallisticsLevelInfo & sbi) -> int
|
auto getCatapultHitChance = [&](EWallPart::EWallPart part, const CHeroHandler::SBallisticsLevelInfo & sbi) -> int
|
||||||
{
|
{
|
||||||
switch(part)
|
switch(part)
|
||||||
{
|
{
|
||||||
case EWallParts::GATE:
|
case EWallPart::GATE:
|
||||||
return sbi.gate;
|
return sbi.gate;
|
||||||
case EWallParts::KEEP:
|
case EWallPart::KEEP:
|
||||||
return sbi.keep;
|
return sbi.keep;
|
||||||
case EWallParts::BOTTOM_TOWER:
|
case EWallPart::BOTTOM_TOWER:
|
||||||
case EWallParts::UPPER_TOWER:
|
case EWallPart::UPPER_TOWER:
|
||||||
return sbi.tower;
|
return sbi.tower;
|
||||||
case EWallParts::BOTTOM_WALL:
|
case EWallPart::BOTTOM_WALL:
|
||||||
case EWallParts::BELOW_GATE:
|
case EWallPart::BELOW_GATE:
|
||||||
case EWallParts::OVER_GATE:
|
case EWallPart::OVER_GATE:
|
||||||
case EWallParts::UPPER_WALL:
|
case EWallPart::UPPER_WALL:
|
||||||
return sbi.wall;
|
return sbi.wall;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
@ -3504,8 +3504,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
const CGHeroInstance * attackingHero = gs->curB->battleGetFightingHero(ba.side);
|
const CGHeroInstance * attackingHero = gs->curB->battleGetFightingHero(ba.side);
|
||||||
CHeroHandler::SBallisticsLevelInfo sbi = VLC->heroh->ballistics.at(attackingHero->getSecSkillLevel(SecondarySkill::BALLISTICS));
|
CHeroHandler::SBallisticsLevelInfo sbi = VLC->heroh->ballistics.at(attackingHero->getSecSkillLevel(SecondarySkill::BALLISTICS));
|
||||||
|
|
||||||
EWallParts::EWallParts desiredTarget = gs->curB->battleHexToWallPart(ba.destinationTile);
|
auto wallPart = gs->curB->battleHexToWallPart(ba.destinationTile);
|
||||||
if(desiredTarget < 0)
|
if(!gs->curB->isWallPartPotentiallyAttackable(wallPart))
|
||||||
{
|
{
|
||||||
complain("catapult tried to attack non-catapultable hex!");
|
complain("catapult tried to attack non-catapultable hex!");
|
||||||
break;
|
break;
|
||||||
@ -3514,7 +3514,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
//in successive iterations damage is dealt but not yet subtracted from wall's HPs
|
//in successive iterations damage is dealt but not yet subtracted from wall's HPs
|
||||||
auto ¤tHP = gs->curB->si.wallState;
|
auto ¤tHP = gs->curB->si.wallState;
|
||||||
|
|
||||||
if (currentHP.at(desiredTarget) == EWallState::DESTROYED || currentHP.at(desiredTarget) == EWallState::NONE)
|
if (currentHP.at(wallPart) == EWallState::DESTROYED || currentHP.at(wallPart) == EWallState::NONE)
|
||||||
{
|
{
|
||||||
complain("catapult tried to attack already destroyed wall part!");
|
complain("catapult tried to attack already destroyed wall part!");
|
||||||
break;
|
break;
|
||||||
@ -3523,7 +3523,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
for(int g=0; g<sbi.shots; ++g)
|
for(int g=0; g<sbi.shots; ++g)
|
||||||
{
|
{
|
||||||
bool hitSuccessfull = false;
|
bool hitSuccessfull = false;
|
||||||
EWallParts::EWallParts attackedPart = desiredTarget;
|
auto attackedPart = wallPart;
|
||||||
|
|
||||||
do // catapult has chance to attack desired target. Othervice - attacks randomly
|
do // catapult has chance to attack desired target. Othervice - attacks randomly
|
||||||
{
|
{
|
||||||
@ -3535,12 +3535,12 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
}
|
}
|
||||||
else // select new target
|
else // select new target
|
||||||
{
|
{
|
||||||
std::vector<EWallParts::EWallParts> allowedTargets;
|
std::vector<EWallPart::EWallPart> allowedTargets;
|
||||||
for (size_t i=0; i< currentHP.size(); i++)
|
for (size_t i=0; i< currentHP.size(); i++)
|
||||||
{
|
{
|
||||||
if (currentHP.at(i) != EWallState::DESTROYED &&
|
if (currentHP.at(i) != EWallState::DESTROYED &&
|
||||||
currentHP.at(i) != EWallState::NONE)
|
currentHP.at(i) != EWallState::NONE)
|
||||||
allowedTargets.push_back(EWallParts::EWallParts(i));
|
allowedTargets.push_back(EWallPart::EWallPart(i));
|
||||||
}
|
}
|
||||||
if (allowedTargets.empty())
|
if (allowedTargets.empty())
|
||||||
break;
|
break;
|
||||||
@ -3569,32 +3569,30 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
{
|
{
|
||||||
if(dmgRand <= dmgChance[damage])
|
if(dmgRand <= dmgChance[damage])
|
||||||
{
|
{
|
||||||
currentHP[attackedPart] = SiegeInfo::applyDamage(EWallState::EWallState(currentHP.at(attackedPart)), damage);
|
|
||||||
|
|
||||||
attack.damageDealt = damage;
|
attack.damageDealt = damage;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// attacked tile may have changed - update destination
|
// attacked tile may have changed - update destination
|
||||||
attack.destinationTile = gs->curB->wallPartToBattleHex(EWallParts::EWallParts(attack.attackedPart));
|
attack.destinationTile = gs->curB->wallPartToBattleHex(EWallPart::EWallPart(attack.attackedPart));
|
||||||
|
|
||||||
logGlobal->traceStream() << "Catapult attacks " << (int)attack.attackedPart
|
logGlobal->traceStream() << "Catapult attacks " << (int)attack.attackedPart
|
||||||
<< " dealing " << (int)attack.damageDealt << " damage";
|
<< " dealing " << (int)attack.damageDealt << " damage";
|
||||||
|
|
||||||
//removing creatures in turrets / keep if one is destroyed
|
//removing creatures in turrets / keep if one is destroyed
|
||||||
if(attack.damageDealt > 0 && (attackedPart == EWallParts::KEEP ||
|
if(attack.damageDealt > 0 && (attackedPart == EWallPart::KEEP ||
|
||||||
attackedPart == EWallParts::BOTTOM_TOWER || attackedPart == EWallParts::UPPER_TOWER))
|
attackedPart == EWallPart::BOTTOM_TOWER || attackedPart == EWallPart::UPPER_TOWER))
|
||||||
{
|
{
|
||||||
int posRemove = -1;
|
int posRemove = -1;
|
||||||
switch(attackedPart)
|
switch(attackedPart)
|
||||||
{
|
{
|
||||||
case EWallParts::KEEP:
|
case EWallPart::KEEP:
|
||||||
posRemove = -2;
|
posRemove = -2;
|
||||||
break;
|
break;
|
||||||
case EWallParts::BOTTOM_TOWER:
|
case EWallPart::BOTTOM_TOWER:
|
||||||
posRemove = -3;
|
posRemove = -3;
|
||||||
break;
|
break;
|
||||||
case EWallParts::UPPER_TOWER:
|
case EWallPart::UPPER_TOWER:
|
||||||
posRemove = -4;
|
posRemove = -4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -5975,20 +5973,26 @@ void CGameHandler::runBattle()
|
|||||||
|
|
||||||
if(next->getCreature()->idNumber == CreatureID::CATAPULT && (!curOwner || curOwner->getSecSkillLevel(SecondarySkill::BALLISTICS) == 0)) //catapult, hero has no ballistics
|
if(next->getCreature()->idNumber == CreatureID::CATAPULT && (!curOwner || curOwner->getSecSkillLevel(SecondarySkill::BALLISTICS) == 0)) //catapult, hero has no ballistics
|
||||||
{
|
{
|
||||||
BattleAction attack;
|
const auto & attackableBattleHexes = curB.getAttackableBattleHexes();
|
||||||
static const int wallHexes[] = {50, 183, 182, 130, 62, 29, 12, 95};
|
|
||||||
|
|
||||||
attack.destinationTile = wallHexes[ rand()%ARRAY_COUNT(wallHexes) ];
|
if(!attackableBattleHexes.empty())
|
||||||
|
{
|
||||||
|
BattleAction attack;
|
||||||
|
attack.destinationTile = attackableBattleHexes[rand() % attackableBattleHexes.size()];
|
||||||
attack.actionType = Battle::CATAPULT;
|
attack.actionType = Battle::CATAPULT;
|
||||||
attack.additionalInfo = 0;
|
attack.additionalInfo = 0;
|
||||||
attack.side = !next->attackerOwned;
|
attack.side = !next->attackerOwned;
|
||||||
attack.stackNumber = next->ID;
|
attack.stackNumber = next->ID;
|
||||||
|
|
||||||
makeAutomaticAction(next, attack);
|
makeAutomaticAction(next, attack);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
makeStackDoNothing(next);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(next->getCreature()->idNumber == CreatureID::FIRST_AID_TENT)
|
if(next->getCreature()->idNumber == CreatureID::FIRST_AID_TENT)
|
||||||
{
|
{
|
||||||
std::vector< const CStack * > possibleStacks;
|
std::vector< const CStack * > possibleStacks;
|
||||||
|
Reference in New Issue
Block a user