2017-07-13 11:26:03 +03:00
/*
* NetPacksClient.cpp, 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
*
*/
2011-12-13 21:23:17 +00:00
#include "StdInc.h"
2023-02-12 09:23:39 +02:00
#include "ClientNetPackVisitors.h"
2011-12-13 21:23:17 +00:00
2009-05-20 10:08:56 +00:00
#include "Client.h"
#include "CPlayerInterface.h"
#include "CGameInfo.h"
2023-02-01 20:42:06 +02:00
#include "windows/GUIClasses.h"
2023-03-01 12:31:23 +02:00
#include "mapView/mapHandler.h"
2023-02-01 20:42:06 +02:00
#include "adventureMap/CInGameConsole.h"
#include "battle/BattleInterface.h"
#include "gui/CGuiHandler.h"
#include "widgets/MiscWidgets.h"
#include "CMT.h"
#include "CServerHandler.h"
#include "../CCallback.h"
#include "../lib/filesystem/Filesystem.h"
#include "../lib/filesystem/FileInfo.h"
2016-09-10 03:32:40 +03:00
#include "../lib/serializer/Connection.h"
#include "../lib/serializer/BinarySerializer.h"
2010-12-20 21:22:53 +00:00
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CHeroHandler.h"
2009-03-07 15:55:56 +00:00
#include "../lib/VCMI_Lib.h"
2013-04-07 10:48:07 +00:00
#include "../lib/mapping/CMap.h"
2009-10-10 05:47:59 +00:00
#include "../lib/VCMIDirs.h"
2015-02-02 11:25:26 +03:00
#include "../lib/spells/CSpellHandler.h"
2014-06-05 23:51:24 +03:00
#include "../lib/CSoundBase.h"
2014-06-25 17:11:07 +03:00
#include "../lib/StartInfo.h"
2012-09-29 10:59:43 +00:00
#include "../lib/CConfigHandler.h"
2023-06-02 21:47:37 +03:00
#include "../lib/mapObjects/CGMarket.h"
2013-04-07 10:48:07 +00:00
#include "../lib/mapping/CCampaignHandler.h"
2010-12-25 19:23:30 +00:00
#include "../lib/CGameState.h"
2017-03-17 16:48:44 +01:00
#include "../lib/CStack.h"
2017-06-24 16:42:05 +02:00
#include "../lib/battle/BattleInfo.h"
2011-12-13 21:23:17 +00:00
#include "../lib/GameConstants.h"
2015-12-02 21:39:53 +02:00
#include "../lib/CPlayerState.h"
2009-03-07 15:55:56 +00:00
2018-02-03 17:44:30 +03:00
// TODO: as Tow suggested these template should all be part of CClient
// This will require rework spectator interface properly though
2011-05-29 23:49:25 +00:00
2018-02-03 17:44:30 +03:00
template < typename T , typename ... Args , typename ... Args2 >
2023-02-12 09:23:39 +02:00
bool callOnlyThatInterface ( CClient & cl , PlayerColor player , void ( T ::* ptr )( Args ...), Args2 && ... args )
2018-02-03 17:44:30 +03:00
{
2023-02-12 09:23:39 +02:00
if ( vstd :: contains ( cl . playerint , player ))
2018-02-03 17:44:30 +03:00
{
2023-02-12 09:23:39 +02:00
(( * cl . playerint [ player ]). * ptr )( std :: forward < Args2 > ( args )...);
2018-02-03 17:44:30 +03:00
return true ;
}
return false ;
}
2011-05-09 22:20:47 +00:00
2018-02-03 17:44:30 +03:00
template < typename T , typename ... Args , typename ... Args2 >
2023-02-12 09:23:39 +02:00
bool callInterfaceIfPresent ( CClient & cl , PlayerColor player , void ( T ::* ptr )( Args ...), Args2 && ... args )
2018-02-03 17:44:30 +03:00
{
bool called = callOnlyThatInterface ( cl , player , ptr , std :: forward < Args2 > ( args )...);
return called ;
}
2011-05-09 22:20:47 +00:00
2018-02-03 17:44:30 +03:00
template < typename T , typename ... Args , typename ... Args2 >
2023-02-12 09:23:39 +02:00
void callOnlyThatBattleInterface ( CClient & cl , PlayerColor player , void ( T ::* ptr )( Args ...), Args2 && ... args )
2018-02-03 17:44:30 +03:00
{
2023-02-12 09:23:39 +02:00
if ( vstd :: contains ( cl . battleints , player ))
(( * cl . battleints [ player ]). * ptr )( std :: forward < Args2 > ( args )...);
2011-05-09 22:20:47 +00:00
2023-02-12 09:23:39 +02:00
if ( cl . additionalBattleInts . count ( player ))
2018-02-03 17:44:30 +03:00
{
2023-02-12 09:23:39 +02:00
for ( auto bInt : cl . additionalBattleInts [ player ])
2018-02-03 17:44:30 +03:00
(( * bInt ). * ptr )( std :: forward < Args2 > ( args )...);
}
}
2009-03-07 15:55:56 +00:00
2018-02-03 17:44:30 +03:00
template < typename T , typename ... Args , typename ... Args2 >
2023-02-12 09:23:39 +02:00
void callBattleInterfaceIfPresent ( CClient & cl , PlayerColor player , void ( T ::* ptr )( Args ...), Args2 && ... args )
2018-02-03 17:44:30 +03:00
{
callOnlyThatInterface ( cl , player , ptr , std :: forward < Args2 > ( args )...);
}
2011-05-29 23:49:25 +00:00
2018-02-03 17:44:30 +03:00
//calls all normal interfaces and privileged ones, playerints may be updated when iterating over it, so we need a copy
template < typename T , typename ... Args , typename ... Args2 >
2023-02-12 09:23:39 +02:00
void callAllInterfaces ( CClient & cl , void ( T ::* ptr )( Args ...), Args2 && ... args )
2018-02-03 17:44:30 +03:00
{
2023-02-12 09:23:39 +02:00
for ( auto pInt : cl . playerint )
2018-02-03 17:44:30 +03:00
(( * pInt . second ). * ptr )( std :: forward < Args2 > ( args )...);
}
//calls all normal interfaces and privileged ones, playerints may be updated when iterating over it, so we need a copy
template < typename T , typename ... Args , typename ... Args2 >
2023-02-12 09:23:39 +02:00
void callBattleInterfaceIfPresentForBothSides ( CClient & cl , void ( T ::* ptr )( Args ...), Args2 && ... args )
2018-02-03 17:44:30 +03:00
{
2023-02-12 09:23:39 +02:00
callOnlyThatBattleInterface ( cl , cl . gameState () -> curB -> sides [ 0 ]. color , ptr , std :: forward < Args2 > ( args )...);
callOnlyThatBattleInterface ( cl , cl . gameState () -> curB -> sides [ 1 ]. color , ptr , std :: forward < Args2 > ( args )...);
2018-02-03 17:44:30 +03:00
if ( settings [ "session" ][ "spectate" ]. Bool () && ! settings [ "session" ][ "spectate-skip-battle" ]. Bool () && LOCPLINT -> battleInt )
{
callOnlyThatBattleInterface ( cl , PlayerColor :: SPECTATOR , ptr , std :: forward < Args2 > ( args )...);
}
}
2011-05-29 23:49:25 +00:00
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitSetResources ( SetResources & pack )
2009-03-07 15:55:56 +00:00
{
2016-11-26 15:14:43 +03:00
//todo: inform on actual resource set transfered
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , pack . player , & IGameEventsReceiver :: receivedResource );
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitSetPrimSkill ( SetPrimSkill & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
const CGHeroInstance * h = cl . getHero ( pack . id );
2009-03-19 14:17:19 +00:00
if ( ! h )
{
2023-02-12 09:23:39 +02:00
logNetwork -> error ( "Cannot find hero with pack.id %d" , pack . id . getNum ());
2009-03-19 14:17:19 +00:00
return ;
}
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , h -> tempOwner , & IGameEventsReceiver :: heroPrimarySkillChanged , h , pack . which , pack . val );
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitSetSecSkill ( SetSecSkill & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
const CGHeroInstance * h = cl . getHero ( pack . id );
2010-07-20 14:08:13 +00:00
if ( ! h )
{
2023-02-12 09:23:39 +02:00
logNetwork -> error ( "Cannot find hero with pack.id %d" , pack . id . getNum ());
2010-07-20 14:08:13 +00:00
return ;
}
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , h -> tempOwner , & IGameEventsReceiver :: heroSecondarySkillChanged , h , pack . which , pack . val );
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitHeroVisitCastle ( HeroVisitCastle & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
const CGHeroInstance * h = cl . getHero ( pack . hid );
if ( pack . start ())
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , h -> tempOwner , & IGameEventsReceiver :: heroVisitsTown , h , gs . getTown ( pack . tid ));
2009-03-07 15:55:56 +00:00
}
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitSetMana ( SetMana & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
const CGHeroInstance * h = cl . getHero ( pack . hid );
2018-02-03 17:44:30 +03:00
callInterfaceIfPresent ( cl , h -> tempOwner , & IGameEventsReceiver :: heroManaPointsChanged , h );
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitSetMovePoints ( SetMovePoints & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
const CGHeroInstance * h = cl . getHero ( pack . hid );
cl . invalidatePaths ();
2018-02-03 17:44:30 +03:00
callInterfaceIfPresent ( cl , h -> tempOwner , & IGameEventsReceiver :: heroMovePointsChanged , h );
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitFoWChange ( FoWChange & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
for ( auto & i : cl . playerint )
2014-06-21 17:41:05 +04:00
{
2023-02-12 09:23:39 +02:00
if ( cl . getPlayerRelations ( i . first , pack . player ) == PlayerRelations :: SAME_PLAYER && pack . waitForDialogs && LOCPLINT == i . second . get ())
2014-06-21 17:41:05 +04:00
{
LOCPLINT -> waitWhileDialog ();
}
2023-02-12 09:23:39 +02:00
if ( cl . getPlayerRelations ( i . first , pack . player ) != PlayerRelations :: ENEMIES )
2012-02-20 21:01:54 +00:00
{
2023-02-12 09:23:39 +02:00
if ( pack . mode )
i . second -> tileRevealed ( pack . tiles );
2012-02-20 21:01:54 +00:00
else
2023-02-12 09:23:39 +02:00
i . second -> tileHidden ( pack . tiles );
2012-02-20 21:01:54 +00:00
}
2014-06-21 17:41:05 +04:00
}
2023-02-12 09:23:39 +02:00
cl . invalidatePaths ();
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
static void dispatchGarrisonChange ( CClient & cl , ObjectInstanceID army1 , ObjectInstanceID army2 )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
auto obj1 = cl . getObj ( army1 );
2018-03-11 00:19:36 +03:00
if ( ! obj1 )
{
2023-02-12 09:23:39 +02:00
logNetwork -> error ( "Cannot find army with pack.id %d" , army1 . getNum ());
2018-03-11 00:19:36 +03:00
return ;
}
callInterfaceIfPresent ( cl , obj1 -> tempOwner , & IGameEventsReceiver :: garrisonsChanged , army1 , army2 );
if ( army2 != ObjectInstanceID () && army2 != army1 )
{
2023-02-12 09:23:39 +02:00
auto obj2 = cl . getObj ( army2 );
2018-03-11 00:19:36 +03:00
if ( ! obj2 )
{
2023-02-12 09:23:39 +02:00
logNetwork -> error ( "Cannot find army with pack.id %d" , army2 . getNum ());
2018-03-11 00:19:36 +03:00
return ;
}
if ( obj1 -> tempOwner != obj2 -> tempOwner )
callInterfaceIfPresent ( cl , obj2 -> tempOwner , & IGameEventsReceiver :: garrisonsChanged , army1 , army2 );
}
2010-11-27 20:17:28 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitChangeStackCount ( ChangeStackCount & pack )
2010-11-27 20:17:28 +00:00
{
2023-02-12 09:23:39 +02:00
dispatchGarrisonChange ( cl , pack . army , ObjectInstanceID ());
2010-11-27 20:17:28 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitSetStackType ( SetStackType & pack )
2010-11-27 20:17:28 +00:00
{
2023-02-12 09:23:39 +02:00
dispatchGarrisonChange ( cl , pack . army , ObjectInstanceID ());
2010-11-27 20:17:28 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitEraseStack ( EraseStack & pack )
2010-11-27 20:17:28 +00:00
{
2023-02-12 09:23:39 +02:00
dispatchGarrisonChange ( cl , pack . army , ObjectInstanceID ());
2010-11-27 20:17:28 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitSwapStacks ( SwapStacks & pack )
2010-11-27 20:17:28 +00:00
{
2023-02-12 09:23:39 +02:00
dispatchGarrisonChange ( cl , pack . srcArmy , pack . dstArmy );
2010-11-27 20:17:28 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitInsertNewStack ( InsertNewStack & pack )
2010-11-27 20:17:28 +00:00
{
2023-02-12 09:23:39 +02:00
dispatchGarrisonChange ( cl , pack . army , ObjectInstanceID ());
2018-03-11 00:19:36 +03:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitRebalanceStacks ( RebalanceStacks & pack )
2018-03-11 00:19:36 +03:00
{
2023-02-12 09:23:39 +02:00
dispatchGarrisonChange ( cl , pack . srcArmy , pack . dstArmy );
2010-11-27 20:17:28 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitBulkRebalanceStacks ( BulkRebalanceStacks & pack )
2021-11-28 15:57:38 +03:00
{
2023-02-12 09:23:39 +02:00
if ( ! pack . moves . empty ())
2021-11-28 15:57:38 +03:00
{
2023-02-12 09:23:39 +02:00
auto destArmy = pack . moves [ 0 ]. srcArmy == pack . moves [ 0 ]. dstArmy
2021-11-28 15:57:38 +03:00
? ObjectInstanceID ()
2023-02-12 09:23:39 +02:00
: pack . moves [ 0 ]. dstArmy ;
dispatchGarrisonChange ( cl , pack . moves [ 0 ]. srcArmy , destArmy );
2021-11-28 15:57:38 +03:00
}
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitBulkSmartRebalanceStacks ( BulkSmartRebalanceStacks & pack )
2021-11-28 15:57:38 +03:00
{
2023-02-12 09:23:39 +02:00
if ( ! pack . moves . empty ())
2021-11-28 15:57:38 +03:00
{
2023-02-12 09:23:39 +02:00
assert ( pack . moves [ 0 ]. srcArmy == pack . moves [ 0 ]. dstArmy );
dispatchGarrisonChange ( cl , pack . moves [ 0 ]. srcArmy , ObjectInstanceID ());
2021-11-28 15:57:38 +03:00
}
2023-02-12 09:23:39 +02:00
else if ( ! pack . changes . empty ())
2021-11-28 15:57:38 +03:00
{
2023-02-12 09:23:39 +02:00
dispatchGarrisonChange ( cl , pack . changes [ 0 ]. army , ObjectInstanceID ());
2021-11-28 15:57:38 +03:00
}
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitPutArtifact ( PutArtifact & pack )
2010-12-26 14:34:11 +00:00
{
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , pack . al . owningPlayer (), & IGameEventsReceiver :: artifactPut , pack . al );
2023-04-08 01:54:19 +03:00
if ( pack . askAssemble )
callInterfaceIfPresent ( cl , pack . al . owningPlayer (), & IGameEventsReceiver :: askToAssembleArtifact , pack . al );
2010-12-26 14:34:11 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitEraseArtifact ( EraseArtifact & pack )
2010-12-26 14:34:11 +00:00
{
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , pack . al . owningPlayer (), & IGameEventsReceiver :: artifactRemoved , pack . al );
2010-12-26 14:34:11 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitMoveArtifact ( MoveArtifact & pack )
2010-12-26 14:34:11 +00:00
{
2023-02-12 09:23:39 +02:00
auto moveArtifact = [ this , & pack ]( PlayerColor player ) -> void
2022-11-07 00:36:13 +02:00
{
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , player , & IGameEventsReceiver :: artifactMoved , pack . src , pack . dst );
if ( pack . askAssemble )
2023-02-13 21:10:53 +02:00
callInterfaceIfPresent ( cl , player , & IGameEventsReceiver :: askToAssembleArtifact , pack . dst );
2023-01-02 16:19:45 +02:00
};
2023-02-12 09:23:39 +02:00
moveArtifact ( pack . src . owningPlayer ());
if ( pack . src . owningPlayer () != pack . dst . owningPlayer ())
moveArtifact ( pack . dst . owningPlayer ());
2023-06-21 17:53:02 +03:00
cl . invalidatePaths (); // hero might have equipped/unequipped Angel Wings
2010-12-26 14:34:11 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitBulkMoveArtifacts ( BulkMoveArtifacts & pack )
2022-11-06 23:54:50 +02:00
{
2023-02-12 09:23:39 +02:00
auto applyMove = [ this , & pack ]( std :: vector < BulkMoveArtifacts :: LinkedSlots > & artsPack ) -> void
2022-11-06 23:54:50 +02:00
{
2022-11-10 20:48:19 +02:00
for ( auto & slotToMove : artsPack )
2022-11-06 23:54:50 +02:00
{
2023-02-12 09:23:39 +02:00
auto srcLoc = ArtifactLocation ( pack . srcArtHolder , slotToMove . srcPos );
auto dstLoc = ArtifactLocation ( pack . dstArtHolder , slotToMove . dstPos );
2023-02-13 21:10:53 +02:00
MoveArtifact ma ( & srcLoc , & dstLoc , false );
visitMoveArtifact ( ma );
2022-11-06 23:54:50 +02:00
}
2022-11-10 20:48:19 +02:00
};
2023-02-13 21:10:53 +02:00
// Begin a session of bulk movement of arts. It is not necessary but useful for the client optimization.
callInterfaceIfPresent ( cl , cl . getCurrentPlayer (), & IGameEventsReceiver :: bulkArtMovementStart ,
pack . artsPack0 . size () + pack . artsPack1 . size ());
2023-02-12 09:23:39 +02:00
applyMove ( pack . artsPack0 );
if ( pack . swap )
applyMove ( pack . artsPack1 );
2022-11-06 23:54:50 +02:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitAssembledArtifact ( AssembledArtifact & pack )
2011-01-22 03:43:20 +00:00
{
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , pack . al . owningPlayer (), & IGameEventsReceiver :: artifactAssembled , pack . al );
2023-06-21 17:53:02 +03:00
cl . invalidatePaths (); // hero might have equipped/unequipped Angel Wings
2011-01-22 03:43:20 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitDisassembledArtifact ( DisassembledArtifact & pack )
2011-01-22 03:43:20 +00:00
{
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , pack . al . owningPlayer (), & IGameEventsReceiver :: artifactDisassembled , pack . al );
2023-06-21 17:53:02 +03:00
cl . invalidatePaths (); // hero might have equipped/unequipped Angel Wings
2011-01-22 03:43:20 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitHeroVisit ( HeroVisit & pack )
2011-05-09 22:20:47 +00:00
{
2023-02-12 09:23:39 +02:00
auto hero = cl . getHero ( pack . heroId );
auto obj = cl . getObj ( pack . objId , false );
callInterfaceIfPresent ( cl , pack . player , & IGameEventsReceiver :: heroVisit , hero , obj , pack . starting );
2011-05-09 22:20:47 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitNewTurn ( NewTurn & pack )
2011-08-25 15:24:37 +00:00
{
2023-02-12 09:23:39 +02:00
cl . invalidatePaths ();
2011-08-25 15:24:37 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitGiveBonus ( GiveBonus & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
cl . invalidatePaths ();
switch ( pack . who )
2010-02-10 02:56:00 +00:00
{
2023-03-28 14:46:53 +03:00
case GiveBonus :: ETarget :: HERO :
2010-02-10 02:56:00 +00:00
{
2023-02-12 09:23:39 +02:00
const CGHeroInstance * h = gs . getHero ( ObjectInstanceID ( pack . id ));
2023-05-03 16:09:21 +03:00
callInterfaceIfPresent ( cl , h -> tempOwner , & IGameEventsReceiver :: heroBonusChanged , h , pack . bonus , true );
2010-02-10 02:56:00 +00:00
}
break ;
2023-03-28 14:46:53 +03:00
case GiveBonus :: ETarget :: PLAYER :
2010-02-10 02:56:00 +00:00
{
2023-05-03 16:09:21 +03:00
callInterfaceIfPresent ( cl , PlayerColor ( pack . id ), & IGameEventsReceiver :: playerBonusChanged , pack . bonus , true );
2010-02-10 02:56:00 +00:00
}
break ;
}
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyFirstClientNetPackVisitor :: visitChangeObjPos ( ChangeObjPos & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
CGObjectInstance * obj = gs . getObjInstance ( pack . objid );
2023-02-16 21:35:15 +02:00
if ( CGI -> mh )
CGI -> mh -> onObjectFadeOut ( obj );
2023-02-18 17:37:09 +02:00
CGI -> mh -> waitForOngoingAnimations ();
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitChangeObjPos ( ChangeObjPos & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
CGObjectInstance * obj = gs . getObjInstance ( pack . objid );
2023-02-16 21:35:15 +02:00
if ( CGI -> mh )
CGI -> mh -> onObjectFadeIn ( obj );
2010-03-10 23:16:30 +00:00
2023-02-18 17:37:09 +02:00
CGI -> mh -> waitForOngoingAnimations ();
2023-02-12 09:23:39 +02:00
cl . invalidatePaths ();
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitPlayerEndsGame ( PlayerEndsGame & pack )
2010-01-29 20:52:45 +00:00
{
2023-02-12 09:23:39 +02:00
callAllInterfaces ( cl , & IGameEventsReceiver :: gameOver , pack . player , pack . victoryLossCheckResult );
2017-06-04 11:59:26 +03:00
2023-02-12 09:23:39 +02:00
// In auto testing pack.mode we always close client if red pack.player won or lose
if ( ! settings [ "session" ][ "testmap" ]. isNull () && pack . player == PlayerColor ( 0 ))
2017-06-04 11:59:26 +03:00
handleQuit ( settings [ "session" ][ "spectate" ]. Bool ()); // if spectator is active ask to close client or not
2010-01-29 20:52:45 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitPlayerReinitInterface ( PlayerReinitInterface & pack )
2022-09-30 23:08:37 +04:00
{
2023-02-12 09:23:39 +02:00
auto initInterfaces = [ this ]()
2022-10-13 00:18:15 +04:00
{
2023-02-12 09:23:39 +02:00
cl . initPlayerInterfaces ();
auto currentPlayer = cl . gameState () -> currentPlayer ;
2022-10-13 00:18:15 +04:00
callAllInterfaces ( cl , & IGameEventsReceiver :: playerStartsTurn , currentPlayer );
callOnlyThatInterface ( cl , currentPlayer , & CGameInterface :: yourTurn );
};
2023-02-12 09:23:39 +02:00
for ( auto player : pack . players )
2022-10-01 18:28:45 +04:00
{
2022-10-05 01:54:31 +04:00
auto & plSettings = CSH -> si -> getIthPlayersSettings ( player );
2023-02-12 09:23:39 +02:00
if ( pack . playerConnectionId == PlayerSettings :: PLAYER_AI )
2022-10-05 01:54:31 +04:00
{
plSettings . connectedPlayerIDs . clear ();
2023-02-12 09:23:39 +02:00
cl . initPlayerEnvironments ();
2022-10-13 00:18:15 +04:00
initInterfaces ();
2022-10-05 01:54:31 +04:00
}
2023-02-12 09:23:39 +02:00
else if ( pack . playerConnectionId == CSH -> c -> connectionID )
2022-10-05 01:54:31 +04:00
{
2023-02-12 09:23:39 +02:00
plSettings . connectedPlayerIDs . insert ( pack . playerConnectionId );
cl . playerint . clear ();
2022-10-13 00:18:15 +04:00
initInterfaces ();
2022-10-05 01:54:31 +04:00
}
2022-10-01 18:28:45 +04:00
}
2022-09-30 23:08:37 +04:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitRemoveBonus ( RemoveBonus & pack )
2010-02-10 02:56:00 +00:00
{
2023-02-12 09:23:39 +02:00
cl . invalidatePaths ();
switch ( pack . who )
2010-02-10 02:56:00 +00:00
{
2023-03-28 14:46:53 +03:00
case GiveBonus :: ETarget :: HERO :
2010-02-10 02:56:00 +00:00
{
2023-02-12 09:23:39 +02:00
const CGHeroInstance * h = gs . getHero ( ObjectInstanceID ( pack . id ));
callInterfaceIfPresent ( cl , h -> tempOwner , & IGameEventsReceiver :: heroBonusChanged , h , pack . bonus , false );
2010-02-10 02:56:00 +00:00
}
break ;
2023-03-28 14:46:53 +03:00
case GiveBonus :: ETarget :: PLAYER :
2010-02-10 02:56:00 +00:00
{
2023-02-12 09:23:39 +02:00
//const PlayerState *p = gs.getPlayerState(pack.id);
callInterfaceIfPresent ( cl , PlayerColor ( pack . id ), & IGameEventsReceiver :: playerBonusChanged , pack . bonus , false );
2010-02-10 02:56:00 +00:00
}
break ;
}
}
2023-02-12 09:23:39 +02:00
void ApplyFirstClientNetPackVisitor :: visitRemoveObject ( RemoveObject & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
const CGObjectInstance * o = cl . getObj ( pack . id );
2012-07-19 09:10:55 +00:00
2017-03-12 10:54:24 +03:00
if ( CGI -> mh )
2023-02-16 21:35:15 +02:00
CGI -> mh -> onObjectFadeOut ( o );
2009-08-03 23:53:18 +00:00
//notify interfaces about removal
2023-02-12 09:23:39 +02:00
for ( auto i = cl . playerint . begin (); i != cl . playerint . end (); i ++ )
2009-03-07 15:55:56 +00:00
{
2018-11-02 16:35:25 +01:00
//below line contains little cheat for AI so it will be aware of deletion of enemy heroes that moved or got re-covered by FoW
2023-02-12 09:23:39 +02:00
//TODO: loose requirements as next AI related crashes appear, for example another pack.player collects object that got re-covered by FoW, unsure if AI code workarounds this
if ( gs . isVisible ( o , i -> first ) || ( ! cl . getPlayerState ( i -> first ) -> human && o -> ID == Obj :: HERO && o -> tempOwner != i -> first ))
2009-08-03 23:53:18 +00:00
i -> second -> objectRemoved ( o );
2009-03-07 15:55:56 +00:00
}
2023-02-18 17:37:09 +02:00
CGI -> mh -> waitForOngoingAnimations ();
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitRemoveObject ( RemoveObject & pack )
2009-03-07 17:08:40 +00:00
{
2023-02-12 09:23:39 +02:00
cl . invalidatePaths ();
2023-02-12 13:02:06 +02:00
for ( auto i = cl . playerint . begin (); i != cl . playerint . end (); i ++ )
i -> second -> objectRemovedAfter ();
2009-03-07 17:08:40 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyFirstClientNetPackVisitor :: visitTryMoveHero ( TryMoveHero & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
CGHeroInstance * h = gs . getHero ( pack . id );
2009-12-28 04:08:24 +00:00
2023-02-26 18:17:53 +02:00
if ( CGI -> mh )
2009-12-28 04:08:24 +00:00
{
2023-02-26 18:17:53 +02:00
switch ( pack . result )
2017-06-03 08:25:10 +03:00
{
2023-02-26 18:17:53 +02:00
case TryMoveHero :: EMBARK :
CGI -> mh -> onBeforeHeroEmbark ( h , pack . start , pack . end );
break ;
case TryMoveHero :: TELEPORTATION :
CGI -> mh -> onBeforeHeroTeleported ( h , pack . start , pack . end );
break ;
case TryMoveHero :: DISEMBARK :
CGI -> mh -> onBeforeHeroDisembark ( h , pack . start , pack . end );
break ;
2017-06-03 08:25:10 +03:00
}
2023-02-19 14:17:18 +02:00
CGI -> mh -> waitForOngoingAnimations ();
}
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitTryMoveHero ( TryMoveHero & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
const CGHeroInstance * h = cl . getHero ( pack . id );
cl . invalidatePaths ();
2009-03-07 15:55:56 +00:00
2017-03-12 10:54:24 +03:00
if ( CGI -> mh )
2011-06-21 16:00:19 +00:00
{
2023-02-16 21:35:15 +02:00
switch ( pack . result )
{
case TryMoveHero :: SUCCESS :
CGI -> mh -> onHeroMoved ( h , pack . start , pack . end );
break ;
case TryMoveHero :: EMBARK :
2023-02-26 18:17:53 +02:00
CGI -> mh -> onAfterHeroEmbark ( h , pack . start , pack . end );
break ;
case TryMoveHero :: TELEPORTATION :
CGI -> mh -> onAfterHeroTeleported ( h , pack . start , pack . end );
2023-02-16 21:35:15 +02:00
break ;
case TryMoveHero :: DISEMBARK :
2023-02-26 18:17:53 +02:00
CGI -> mh -> onAfterHeroDisembark ( h , pack . start , pack . end );
2023-02-16 21:35:15 +02:00
break ;
}
2017-03-12 10:54:24 +03:00
}
2009-07-19 03:10:24 +00:00
2013-03-03 17:06:03 +00:00
PlayerColor player = h -> tempOwner ;
2009-03-07 15:55:56 +00:00
2023-02-12 09:23:39 +02:00
for ( auto & i : cl . playerint )
if ( cl . getPlayerRelations ( i . first , player ) != PlayerRelations :: ENEMIES )
i . second -> tileRevealed ( pack . fowRevealed );
2009-03-07 15:55:56 +00:00
2023-02-12 09:23:39 +02:00
for ( auto i = cl . playerint . begin (); i != cl . playerint . end (); i ++ )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
if ( i -> first != PlayerColor :: SPECTATOR && gs . checkForStandardLoss ( i -> first )) // Do not notify vanquished pack.player's interface
2022-01-25 14:19:48 +03:00
continue ;
2023-02-16 21:35:15 +02:00
if ( gs . isVisible ( h -> convertToVisitablePos ( pack . start ), i -> first )
|| gs . isVisible ( h -> convertToVisitablePos ( pack . end ), i -> first ))
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
// pack.src and pack.dst of enemy hero move may be not visible => 'verbose' should be false
const bool verbose = cl . getPlayerRelations ( i -> first , player ) != PlayerRelations :: ENEMIES ;
i -> second -> heroMoved ( pack , verbose );
2009-03-07 15:55:56 +00:00
}
}
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitNewStructures ( NewStructures & pack )
2017-09-16 10:42:27 +03:00
{
2023-02-12 09:23:39 +02:00
CGTownInstance * town = gs . getTown ( pack . tid );
for ( const auto & id : pack . bid )
2013-11-17 17:57:04 +00:00
{
2018-02-03 17:44:30 +03:00
callInterfaceIfPresent ( cl , town -> tempOwner , & IGameEventsReceiver :: buildChanged , town , id , 1 );
2009-03-07 15:55:56 +00:00
}
2023-03-22 14:41:36 +02:00
// invalidate section of map view with our object and force an update
CGI -> mh -> onObjectInstantRemove ( town );
CGI -> mh -> onObjectInstantAdd ( town );
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitRazeStructures ( RazeStructures & pack )
2009-09-22 14:27:46 +00:00
{
2023-02-12 09:23:39 +02:00
CGTownInstance * town = gs . getTown ( pack . tid );
for ( const auto & id : pack . bid )
2013-11-17 17:57:04 +00:00
{
2018-02-03 17:44:30 +03:00
callInterfaceIfPresent ( cl , town -> tempOwner , & IGameEventsReceiver :: buildChanged , town , id , 2 );
2009-09-22 14:27:46 +00:00
}
2023-03-22 14:41:36 +02:00
// invalidate section of map view with our object and force an update
CGI -> mh -> onObjectInstantRemove ( town );
CGI -> mh -> onObjectInstantAdd ( town );
2009-09-22 14:27:46 +00:00
}
2009-03-07 15:55:56 +00:00
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitSetAvailableCreatures ( SetAvailableCreatures & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
const CGDwelling * dw = static_cast < const CGDwelling *> ( cl . getObj ( pack . tid ));
2010-05-15 08:33:32 +00:00
2013-03-03 17:06:03 +00:00
PlayerColor p ;
2012-09-23 18:01:04 +00:00
if ( dw -> ID == Obj :: WAR_MACHINE_FACTORY ) //War Machines Factory is not flaggable, it's "owned" by visitor
2023-02-12 09:23:39 +02:00
p = cl . getTile ( dw -> visitablePos ()) -> visitableObjects . back () -> tempOwner ;
2010-05-15 08:33:32 +00:00
else
p = dw -> tempOwner ;
2018-02-03 17:44:30 +03:00
callInterfaceIfPresent ( cl , p , & IGameEventsReceiver :: availableCreaturesChanged , dw );
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitSetHeroesInTown ( SetHeroesInTown & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
CGTownInstance * t = gs . getTown ( pack . tid );
CGHeroInstance * hGarr = gs . getHero ( pack . garrison );
CGHeroInstance * hVisit = gs . getHero ( pack . visiting );
2013-02-23 12:22:23 +00:00
2016-09-11 13:56:00 +03:00
//inform all players that see this object
2023-02-12 09:23:39 +02:00
for ( auto i = cl . playerint . cbegin (); i != cl . playerint . cend (); ++ i )
2016-09-11 13:56:00 +03:00
{
if ( i -> first >= PlayerColor :: PLAYER_LIMIT )
continue ;
2013-02-23 12:22:23 +00:00
2023-02-12 09:23:39 +02:00
if ( gs . isVisible ( t , i -> first ) ||
( hGarr && gs . isVisible ( hGarr , i -> first )) ||
( hVisit && gs . isVisible ( hVisit , i -> first )))
2016-09-11 13:56:00 +03:00
{
2023-02-12 09:23:39 +02:00
cl . playerint [ i -> first ] -> heroInGarrisonChange ( t );
2016-09-11 13:56:00 +03:00
}
}
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitHeroRecruited ( HeroRecruited & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
CGHeroInstance * h = gs . map -> heroesOnMap . back ();
if ( h -> subID != pack . hid )
2009-03-07 15:55:56 +00:00
{
2017-08-10 19:39:27 +03:00
logNetwork -> error ( "Something wrong with hero recruited!" );
2009-03-07 15:55:56 +00:00
}
2018-02-03 17:44:30 +03:00
if ( callInterfaceIfPresent ( cl , h -> tempOwner , & IGameEventsReceiver :: heroCreated , h ))
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
if ( const CGTownInstance * t = gs . getTown ( pack . tid ))
2018-02-03 17:44:30 +03:00
callInterfaceIfPresent ( cl , h -> tempOwner , & IGameEventsReceiver :: heroInGarrisonChange , t );
2016-10-02 16:27:01 +02:00
}
2023-02-22 22:06:27 +02:00
if ( CGI -> mh )
2023-02-16 21:35:15 +02:00
CGI -> mh -> onObjectInstantAdd ( h );
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitGiveHero ( GiveHero & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
CGHeroInstance * h = gs . getHero ( pack . id );
2017-03-12 10:54:24 +03:00
if ( CGI -> mh )
2023-02-16 21:35:15 +02:00
CGI -> mh -> onObjectInstantAdd ( h );
2018-02-03 17:44:30 +03:00
callInterfaceIfPresent ( cl , h -> tempOwner , & IGameEventsReceiver :: heroCreated , h );
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyFirstClientNetPackVisitor :: visitGiveHero ( GiveHero & pack )
2009-03-07 15:55:56 +00:00
{
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitInfoWindow ( InfoWindow & pack )
2009-03-07 15:55:56 +00:00
{
2023-06-18 12:18:25 +03:00
std :: string str = pack . text . toString ();
2013-11-17 17:57:04 +00:00
2023-03-06 02:30:21 +03:00
if ( ! callInterfaceIfPresent ( cl , pack . player , & CGameInterface :: showInfoDialog , pack . type , str , pack . components ,( soundBase :: soundID ) pack . soundID ))
2017-08-10 19:39:27 +03:00
logNetwork -> warn ( "We received InfoWindow for not our player..." );
2013-11-17 17:57:04 +00:00
}
2009-03-07 15:55:56 +00:00
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitSetObjectProperty ( SetObjectProperty & pack )
2009-07-30 12:49:45 +00:00
{
//inform all players that see this object
2023-02-12 09:23:39 +02:00
for ( auto it = cl . playerint . cbegin (); it != cl . playerint . cend (); ++ it )
2009-07-30 12:49:45 +00:00
{
2023-02-12 09:23:39 +02:00
if ( gs . isVisible ( gs . getObjInstance ( pack . id ), it -> first ))
callInterfaceIfPresent ( cl , it -> first , & IGameEventsReceiver :: objectPropertyChanged , & pack );
2009-07-30 12:49:45 +00:00
}
2023-03-15 00:30:58 +02:00
if ( pack . what == ObjProperty :: OWNER )
{
2023-03-22 14:41:36 +02:00
// invalidate section of map view with our object and force an update with new flag color
2023-03-15 00:30:58 +02:00
CGI -> mh -> onObjectInstantRemove ( gs . getObjInstance ( pack . id ));
CGI -> mh -> onObjectInstantAdd ( gs . getObjInstance ( pack . id ));
}
2009-07-30 12:49:45 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitHeroLevelUp ( HeroLevelUp & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
const CGHeroInstance * hero = cl . getHero ( pack . heroId );
2018-03-10 22:19:55 +03:00
assert ( hero );
2023-02-12 09:23:39 +02:00
callOnlyThatInterface ( cl , pack . player , & CGameInterface :: heroGotLevel , hero , pack . primskill , pack . skills , pack . queryID );
2009-03-07 15:55:56 +00:00
}
2012-07-15 15:34:00 +00:00
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitCommanderLevelUp ( CommanderLevelUp & pack )
2012-05-16 17:29:05 +00:00
{
2023-02-12 09:23:39 +02:00
const CGHeroInstance * hero = cl . getHero ( pack . heroId );
2018-03-10 22:19:55 +03:00
assert ( hero );
2013-04-20 11:34:01 +00:00
const CCommanderInstance * commander = hero -> commander ;
2018-02-03 17:44:30 +03:00
assert ( commander );
assert ( commander -> armyObj ); //is it possible for Commander to exist beyond armed instance?
2023-02-12 09:23:39 +02:00
callOnlyThatInterface ( cl , pack . player , & CGameInterface :: commanderGotLevel , commander , pack . skills , pack . queryID );
2012-05-16 17:29:05 +00:00
}
2009-03-07 15:55:56 +00:00
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitBlockingDialog ( BlockingDialog & pack )
2009-03-07 15:55:56 +00:00
{
2023-06-18 12:18:25 +03:00
std :: string str = pack . text . toString ();
2013-11-17 17:57:04 +00:00
2023-02-12 09:23:39 +02:00
if ( ! callOnlyThatInterface ( cl , pack . player , & CGameInterface :: showBlockingDialog , str , pack . components , pack . queryID , ( soundBase :: soundID ) pack . soundID , pack . selection (), pack . cancel ()))
2017-08-10 19:39:27 +03:00
logNetwork -> warn ( "We received YesNoDialog for not our player..." );
2013-11-17 17:57:04 +00:00
}
2009-03-07 15:55:56 +00:00
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitGarrisonDialog ( GarrisonDialog & pack )
2009-04-12 00:58:41 +00:00
{
2023-02-12 09:23:39 +02:00
const CGHeroInstance * h = cl . getHero ( pack . hid );
const CArmedInstance * obj = static_cast < const CArmedInstance *> ( cl . getObj ( pack . objid ));
2009-04-12 00:58:41 +00:00
2023-02-12 09:23:39 +02:00
callOnlyThatInterface ( cl , h -> getOwner (), & CGameInterface :: showGarrisonDialog , obj , h , pack . removableUnits , pack . queryID );
2013-11-17 17:57:04 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitExchangeDialog ( ExchangeDialog & pack )
2013-05-27 10:53:28 +00:00
{
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , pack . player , & IGameEventsReceiver :: heroExchangeStarted , pack . hero1 , pack . hero2 , pack . queryID );
2013-05-27 10:53:28 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitTeleportDialog ( TeleportDialog & pack )
2015-03-08 16:37:33 +03:00
{
2023-02-12 09:23:39 +02:00
callOnlyThatInterface ( cl , pack . player , & CGameInterface :: showTeleportDialog , pack . channel , pack . exits , pack . impassable , pack . queryID );
2015-03-08 16:37:33 +03:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitMapObjectSelectDialog ( MapObjectSelectDialog & pack )
2017-06-06 07:53:51 +03:00
{
2023-02-12 09:23:39 +02:00
callOnlyThatInterface ( cl , pack . player , & CGameInterface :: showMapObjectSelectDialog , pack . queryID , pack . icon , pack . title , pack . description , pack . objects );
2017-06-06 07:53:51 +03:00
}
2023-02-12 09:23:39 +02:00
void ApplyFirstClientNetPackVisitor :: visitBattleStart ( BattleStart & pack )
2013-09-14 19:09:35 +00:00
{
2018-02-03 17:44:30 +03:00
// Cannot use the usual code because curB is not set yet
2023-02-12 09:23:39 +02:00
callOnlyThatBattleInterface ( cl , pack . info -> sides [ 0 ]. color , & IBattleEventsReceiver :: battleStartBefore , pack . info -> sides [ 0 ]. armyObject , pack . info -> sides [ 1 ]. armyObject ,
pack . info -> tile , pack . info -> sides [ 0 ]. hero , pack . info -> sides [ 1 ]. hero );
callOnlyThatBattleInterface ( cl , pack . info -> sides [ 1 ]. color , & IBattleEventsReceiver :: battleStartBefore , pack . info -> sides [ 0 ]. armyObject , pack . info -> sides [ 1 ]. armyObject ,
pack . info -> tile , pack . info -> sides [ 0 ]. hero , pack . info -> sides [ 1 ]. hero );
callOnlyThatBattleInterface ( cl , PlayerColor :: SPECTATOR , & IBattleEventsReceiver :: battleStartBefore , pack . info -> sides [ 0 ]. armyObject , pack . info -> sides [ 1 ]. armyObject ,
pack . info -> tile , pack . info -> sides [ 0 ]. hero , pack . info -> sides [ 1 ]. hero );
2013-09-14 19:09:35 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitBattleStart ( BattleStart & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
cl . battleStarted ( pack . info );
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyFirstClientNetPackVisitor :: visitBattleNextRound ( BattleNextRound & pack )
2010-05-07 12:29:41 +00:00
{
2023-02-12 09:23:39 +02:00
callBattleInterfaceIfPresentForBothSides ( cl , & IBattleEventsReceiver :: battleNewRoundFirst , pack . round );
2010-05-07 12:29:41 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitBattleNextRound ( BattleNextRound & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
callBattleInterfaceIfPresentForBothSides ( cl , & IBattleEventsReceiver :: battleNewRound , pack . round );
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitBattleSetActiveStack ( BattleSetActiveStack & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
if ( ! pack . askPlayerInterface )
2012-08-27 12:34:43 +00:00
return ;
2023-02-12 09:23:39 +02:00
const CStack * activated = gs . curB -> battleGetStackByID ( pack . stack );
PlayerColor playerToCall ; //pack.player that will move activated stack
2023-05-01 01:20:01 +03:00
if ( activated -> hasBonusOfType ( BonusType :: HYPNOTIZED ))
2009-08-18 11:49:34 +00:00
{
2023-04-27 20:43:20 +03:00
playerToCall = ( gs . curB -> sides [ 0 ]. color == activated -> unitOwner ()
2023-02-12 09:23:39 +02:00
? gs . curB -> sides [ 1 ]. color
: gs . curB -> sides [ 0 ]. color );
2009-08-18 11:49:34 +00:00
}
else
{
2023-04-27 20:43:20 +03:00
playerToCall = activated -> unitOwner ();
2009-08-18 11:49:34 +00:00
}
2017-11-16 14:15:43 +03:00
2023-02-12 09:23:39 +02:00
cl . startPlayerBattleAction ( playerToCall );
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitBattleLogMessage ( BattleLogMessage & pack )
2018-03-17 17:58:30 +03:00
{
2023-02-12 09:23:39 +02:00
callBattleInterfaceIfPresentForBothSides ( cl , & IBattleEventsReceiver :: battleLogMessage , pack . lines );
2018-03-17 17:58:30 +03:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitBattleTriggerEffect ( BattleTriggerEffect & pack )
2011-10-08 13:02:58 +00:00
{
2023-02-12 09:23:39 +02:00
callBattleInterfaceIfPresentForBothSides ( cl , & IBattleEventsReceiver :: battleTriggerEffect , pack );
2011-10-08 13:02:58 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyFirstClientNetPackVisitor :: visitBattleUpdateGateState ( BattleUpdateGateState & pack )
2016-02-10 07:10:32 +03:00
{
2023-02-12 09:23:39 +02:00
callBattleInterfaceIfPresentForBothSides ( cl , & IBattleEventsReceiver :: battleGateStateChanged , pack . state );
2016-02-10 07:10:32 +03:00
}
2023-02-12 09:23:39 +02:00
void ApplyFirstClientNetPackVisitor :: visitBattleResult ( BattleResult & pack )
2009-03-07 15:55:56 +00:00
{
2023-04-06 19:59:22 +04:00
callBattleInterfaceIfPresentForBothSides ( cl , & IBattleEventsReceiver :: battleEnd , & pack , pack . queryID );
2023-02-12 09:23:39 +02:00
cl . battleFinished ();
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyFirstClientNetPackVisitor :: visitBattleStackMoved ( BattleStackMoved & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
const CStack * movedStack = gs . curB -> battleGetStackByID ( pack . stack );
callBattleInterfaceIfPresentForBothSides ( cl , & IBattleEventsReceiver :: battleStackMoved , movedStack , pack . tilesToMove , pack . distance , pack . teleporting );
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyFirstClientNetPackVisitor :: visitBattleAttack ( BattleAttack & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
callBattleInterfaceIfPresentForBothSides ( cl , & IBattleEventsReceiver :: battleAttack , & pack );
2023-03-25 15:00:25 +01:00
// battleStacksAttacked should be excuted before BattleAttack.applyGs() to play animation before damaging unit
// so this has to be here instead of ApplyClientNetPackVisitor::visitBattleAttack()
callBattleInterfaceIfPresentForBothSides ( cl , & IBattleEventsReceiver :: battleStacksAttacked , pack . bsa , pack . shot ());
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitBattleAttack ( BattleAttack & pack )
2009-03-07 15:55:56 +00:00
{
}
2023-02-12 09:23:39 +02:00
void ApplyFirstClientNetPackVisitor :: visitStartAction ( StartAction & pack )
2009-03-07 15:55:56 +00:00
{
2023-04-16 20:42:56 +03:00
cl . curbaction = std :: make_optional ( pack . ba );
2023-02-12 09:23:39 +02:00
callBattleInterfaceIfPresentForBothSides ( cl , & IBattleEventsReceiver :: actionStarted , pack . ba );
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitBattleSpellCast ( BattleSpellCast & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
callBattleInterfaceIfPresentForBothSides ( cl , & IBattleEventsReceiver :: battleSpellCast , & pack );
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitSetStackEffect ( SetStackEffect & pack )
2009-03-07 15:55:56 +00:00
{
2009-03-21 16:03:07 +00:00
//informing about effects
2023-02-12 09:23:39 +02:00
callBattleInterfaceIfPresentForBothSides ( cl , & IBattleEventsReceiver :: battleStacksEffectsSet , pack );
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitStacksInjured ( StacksInjured & pack )
2009-04-16 00:28:54 +00:00
{
2023-02-12 09:23:39 +02:00
callBattleInterfaceIfPresentForBothSides ( cl , & IBattleEventsReceiver :: battleStacksAttacked , pack . stacks , false );
2009-04-16 00:28:54 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitBattleResultsApplied ( BattleResultsApplied & pack )
2009-08-03 23:53:18 +00:00
{
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , pack . player1 , & IGameEventsReceiver :: battleResultsApplied );
callInterfaceIfPresent ( cl , pack . player2 , & IGameEventsReceiver :: battleResultsApplied );
2018-02-03 17:44:30 +03:00
callInterfaceIfPresent ( cl , PlayerColor :: SPECTATOR , & IGameEventsReceiver :: battleResultsApplied );
2009-08-03 23:53:18 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitBattleUnitsChanged ( BattleUnitsChanged & pack )
2009-08-05 12:46:08 +00:00
{
2023-02-12 09:23:39 +02:00
callBattleInterfaceIfPresentForBothSides ( cl , & IBattleEventsReceiver :: battleUnitsChanged , pack . changedStacks );
2009-08-05 12:46:08 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitBattleObstaclesChanged ( BattleObstaclesChanged & pack )
2009-08-19 10:59:42 +00:00
{
//inform interfaces about removed obstacles
2023-02-12 09:23:39 +02:00
callBattleInterfaceIfPresentForBothSides ( cl , & IBattleEventsReceiver :: battleObstaclesChanged , pack . changes );
2009-08-19 10:59:42 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitCatapultAttack ( CatapultAttack & pack )
2009-09-01 13:54:13 +00:00
{
//inform interfaces about catapult attack
2023-02-12 09:23:39 +02:00
callBattleInterfaceIfPresentForBothSides ( cl , & IBattleEventsReceiver :: battleCatapultAttacked , pack );
2009-09-01 13:54:13 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitEndAction ( EndAction & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
callBattleInterfaceIfPresentForBothSides ( cl , & IBattleEventsReceiver :: actionFinished , * cl . curbaction );
cl . curbaction . reset ();
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitPackageApplied ( PackageApplied & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , pack . player , & IGameEventsReceiver :: requestRealized , & pack );
if ( ! CClient :: waitingRequest . tryRemovingElement ( pack . requestID ))
2018-01-05 20:21:07 +03:00
logNetwork -> warn ( "Surprising server message! PackageApplied for unknown requestID!" );
2009-04-16 00:28:54 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitSystemMessage ( SystemMessage & pack )
2009-03-07 15:55:56 +00:00
{
2009-04-04 19:26:41 +00:00
std :: ostringstream str ;
2023-02-12 09:23:39 +02:00
str << "System message: " << pack . text ;
2009-04-04 19:26:41 +00:00
2017-08-11 14:38:10 +03:00
logNetwork -> error ( str . str ()); // usually used to receive error messages from server
2016-09-26 16:05:27 +03:00
if ( LOCPLINT && ! settings [ "session" ][ "hideSystemMessages" ]. Bool ())
2009-04-04 19:26:41 +00:00
LOCPLINT -> cingconsole -> print ( str . str ());
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitPlayerBlocked ( PlayerBlocked & pack )
2009-08-03 23:53:18 +00:00
{
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , pack . player , & IGameEventsReceiver :: playerBlocked , pack . reason , pack . startOrEnd == PlayerBlocked :: BLOCKADE_STARTED );
2009-08-03 23:53:18 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitYourTurn ( YourTurn & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
logNetwork -> debug ( "Server gives turn to %s" , pack . player . getStr ());
2018-01-05 20:21:07 +03:00
2023-02-12 09:23:39 +02:00
callAllInterfaces ( cl , & IGameEventsReceiver :: playerStartsTurn , pack . player );
callOnlyThatInterface ( cl , pack . player , & CGameInterface :: yourTurn );
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitSaveGameClient ( SaveGameClient & pack )
2009-03-28 18:46:20 +00:00
{
2023-02-12 09:23:39 +02:00
const auto stem = FileInfo :: GetPathStem ( pack . fname );
2022-10-06 15:54:46 +04:00
if ( ! CResourceHandler :: get ( "local" ) -> createResource ( stem . to_string () + ".vcgm1" ))
{
logNetwork -> error ( "Failed to create resource %s" , stem . to_string () + ".vcgm1" );
return ;
}
2012-08-07 11:28:52 +00:00
2012-06-09 19:58:17 +00:00
try
{
2016-01-26 14:51:38 +01:00
CSaveFile save ( * CResourceHandler :: get () -> getResourceName ( ResourceID ( stem . to_string (), EResType :: CLIENT_SAVEGAME )));
2023-02-12 09:23:39 +02:00
save << cl ;
2012-06-09 19:58:17 +00:00
}
catch ( std :: exception & e )
{
2017-08-11 14:38:10 +03:00
logNetwork -> error ( "Failed to save game:%s" , e . what ());
2012-06-09 19:58:17 +00:00
}
2009-03-28 18:46:20 +00:00
}
2009-03-07 15:55:56 +00:00
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitPlayerMessageClient ( PlayerMessageClient & pack )
2009-03-07 15:55:56 +00:00
{
2023-02-12 09:23:39 +02:00
logNetwork -> debug ( "pack.player %s sends a message: %s" , pack . player . getStr (), pack . text );
2009-04-04 19:26:41 +00:00
2015-11-08 22:16:58 +03:00
std :: ostringstream str ;
2023-02-12 09:23:39 +02:00
if ( pack . player . isSpectator ())
str << "Spectator: " << pack . text ;
2017-06-03 08:25:10 +03:00
else
2023-02-12 09:23:39 +02:00
str << cl . getPlayerState ( pack . player ) -> nodeName () << ": " << pack . text ;
2009-04-04 19:26:41 +00:00
if ( LOCPLINT )
LOCPLINT -> cingconsole -> print ( str . str ());
2009-03-07 15:55:56 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitAdvmapSpellCast ( AdvmapSpellCast & pack )
2010-05-16 13:42:19 +00:00
{
2023-02-12 09:23:39 +02:00
cl . invalidatePaths ();
auto caster = cl . getHero ( pack . casterID );
2018-03-10 22:19:55 +03:00
if ( caster )
//consider notifying other interfaces that see hero?
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , caster -> getOwner (), & IGameEventsReceiver :: advmapSpellCast , caster , pack . spellID );
2018-03-10 22:19:55 +03:00
else
logNetwork -> error ( "Invalid hero instance" );
2010-05-16 13:42:19 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitShowWorldViewEx ( ShowWorldViewEx & pack )
2015-02-26 17:15:17 +03:00
{
2023-02-21 14:38:08 +02:00
callOnlyThatInterface ( cl , pack . player , & CGameInterface :: showWorldViewEx , pack . objectPositions , pack . showTerrain );
2015-02-26 17:15:17 +03:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitOpenWindow ( OpenWindow & pack )
2009-06-16 11:18:14 +00:00
{
2023-02-12 09:23:39 +02:00
switch ( pack . window )
2009-07-06 19:41:27 +00:00
{
2023-03-08 01:32:21 +03:00
case EOpenWindowMode :: RECRUITMENT_FIRST :
case EOpenWindowMode :: RECRUITMENT_ALL :
2009-07-06 19:41:27 +00:00
{
2023-02-12 09:23:39 +02:00
const CGDwelling * dw = dynamic_cast < const CGDwelling *> ( cl . getObj ( ObjectInstanceID ( pack . id1 )));
const CArmedInstance * dst = dynamic_cast < const CArmedInstance *> ( cl . getObj ( ObjectInstanceID ( pack . id2 )));
2023-03-08 01:32:21 +03:00
callInterfaceIfPresent ( cl , dst -> tempOwner , & IGameEventsReceiver :: showRecruitmentDialog , dw , dst , pack . window == EOpenWindowMode :: RECRUITMENT_FIRST ? 0 : - 1 );
2009-07-06 19:41:27 +00:00
}
2009-07-26 03:33:13 +00:00
break ;
2023-03-08 01:32:21 +03:00
case EOpenWindowMode :: SHIPYARD_WINDOW :
2009-07-26 03:33:13 +00:00
{
2023-02-12 09:23:39 +02:00
const IShipyard * sy = IShipyard :: castFrom ( cl . getObj ( ObjectInstanceID ( pack . id1 )));
2023-06-07 01:55:21 +03:00
callInterfaceIfPresent ( cl , sy -> getObject () -> getOwner (), & IGameEventsReceiver :: showShipyardDialog , sy );
2009-07-26 03:33:13 +00:00
}
break ;
2023-03-08 01:32:21 +03:00
case EOpenWindowMode :: THIEVES_GUILD :
2010-02-07 15:06:14 +00:00
{
//displays Thieves' Guild window (when hero enters Den of Thieves)
2023-02-12 09:23:39 +02:00
const CGObjectInstance * obj = cl . getObj ( ObjectInstanceID ( pack . id2 ));
callInterfaceIfPresent ( cl , PlayerColor ( pack . id1 ), & IGameEventsReceiver :: showThievesGuildWindow , obj );
2010-02-07 15:06:14 +00:00
}
break ;
2023-03-08 01:32:21 +03:00
case EOpenWindowMode :: UNIVERSITY_WINDOW :
2010-07-20 14:08:13 +00:00
{
//displays University window (when hero enters University on adventure map)
2023-02-12 09:23:39 +02:00
const IMarket * market = IMarket :: castFrom ( cl . getObj ( ObjectInstanceID ( pack . id1 )));
const CGHeroInstance * hero = cl . getHero ( ObjectInstanceID ( pack . id2 ));
2018-02-03 17:44:30 +03:00
callInterfaceIfPresent ( cl , hero -> tempOwner , & IGameEventsReceiver :: showUniversityWindow , market , hero );
2010-07-20 14:08:13 +00:00
}
break ;
2023-03-08 01:32:21 +03:00
case EOpenWindowMode :: MARKET_WINDOW :
2010-05-18 07:01:54 +00:00
{
//displays Thieves' Guild window (when hero enters Den of Thieves)
2023-02-12 09:23:39 +02:00
const CGObjectInstance * obj = cl . getObj ( ObjectInstanceID ( pack . id1 ));
const CGHeroInstance * hero = cl . getHero ( ObjectInstanceID ( pack . id2 ));
2010-05-18 07:01:54 +00:00
const IMarket * market = IMarket :: castFrom ( obj );
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , cl . getTile ( obj -> visitablePos ()) -> visitableObjects . back () -> tempOwner , & IGameEventsReceiver :: showMarketWindow , market , hero );
2010-05-18 07:01:54 +00:00
}
break ;
2023-03-08 01:32:21 +03:00
case EOpenWindowMode :: HILL_FORT_WINDOW :
2010-07-22 00:32:45 +00:00
{
//displays Hill fort window
2023-02-12 09:23:39 +02:00
const CGObjectInstance * obj = cl . getObj ( ObjectInstanceID ( pack . id1 ));
const CGHeroInstance * hero = cl . getHero ( ObjectInstanceID ( pack . id2 ));
callInterfaceIfPresent ( cl , cl . getTile ( obj -> visitablePos ()) -> visitableObjects . back () -> tempOwner , & IGameEventsReceiver :: showHillFortWindow , obj , hero );
2010-07-22 00:32:45 +00:00
}
break ;
2023-03-08 01:32:21 +03:00
case EOpenWindowMode :: PUZZLE_MAP :
2010-02-10 02:56:00 +00:00
{
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , PlayerColor ( pack . id1 ), & IGameEventsReceiver :: showPuzzleMap );
2010-02-10 02:56:00 +00:00
}
2010-07-20 14:08:13 +00:00
break ;
2023-03-08 01:32:21 +03:00
case EOpenWindowMode :: TAVERN_WINDOW :
2023-02-12 09:23:39 +02:00
const CGObjectInstance * obj1 = cl . getObj ( ObjectInstanceID ( pack . id1 )),
* obj2 = cl . getObj ( ObjectInstanceID ( pack . id2 ));
2018-02-03 17:44:30 +03:00
callInterfaceIfPresent ( cl , obj1 -> tempOwner , & IGameEventsReceiver :: showTavernWindow , obj2 );
2010-02-10 02:56:00 +00:00
break ;
2009-07-06 19:41:27 +00:00
}
2009-06-16 11:18:14 +00:00
}
2009-07-26 03:33:13 +00:00
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitCenterView ( CenterView & pack )
2009-08-11 07:50:29 +00:00
{
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , pack . player , & IGameEventsReceiver :: centerView , pack . pos , pack . focusTime );
2009-08-11 07:50:29 +00:00
}
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitNewObject ( NewObject & pack )
2009-07-26 03:33:13 +00:00
{
2023-02-12 09:23:39 +02:00
cl . invalidatePaths ();
2010-06-24 12:10:45 +00:00
2023-06-20 22:06:45 +03:00
const CGObjectInstance * obj = cl . getObj ( pack . createdObjectID );
2017-03-12 10:54:24 +03:00
if ( CGI -> mh )
2023-02-16 21:35:15 +02:00
CGI -> mh -> onObjectFadeIn ( obj );
2011-08-25 20:02:38 +00:00
2023-02-12 09:23:39 +02:00
for ( auto i = cl . playerint . begin (); i != cl . playerint . end (); i ++ )
2009-07-26 03:33:13 +00:00
{
2023-02-12 09:23:39 +02:00
if ( gs . isVisible ( obj , i -> first ))
2009-07-26 03:33:13 +00:00
i -> second -> newObject ( obj );
}
2023-02-18 17:37:09 +02:00
CGI -> mh -> waitForOngoingAnimations ();
2009-07-26 03:33:13 +00:00
}
2009-10-03 11:16:42 +00:00
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitSetAvailableArtifacts ( SetAvailableArtifacts & pack )
2010-06-27 16:03:01 +00:00
{
2023-02-12 09:23:39 +02:00
if ( pack . id < 0 ) //artifact merchants globally
2010-06-27 16:03:01 +00:00
{
2018-02-03 17:44:30 +03:00
callAllInterfaces ( cl , & IGameEventsReceiver :: availableArtifactsChanged , nullptr );
2010-06-27 16:03:01 +00:00
}
else
{
2023-02-12 09:23:39 +02:00
const CGBlackMarket * bm = dynamic_cast < const CGBlackMarket *> ( cl . getObj ( ObjectInstanceID ( pack . id )));
2010-06-27 16:03:01 +00:00
assert ( bm );
2023-02-12 09:23:39 +02:00
callInterfaceIfPresent ( cl , cl . getTile ( bm -> visitablePos ()) -> visitableObjects . back () -> tempOwner , & IGameEventsReceiver :: availableArtifactsChanged , bm );
2010-06-27 16:03:01 +00:00
}
}
2018-03-17 17:58:30 +03:00
2023-02-12 09:23:39 +02:00
void ApplyClientNetPackVisitor :: visitEntitiesChanged ( EntitiesChanged & pack )
2018-03-17 17:58:30 +03:00
{
2023-02-12 09:23:39 +02:00
cl . invalidatePaths ();
2018-03-17 17:58:30 +03:00
}