2015-03-18 21:22:52 +02:00
/*
* BattleState . h , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
2010-12-25 21:23:30 +02:00
2015-03-18 21:22:52 +02:00
# pragma once
2011-12-14 00:23:17 +03:00
2011-12-22 16:05:19 +03:00
# include "BattleHex.h"
2014-06-25 17:11:07 +03:00
# include "mapObjects/CArmedInstance.h" // for army serialization
# include "mapObjects/CGHeroInstance.h" // for commander serialization
2011-02-06 19:26:27 +02:00
# include "CCreatureHandler.h"
2010-12-25 21:23:30 +02:00
# include "ConstTransitivePtr.h"
2011-12-14 00:23:17 +03:00
# include "GameConstants.h"
2012-08-26 12:07:48 +03:00
# include "CBattleCallback.h"
2014-06-05 19:52:14 +03:00
# include "int3.h"
2015-03-18 21:22:52 +02:00
# include "spells/Magic.h"
2010-12-25 21:23:30 +02:00
class CGHeroInstance ;
class CStack ;
class CArmedInstance ;
class CGTownInstance ;
class CStackInstance ;
2011-01-08 20:33:40 +02:00
struct BattleStackAttacked ;
2014-03-17 22:51:07 +03:00
class CRandomGenerator ;
2011-12-14 00:23:17 +03:00
2012-08-26 12:07:48 +03:00
2010-12-25 21:23:30 +02:00
//only for use in BattleInfo
2011-12-14 00:23:17 +03:00
struct DLL_LINKAGE SiegeInfo
2010-12-25 21:23:30 +02:00
{
2013-12-08 20:54:13 +03:00
std : : array < si8 , EWallPart : : PARTS_COUNT > wallState ;
2016-02-13 16:40:31 +02:00
EGateState gateState ;
2013-08-06 14:20:28 +03:00
// return EWallState decreased by value of damage points
static EWallState : : EWallState applyDamage ( EWallState : : EWallState state , unsigned int value )
{
if ( value = = 0 )
return state ;
switch ( applyDamage ( state , value - 1 ) )
{
case EWallState : : INTACT : return EWallState : : DAMAGED ;
case EWallState : : DAMAGED : return EWallState : : DESTROYED ;
case EWallState : : DESTROYED : return EWallState : : DESTROYED ;
default : return EWallState : : NONE ;
}
}
2013-01-15 17:20:48 +03:00
2010-12-25 21:23:30 +02:00
template < typename Handler > void serialize ( Handler & h , const int version )
{
2016-02-13 16:40:31 +02:00
h & wallState & gateState ;
2010-12-25 21:23:30 +02:00
}
} ;
2013-07-22 01:01:29 +03:00
struct DLL_LINKAGE SideInBattle
{
PlayerColor color ;
const CGHeroInstance * hero ; //may be NULL if army is not commanded by hero
const CArmedInstance * armyObject ; //adv. map object with army that participates in battle; may be same as hero
ui8 castSpellsCount ; //how many spells each side has cast this turn
std : : vector < const CSpell * > usedSpellsHistory ; //every time hero casts spell, it's inserted here -> eagle eye skill
si16 enchanterCounter ; //tends to pass through 0, so sign is needed
SideInBattle ( ) ;
void init ( const CGHeroInstance * Hero , const CArmedInstance * Army ) ;
2011-09-10 16:04:20 +03:00
2013-07-22 01:01:29 +03:00
template < typename Handler > void serialize ( Handler & h , const int version )
{
h & color & hero & armyObject ;
h & castSpellsCount & usedSpellsHistory & enchanterCounter ;
}
} ;
2012-08-26 12:07:48 +03:00
struct DLL_LINKAGE BattleInfo : public CBonusSystemNode , public CBattleInfoCallback
2010-12-25 21:23:30 +02:00
{
2013-07-22 01:01:29 +03:00
std : : array < SideInBattle , 2 > sides ; //sides[0] - attacker, sides[1] - defender
2012-04-28 22:40:27 +03:00
si32 round , activeStack , selectedStack ;
2014-06-25 17:11:07 +03:00
const CGTownInstance * town ; //used during town siege, nullptr if this is not a siege (note that fortless town IS also a siege)
2010-12-25 21:23:30 +02:00
int3 tile ; //for background and bonuses
std : : vector < CStack * > stacks ;
2015-12-29 04:43:33 +02:00
std : : vector < std : : shared_ptr < CObstacleInstance > > obstacles ;
2010-12-25 21:23:30 +02:00
SiegeInfo si ;
2012-05-18 23:50:16 +03:00
2013-02-13 01:24:48 +03:00
BFieldType battlefieldType ; //like !!BA:B
ETerrainType terrainType ; //used for some stack nativity checks (not the bonus limiters though that have their own copy)
2010-12-25 21:23:30 +02:00
2011-02-12 18:12:48 +02:00
ui8 tacticsSide ; //which side is requested to play tactics phase
ui8 tacticDistance ; //how many hexes we can go forward (1 = only hexes adjacent to margin line)
2010-12-25 21:23:30 +02:00
template < typename Handler > void serialize ( Handler & h , const int version )
{
2013-07-22 01:01:29 +03:00
h & sides ;
2014-06-25 17:11:07 +03:00
h & round & activeStack & selectedStack & town & tile & stacks & obstacles
2013-07-22 01:01:29 +03:00
& si & battlefieldType & terrainType ;
2011-02-12 18:12:48 +02:00
h & tacticsSide & tacticDistance ;
2010-12-25 21:23:30 +02:00
h & static_cast < CBonusSystemNode & > ( * this ) ;
}
2012-08-26 12:07:48 +03:00
//////////////////////////////////////////////////////////////////////////
BattleInfo ( ) ;
~ BattleInfo ( ) { } ;
2010-12-25 21:23:30 +02:00
//////////////////////////////////////////////////////////////////////////
2012-08-26 12:07:48 +03:00
CStack * getStack ( int stackID , bool onlyAlive = true ) ;
2013-07-22 01:01:29 +03:00
using CBattleInfoEssentials : : battleGetArmyObject ;
2016-02-27 23:13:34 +02:00
CArmedInstance * battleGetArmyObject ( ui8 side ) const ;
2013-07-22 01:01:29 +03:00
using CBattleInfoEssentials : : battleGetFightingHero ;
2016-02-27 23:13:34 +02:00
CGHeroInstance * battleGetFightingHero ( ui8 side ) const ;
2010-12-25 21:23:30 +02:00
const CStack * getNextStack ( ) const ; //which stack will have turn after current one
2012-08-26 12:07:48 +03:00
//void getStackQueue(std::vector<const CStack *> &out, int howMany, int turn = 0, int lastMoved = -1) const; //returns stack in order of their movement action
2013-06-26 14:18:27 +03:00
//void getAccessibilityMap(bool *accessibility, bool twoHex, bool attackerOwned, bool addOccupiable, std::set<BattleHex> & occupyable, bool flying, const CStack* stackToOmmit = nullptr) const; //send pointer to at least 187 allocated bytes
2012-08-26 12:07:48 +03:00
//static bool isAccessible(BattleHex hex, bool * accessibility, bool twoHex, bool attackerOwned, bool flying, bool lastPos); //helper for makeBFS
2013-02-11 02:24:57 +03:00
int getAvaliableHex ( CreatureID creID , bool attackerOwned , int initialPos = - 1 ) const ; //find place for summon / clone effects
2012-08-26 12:07:48 +03:00
//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
2013-06-26 14:18:27 +03:00
//std::vector<BattleHex> getAccessibility(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = nullptr, bool forPassingBy = false) const; //returns vector of accessible tiles (taking into account the creature range)
2011-01-07 12:48:31 +02:00
2012-08-26 12:07:48 +03:00
//bool isObstacleVisibleForSide(const CObstacleInstance &obstacle, ui8 side) const;
2015-12-29 04:43:33 +02:00
std : : shared_ptr < CObstacleInstance > getObstacleOnTile ( BattleHex tile ) const ;
2012-05-18 23:50:16 +03:00
std : : set < BattleHex > getStoppers ( bool whichSidePerspective ) const ;
2010-12-25 21:23:30 +02:00
2014-04-10 20:11:09 +03:00
ui32 calculateDmg ( const CStack * attacker , const CStack * defender , const CGHeroInstance * attackerHero , const CGHeroInstance * defendingHero , bool shooting , ui8 charge , bool lucky , bool unlucky , bool deathBlow , bool ballistaDoubleDmg , CRandomGenerator & rand ) ; //charge - number of hexes travelled before attack (for champion's jousting)
2010-12-25 21:23:30 +02:00
void calculateCasualties ( std : : map < ui32 , si32 > * casualties ) const ; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount)
2013-01-15 17:20:48 +03:00
2012-08-26 12:07:48 +03:00
//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
2014-11-25 18:44:43 +02:00
2013-02-16 17:03:47 +03:00
CStack * generateNewStack ( const CStackInstance & base , bool attackerOwned , SlotID slot , BattleHex position ) const ; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
CStack * generateNewStack ( const CStackBasicDescriptor & base , bool attackerOwned , SlotID slot , BattleHex position ) const ; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
2012-02-29 04:31:48 +03:00
int getIdForNewStack ( ) const ; //suggest a currently unused ID that'd suitable for generating a new stack
2012-08-26 12:07:48 +03:00
//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)
2013-01-15 17:20:48 +03:00
2013-03-03 20:06:03 +03:00
const CGHeroInstance * getHero ( PlayerColor player ) const ; //returns fighting hero that belongs to given player
2011-01-07 12:48:31 +02:00
2013-06-26 14:18:27 +03:00
const CGHeroInstance * battleGetOwner ( const CStack * stack ) const ; //returns hero that owns given stack; nullptr if none
2010-12-25 21:23:30 +02:00
void localInit ( ) ;
2012-02-29 04:31:48 +03:00
void localInitStack ( CStack * s ) ;
2013-02-13 01:24:48 +03:00
static BattleInfo * setupBattle ( int3 tile , ETerrainType terrain , BFieldType battlefieldType , const CArmedInstance * armies [ 2 ] , const CGHeroInstance * heroes [ 2 ] , bool creatureBank , const CGTownInstance * town ) ;
2012-08-26 12:07:48 +03:00
//bool hasNativeStack(ui8 side) const;
2011-03-05 18:38:22 +02:00
2013-03-03 20:06:03 +03:00
PlayerColor theOtherPlayer ( PlayerColor player ) const ;
ui8 whatSide ( PlayerColor player ) const ;
2012-04-23 22:56:37 +03:00
2013-02-13 01:24:48 +03:00
static BattlefieldBI : : BattlefieldBI battlefieldTypeToBI ( BFieldType bfieldType ) ; //converts above to ERM BI format
2012-04-23 22:56:37 +03:00
static int battlefieldTypeToTerrain ( int bfieldType ) ; //converts above to ERM BI format
2010-12-25 21:23:30 +02:00
} ;
2015-03-18 21:22:52 +02:00
class DLL_LINKAGE CStack : public CBonusSystemNode , public CStackBasicDescriptor , public ISpellCaster
2013-01-15 17:20:48 +03:00
{
2010-12-25 21:23:30 +02:00
public :
2013-06-26 14:18:27 +03:00
const CStackInstance * base ; //garrison slot from which stack originates (nullptr for war machines, summoned cres, etc)
2010-12-25 21:23:30 +02:00
ui32 ID ; //unique ID of stack
ui32 baseAmount ;
ui32 firstHPleft ; //HP of first creature in stack
2013-03-03 20:06:03 +03:00
PlayerColor owner ; //owner - player colour (255 for neutrals)
2013-02-16 17:03:47 +03:00
SlotID slot ; //slot - position in garrison (may be 255 for neutrals/called creatures)
2013-02-04 00:05:44 +03:00
bool attackerOwned ; //if true, this stack is owned by attakcer (this one from left hand side of battle)
2011-12-22 16:05:19 +03:00
BattleHex position ; //position on battlefield; -2 - keep, -3 - lower tower, -4 - upper tower
2015-09-14 17:38:41 +02:00
///how many times this stack has been counterattacked this round
ui8 counterAttacksPerformed ;
///cached total count of counterattacks; should be cleared each round;do not serialize
mutable ui8 counterAttacksTotalCache ;
2010-12-25 21:23:30 +02:00
si16 shots ; //how many shots left
2011-07-08 17:54:20 +03:00
ui8 casts ; //how many casts left
2013-07-27 22:01:31 +03:00
TQuantity resurrected ; // these units will be taken back after battle is over
2015-09-14 19:13:26 +02:00
///id of alive clone of this stack clone if any
si32 cloneID ;
2011-12-14 00:23:17 +03:00
std : : set < EBattleStackState : : EBattleStackState > state ;
2010-12-25 21:23:30 +02:00
//overrides
const CCreature * getCreature ( ) const { return type ; }
2013-03-03 20:06:03 +03:00
CStack ( const CStackInstance * base , PlayerColor O , int I , bool AO , SlotID S ) ; //c-tor
CStack ( const CStackBasicDescriptor * stack , PlayerColor O , int I , bool AO , SlotID S = SlotID ( 255 ) ) ; //c-tor
2010-12-25 21:23:30 +02:00
CStack ( ) ; //c-tor
~ CStack ( ) ;
2013-06-26 14:18:27 +03:00
std : : string nodeName ( ) const override ;
2010-12-25 21:23:30 +02:00
void init ( ) ; //set initial (invalid) values
void postInit ( ) ; //used to finish initialization when inheriting creature parameters is working
2011-10-22 10:05:57 +03:00
std : : string getName ( ) const ; //plural or singular
2010-12-25 21:23:30 +02:00
bool willMove ( int turn = 0 ) const ; //if stack has remaining move this turn
2011-09-01 04:40:46 +03:00
bool ableToRetaliate ( ) const ; //if stack can retaliate after attacked
2015-09-14 17:38:41 +02:00
///how many times this stack can counterattack in one round
ui8 counterAttacksTotal ( ) const ;
///how many times this stack can counterattack in one round more
si8 counterAttacksRemaining ( ) const ;
2010-12-25 21:23:30 +02:00
bool moved ( int turn = 0 ) const ; //if stack was already moved this turn
2012-09-20 19:55:21 +03:00
bool waited ( int turn = 0 ) const ;
2010-12-25 21:23:30 +02:00
bool canMove ( int turn = 0 ) const ; //if stack can move
2012-03-31 00:36:07 +03:00
bool canBeHealed ( ) const ; //for first aid tent - only harmed stacks that are not war machines
2015-09-16 04:57:02 +02:00
///returns actual heal value based on internal state
ui32 calculateHealedHealthPoints ( ui32 toHeal , const bool resurrect ) const ;
2013-03-30 23:09:50 +03:00
ui32 level ( ) const ;
2013-07-22 01:01:29 +03:00
si32 magicResistance ( ) const override ; //include aura of resistance
2011-01-20 21:57:12 +02:00
static void stackEffectToFeature ( std : : vector < Bonus > & sf , const Bonus & sse ) ;
2010-12-25 21:23:30 +02:00
std : : vector < si32 > activeSpells ( ) const ; //returns vector of active spell IDs sorted by time of cast
2013-06-26 14:18:27 +03:00
const CGHeroInstance * getMyHero ( ) const ; //if stack belongs to hero (directly or was by him summoned) returns hero, nullptr otherwise
2016-03-14 14:28:17 +02:00
ui32 totalHelth ( ) const ; // total health for all creatures in stack;
2010-12-25 21:23:30 +02:00
2013-02-02 01:04:25 +03:00
static inline Bonus featureGenerator ( Bonus : : BonusType type , si16 subtype , si32 value , ui16 turnsRemain , si32 additionalInfo = 0 , Bonus : : LimitEffect limit = Bonus : : NO_LIMIT )
2010-12-25 21:23:30 +02:00
{
2011-01-20 21:57:12 +02:00
Bonus hb = makeFeatureVal ( type , Bonus : : N_TURNS , subtype , value , Bonus : : SPELL_EFFECT , turnsRemain , additionalInfo ) ;
hb . effectRange = limit ;
2010-12-25 21:23:30 +02:00
return hb ;
}
2011-12-22 16:05:19 +03:00
static bool isMeleeAttackPossible ( const CStack * attacker , const CStack * defender , BattleHex attackerPos = BattleHex : : INVALID , BattleHex defenderPos = BattleHex : : INVALID ) ;
2011-01-08 20:33:40 +02:00
2010-12-25 21:23:30 +02:00
bool doubleWide ( ) const ;
2011-12-22 16:05:19 +03:00
BattleHex occupiedHex ( ) const ; //returns number of occupied hex (not the position) if stack is double wide; otherwise -1
2012-08-26 12:07:48 +03:00
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
2011-12-22 16:05:19 +03:00
std : : vector < BattleHex > getHexes ( ) const ; //up to two occupied hexes, starting from front
2012-08-26 12:07:48 +03:00
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
2011-12-22 16:05:19 +03:00
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
2010-12-25 21:23:30 +02:00
2013-06-21 23:59:32 +03:00
std : : pair < int , int > countKilledByAttack ( int damageReceived ) const ; //returns pair<killed count, new left HP>
2014-03-17 22:51:07 +03:00
void prepareAttacked ( BattleStackAttacked & bsa , CRandomGenerator & rand , boost : : optional < int > customCount = boost : : none ) const ; //requires bsa.damageAmout filled
2011-01-08 20:33:40 +02:00
2015-03-18 21:22:52 +02:00
///ISpellCaster
ui8 getSpellSchoolLevel ( const CSpell * spell , int * outSelectedSchool = nullptr ) const override ;
ui32 getSpellBonus ( const CSpell * spell , ui32 base , const CStack * affectedStack ) const override ;
2015-09-17 07:42:30 +02:00
///default spell school level for effect calculation
int getEffectLevel ( const CSpell * spell ) const override ;
///default spell-power for damage/heal calculation
int getEffectPower ( const CSpell * spell ) const override ;
///default spell-power for timed effects duration
int getEnchantPower ( const CSpell * spell ) const override ;
///damage/heal override(ignores spell configuration, effect level and effect power)
int getEffectValue ( const CSpell * spell ) const override ;
2015-09-17 08:29:57 +02:00
const PlayerColor getOwner ( ) const override ;
2016-02-27 23:13:34 +02:00
2016-03-01 04:24:35 +02:00
///stack will be ghost in next battle state update
2016-02-28 00:35:23 +02:00
void makeGhost ( ) ;
2010-12-25 21:23:30 +02:00
template < typename Handler > void serialize ( Handler & h , const int version )
{
assert ( isIndependentNode ( ) ) ;
h & static_cast < CBonusSystemNode & > ( * this ) ;
h & static_cast < CStackBasicDescriptor & > ( * this ) ;
2015-09-14 17:38:41 +02:00
h & ID & baseAmount & firstHPleft & owner & slot & attackerOwned & position & state & counterAttacksPerformed
2013-07-27 22:01:31 +03:00
& shots & casts & count & resurrected ;
2010-12-25 21:23:30 +02:00
2013-06-26 14:18:27 +03:00
const CArmedInstance * army = ( base ? base - > armyObj : nullptr ) ;
2013-02-16 17:03:47 +03:00
SlotID slot = ( base ? base - > armyObj - > findStack ( base ) : SlotID ( ) ) ;
2012-08-20 19:10:50 +03:00
2010-12-25 21:23:30 +02:00
if ( h . saving )
{
h & army & slot ;
}
else
{
h & army & slot ;
2013-02-16 17:03:47 +03:00
if ( slot = = SlotID : : COMMANDER_SLOT_PLACEHOLDER ) //TODO
2012-08-20 19:10:50 +03:00
{
auto hero = dynamic_cast < const CGHeroInstance * > ( army ) ;
assert ( hero ) ;
base = hero - > commander ;
}
2013-02-16 17:03:47 +03:00
else if ( ! army | | slot = = SlotID ( ) | | ! army - > hasStackAtSlot ( slot ) )
2010-12-25 21:23:30 +02:00
{
2013-06-26 14:18:27 +03:00
base = nullptr ;
2016-03-12 03:41:27 +02:00
logGlobal - > warnStream ( ) < < type - > nameSing < < " doesn't have a base stack! " ;
2010-12-25 21:23:30 +02:00
}
else
{
base = & army - > getStack ( slot ) ;
}
}
}
bool alive ( ) const //determines if stack is alive
{
2011-12-14 00:23:17 +03:00
return vstd : : contains ( state , EBattleStackState : : ALIVE ) ;
2010-12-25 21:23:30 +02:00
}
2016-02-28 04:10:20 +02:00
bool isDead ( ) const ;
bool isGhost ( ) const ; //determines if stack was removed
bool isValidTarget ( bool allowDead = false ) const ; //non-turret non-ghost stacks (can be attacked or be object of magic effect)
bool isTurret ( ) const ;
2010-12-25 21:23:30 +02:00
} ;
2011-12-14 00:23:17 +03:00
class DLL_LINKAGE CMP_stack
2010-12-25 21:23:30 +02:00
{
int phase ; //rules of which phase will be used
int turn ;
public :
bool operator ( ) ( const CStack * a , const CStack * b ) ;
CMP_stack ( int Phase = 1 , int Turn = 0 ) ;
} ;