2023-10-19 16:19:09 +02:00
/*
* CGameHandler . 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 <vcmi/Environment.h>
# include "../lib/IGameCallback.h"
# include "../lib/LoadProgress.h"
# include "../lib/ScriptHandler.h"
# include "TurnTimerHandler.h"
VCMI_LIB_NAMESPACE_BEGIN
struct SideInBattle ;
class IMarket ;
class SpellCastEnvironment ;
class CConnection ;
class CCommanderInstance ;
class EVictoryLossCheckResult ;
struct CPack ;
struct CPackForServer ;
struct NewTurn ;
struct CGarrisonOperationPack ;
struct SetResources ;
struct NewStructures ;
# if SCRIPTING_ENABLED
namespace scripting
{
class PoolImpl ;
}
# endif
template < typename T > class CApplier ;
VCMI_LIB_NAMESPACE_END
class HeroPoolProcessor ;
class CVCMIServer ;
class CBaseForGHApply ;
class PlayerMessageProcessor ;
class BattleProcessor ;
class TurnOrderProcessor ;
class QueriesProcessor ;
class CObjectVisitQuery ;
class CGameHandler : public IGameCallback , public Environment
{
CVCMIServer * lobby ;
std : : shared_ptr < CApplier < CBaseForGHApply > > applier ;
public :
std : : unique_ptr < HeroPoolProcessor > heroPool ;
std : : unique_ptr < BattleProcessor > battles ;
std : : unique_ptr < QueriesProcessor > queries ;
std : : unique_ptr < TurnOrderProcessor > turnOrder ;
//use enums as parameters, because doMove(sth, true, false, true) is not readable
enum EGuardLook { CHECK_FOR_GUARDS , IGNORE_GUARDS } ;
enum EVisitDest { VISIT_DEST , DONT_VISIT_DEST } ;
enum ELEaveTile { LEAVING_TILE , REMAINING_ON_TILE } ;
std : : unique_ptr < PlayerMessageProcessor > playerMessages ;
std : : map < PlayerColor , std : : set < std : : shared_ptr < CConnection > > > connections ; //player color -> connection to client with interface of that player
//queries stuff
ui32 QID ;
SpellCastEnvironment * spellEnv ;
TurnTimerHandler turnTimerHandler ;
const Services * services ( ) const override ;
const BattleCb * battle ( const BattleID & battleID ) const override ;
const GameCb * game ( ) const override ;
vstd : : CLoggerBase * logger ( ) const override ;
events : : EventBus * eventBus ( ) const override ;
CVCMIServer * gameLobby ( ) const ;
bool isValidObject ( const CGObjectInstance * obj ) const ;
bool isBlockedByQueries ( const CPack * pack , PlayerColor player ) ;
bool isAllowedExchange ( ObjectInstanceID id1 , ObjectInstanceID id2 ) ;
void giveSpells ( const CGTownInstance * t , const CGHeroInstance * h ) ;
2023-12-17 19:31:32 +02:00
explicit CGameHandler ( CVCMIServer * lobby ) ;
2023-10-19 16:19:09 +02:00
~ CGameHandler ( ) ;
//////////////////////////////////////////////////////////////////////////
//from IGameCallback
//do sth
void changeSpells ( const CGHeroInstance * hero , bool give , const std : : set < SpellID > & spells ) override ;
bool removeObject ( const CGObjectInstance * obj , const PlayerColor & initiator ) override ;
2023-11-06 18:27:16 +02:00
void createObject ( const int3 & visitablePosition , const PlayerColor & initiator , MapObjectID type , MapObjectSubID subtype ) override ;
2023-10-19 16:19:09 +02:00
void setOwner ( const CGObjectInstance * obj , PlayerColor owner ) override ;
2024-01-04 23:57:36 +02:00
void giveExperience ( const CGHeroInstance * hero , TExpType val ) override ;
2023-10-19 16:19:09 +02:00
void changePrimSkill ( const CGHeroInstance * hero , PrimarySkill which , si64 val , bool abs = false ) override ;
void changeSecSkill ( const CGHeroInstance * hero , SecondarySkill which , int val , bool abs = false ) override ;
void showBlockingDialog ( BlockingDialog * iw ) override ;
void showTeleportDialog ( TeleportDialog * iw ) override ;
void showGarrisonDialog ( ObjectInstanceID upobj , ObjectInstanceID hid , bool removableUnits ) override ;
void showObjectWindow ( const CGObjectInstance * object , EOpenWindowMode window , const CGHeroInstance * visitor , bool addQuery ) override ;
void giveResource ( PlayerColor player , GameResID which , int val ) override ;
void giveResources ( PlayerColor player , TResources resources ) override ;
void giveCreatures ( const CArmedInstance * objid , const CGHeroInstance * h , const CCreatureSet & creatures , bool remove ) override ;
void takeCreatures ( ObjectInstanceID objid , const std : : vector < CStackBasicDescriptor > & creatures ) override ;
bool changeStackType ( const StackLocation & sl , const CCreature * c ) override ;
bool changeStackCount ( const StackLocation & sl , TQuantity count , bool absoluteValue = false ) override ;
bool insertNewStack ( const StackLocation & sl , const CCreature * c , TQuantity count ) override ;
bool eraseStack ( const StackLocation & sl , bool forceRemoval = false ) override ;
bool swapStacks ( const StackLocation & sl1 , const StackLocation & sl2 ) override ;
bool addToSlot ( const StackLocation & sl , const CCreature * c , TQuantity count ) override ;
void tryJoiningArmy ( const CArmedInstance * src , const CArmedInstance * dst , bool removeObjWhenFinished , bool allowMerging ) override ;
bool moveStack ( const StackLocation & src , const StackLocation & dst , TQuantity count = - 1 ) override ;
void removeAfterVisit ( const CGObjectInstance * object ) override ;
bool giveHeroNewArtifact ( const CGHeroInstance * h , const CArtifact * artType , ArtifactPosition pos = ArtifactPosition : : FIRST_AVAILABLE ) override ;
2023-11-08 19:54:02 +02:00
bool putArtifact ( const ArtifactLocation & al , const CArtifactInstance * art , std : : optional < bool > askAssemble ) override ;
2023-10-19 16:19:09 +02:00
void removeArtifact ( const ArtifactLocation & al ) override ;
2023-10-14 21:00:39 +02:00
bool moveArtifact ( const ArtifactLocation & src , const ArtifactLocation & dst ) override ;
2024-01-16 16:22:40 +02:00
bool bulkMoveArtifacts ( ObjectInstanceID srcId , ObjectInstanceID dstId , bool swap , bool equipped , bool backpack ) ;
2023-10-19 16:19:09 +02:00
bool eraseArtifactByClient ( const ArtifactLocation & al ) ;
void synchronizeArtifactHandlerLists ( ) ;
void heroVisitCastle ( const CGTownInstance * obj , const CGHeroInstance * hero ) override ;
void stopHeroVisitCastle ( const CGTownInstance * obj , const CGHeroInstance * hero ) override ;
void startBattlePrimary ( const CArmedInstance * army1 , const CArmedInstance * army2 , int3 tile , const CGHeroInstance * hero1 , const CGHeroInstance * hero2 , bool creatureBank = false , const CGTownInstance * town = nullptr ) override ; //use hero=nullptr for no hero
void startBattleI ( const CArmedInstance * army1 , const CArmedInstance * army2 , int3 tile , bool creatureBank = false ) override ; //if any of armies is hero, hero will be used
void startBattleI ( const CArmedInstance * army1 , const CArmedInstance * army2 , bool creatureBank = false ) override ; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle
bool moveHero ( ObjectInstanceID hid , int3 dst , ui8 teleporting , bool transit = false , PlayerColor asker = PlayerColor : : NEUTRAL ) override ;
void giveHeroBonus ( GiveBonus * bonus ) override ;
void setMovePoints ( SetMovePoints * smp ) override ;
2024-01-15 22:25:52 +02:00
void setMovePoints ( ObjectInstanceID hid , int val , bool absolute ) override ;
2023-10-19 16:19:09 +02:00
void setManaPoints ( ObjectInstanceID hid , int val ) override ;
void giveHero ( ObjectInstanceID id , PlayerColor player , ObjectInstanceID boatId = ObjectInstanceID ( ) ) override ;
void changeObjPos ( ObjectInstanceID objid , int3 newPos , const PlayerColor & initiator ) override ;
void heroExchange ( ObjectInstanceID hero1 , ObjectInstanceID hero2 ) override ;
2023-10-22 17:36:41 +02:00
void changeFogOfWar ( int3 center , ui32 radius , PlayerColor player , ETileVisibility mode ) override ;
void changeFogOfWar ( std : : unordered_set < int3 > & tiles , PlayerColor player , ETileVisibility mode ) override ;
2023-10-19 16:19:09 +02:00
void castSpell ( const spells : : Caster * caster , SpellID spellID , const int3 & pos ) override ;
/// Returns hero that is currently visiting this object, or nullptr if no visit is active
const CGHeroInstance * getVisitingHero ( const CGObjectInstance * obj ) ;
2024-02-29 00:13:51 +02:00
const CGObjectInstance * getVisitingObject ( const CGHeroInstance * hero ) ;
2023-10-19 16:19:09 +02:00
bool isVisitCoveredByAnotherQuery ( const CGObjectInstance * obj , const CGHeroInstance * hero ) override ;
2023-11-06 18:27:16 +02:00
void setObjPropertyValue ( ObjectInstanceID objid , ObjProperty prop , int32_t value ) override ;
void setObjPropertyID ( ObjectInstanceID objid , ObjProperty prop , ObjPropertyID identifier ) override ;
2023-10-19 16:19:09 +02:00
void showInfoDialog ( InfoWindow * iw ) override ;
void showInfoDialog ( const std : : string & msg , PlayerColor player ) override ;
//////////////////////////////////////////////////////////////////////////
void useScholarSkill ( ObjectInstanceID hero1 , ObjectInstanceID hero2 ) ;
void setPortalDwelling ( const CGTownInstance * town , bool forced , bool clear ) ;
void visitObjectOnTile ( const TerrainTile & t , const CGHeroInstance * h ) ;
bool teleportHero ( ObjectInstanceID hid , ObjectInstanceID dstid , ui8 source , PlayerColor asker = PlayerColor : : NEUTRAL ) ;
void visitCastleObjects ( const CGTownInstance * obj , const CGHeroInstance * hero ) override ;
void levelUpHero ( const CGHeroInstance * hero , SecondarySkill skill ) ; //handle client respond and send one more request if needed
void levelUpHero ( const CGHeroInstance * hero ) ; //initial call - check if hero have remaining levelups & handle them
void levelUpCommander ( const CCommanderInstance * c , int skill ) ; //secondary skill 1 to 6, special skill : skill - 100
void levelUpCommander ( const CCommanderInstance * c ) ;
void expGiven ( const CGHeroInstance * hero ) ; //triggers needed level-ups, handles also commander of this hero
//////////////////////////////////////////////////////////////////////////
void init ( StartInfo * si , Load : : ProgressAccumulator & progressTracking ) ;
void handleClientDisconnection ( std : : shared_ptr < CConnection > c ) ;
void handleReceivedPack ( CPackForServer * pack ) ;
bool hasPlayerAt ( PlayerColor player , std : : shared_ptr < CConnection > c ) const ;
bool hasBothPlayersAtSameConnection ( PlayerColor left , PlayerColor right ) const ;
bool queryReply ( QueryID qid , std : : optional < int32_t > reply , PlayerColor player ) ;
bool buildBoat ( ObjectInstanceID objid , PlayerColor player ) ;
2023-11-06 18:27:16 +02:00
bool setFormation ( ObjectInstanceID hid , EArmyFormation formation ) ;
bool tradeResources ( const IMarket * market , ui32 amountToSell , PlayerColor player , GameResID toSell , GameResID toBuy ) ;
2023-10-19 16:19:09 +02:00
bool sacrificeCreatures ( const IMarket * market , const CGHeroInstance * hero , const std : : vector < SlotID > & slot , const std : : vector < ui32 > & count ) ;
bool sendResources ( ui32 val , PlayerColor player , GameResID r1 , PlayerColor r2 ) ;
bool sellCreatures ( ui32 count , const IMarket * market , const CGHeroInstance * hero , SlotID slot , GameResID resourceID ) ;
bool transformInUndead ( const IMarket * market , const CGHeroInstance * hero , SlotID slot ) ;
bool assembleArtifacts ( ObjectInstanceID heroID , ArtifactPosition artifactSlot , bool assemble , ArtifactID assembleTo ) ;
bool buyArtifact ( ObjectInstanceID hid , ArtifactID aid ) ; //for blacksmith and mage guild only -> buying for gold in common buildings
bool buyArtifact ( const IMarket * m , const CGHeroInstance * h , GameResID rid , ArtifactID aid ) ; //for artifact merchant and black market -> buying for any resource in special building / advobject
bool sellArtifact ( const IMarket * m , const CGHeroInstance * h , ArtifactInstanceID aid , GameResID rid ) ; //for artifact merchant selling
//void lootArtifacts (TArtHolder source, TArtHolder dest, std::vector<ui32> &arts); //after battle - move al arts to winer
bool buySecSkill ( const IMarket * m , const CGHeroInstance * h , SecondarySkill skill ) ;
bool garrisonSwap ( ObjectInstanceID tid ) ;
bool swapGarrisonOnSiege ( ObjectInstanceID tid ) override ;
bool upgradeCreature ( ObjectInstanceID objid , SlotID pos , CreatureID upgID ) ;
bool recruitCreatures ( ObjectInstanceID objid , ObjectInstanceID dst , CreatureID crid , ui32 cram , si32 level , PlayerColor player ) ;
bool buildStructure ( ObjectInstanceID tid , BuildingID bid , bool force = false ) ; //force - for events: no cost, no checkings
bool razeStructure ( ObjectInstanceID tid , BuildingID bid ) ;
bool disbandCreature ( ObjectInstanceID id , SlotID pos ) ;
bool arrangeStacks ( ObjectInstanceID id1 , ObjectInstanceID id2 , ui8 what , SlotID p1 , SlotID p2 , si32 val , PlayerColor player ) ;
bool bulkMoveArmy ( ObjectInstanceID srcArmy , ObjectInstanceID destArmy , SlotID srcSlot ) ;
bool bulkSplitStack ( SlotID src , ObjectInstanceID srcOwner , si32 howMany ) ;
bool bulkMergeStacks ( SlotID slotSrc , ObjectInstanceID srcOwner ) ;
bool bulkSmartSplitStack ( SlotID slotSrc , ObjectInstanceID srcOwner ) ;
void save ( const std : : string & fname ) ;
bool load ( const std : : string & fname ) ;
void onPlayerTurnStarted ( PlayerColor which ) ;
void onPlayerTurnEnded ( PlayerColor which ) ;
void onNewTurn ( ) ;
void handleTimeEvents ( ) ;
void handleTownEvents ( CGTownInstance * town , NewTurn & n ) ;
bool complain ( const std : : string & problem ) ; //sends message to all clients, prints on the logs and return true
void objectVisited ( const CGObjectInstance * obj , const CGHeroInstance * h ) ;
void objectVisitEnded ( const CObjectVisitQuery & query ) ;
bool dig ( const CGHeroInstance * h ) ;
void moveArmy ( const CArmedInstance * src , const CArmedInstance * dst , bool allowMerging ) ;
2024-01-20 20:34:51 +02:00
template < typename Handler > void serialize ( Handler & h )
2023-10-19 16:19:09 +02:00
{
h & QID ;
h & getRandomGenerator ( ) ;
h & * battles ;
h & * heroPool ;
h & * playerMessages ;
h & * turnOrder ;
# if SCRIPTING_ENABLED
JsonNode scriptsState ;
if ( h . saving )
serverScripts - > serializeState ( h . saving , scriptsState ) ;
h & scriptsState ;
if ( ! h . saving )
serverScripts - > serializeState ( h . saving , scriptsState ) ;
# endif
}
void sendToAllClients ( CPackForClient * pack ) ;
void sendAndApply ( CPackForClient * pack ) override ;
void sendAndApply ( CGarrisonOperationPack * pack ) ;
void sendAndApply ( SetResources * pack ) ;
void sendAndApply ( NewStructures * pack ) ;
void wrongPlayerMessage ( CPackForServer * pack , PlayerColor expectedplayer ) ;
/// Unconditionally throws with "Action not allowed" message
2024-01-13 19:39:45 +02:00
[[noreturn]] void throwNotAllowedAction ( CPackForServer * pack ) ;
2023-10-19 16:19:09 +02:00
/// Throws if player stated in pack is not making turn right now
void throwIfPlayerNotActive ( CPackForServer * pack ) ;
/// Throws if object is not owned by pack sender
void throwIfWrongOwner ( CPackForServer * pack , ObjectInstanceID id ) ;
/// Throws if player is not present on connection of this pack
void throwIfWrongPlayer ( CPackForServer * pack , PlayerColor player ) ;
void throwIfWrongPlayer ( CPackForServer * pack ) ;
2024-01-13 19:39:45 +02:00
[[noreturn]] void throwAndComplain ( CPackForServer * pack , std : : string txt ) ;
2023-10-19 16:19:09 +02:00
bool isPlayerOwns ( CPackForServer * pack , ObjectInstanceID id ) ;
2023-11-18 16:34:18 +02:00
void start ( bool resume ) ;
void tick ( int millisecondsPassed ) ;
2024-01-16 21:54:00 +02:00
bool sacrificeArtifact ( const IMarket * m , const CGHeroInstance * hero , const std : : vector < ArtifactInstanceID > & arts ) ;
2023-10-19 16:19:09 +02:00
void spawnWanderingMonsters ( CreatureID creatureID ) ;
// Check for victory and loss conditions
void checkVictoryLossConditionsForPlayer ( PlayerColor player ) ;
void checkVictoryLossConditions ( const std : : set < PlayerColor > & playerColors ) ;
void checkVictoryLossConditionsForAll ( ) ;
CRandomGenerator & getRandomGenerator ( ) ;
# if SCRIPTING_ENABLED
scripting : : Pool * getGlobalContextPool ( ) const override ;
// scripting::Pool * getContextPool() const override;
# endif
friend class CVCMIServer ;
private :
std : : unique_ptr < events : : EventBus > serverEventBus ;
# if SCRIPTING_ENABLED
std : : shared_ptr < scripting : : PoolImpl > serverScripts ;
# endif
void reinitScripting ( ) ;
void getVictoryLossMessage ( PlayerColor player , const EVictoryLossCheckResult & victoryLossCheckResult , InfoWindow & out ) const ;
const std : : string complainNoCreatures ;
const std : : string complainNotEnoughCreatures ;
const std : : string complainInvalidSlot ;
} ;
class ExceptionNotAllowedAction : public std : : exception
{
} ;