2010-12-25 21:23:30 +02:00
# pragma once
# include "../global.h"
# include "HeroBonus.h"
# include "CCreatureSet.h"
2011-02-06 19:26:27 +02:00
# include "CObjectHandler.h"
# include "CCreatureHandler.h"
2011-05-10 01:20:47 +03:00
# include "CObstacleInstance.h"
2010-12-25 21:23:30 +02:00
# include "ConstTransitivePtr.h"
/*
* 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
*
*/
class CGHeroInstance ;
class CStack ;
class CArmedInstance ;
class CGTownInstance ;
class CStackInstance ;
2011-01-08 20:33:40 +02:00
struct BattleStackAttacked ;
2010-12-25 21:23:30 +02:00
//only for use in BattleInfo
struct DLL_EXPORT 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
template < typename Handler > void serialize ( Handler & h , const int version )
{
h & wallState ;
}
} ;
2011-09-10 16:04:20 +03:00
struct DLL_EXPORT AttackableTiles
{
std : : set < THex > hostileCreaturePositions ;
std : : set < THex > friendlyCreaturePositions ; //for Dragon Breath
template < typename Handler > void serialize ( Handler & h , const int version )
{
h & hostileCreaturePositions & friendlyCreaturePositions ;
}
} ;
2010-12-25 21:23:30 +02:00
struct DLL_EXPORT BattleInfo : public CBonusSystemNode
{
2011-01-09 19:41:46 +02:00
ui8 sides [ 2 ] ; //sides[0] - attacker, sides[1] - defender
2010-12-25 21:23:30 +02:00
si32 round , activeStack ;
ui8 siege ; // = 0 ordinary battle = 1 a siege with a Fort = 2 a siege with a Citadel = 3 a siege with a Castle
2011-01-07 12:48:31 +02:00
const CGTownInstance * town ; //used during town siege - id of attacked town; -1 if not town defence
2010-12-25 21:23:30 +02:00
int3 tile ; //for background and bonuses
CGHeroInstance * heroes [ 2 ] ;
CArmedInstance * belligerents [ 2 ] ; //may be same as heroes
std : : vector < CStack * > stacks ;
std : : vector < CObstacleInstance > obstacles ;
2011-02-11 21:12:08 +02:00
ui8 castSpells [ 2 ] ; //how many spells each side has cast this turn [0] - attacker, [1] - defender
std : : vector < const CSpell * > usedSpellsHistory [ 2 ] ; //each time hero casts spell, it's inserted here -> eagle eye skill
2010-12-25 21:23:30 +02:00
SiegeInfo si ;
si32 battlefieldType ;
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 )
{
2011-01-09 19:41:46 +02:00
h & sides & round & activeStack & siege & town & tile & stacks & belligerents & obstacles
2010-12-25 21:23:30 +02:00
& castSpells & si & battlefieldType ;
h & heroes ;
2011-02-11 21:12:08 +02:00
h & usedSpellsHistory ;
2011-02-12 18:12:48 +02:00
h & tacticsSide & tacticDistance ;
2010-12-25 21:23:30 +02:00
h & static_cast < CBonusSystemNode & > ( * this ) ;
}
//////////////////////////////////////////////////////////////////////////
//void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) 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 ( THex tileID , bool onlyAlive = true ) ;
const CStack * getStackT ( THex tileID , bool onlyAlive = true ) const ;
2011-01-07 12:48:31 +02:00
void getAccessibilityMap ( bool * accessibility , bool twoHex , bool attackerOwned , bool addOccupiable , std : : set < THex > & occupyable , bool flying , const CStack * stackToOmmit = NULL ) const ; //send pointer to at least 187 allocated bytes
2011-01-09 19:41:46 +02:00
static bool isAccessible ( THex hex , bool * accessibility , bool twoHex , bool attackerOwned , bool flying , bool lastPos ) ; //helper for makeBFS
2011-10-01 22:56:54 +03:00
int getAvaliableHex ( TCreature creID , bool attackerOwned , int initialPos = - 1 ) const ; //find place for summon / clone effects
2011-01-09 19:41:46 +02:00
void makeBFS ( THex start , bool * accessibility , THex * 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 < THex > , int > getPath ( THex start , THex 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
2011-02-26 19:32:56 +02:00
std : : vector < THex > getAccessibility ( const CStack * stack , bool addOccupiable , std : : vector < THex > * attackable = NULL ) const ; //returns vector of accessible tiles (taking into account the creature range)
2011-01-07 12:48:31 +02:00
2011-01-08 20:33:40 +02:00
bool isStackBlocked ( const CStack * stack ) const ; //returns true if there is neighboring enemy stack
2010-12-25 21:23:30 +02:00
2011-07-06 20:00:45 +03:00
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>
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)
2011-01-09 19:41:46 +02:00
std : : set < CStack * > getAttackedCreatures ( const CSpell * s , int skillLevel , ui8 attackerOwner , THex destinationTile ) ; //calculates stack affected by given spell
2011-09-10 16:04:20 +03:00
void getPotentiallyAttackableHexes ( AttackableTiles & at , const CStack * attacker , THex destinationTile , THex attackerPos ) ; //hexes around target that could be attacked in melee
std : : set < CStack * > getAttackedCreatures ( const CStack * attacker , THex destinationTile , THex attackerPos = THex : : INVALID ) ; //calculates range of multi-hex attacks
std : : set < THex > getAttackedHexes ( const CStack * attacker , THex destinationTile , THex attackerPos = THex : : INVALID ) ; //calculates range of multi-hex attacks
2010-12-25 21:23:30 +02:00
static int calculateSpellDuration ( const CSpell * spell , const CGHeroInstance * caster , int usedSpellPower ) ;
2011-01-09 19:41:46 +02:00
CStack * generateNewStack ( const CStackInstance & base , int stackID , bool attackerOwned , int slot , THex position ) const ; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
CStack * generateNewStack ( const CStackBasicDescriptor & base , int stackID , bool attackerOwned , int slot , THex position ) const ; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
2010-12-25 21:23:30 +02:00
ui32 getSpellCost ( const CSpell * sp , const CGHeroInstance * caster ) const ; //returns cost of given spell
2011-01-07 12:48:31 +02:00
int hexToWallPart ( THex hex ) const ; //returns part of destructible wall / gate / keep under given hex or -1 if not found
2010-12-25 21:23:30 +02:00
int lineToWallHex ( int line ) const ; //returns hex with wall in given line
2011-01-09 19:41:46 +02:00
std : : pair < const CStack * , THex > 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)
2010-12-25 21:23:30 +02:00
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 ;
2011-07-08 16:17:05 +03:00
ui32 calculateHealedHP ( int healedHealth , const CSpell * spell , const CStack * stack ) const ; //for Archangel
2011-07-10 01:42:39 +03:00
ui32 calculateHealedHP ( const CSpell * spell , int usedSpellPower , int spellSchoolLevel , const CStack * stack ) const ; //unused
2011-07-08 16:17:05 +03:00
bool resurrects ( TSpell spellid ) const ; //TODO: move it to spellHandler?
2011-01-08 20:33:40 +02:00
si8 hasDistancePenalty ( const CStack * stackID , THex 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 , THex destHex ) const ; //determines if given stack has wall penalty shooting given pos
si8 canTeleportTo ( const CStack * stack , THex destHex , int telportLevel ) const ; //determines if given stack can teleport to given place
bool battleCanShoot ( const CStack * stack , THex dest ) const ; //determines if stack with given ID shoot at the selected destination
2011-02-21 18:53:23 +02:00
const CGHeroInstance * getHero ( int player ) const ; //returns fighting hero that belongs to given player
2011-01-07 12:48:31 +02:00
2011-02-22 15:44:34 +02:00
SpellCasting : : ESpellCastProblem battleCanCastSpell ( int player , SpellCasting : : ECastingMode mode ) const ; //returns true if there are no general issues preventing from casting a spell
SpellCasting : : ESpellCastProblem battleCanCastThisSpell ( int player , const CSpell * spell , SpellCasting : : ECastingMode mode ) const ; //checks if given player can cast given spell
2011-03-01 15:54:48 +02:00
SpellCasting : : ESpellCastProblem battleIsImmune ( const CGHeroInstance * caster , const CSpell * spell , SpellCasting : : ECastingMode mode , THex 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.
2011-02-22 15:44:34 +02:00
SpellCasting : : ESpellCastProblem battleCanCastThisSpellHere ( int player , const CSpell * spell , SpellCasting : : ECastingMode mode , THex dest ) ; //checks if given player can cast given spell at given tile in given mode
2011-06-25 09:55:35 +03:00
bool battleTestElementalImmunity ( const CStack * subject , const CSpell * spell , Bonus : : BonusType element , bool damageSpell ) const ;
2011-10-03 22:29:36 +03:00
TSpell getRandomBeneficialSpell ( const CStack * subject ) const ;
2011-02-22 15:44:34 +02:00
std : : vector < ui32 > calculateResistedStacks ( const CSpell * sp , const CGHeroInstance * caster , const CGHeroInstance * hero2 , const std : : set < CStack * > affectedCreatures , int casterSideOwner , SpellCasting : : ECastingMode mode ) const ;
2011-02-20 20:32:39 +02:00
2011-02-15 21:54:55 +02:00
2011-01-08 20:33:40 +02:00
bool battleCanFlee ( int player ) const ; //returns true if player can flee from the battle
2011-01-07 12:48:31 +02:00
const CStack * battleGetStack ( THex pos , bool onlyAlive ) ; //returns stack at given tile
2011-01-08 20:33:40 +02:00
const CGHeroInstance * battleGetOwner ( const CStack * stack ) const ; //returns hero that owns given stack; NULL if none
2011-02-21 18:53:23 +02:00
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
2010-12-25 21:23:30 +02:00
void localInit ( ) ;
2011-02-06 19:26:27 +02:00
static BattleInfo * setupBattle ( int3 tile , int terrain , int terType , const CArmedInstance * armies [ 2 ] , const CGHeroInstance * heroes [ 2 ] , bool creatureBank , const CGTownInstance * town ) ;
2011-02-12 18:12:48 +02:00
bool isInTacticRange ( THex dest ) const ;
2011-03-05 18:38:22 +02:00
int getSurrenderingCost ( int player ) const ;
int theOtherPlayer ( int player ) const ;
ui8 whatSide ( int player ) const ;
2010-12-25 21:23:30 +02:00
} ;
class DLL_EXPORT CStack : public CBonusSystemNode , public CStackBasicDescriptor
{
public :
const CStackInstance * base ;
ui32 ID ; //unique ID of stack
ui32 baseAmount ;
ui32 firstHPleft ; //HP of first creature in stack
ui8 owner , slot ; //owner - player colour (255 for neutrals), slot - position in garrison (may be 255 for neutrals/called creatures)
ui8 attackerOwned ; //if true, this stack is owned by attakcer (this one from left hand side of battle)
THex position ; //position on battlefield; -2 - keep, -3 - lower tower, -4 - upper tower
ui8 counterAttacks ; //how many counter attacks can be performed more in this turn (by default set at the beginning of the round to 1)
si16 shots ; //how many shots left
2011-07-08 17:54:20 +03:00
ui8 casts ; //how many casts left
2010-12-25 21:23:30 +02:00
std : : set < ECombatInfo > state ;
//overrides
const CCreature * getCreature ( ) const { return type ; }
CStack ( const CStackInstance * base , int O , int I , bool AO , int S ) ; //c-tor
CStack ( const CStackBasicDescriptor * stack , int O , int I , bool AO , int S = 255 ) ; //c-tor
CStack ( ) ; //c-tor
~ CStack ( ) ;
std : : string nodeName ( ) const OVERRIDE ;
void init ( ) ; //set initial (invalid) values
void postInit ( ) ; //used to finish initialization when inheriting creature parameters is working
const Bonus * getEffect ( ui16 id , int turn = 0 ) const ; //effect id (SP)
ui8 howManyEffectsSet ( ui16 id ) const ; //returns amount of effects with given id set for this stack
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
2010-12-25 21:23:30 +02:00
bool moved ( int turn = 0 ) const ; //if stack was already moved this turn
bool canMove ( int turn = 0 ) const ; //if stack can move
ui32 Speed ( int turn = 0 ) const ; //get speed of creature with all modificators
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
const CGHeroInstance * getMyHero ( ) const ; //if stack belongs to hero (directly or was by him summoned) returns hero, NULL otherwise
2011-01-20 21:57:12 +02:00
static inline Bonus featureGenerator ( Bonus : : BonusType type , si16 subtype , si32 value , ui16 turnsRemain , si32 additionalInfo = 0 , si32 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 ;
hb . source = Bonus : : SPELL_EFFECT ;
2010-12-25 21:23:30 +02:00
return hb ;
}
2011-01-20 21:57:12 +02:00
static inline Bonus featureGeneratorVT ( Bonus : : BonusType type , si16 subtype , si32 value , ui16 turnsRemain , ui8 valType )
2010-12-25 21:23:30 +02:00
{
2011-01-20 21:57:12 +02:00
Bonus ret = makeFeatureVal ( type , Bonus : : N_TURNS , subtype , value , Bonus : : SPELL_EFFECT , turnsRemain ) ;
ret . valType = valType ;
ret . source = Bonus : : SPELL_EFFECT ;
2010-12-25 21:23:30 +02:00
return ret ;
}
2011-01-08 20:33:40 +02:00
static bool isMeleeAttackPossible ( const CStack * attacker , const CStack * defender , THex attackerPos = THex : : INVALID , THex defenderPos = THex : : INVALID ) ;
2010-12-25 21:23:30 +02:00
bool doubleWide ( ) const ;
2011-01-09 19:41:46 +02:00
THex occupiedHex ( ) const ; //returns number of occupied hex (not the position) if stack is double wide; otherwise -1
2011-07-03 08:55:57 +03:00
std : : vector < THex > getHexes ( ) const ; //up to two occupied hexes, starting from front
2011-07-03 22:10:36 +03:00
bool coversPos ( THex position ) const ; //checks also if unit is double-wide
2011-09-10 16:04:20 +03:00
std : : vector < THex > getSurroundingHexes ( THex attackerPos = THex : : INVALID ) const ; // get six or 8 surrounding hexes depending on creature size
2010-12-25 21:23:30 +02:00
2011-01-08 20:33:40 +02:00
void prepareAttacked ( BattleStackAttacked & bsa ) const ; //requires bsa.damageAmout filled
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 ) ;
h & ID & baseAmount & firstHPleft & owner & slot & attackerOwned & position & state & counterAttacks
2011-07-08 17:54:20 +03:00
& shots & casts & count ;
2010-12-25 21:23:30 +02:00
TSlot slot = ( base ? base - > armyObj - > findStack ( base ) : - 1 ) ;
const CArmedInstance * army = ( base ? base - > armyObj : NULL ) ;
if ( h . saving )
{
h & army & slot ;
}
else
{
h & army & slot ;
if ( ! army | | slot = = - 1 | | ! army - > hasStackAtSlot ( slot ) )
{
base = NULL ;
2011-06-19 02:56:48 +03:00
tlog3 < < type - > nameSing < < " doesn't have a base stack! \n " ;
2010-12-25 21:23:30 +02:00
}
else
{
base = & army - > getStack ( slot ) ;
}
}
}
bool alive ( ) const //determines if stack is alive
{
return vstd : : contains ( state , ALIVE ) ;
}
} ;
class DLL_EXPORT CMP_stack
{
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 ) ;
} ;