2017-07-13 10:26:03 +02:00
/*
2014-06-05 20:26:50 +03:00
* CGHeroInstance . h , part of VCMI engine
2014-06-05 19:52:14 +03:00
*
* 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
*
*/
2017-07-13 10:26:03 +02:00
# pragma once
# include "CObjectHandler.h"
# include "CArmedInstance.h"
# include "../spells/Magic.h"
# include "../CArtHandler.h" // For CArtifactSet
# include "../CRandomGenerator.h"
2014-06-05 19:52:14 +03:00
class CHero ;
class CGBoat ;
2014-06-25 17:11:07 +03:00
class CGTownInstance ;
2016-01-27 12:47:42 +02:00
class CMap ;
2014-08-11 21:17:17 +03:00
struct TerrainTile ;
2015-11-10 13:26:45 +02:00
struct TurnInfo ;
2014-06-05 19:52:14 +03:00
class CGHeroPlaceholder : public CGObjectInstance
{
public :
//subID stores id of hero type. If it's 0xff then following field is used
ui8 power ;
template < typename Handler > void serialize ( Handler & h , const int version )
{
h & static_cast < CGObjectInstance & > ( * this ) ;
h & power ;
}
} ;
2017-07-20 06:08:49 +02:00
class DLL_LINKAGE CGHeroInstance : public CArmedInstance , public IBoatGenerator , public CArtifactSet , public spells : : Caster
2014-06-05 19:52:14 +03:00
{
2018-01-05 19:21:07 +02:00
// We serialize heroes into JSON for crossover
friend class CCampaignState ;
2018-12-20 23:42:31 +02:00
friend class CMapLoaderH3M ;
private :
std : : set < SpellID > spells ; //known spells (spell IDs)
2014-06-05 19:52:14 +03:00
public :
//////////////////////////////////////////////////////////////////////////
ui8 moveDir ; //format: 123
// 8 4
// 765
mutable ui8 isStanding , tacticFormationEnabled ;
//////////////////////////////////////////////////////////////////////////
ConstTransitivePtr < CHero > type ;
TExpType exp ; //experience points
ui32 level ; //current level of hero
std : : string name ; //may be custom
std : : string biography ; //if custom
si32 portrait ; //may be custom
si32 mana ; // remaining spell points
std : : vector < std : : pair < SecondarySkill , ui8 > > secSkills ; //first - ID of skill, second - level of skill (1 - basic, 2 - adv., 3 - expert); if hero has ability (-1, -1) it meansthat it should have default secondary abilities
ui32 movement ; //remaining movement points
ui8 sex ;
bool inTownGarrison ; // if hero is in town garrison
ConstTransitivePtr < CGTownInstance > visitedTown ; //set if hero is visiting town or in the town garrison
ConstTransitivePtr < CCommanderInstance > commander ;
const CGBoat * boat ; //set to CGBoat when sailing
2016-11-13 12:38:42 +02:00
static const si32 UNINITIALIZED_PORTRAIT = - 1 ;
static const si32 UNINITIALIZED_MANA = - 1 ;
2016-01-27 11:13:33 +02:00
static const ui32 UNINITIALIZED_MOVEMENT = - 1 ;
2014-06-05 19:52:14 +03:00
//std::vector<const CArtifact*> artifacts; //hero's artifacts from bag
//std::map<ui16, const CArtifact*> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
std : : set < ObjectInstanceID > visitedObjects ;
struct DLL_LINKAGE Patrol
{
2016-01-31 17:01:58 +02:00
Patrol ( ) { patrolling = false ; initialPos = int3 ( ) ; patrolRadius = - 1 ; } ;
2014-06-05 19:52:14 +03:00
bool patrolling ;
2015-11-27 10:04:01 +02:00
int3 initialPos ;
2016-01-31 17:01:58 +02:00
ui32 patrolRadius ;
2014-06-05 19:52:14 +03:00
template < typename Handler > void serialize ( Handler & h , const int version )
{
2015-11-28 16:58:59 +02:00
h & patrolling ;
2015-12-06 01:51:54 +02:00
if ( version > = 755 ) //save format backward compatibility
2015-11-28 16:58:59 +02:00
{
h & initialPos ;
}
else if ( ! h . saving )
{
patrolling = false ;
initialPos = int3 ( ) ;
}
2016-01-31 17:01:58 +02:00
h & patrolRadius ;
2014-06-05 19:52:14 +03:00
}
} patrol ;
2017-09-16 00:47:17 +02:00
// deprecated - used only for loading of old saves
struct HeroSpecial : CBonusSystemNode
{
bool growsWithLevel ;
HeroSpecial ( ) { growsWithLevel = false ; } ;
template < typename Handler > void serialize ( Handler & h , const int version )
{
h & static_cast < CBonusSystemNode & > ( * this ) ;
h & growsWithLevel ;
}
} ;
2014-06-05 19:52:14 +03:00
struct DLL_LINKAGE SecondarySkillsInfo
{
//skills are determined, initialized at map start
//FIXME remove mutable
mutable CRandomGenerator rand ;
ui8 magicSchoolCounter ;
ui8 wisdomCounter ;
2016-08-18 17:53:28 +02:00
SecondarySkillsInfo ( ) ;
2014-06-05 19:52:14 +03:00
void resetMagicSchoolCounter ( ) ;
void resetWisdomCounter ( ) ;
template < typename Handler > void serialize ( Handler & h , const int version )
{
2017-07-31 15:35:42 +02:00
h & magicSchoolCounter ;
h & wisdomCounter ;
h & rand ;
2014-06-05 19:52:14 +03:00
}
} skillsInfo ;
2016-01-26 21:24:38 +02:00
inline bool isInitialized ( ) const
{ // has this hero been on the map at least once?
2016-01-27 08:44:04 +02:00
return movement ! = UNINITIALIZED_MOVEMENT & & mana ! = UNINITIALIZED_MANA ;
2016-01-26 21:24:38 +02:00
}
2014-06-24 02:26:36 +03:00
//int3 getSightCenter() const; //"center" tile from which the sight distance is calculated
2016-01-31 17:01:58 +02:00
int getSightRadius ( ) const override ; //sight distance (should be used if player-owned structure)
2014-06-05 19:52:14 +03:00
//////////////////////////////////////////////////////////////////////////
2015-10-12 15:47:10 +02:00
int getBoatType ( ) const override ; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
void getOutOffsets ( std : : vector < int3 > & offsets ) const override ; //offsets to obj pos when we boat can be placed
2014-06-05 19:52:14 +03:00
//////////////////////////////////////////////////////////////////////////
bool hasSpellbook ( ) const ;
2017-08-26 10:49:29 +02:00
int maxSpellLevel ( ) const ;
2018-12-20 23:42:31 +02:00
void addSpellToSpellbook ( SpellID spell ) ;
void removeSpellFromSpellbook ( SpellID spell ) ;
bool spellbookContainsSpell ( SpellID spell ) const ;
void removeSpellbook ( ) ;
const std : : set < SpellID > & getSpellsInSpellbook ( ) const ;
2014-06-05 19:52:14 +03:00
EAlignment : : EAlignment getAlignment ( ) const ;
const std : : string & getBiography ( ) const ;
2015-10-12 15:47:10 +02:00
bool needsLastStack ( ) const override ;
2017-07-15 00:15:08 +02:00
TFaction getFaction ( ) const ;
2015-11-10 13:26:45 +02:00
ui32 getTileCost ( const TerrainTile & dest , const TerrainTile & from , const TurnInfo * ti ) const ; //move cost - applying pathfinding skill, road and terrain modifiers. NOT includes diagonal move penalty, last move levelling
2015-11-21 12:30:39 +02:00
int getNativeTerrain ( ) const ;
2014-06-05 19:52:14 +03:00
ui32 getLowestCreatureSpeed ( ) const ;
int3 getPosition ( bool h3m = false ) const ; //h3m=true - returns position of hero object; h3m=false - returns position of hero 'manifestation'
si32 manaRegain ( ) const ; //how many points of mana can hero regain "naturally" in one day
2016-01-30 09:20:49 +02:00
si32 getManaNewTurn ( ) const ; //calculate how much mana this hero is going to have the next day
2014-06-05 19:52:14 +03:00
int getCurrentLuck ( int stack = - 1 , bool town = false ) const ;
int getSpellCost ( const CSpell * sp ) const ; //do not use during battles -> bonuses from army would be ignored
2016-10-09 12:38:54 +02:00
bool canLearnSpell ( const CSpell * spell ) const ;
2014-06-05 19:52:14 +03:00
// ----- primary and secondary skill, experience, level handling -----
/// Returns true if hero has lower level than should upon his experience.
bool gainsLevel ( ) const ;
/// Returns the next primary skill on level up. Can only be called if hero can gain a level up.
2016-08-23 18:12:10 +02:00
PrimarySkill : : PrimarySkill nextPrimarySkill ( CRandomGenerator & rand ) const ;
2014-06-05 19:52:14 +03:00
/// Returns the next secondary skill randomly on level up. Can only be called if hero can gain a level up.
2016-09-09 19:30:36 +02:00
boost : : optional < SecondarySkill > nextSecondarySkill ( CRandomGenerator & rand ) const ;
2014-06-05 19:52:14 +03:00
/// Gets 0, 1 or 2 secondary skills which are proposed on hero level up.
std : : vector < SecondarySkill > getLevelUpProposedSecondarySkills ( ) const ;
ui8 getSecSkillLevel ( SecondarySkill skill ) const ; //0 - no skill
/// Returns true if hero has free secondary skill slot.
bool canLearnSkill ( ) const ;
void setPrimarySkill ( PrimarySkill : : PrimarySkill primarySkill , si64 value , ui8 abs ) ;
void setSecSkillLevel ( SecondarySkill which , int val , bool abs ) ; // abs == 0 - changes by value; 1 - sets to value
void levelUp ( std : : vector < SecondarySkill > skills ) ;
2019-01-15 07:52:55 +02:00
int maxMovePoints ( bool onLand ) const ;
//cached version is much faster, TurnInfo construction is costly
int maxMovePointsCached ( bool onLand , const TurnInfo * ti ) const ;
2015-11-12 13:04:33 +02:00
int movementPointsAfterEmbark ( int MPsBefore , int basicCost , bool disembark = false , const TurnInfo * ti = nullptr ) const ;
2014-06-05 19:52:14 +03:00
static int3 convertPosition ( int3 src , bool toh3m ) ; //toh3m=true: manifest->h3m; toh3m=false: h3m->manifest
double getFightingStrength ( ) const ; // takes attack / defense skill into account
double getMagicStrength ( ) const ; // takes knowledge / spell power skill into account
double getHeroStrength ( ) const ; // includes fighting and magic strength
ui64 getTotalStrength ( ) const ; // includes fighting strength and army strength
TExpType calculateXp ( TExpType exp ) const ; //apply learning skill
2016-01-24 01:27:14 +02:00
2014-06-05 19:52:14 +03:00
bool canCastThisSpell ( const CSpell * spell ) const ; //determines if this hero can cast given spell; takes into account existing spell in spellbook, existing spellbook and artifact bonuses
CStackBasicDescriptor calculateNecromancy ( const BattleResult & battleResult ) const ;
2016-09-09 19:30:36 +02:00
void showNecromancyDialog ( const CStackBasicDescriptor & raisedStack , CRandomGenerator & rand ) const ;
2015-11-29 11:32:06 +02:00
EDiggingStatus diggingStatus ( ) const ;
2014-06-05 19:52:14 +03:00
//////////////////////////////////////////////////////////////////////////
2015-10-12 15:47:10 +02:00
void setType ( si32 ID , si32 subID ) override ;
2014-06-05 19:52:14 +03:00
2016-09-09 19:30:36 +02:00
void initHero ( CRandomGenerator & rand ) ;
void initHero ( CRandomGenerator & rand , HeroTypeID SUBID ) ;
2014-06-05 19:52:14 +03:00
2016-11-13 12:38:42 +02:00
void putArtifact ( ArtifactPosition pos , CArtifactInstance * art ) override ;
2014-06-05 19:52:14 +03:00
void putInBackpack ( CArtifactInstance * art ) ;
2016-09-09 19:30:36 +02:00
void initExp ( CRandomGenerator & rand ) ;
2016-08-23 07:13:52 +02:00
void initArmy ( CRandomGenerator & rand , IArmyDescriptor * dst = nullptr ) ;
2014-06-05 19:52:14 +03:00
//void giveArtifact (ui32 aid);
void pushPrimSkill ( PrimarySkill : : PrimarySkill which , int val ) ;
ui8 maxlevelsToMagicSchool ( ) const ;
ui8 maxlevelsToWisdom ( ) const ;
void recreateSecondarySkillsBonuses ( ) ;
2018-03-05 09:02:23 +02:00
void updateSkillBonus ( SecondarySkill which , int val ) ;
2016-01-24 01:27:14 +02:00
2015-02-06 16:36:09 +02:00
bool hasVisions ( const CGObjectInstance * target , const int subtype ) const ;
2016-01-27 12:47:42 +02:00
/// If this hero perishes, the scenario is failed
bool isMissionCritical ( ) const ;
2014-06-05 19:52:14 +03:00
CGHeroInstance ( ) ;
virtual ~ CGHeroInstance ( ) ;
2016-01-24 01:27:14 +02:00
2015-03-18 21:22:52 +02:00
///ArtBearer
2014-06-05 19:52:14 +03:00
ArtBearer : : ArtBearer bearerType ( ) const override ;
2015-03-18 21:22:52 +02:00
///IBonusBearer
2014-06-05 19:52:14 +03:00
CBonusSystemNode * whereShouldBeAttached ( CGameState * gs ) override ;
std : : string nodeName ( ) const override ;
2016-01-24 01:27:14 +02:00
2017-07-20 06:08:49 +02:00
///spells::Caster
2018-03-04 10:13:07 +02:00
int32_t getCasterUnitId ( ) const override ;
2017-07-20 06:08:49 +02:00
ui8 getSpellSchoolLevel ( const spells : : Spell * spell , int * outSelectedSchool = nullptr ) const override ;
int64_t getSpellBonus ( const spells : : Spell * spell , int64_t base , const battle : : Unit * affectedStack ) const override ;
int64_t getSpecificSpellBonus ( const spells : : Spell * spell , int64_t base ) const override ;
2016-01-24 01:27:14 +02:00
2017-07-20 06:08:49 +02:00
int getEffectLevel ( const spells : : Spell * spell ) const override ;
2015-09-17 07:42:30 +02:00
2017-07-20 06:08:49 +02:00
int getEffectPower ( const spells : : Spell * spell ) const override ;
2015-09-17 07:42:30 +02:00
2017-07-20 06:08:49 +02:00
int getEnchantPower ( const spells : : Spell * spell ) const override ;
2015-09-17 07:42:30 +02:00
2017-07-20 06:08:49 +02:00
int64_t getEffectValue ( const spells : : Spell * spell ) const override ;
2016-01-24 01:27:14 +02:00
2015-09-17 08:29:57 +02:00
const PlayerColor getOwner ( ) const override ;
2016-01-24 01:27:14 +02:00
2016-09-10 17:23:55 +02:00
void getCasterName ( MetaString & text ) const override ;
2017-07-20 06:08:49 +02:00
void getCastDescription ( const spells : : Spell * spell , const std : : vector < const battle : : Unit * > & attacked , MetaString & text ) const override ;
void spendMana ( const spells : : PacketSender * server , const int spellCost ) const override ;
2016-09-10 17:23:55 +02:00
2014-06-05 19:52:14 +03:00
void deserializationFix ( ) ;
2016-09-09 19:30:36 +02:00
void initObj ( CRandomGenerator & rand ) override ;
2014-06-05 19:52:14 +03:00
void onHeroVisit ( const CGHeroInstance * h ) const override ;
2014-06-24 20:39:36 +03:00
std : : string getObjectName ( ) const override ;
2017-05-28 15:23:42 +02:00
void afterAddToMap ( CMap * map ) override ;
2014-06-05 19:52:14 +03:00
protected :
void setPropertyDer ( ui8 what , ui32 val ) override ; //synchr
2016-11-13 12:38:42 +02:00
///common part of hero instance and hero definition
void serializeCommonOptions ( JsonSerializeFormat & handler ) ;
2016-02-22 01:37:19 +02:00
void serializeJsonOptions ( JsonSerializeFormat & handler ) override ;
2014-06-05 19:52:14 +03:00
private :
2016-09-09 19:30:36 +02:00
void levelUpAutomatically ( CRandomGenerator & rand ) ;
2017-09-15 03:59:04 +02:00
void recreateSpecialtyBonuses ( std : : vector < HeroSpecial * > & specialtyDeprecated ) ;
2014-06-05 19:52:14 +03:00
public :
2016-11-13 12:38:42 +02:00
std : : string getHeroTypeName ( ) const ;
void setHeroTypeName ( const std : : string & identifier ) ;
void serializeJsonDefinition ( JsonSerializeFormat & handler ) ;
2014-06-05 19:52:14 +03:00
template < typename Handler > void serialize ( Handler & h , const int version )
{
h & static_cast < CArmedInstance & > ( * this ) ;
h & static_cast < CArtifactSet & > ( * this ) ;
2017-07-31 15:35:42 +02:00
h & exp ;
h & level ;
h & name ;
h & biography ;
h & portrait ;
h & mana ;
h & secSkills ;
h & movement ;
h & sex ;
h & inTownGarrison ;
h & spells ;
h & patrol ;
h & moveDir ;
h & skillsInfo ;
h & visitedTown ;
h & boat ;
h & type ;
2018-02-18 12:32:52 +02:00
if ( version < 781 )
2017-09-15 03:59:04 +02:00
{
std : : vector < HeroSpecial * > specialtyDeprecated ;
2017-09-10 06:03:02 +02:00
h & specialtyDeprecated ;
2017-09-15 03:59:04 +02:00
if ( ! h . saving )
recreateSpecialtyBonuses ( specialtyDeprecated ) ;
}
2017-07-31 15:35:42 +02:00
h & commander ;
h & visitedObjects ;
2014-06-05 19:52:14 +03:00
BONUS_TREE_DESERIALIZATION_FIX
//visitied town pointer will be restored by map serialization method
2017-08-28 03:56:00 +02:00
if ( version < 777 & & ! h . saving )
recreateSecondarySkillsBonuses ( ) ;
2014-06-05 19:52:14 +03:00
}
} ;