2023-10-19 16:19:09 +02:00
/*
* CGameState . 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
*
*/
# pragma once
# include "bonuses/CBonusSystemNode.h"
# include "IGameCallback.h"
# include "LoadProgress.h"
# include "ConstTransitivePtr.h"
2024-01-31 00:17:40 +02:00
# include "../CRandomGenerator.h"
2023-10-19 16:19:09 +02:00
namespace boost
{
class shared_mutex ;
}
VCMI_LIB_NAMESPACE_BEGIN
class EVictoryLossCheckResult ;
class Services ;
class IMapService ;
class CMap ;
struct CPack ;
class CHeroClass ;
struct EventCondition ;
struct CampaignTravel ;
class CStackInstance ;
class CGameStateCampaign ;
class TavernHeroesPool ;
struct SThievesGuildInfo ;
template < typename T > class CApplier ;
class CBaseForGSApply ;
struct DLL_LINKAGE RumorState
{
enum ERumorType : ui8
{
TYPE_NONE = 0 , TYPE_RAND , TYPE_SPECIAL , TYPE_MAP
} ;
enum ERumorTypeSpecial : ui8
{
RUMOR_OBELISKS = 208 ,
RUMOR_ARTIFACTS = 209 ,
RUMOR_ARMY = 210 ,
RUMOR_INCOME = 211 ,
RUMOR_GRAIL = 212
} ;
ERumorType type ;
std : : map < ERumorType , std : : pair < int , int > > last ;
RumorState ( ) { type = TYPE_NONE ; } ;
bool update ( int id , int extra ) ;
2024-01-20 20:34:51 +02:00
template < typename Handler > void serialize ( Handler & h )
2023-10-19 16:19:09 +02:00
{
h & type ;
h & last ;
}
} ;
struct UpgradeInfo
{
CreatureID oldID ; //creature to be upgraded
std : : vector < CreatureID > newID ; //possible upgrades
std : : vector < ResourceSet > cost ; // cost[upgrade_serial] -> set of pairs<resource_ID,resource_amount>; cost is for single unit (not entire stack)
UpgradeInfo ( ) { oldID = CreatureID : : NONE ; } ;
} ;
class BattleInfo ;
DLL_LINKAGE std : : ostream & operator < < ( std : : ostream & os , const EVictoryLossCheckResult & victoryLossCheckResult ) ;
class DLL_LINKAGE CGameState : public CNonConstInfoCallback
{
friend class CGameStateCampaign ;
public :
2023-11-07 14:27:25 +02:00
/// Stores number of times each artifact was placed on map via randomization
std : : map < ArtifactID , int > allocatedArtifacts ;
2023-10-19 16:19:09 +02:00
/// List of currently ongoing battles
std : : vector < std : : unique_ptr < BattleInfo > > currentBattles ;
/// ID that can be allocated to next battle
BattleID nextBattleID = BattleID ( 0 ) ;
//we have here all heroes available on this map that are not hired
std : : unique_ptr < TavernHeroesPool > heroesPool ;
/// list of players currently making turn. Usually - just one, except for simturns
std : : set < PlayerColor > actingPlayers ;
2024-01-01 16:37:48 +02:00
IGameCallback * callback ;
2023-10-19 16:19:09 +02:00
CGameState ( ) ;
virtual ~ CGameState ( ) ;
2024-01-01 16:37:48 +02:00
void preInit ( Services * services , IGameCallback * callback ) ;
2023-10-19 16:19:09 +02:00
2023-10-22 17:36:41 +02:00
void init ( const IMapService * mapService , StartInfo * si , Load : : ProgressAccumulator & , bool allowSavingRandomMap = true ) ;
2023-10-19 16:19:09 +02:00
void updateOnLoad ( StartInfo * si ) ;
2024-01-10 00:38:54 +02:00
ConstTransitivePtr < StartInfo > scenarioOps ;
ConstTransitivePtr < StartInfo > initialOpts ; //copy of settings received from pregame (not randomized)
2023-10-19 16:19:09 +02:00
ui32 day ; //total number of days in game
ConstTransitivePtr < CMap > map ;
std : : map < PlayerColor , PlayerState > players ;
std : : map < TeamID , TeamState > teams ;
CBonusSystemNode globalEffects ;
RumorState rumor ;
static boost : : shared_mutex mutex ;
void updateEntity ( Metatype metatype , int32_t index , const JsonNode & data ) override ;
bool giveHeroArtifact ( CGHeroInstance * h , const ArtifactID & aid ) ;
2023-10-25 20:56:00 +02:00
/// picks next free hero type of the H3 hero init sequence -> chosen starting hero, then unused hero type randomly
HeroTypeID pickNextHeroType ( const PlayerColor & owner ) ;
2023-10-19 16:19:09 +02:00
void apply ( CPack * pack ) ;
BattleField battleGetBattlefieldType ( int3 tile , CRandomGenerator & rand ) ;
void fillUpgradeInfo ( const CArmedInstance * obj , SlotID stackPos , UpgradeInfo & out ) const override ;
PlayerRelations getPlayerRelations ( PlayerColor color1 , PlayerColor color2 ) const override ;
bool checkForVisitableDir ( const int3 & src , const int3 & dst ) const ; //check if src tile is visitable from dst tile
void calculatePaths ( const CGHeroInstance * hero , CPathsInfo & out ) override ; //calculates possible paths for hero, by default uses current hero position and movement left; returns pointer to newly allocated CPath or nullptr if path does not exists
void calculatePaths ( const std : : shared_ptr < PathfinderConfig > & config ) override ;
int3 guardingCreaturePosition ( int3 pos ) const override ;
std : : vector < CGObjectInstance * > guardingCreatures ( int3 pos ) const ;
void updateRumor ( ) ;
2023-11-07 14:27:25 +02:00
/// Gets a artifact ID randomly and removes the selected artifact from this handler.
ArtifactID pickRandomArtifact ( CRandomGenerator & rand , int flags ) ;
ArtifactID pickRandomArtifact ( CRandomGenerator & rand , std : : function < bool ( ArtifactID ) > accepts ) ;
ArtifactID pickRandomArtifact ( CRandomGenerator & rand , int flags , std : : function < bool ( ArtifactID ) > accepts ) ;
ArtifactID pickRandomArtifact ( CRandomGenerator & rand , std : : set < ArtifactID > filtered ) ;
2023-10-19 16:19:09 +02:00
/// Returns battle in which selected player is engaged, or nullptr if none.
/// Can NOT be used with neutral player, use battle by ID instead
const BattleInfo * getBattle ( const PlayerColor & player ) const ;
/// Returns battle by its unique identifier, or nullptr if not found
const BattleInfo * getBattle ( const BattleID & battle ) const ;
BattleInfo * getBattle ( const BattleID & battle ) ;
// ----- victory, loss condition checks -----
EVictoryLossCheckResult checkForVictoryAndLoss ( const PlayerColor & player ) const ;
bool checkForVictory ( const PlayerColor & player , const EventCondition & condition ) const ; //checks if given player is winner
PlayerColor checkForStandardWin ( ) const ; //returns color of player that accomplished standard victory conditions or 255 (NEUTRAL) if no winner
bool checkForStandardLoss ( const PlayerColor & player ) const ; //checks if given player lost the game
void obtainPlayersStats ( SThievesGuildInfo & tgi , int level ) ; //fills tgi with info about other players that is available at given level of thieves' guild
bool isVisible ( int3 pos , const std : : optional < PlayerColor > & player ) const override ;
bool isVisible ( const CGObjectInstance * obj , const std : : optional < PlayerColor > & player ) const override ;
int getDate ( Date mode = Date : : DAY ) const override ; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month
// ----- getters, setters -----
/// This RNG should only be used inside GS or CPackForClient-derived applyGs
/// If this doesn't work for your code that mean you need a new netpack
///
/// Client-side must use CRandomGenerator::getDefault which is not serialized
///
/// CGameHandler have it's own getter for CRandomGenerator::getDefault
/// Any server-side code outside of GH must use CRandomGenerator::getDefault
CRandomGenerator & getRandomGenerator ( ) ;
2024-01-20 20:34:51 +02:00
template < typename Handler > void serialize ( Handler & h )
2023-10-19 16:19:09 +02:00
{
h & scenarioOps ;
h & initialOpts ;
h & actingPlayers ;
h & day ;
h & map ;
h & players ;
h & teams ;
h & heroesPool ;
h & globalEffects ;
h & rand ;
h & rumor ;
h & campaign ;
2023-11-07 14:27:25 +02:00
h & allocatedArtifacts ;
2023-10-19 16:19:09 +02:00
BONUS_TREE_DESERIALIZATION_FIX
}
private :
// ----- initialization -----
void initNewGame ( const IMapService * mapService , bool allowSavingRandomMap , Load : : ProgressAccumulator & progressTracking ) ;
void checkMapChecksum ( ) ;
void initGlobalBonuses ( ) ;
void initGrailPosition ( ) ;
void initRandomFactionsForPlayers ( ) ;
void randomizeMapObjects ( ) ;
void initPlayerStates ( ) ;
void placeStartingHeroes ( ) ;
void placeStartingHero ( const PlayerColor & playerColor , const HeroTypeID & heroTypeId , int3 townPos ) ;
void removeHeroPlaceholders ( ) ;
void initDifficulty ( ) ;
void initHeroes ( ) ;
void placeHeroesInTowns ( ) ;
void initFogOfWar ( ) ;
void initStartingBonus ( ) ;
void initTowns ( ) ;
2024-02-19 00:36:08 +02:00
void initTownNames ( ) ;
2023-10-19 16:19:09 +02:00
void initMapObjects ( ) ;
void initVisitingAndGarrisonedHeroes ( ) ;
void initCampaign ( ) ;
// ----- bonus system handling -----
void buildBonusSystemTree ( ) ;
void attachArmedObjects ( ) ;
void buildGlobalTeamPlayerTree ( ) ;
void deserializationFix ( ) ;
// ---- misc helpers -----
CGHeroInstance * getUsedHero ( const HeroTypeID & hid ) const ;
bool isUsedHero ( const HeroTypeID & hid ) const ; //looks in heroes and prisons
std : : set < HeroTypeID > getUnusedAllowedHeroes ( bool alsoIncludeNotAllowed = false ) const ;
HeroTypeID pickUnusedHeroTypeRandomly ( const PlayerColor & owner ) ; // picks a unused hero type randomly
UpgradeInfo fillUpgradeInfo ( const CStackInstance & stack ) const ;
// ---- data -----
std : : shared_ptr < CApplier < CBaseForGSApply > > applier ;
CRandomGenerator rand ;
Services * services ;
/// Ponter to campaign state manager. Nullptr for single scenarios
std : : unique_ptr < CGameStateCampaign > campaign ;
friend class IGameCallback ;
friend class CMapHandler ;
friend class CGameHandler ;
} ;
VCMI_LIB_NAMESPACE_END