2014-04-19 21:44:21 +04:00
/*
2014-04-20 12:58:58 +04:00
* CGameInfoCallback . cpp , part of VCMI engine
2014-04-19 21:44:21 +04: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
*
*/
# include "StdInc.h"
2014-04-20 12:58:58 +04:00
# include "CGameInfoCallback.h"
2014-04-19 21:44:21 +04:00
2025-05-11 11:58:09 +03:00
# include "../entities/building/CBuilding.h"
# include "../gameState/CGameState.h"
2025-05-14 15:50:13 +03:00
# include "../gameState/UpgradeInfo.h"
2025-05-11 11:58:09 +03:00
# include "../gameState/InfoAboutArmy.h"
# include "../gameState/TavernHeroesPool.h"
# include "../mapObjects/CGHeroInstance.h"
# include "../mapObjects/CGTownInstance.h"
# include "../mapObjects/MiscObjects.h"
# include "../StartInfo.h"
# include "../battle/BattleInfo.h"
# include "../IGameSettings.h"
# include "../spells/CSpellHandler.h"
# include "../mapping/CMap.h"
# include "../CPlayerState.h"
# define ASSERT_IF_CALLED_WITH_PLAYER if(!getPlayerID()) {logGlobal->error(BOOST_CURRENT_FUNCTION); assert(0);}
2014-04-19 21:44:21 +04:00
2022-07-26 16:07:42 +03:00
VCMI_LIB_NAMESPACE_BEGIN
2014-04-19 21:44:21 +04:00
//TODO make clean
2017-08-11 20:03:05 +03:00
# define ERROR_VERBOSE_OR_NOT_RET_VAL_IF(cond, verbose, txt, retVal) do {if(cond){if(verbose)logGlobal->error("%s: %s",BOOST_CURRENT_FUNCTION, txt); return retVal;}} while(0)
# define ERROR_RET_IF(cond, txt) do {if(cond){logGlobal->error("%s: %s", BOOST_CURRENT_FUNCTION, txt); return;}} while(0)
# define ERROR_RET_VAL_IF(cond, txt, retVal) do {if(cond){logGlobal->error("%s: %s", BOOST_CURRENT_FUNCTION, txt); return retVal;}} while(0)
2014-04-19 21:44:21 +04:00
PlayerColor CGameInfoCallback : : getOwner ( ObjectInstanceID heroID ) const
{
const CGObjectInstance * obj = getObj ( heroID ) ;
ERROR_RET_VAL_IF ( ! obj , " No such object! " , PlayerColor : : CANNOT_DETERMINE ) ;
return obj - > tempOwner ;
}
2023-04-05 03:26:29 +03:00
int CGameInfoCallback : : getResource ( PlayerColor Player , GameResID which ) const
2014-04-19 21:44:21 +04:00
{
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 17:58:30 +03:00
const PlayerState * p = getPlayerState ( Player ) ;
2014-04-19 21:44:21 +04:00
ERROR_RET_VAL_IF ( ! p , " No player info! " , - 1 ) ;
2023-08-18 13:38:19 +03:00
ERROR_RET_VAL_IF ( p - > resources . size ( ) < = which . getNum ( ) | | which . getNum ( ) < 0 , " No such resource! " , - 1 ) ;
2014-04-19 21:44:21 +04:00
return p - > resources [ which ] ;
}
const PlayerSettings * CGameInfoCallback : : getPlayerSettings ( PlayerColor color ) const
{
2025-04-19 14:14:12 +03:00
return & gameState ( ) . getStartInfo ( ) - > getIthPlayersSettings ( color ) ;
2014-04-19 21:44:21 +04:00
}
2023-11-05 15:24:26 +02:00
bool CGameInfoCallback : : isAllowed ( SpellID id ) const
2014-04-19 21:44:21 +04:00
{
2025-04-19 14:14:12 +03:00
return gameState ( ) . getMap ( ) . allowedSpells . count ( id ) ! = 0 ;
2023-11-05 15:24:26 +02:00
}
bool CGameInfoCallback : : isAllowed ( ArtifactID id ) const
{
2025-04-19 14:14:12 +03:00
return gameState ( ) . getMap ( ) . allowedArtifact . count ( id ) ! = 0 ;
2023-11-05 15:24:26 +02:00
}
bool CGameInfoCallback : : isAllowed ( SecondarySkill id ) const
{
2025-04-19 14:14:12 +03:00
return gameState ( ) . getMap ( ) . allowedAbilities . count ( id ) ! = 0 ;
2014-04-19 21:44:21 +04:00
}
2023-08-30 22:07:02 +03:00
std : : optional < PlayerColor > CGameInfoCallback : : getPlayerID ( ) const
{
return std : : nullopt ;
}
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 17:58:30 +03:00
const Player * CGameInfoCallback : : getPlayer ( PlayerColor color ) const
{
return getPlayerState ( color , false ) ;
}
const PlayerState * CGameInfoCallback : : getPlayerState ( PlayerColor color , bool verbose ) const
2014-04-19 21:44:21 +04:00
{
2024-06-24 03:23:26 +02:00
//function written from scratch since it's accessed A LOT by AI
2015-08-30 20:51:22 +02:00
2016-01-27 13:47:42 +03:00
if ( ! color . isValidPlayer ( ) )
{
return nullptr ;
}
2025-04-19 14:14:12 +03:00
auto player = gameState ( ) . players . find ( color ) ;
if ( player ! = gameState ( ) . players . end ( ) )
2015-08-30 20:51:22 +02:00
{
if ( hasAccess ( color ) )
return & player - > second ;
else
{
if ( verbose )
2016-08-12 19:20:57 +03:00
logGlobal - > error ( " Cannot access player %d info! " , color ) ;
2015-08-30 20:51:22 +02:00
return nullptr ;
}
}
else
{
if ( verbose )
2016-08-12 19:20:57 +03:00
logGlobal - > error ( " Cannot find player %d info! " , color ) ;
2015-08-30 20:51:22 +02:00
return nullptr ;
}
2014-04-19 21:44:21 +04:00
}
2023-08-14 02:16:25 +04:00
TurnTimerInfo CGameInfoCallback : : getPlayerTurnTime ( PlayerColor color ) const
2023-08-13 14:06:35 +04:00
{
if ( ! color . isValidPlayer ( ) )
{
2023-08-14 02:16:25 +04:00
return TurnTimerInfo { } ;
2023-08-13 14:06:35 +04:00
}
2025-04-19 14:14:12 +03:00
auto player = gameState ( ) . players . find ( color ) ;
if ( player ! = gameState ( ) . players . end ( ) )
2023-08-13 14:06:35 +04:00
{
2023-08-14 02:16:25 +04:00
return player - > second . turnTimer ;
2023-08-13 14:06:35 +04:00
}
2023-08-14 02:16:25 +04:00
return TurnTimerInfo { } ;
2023-08-13 14:06:35 +04:00
}
2014-04-19 21:44:21 +04:00
/************************************************************************/
/* */
/************************************************************************/
const CGObjectInstance * CGameInfoCallback : : getObj ( ObjectInstanceID objid , bool verbose ) const
{
2025-04-01 15:59:08 +03:00
if ( ! objid . hasValue ( ) )
{
if ( verbose )
logGlobal - > error ( " Cannot get object with id %d. No such object " , objid . getNum ( ) ) ;
return nullptr ;
}
2025-04-19 14:14:12 +03:00
const CGObjectInstance * ret = gameState ( ) . getMap ( ) . getObject ( objid ) ;
2014-04-19 21:44:21 +04:00
if ( ! ret )
{
if ( verbose )
2025-03-15 17:40:10 +00:00
logGlobal - > error ( " Cannot get object with id %d. Object was removed " , objid . getNum ( ) ) ;
2014-04-19 21:44:21 +04:00
return nullptr ;
}
2025-05-14 15:50:13 +03:00
if ( getPlayerID ( ) . has_value ( ) & & ! isVisibleFor ( ret , * getPlayerID ( ) ) & & ret - > tempOwner ! = getPlayerID ( ) )
2014-04-19 21:44:21 +04:00
{
if ( verbose )
2025-03-15 17:40:10 +00:00
logGlobal - > error ( " Cannot get object with id %d. Object is not visible. " , objid . getNum ( ) ) ;
2014-04-19 21:44:21 +04:00
return nullptr ;
}
return ret ;
}
const CGHeroInstance * CGameInfoCallback : : getHero ( ObjectInstanceID objid ) const
{
const CGObjectInstance * obj = getObj ( objid , false ) ;
if ( obj )
return dynamic_cast < const CGHeroInstance * > ( obj ) ;
else
return nullptr ;
}
const CGTownInstance * CGameInfoCallback : : getTown ( ObjectInstanceID objid ) const
{
const CGObjectInstance * obj = getObj ( objid , false ) ;
if ( obj )
return dynamic_cast < const CGTownInstance * > ( obj ) ;
else
return nullptr ;
}
2024-08-20 17:15:50 +03:00
const IMarket * CGameInfoCallback : : getMarket ( ObjectInstanceID objid ) const
{
const CGObjectInstance * obj = getObj ( objid , false ) ;
if ( obj )
return dynamic_cast < const IMarket * > ( obj ) ;
else
return nullptr ;
}
2024-11-19 10:49:14 +01:00
void CGameInfoCallback : : fillUpgradeInfo ( const CArmedInstance * obj , SlotID stackPos , UpgradeInfo & out ) const
2014-04-19 21:44:21 +04:00
{
ERROR_RET_IF ( ! canGetFullInfo ( obj ) , " Cannot get info about not owned object! " ) ;
ERROR_RET_IF ( ! obj - > hasStackAtSlot ( stackPos ) , " There is no such stack! " ) ;
2025-05-14 15:50:13 +03:00
const auto & stack = obj - > getStack ( stackPos ) ;
const CCreature * base = stack . getCreature ( ) ;
UpgradeInfo ret ( base - > getId ( ) ) ;
if ( stack . getArmy ( ) - > ID = = Obj : : HERO )
{
auto hero = dynamic_cast < const CGHeroInstance * > ( stack . getArmy ( ) ) ;
hero - > fillUpgradeInfo ( ret , stack ) ;
if ( hero - > getVisitedTown ( ) )
{
hero - > getVisitedTown ( ) - > fillUpgradeInfo ( ret , stack ) ;
}
else
{
auto object = vstd : : frontOrNull ( getVisitableObjs ( hero - > visitablePos ( ) ) ) ;
auto upgradeSource = dynamic_cast < const ICreatureUpgrader * > ( object ) ;
if ( object ! = hero & & upgradeSource ! = nullptr )
upgradeSource - > fillUpgradeInfo ( ret , stack ) ;
}
}
if ( stack . getArmy ( ) - > ID = = Obj : : TOWN )
{
auto town = dynamic_cast < const CGTownInstance * > ( stack . getArmy ( ) ) ;
town - > fillUpgradeInfo ( ret , stack ) ;
}
out = ret ;
2014-04-19 21:44:21 +04:00
}
2025-03-03 14:46:15 +00:00
const StartInfo * CGameInfoCallback : : getStartInfo ( ) const
2014-04-19 21:44:21 +04:00
{
2025-04-19 14:14:12 +03:00
return gameState ( ) . getStartInfo ( ) ;
2025-03-03 14:46:15 +00:00
}
const StartInfo * CGameInfoCallback : : getInitialStartInfo ( ) const
{
2025-04-19 14:14:12 +03:00
return gameState ( ) . getInitialStartInfo ( ) ;
2014-04-19 21:44:21 +04:00
}
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 17:58:30 +03:00
int32_t CGameInfoCallback : : getSpellCost ( const spells : : Spell * sp , const CGHeroInstance * caster ) const
2014-04-19 21:44:21 +04:00
{
ERROR_RET_VAL_IF ( ! canGetFullInfo ( caster ) , " Cannot get info about caster! " , - 1 ) ;
//if there is a battle
2025-04-19 14:14:12 +03:00
auto casterBattle = gameState ( ) . getBattle ( caster - > getOwner ( ) ) ;
2023-08-25 18:23:15 +03:00
if ( casterBattle )
return casterBattle - > battleGetSpellCost ( sp , caster ) ;
2014-04-19 21:44:21 +04:00
//if there is no battle
return caster - > getSpellCost ( sp ) ;
}
2017-07-20 07:08:49 +03:00
int64_t CGameInfoCallback : : estimateSpellDamage ( const CSpell * sp , const CGHeroInstance * hero ) const
2014-04-19 21:44:21 +04:00
{
ERROR_RET_VAL_IF ( hero & & ! canGetFullInfo ( hero ) , " Cannot get info about caster! " , - 1 ) ;
2014-11-13 15:16:27 +03:00
2017-07-20 07:08:49 +03:00
if ( hero ) //we see hero's spellbook
return sp - > calculateDamage ( hero ) ;
2014-11-13 15:16:27 +03:00
else
return 0 ; //mage guild
2014-04-19 21:44:21 +04:00
}
void CGameInfoCallback : : getThievesGuildInfo ( SThievesGuildInfo & thi , const CGObjectInstance * obj )
{
ERROR_RET_IF ( ! obj , " No guild object! " ) ;
ERROR_RET_IF ( obj - > ID = = Obj : : TOWN & & ! canGetFullInfo ( obj ) , " Cannot get info about town guild object! " ) ;
//TODO: advmap object -> check if they're visited by our hero
2024-05-30 21:58:35 +02:00
if ( obj - > ID = = Obj : : TOWN | | obj - > ID = = Obj : : TAVERN )
2014-04-19 21:44:21 +04:00
{
2025-04-19 14:14:12 +03:00
int taverns = gameState ( ) . players . at ( * getPlayerID ( ) ) . valOfBonuses ( BonusType : : THIEVES_GUILD_ACCESS ) ;
gameState ( ) . obtainPlayersStats ( thi , taverns ) ;
2014-04-19 21:44:21 +04:00
}
else if ( obj - > ID = = Obj : : DEN_OF_THIEVES )
{
2025-04-19 14:14:12 +03:00
gameState ( ) . obtainPlayersStats ( thi , 20 ) ;
2014-04-19 21:44:21 +04:00
}
}
int CGameInfoCallback : : howManyTowns ( PlayerColor Player ) const
{
ERROR_RET_VAL_IF ( ! hasAccess ( Player ) , " Access forbidden! " , - 1 ) ;
2025-04-19 14:14:12 +03:00
return static_cast < int > ( gameState ( ) . players . at ( Player ) . getTowns ( ) . size ( ) ) ;
2014-04-19 21:44:21 +04:00
}
2017-07-15 14:08:20 +03:00
bool CGameInfoCallback : : getTownInfo ( const CGObjectInstance * town , InfoAboutTown & dest , const CGObjectInstance * selectedObject ) const
2014-04-19 21:44:21 +04:00
{
2025-05-14 15:50:13 +03:00
ERROR_RET_VAL_IF ( getPlayerID ( ) . has_value ( ) & & ! isVisibleFor ( town , * getPlayerID ( ) ) , " Town is not visible! " , false ) ; //it's not a town or it's not visible for layer
2014-04-19 21:44:21 +04:00
bool detailed = hasAccess ( town - > tempOwner ) ;
if ( town - > ID = = Obj : : TOWN )
2015-02-06 17:36:09 +03:00
{
if ( ! detailed & & nullptr ! = selectedObject )
{
2023-03-14 00:26:44 +03:00
const auto * selectedHero = dynamic_cast < const CGHeroInstance * > ( selectedObject ) ;
2015-02-06 17:36:09 +03:00
if ( nullptr ! = selectedHero )
2023-10-21 14:50:42 +03:00
detailed = selectedHero - > hasVisions ( town , BonusCustomSubtype : : visionsTowns ) ;
2015-02-06 17:36:09 +03:00
}
2016-01-27 13:47:42 +03:00
2023-03-14 00:26:44 +03:00
dest . initFromTown ( dynamic_cast < const CGTownInstance * > ( town ) , detailed ) ;
2016-01-27 13:47:42 +03:00
}
2014-04-19 21:44:21 +04:00
else if ( town - > ID = = Obj : : GARRISON | | town - > ID = = Obj : : GARRISON2 )
2023-03-14 00:26:44 +03:00
dest . initFromArmy ( dynamic_cast < const CArmedInstance * > ( town ) , detailed ) ;
2014-04-19 21:44:21 +04:00
else
return false ;
return true ;
}
2024-08-31 11:00:36 +00:00
const IGameSettings & CGameInfoCallback : : getSettings ( ) const
{
2025-04-19 14:14:12 +03:00
return gameState ( ) . getSettings ( ) ;
2024-08-31 11:00:36 +00:00
}
2025-05-14 15:50:13 +03:00
int3 CGameInfoCallback : : guardingCreaturePosition ( int3 pos ) const
2014-04-19 21:44:21 +04:00
{
ERROR_RET_VAL_IF ( ! isVisible ( pos ) , " Tile is not visible! " , int3 ( - 1 , - 1 , - 1 ) ) ;
2025-05-14 15:50:13 +03:00
return gameState ( ) . getMap ( ) . guardingCreaturePositions [ pos . z ] [ pos . x ] [ pos . y ] ;
2014-04-19 21:44:21 +04:00
}
std : : vector < const CGObjectInstance * > CGameInfoCallback : : getGuardingCreatures ( int3 pos ) const
{
ERROR_RET_VAL_IF ( ! isVisible ( pos ) , " Tile is not visible! " , std : : vector < const CGObjectInstance * > ( ) ) ;
std : : vector < const CGObjectInstance * > ret ;
2025-04-19 14:14:12 +03:00
for ( auto * cr : gameState ( ) . guardingCreatures ( pos ) )
2014-04-19 21:44:21 +04:00
{
ret . push_back ( cr ) ;
}
return ret ;
}
2024-04-10 18:19:48 +03:00
bool CGameInfoCallback : : isTileGuardedUnchecked ( int3 tile ) const
2024-04-01 20:18:35 +02:00
{
2025-04-19 14:14:12 +03:00
return ! gameState ( ) . guardingCreatures ( tile ) . empty ( ) ;
2024-04-01 20:18:35 +02:00
}
2017-07-15 14:08:20 +03:00
bool CGameInfoCallback : : getHeroInfo ( const CGObjectInstance * hero , InfoAboutHero & dest , const CGObjectInstance * selectedObject ) const
2014-04-19 21:44:21 +04:00
{
2023-03-14 00:26:44 +03:00
const auto * h = dynamic_cast < const CGHeroInstance * > ( hero ) ;
2014-04-19 21:44:21 +04:00
ERROR_RET_VAL_IF ( ! h , " That's not a hero! " , false ) ;
2016-09-28 13:22:33 +02:00
InfoAboutHero : : EInfoLevel infoLevel = InfoAboutHero : : EInfoLevel : : BASIC ;
2016-01-27 13:47:42 +03:00
2016-09-28 13:22:33 +02:00
if ( hasAccess ( h - > tempOwner ) )
infoLevel = InfoAboutHero : : EInfoLevel : : DETAILED ;
2016-12-10 13:34:58 +01:00
if ( infoLevel = = InfoAboutHero : : EInfoLevel : : BASIC )
2016-09-27 13:48:04 +02:00
{
2025-04-19 14:14:12 +03:00
auto ourBattle = gameState ( ) . getBattle ( * getPlayerID ( ) ) ;
2023-08-25 18:23:15 +03:00
2023-08-30 22:07:02 +03:00
if ( ourBattle & & ourBattle - > playerHasAccessToHeroInfo ( * getPlayerID ( ) , h ) ) //if it's battle we can get enemy hero full data
2016-09-28 13:22:33 +02:00
infoLevel = InfoAboutHero : : EInfoLevel : : INBATTLE ;
2016-12-10 13:34:58 +01:00
else
2022-12-07 22:10:08 +02:00
ERROR_RET_VAL_IF ( ! isVisible ( h - > visitablePos ( ) ) , " That hero is not visible! " , false ) ;
2017-08-11 20:03:05 +03:00
}
2016-09-27 13:48:04 +02:00
2016-09-28 13:22:33 +02:00
if ( ( infoLevel = = InfoAboutHero : : EInfoLevel : : BASIC ) & & nullptr ! = selectedObject )
2015-02-06 17:36:09 +03:00
{
2023-03-14 00:26:44 +03:00
const auto * selectedHero = dynamic_cast < const CGHeroInstance * > ( selectedObject ) ;
2015-02-06 17:36:09 +03:00
if ( nullptr ! = selectedHero )
2023-10-21 14:50:42 +03:00
if ( selectedHero - > hasVisions ( hero , BonusCustomSubtype : : visionsHeroes ) )
2016-09-28 13:22:33 +02:00
infoLevel = InfoAboutHero : : EInfoLevel : : DETAILED ;
2015-02-06 17:36:09 +03:00
}
2016-01-27 13:47:42 +03:00
2016-09-28 13:22:33 +02:00
dest . initFromHero ( h , infoLevel ) ;
2016-09-28 00:20:45 +02:00
2015-02-07 18:12:29 +03:00
//DISGUISED bonus implementation
2023-08-30 22:07:02 +03:00
if ( getPlayerRelations ( * getPlayerID ( ) , hero - > tempOwner ) = = PlayerRelations : : ENEMIES )
2015-02-07 18:12:29 +03:00
{
2016-01-27 13:47:42 +03:00
//todo: bonus cashing
2023-10-05 16:13:52 +03:00
int disguiseLevel = h - > valOfBonuses ( BonusType : : DISGUISED ) ;
2016-01-27 13:47:42 +03:00
2019-01-19 13:52:02 +03:00
auto doBasicDisguise = [ ] ( InfoAboutHero & info )
2015-02-07 18:12:29 +03:00
{
int maxAIValue = 0 ;
const CCreature * mostStrong = nullptr ;
2016-01-27 13:47:42 +03:00
2015-02-07 18:12:29 +03:00
for ( auto & elem : info . army )
{
2024-10-12 16:02:35 +00:00
if ( static_cast < int > ( elem . second . getCreature ( ) - > getAIValue ( ) ) > maxAIValue )
2015-02-07 18:12:29 +03:00
{
2024-10-12 16:02:35 +00:00
maxAIValue = elem . second . getCreature ( ) - > getAIValue ( ) ;
mostStrong = elem . second . getCreature ( ) ;
2015-02-07 18:12:29 +03:00
}
}
2016-01-27 13:47:42 +03:00
2015-02-07 18:12:29 +03:00
if ( nullptr = = mostStrong ) //just in case
2017-08-11 20:03:05 +03:00
logGlobal - > error ( " CGameInfoCallback::getHeroInfo: Unable to select most strong stack " ) ;
2015-02-07 18:12:29 +03:00
else
for ( auto & elem : info . army )
{
2024-10-12 16:02:35 +00:00
elem . second . setType ( mostStrong ) ;
2015-02-07 18:12:29 +03:00
}
} ;
2016-01-27 13:47:42 +03:00
2019-01-19 13:52:02 +03:00
auto doAdvancedDisguise = [ & doBasicDisguise ] ( InfoAboutHero & info )
2015-02-07 18:12:29 +03:00
{
doBasicDisguise ( info ) ;
2016-01-27 13:47:42 +03:00
2015-02-07 18:12:29 +03:00
for ( auto & elem : info . army )
2025-05-01 13:41:48 +03:00
elem . second . setCount ( 0 ) ;
2015-02-07 18:12:29 +03:00
} ;
2016-01-27 13:47:42 +03:00
auto doExpertDisguise = [ this , h ] ( InfoAboutHero & info )
2015-02-07 18:12:29 +03:00
{
for ( auto & elem : info . army )
2025-05-01 13:41:48 +03:00
elem . second . setCount ( 0 ) ;
2016-01-27 13:47:42 +03:00
2025-03-03 14:46:15 +00:00
const auto factionIndex = getStartInfo ( ) - > playerInfos . at ( h - > tempOwner ) . castle ;
2016-01-27 13:47:42 +03:00
2015-02-07 18:12:29 +03:00
int maxAIValue = 0 ;
const CCreature * mostStrong = nullptr ;
2016-01-27 13:47:42 +03:00
2025-02-14 16:23:37 +00:00
for ( const auto & creature : LIBRARY - > creh - > objects )
2015-02-07 18:12:29 +03:00
{
2024-10-05 19:37:52 +00:00
if ( creature - > getFactionID ( ) = = factionIndex & & static_cast < int > ( creature - > getAIValue ( ) ) > maxAIValue )
2015-02-07 18:12:29 +03:00
{
2023-04-05 03:26:29 +03:00
maxAIValue = creature - > getAIValue ( ) ;
2023-12-31 23:43:35 +02:00
mostStrong = creature . get ( ) ;
2015-02-07 18:12:29 +03:00
}
}
2016-01-27 13:47:42 +03:00
2015-02-07 18:12:29 +03:00
if ( nullptr ! = mostStrong ) //possible, faction may have no creatures at all
for ( auto & elem : info . army )
2024-10-12 16:02:35 +00:00
elem . second . setType ( mostStrong ) ;
2016-01-27 13:47:42 +03:00
} ;
2015-02-07 18:12:29 +03:00
switch ( disguiseLevel )
{
case 0 :
//no bonus at all - do nothing
2016-01-27 13:47:42 +03:00
break ;
2015-02-07 18:12:29 +03:00
case 1 :
doBasicDisguise ( dest ) ;
2016-01-27 13:47:42 +03:00
break ;
2015-02-07 18:12:29 +03:00
case 2 :
doAdvancedDisguise ( dest ) ;
2016-01-27 13:47:42 +03:00
break ;
2015-02-07 18:12:29 +03:00
case 3 :
doExpertDisguise ( dest ) ;
2016-01-27 13:47:42 +03:00
break ;
2015-02-07 18:12:29 +03:00
default :
//invalid value
2017-08-11 20:03:05 +03:00
logGlobal - > error ( " CGameInfoCallback::getHeroInfo: Invalid DISGUISED bonus value %d " , disguiseLevel ) ;
2015-02-07 18:12:29 +03:00
break ;
}
}
2014-04-19 21:44:21 +04:00
return true ;
}
2023-08-19 22:35:44 +03:00
int CGameInfoCallback : : getDate ( Date mode ) const
2014-04-19 21:44:21 +04:00
{
2025-04-19 14:14:12 +03:00
return gameState ( ) . getDate ( mode ) ;
2014-04-19 21:44:21 +04:00
}
2025-05-14 15:50:13 +03:00
bool CGameInfoCallback : : isVisibleFor ( int3 pos , PlayerColor player ) const
2014-04-19 21:44:21 +04:00
{
2025-05-14 15:50:13 +03:00
return gameState ( ) . isVisibleFor ( pos , player ) ;
2014-04-19 21:44:21 +04:00
}
bool CGameInfoCallback : : isVisible ( int3 pos ) const
{
2025-05-15 13:46:54 +03:00
if ( ! getPlayerID ( ) . has_value ( ) )
return true ; // weird, but we do have such calls
return gameState ( ) . isVisibleFor ( pos , * getPlayerID ( ) ) ;
2014-04-19 21:44:21 +04:00
}
2025-05-14 15:50:13 +03:00
bool CGameInfoCallback : : isVisibleFor ( const CGObjectInstance * obj , PlayerColor player ) const
2014-04-19 21:44:21 +04:00
{
2025-05-14 15:50:13 +03:00
return gameState ( ) . isVisibleFor ( obj , player ) ;
2014-04-19 21:44:21 +04:00
}
bool CGameInfoCallback : : isVisible ( const CGObjectInstance * obj ) const
{
2025-05-15 13:46:54 +03:00
if ( ! getPlayerID ( ) . has_value ( ) )
return true ; // weird, but we do have such calls
return gameState ( ) . isVisibleFor ( obj , * getPlayerID ( ) ) ;
2014-04-19 21:44:21 +04:00
}
2024-03-27 22:06:31 +01:00
std : : vector < const CGObjectInstance * > CGameInfoCallback : : getBlockingObjs ( int3 pos ) const
2014-04-19 21:44:21 +04:00
{
std : : vector < const CGObjectInstance * > ret ;
const TerrainTile * t = getTile ( pos ) ;
ERROR_RET_VAL_IF ( ! t , " Not a valid tile requested! " , ret ) ;
2025-03-19 14:40:45 +00:00
for ( const auto & objID : t - > blockingObjects )
ret . push_back ( getObj ( objID ) ) ;
2014-04-19 21:44:21 +04:00
return ret ;
}
2024-03-27 22:06:31 +01:00
std : : vector < const CGObjectInstance * > CGameInfoCallback : : getVisitableObjs ( int3 pos , bool verbose ) const
2014-04-19 21:44:21 +04:00
{
std : : vector < const CGObjectInstance * > ret ;
const TerrainTile * t = getTile ( pos , verbose ) ;
2017-08-11 20:03:05 +03:00
ERROR_VERBOSE_OR_NOT_RET_VAL_IF ( ! t , verbose , pos . toString ( ) + " is not visible! " , ret ) ;
2014-04-19 21:44:21 +04:00
2025-03-19 14:40:45 +00:00
for ( const auto & objID : t - > visitableObjects )
2014-04-19 21:44:21 +04:00
{
2025-04-10 12:27:18 +03:00
const auto & object = getObj ( objID , false ) ;
if ( ! object )
continue ; // event - visitable, but not visible
2025-03-19 14:40:45 +00:00
if ( ! getPlayerID ( ) . has_value ( ) | | object - > ID ! = Obj : : EVENT ) //hide events from players
ret . push_back ( object ) ;
2014-04-19 21:44:21 +04:00
}
return ret ;
}
2024-10-12 23:01:14 +02:00
2025-03-03 13:49:54 +00:00
std : : vector < const CGObjectInstance * > CGameInfoCallback : : getAllVisitableObjs ( ) const
2024-10-12 23:01:14 +02:00
{
2025-03-03 13:49:54 +00:00
std : : vector < const CGObjectInstance * > ret ;
2025-04-19 14:14:12 +03:00
for ( auto & obj : gameState ( ) . getMap ( ) . getObjects ( ) )
2025-03-15 17:40:10 +00:00
if ( obj - > isVisitable ( ) & & obj - > ID ! = Obj : : EVENT & & isVisible ( obj ) )
ret . push_back ( obj ) ;
2024-10-12 23:01:14 +02:00
return ret ;
}
2014-04-19 21:44:21 +04:00
const CGObjectInstance * CGameInfoCallback : : getTopObj ( int3 pos ) const
{
return vstd : : backOrNull ( getVisitableObjs ( pos ) ) ;
}
2024-03-27 22:06:31 +01:00
std : : vector < const CGObjectInstance * > CGameInfoCallback : : getFlaggableObjects ( int3 pos ) const
2014-04-19 21:44:21 +04:00
{
std : : vector < const CGObjectInstance * > ret ;
const TerrainTile * t = getTile ( pos ) ;
ERROR_RET_VAL_IF ( ! t , " Not a valid tile requested! " , ret ) ;
2025-03-19 14:40:45 +00:00
for ( const auto & objectID : t - > blockingObjects )
{
const auto * obj = getObj ( objectID ) ;
2014-04-19 21:44:21 +04:00
if ( obj - > tempOwner ! = PlayerColor : : UNFLAGGABLE )
ret . push_back ( obj ) ;
2025-03-19 14:40:45 +00:00
}
2014-04-19 21:44:21 +04:00
return ret ;
}
int3 CGameInfoCallback : : getMapSize ( ) const
{
2025-04-19 14:14:12 +03:00
return int3 ( gameState ( ) . getMap ( ) . width , gameState ( ) . getMap ( ) . height , gameState ( ) . getMap ( ) . twoLevel ? 2 : 1 ) ;
2014-04-19 21:44:21 +04:00
}
std : : vector < const CGHeroInstance * > CGameInfoCallback : : getAvailableHeroes ( const CGObjectInstance * townOrTavern ) const
{
ASSERT_IF_CALLED_WITH_PLAYER
std : : vector < const CGHeroInstance * > ret ;
//TODO: town needs to be owned, advmap tavern needs to be visited; to be reimplemented when visit tracking is done
2018-03-23 00:14:43 +13:00
const CGTownInstance * town = getTown ( townOrTavern - > id ) ;
2023-07-11 15:16:02 +03:00
2018-03-23 00:14:43 +13:00
if ( townOrTavern - > ID = = Obj : : TAVERN | | ( town & & town - > hasBuilt ( BuildingID : : TAVERN ) ) )
2025-04-19 14:14:12 +03:00
return gameState ( ) . heroesPool - > getHeroesFor ( * getPlayerID ( ) ) ;
2023-07-11 15:16:02 +03:00
2014-04-19 21:44:21 +04:00
return ret ;
}
2024-03-24 23:58:04 +01:00
const TerrainTile * CGameInfoCallback : : getTile ( int3 tile , bool verbose ) const
2014-04-19 21:44:21 +04:00
{
2022-01-25 14:19:48 +03:00
if ( isVisible ( tile ) )
2025-04-19 14:14:12 +03:00
return & gameState ( ) . getMap ( ) . getTile ( tile ) ;
2014-04-19 21:44:21 +04:00
2022-01-25 14:19:48 +03:00
if ( verbose )
logGlobal - > error ( " \r \n %s: %s \r \n " , BOOST_CURRENT_FUNCTION , tile . toString ( ) + " is not visible! " ) ;
return nullptr ;
2014-04-19 21:44:21 +04:00
}
2024-04-10 18:19:48 +03:00
const TerrainTile * CGameInfoCallback : : getTileUnchecked ( int3 tile ) const
2024-03-24 23:58:04 +01:00
{
2024-04-10 18:19:48 +03:00
if ( isInTheMap ( tile ) )
2025-04-19 14:14:12 +03:00
return & gameState ( ) . getMap ( ) . getTile ( tile ) ;
2024-03-24 23:58:04 +01:00
2024-04-10 18:19:48 +03:00
return nullptr ;
2024-03-24 23:58:04 +01:00
}
2023-02-22 17:24:42 +02:00
EDiggingStatus CGameInfoCallback : : getTileDigStatus ( int3 tile , bool verbose ) const
{
if ( ! isVisible ( tile ) )
return EDiggingStatus : : UNKNOWN ;
2025-04-19 14:14:12 +03:00
for ( const auto & object : gameState ( ) . getMap ( ) . getObjects ( ) )
2023-02-22 17:24:42 +02:00
{
2025-03-15 17:40:10 +00:00
if ( object - > ID = = Obj : : HOLE & & object - > anchorPos ( ) = = tile )
2023-02-22 17:24:42 +02:00
return EDiggingStatus : : TILE_OCCUPIED ;
}
return getTile ( tile ) - > getDiggingStatus ( ) ;
}
2023-08-19 22:35:44 +03:00
EBuildingState CGameInfoCallback : : canBuildStructure ( const CGTownInstance * t , BuildingID ID )
2014-04-19 21:44:21 +04:00
{
ERROR_RET_VAL_IF ( ! canGetFullInfo ( t ) , " Town is not owned! " , EBuildingState : : TOWN_NOT_OWNED ) ;
2024-10-05 19:37:52 +00:00
if ( ! t - > getTown ( ) - > buildings . count ( ID ) )
2014-04-19 21:44:21 +04:00
return EBuildingState : : BUILDING_ERROR ;
2025-03-03 13:49:54 +00:00
const auto & building = t - > getTown ( ) - > buildings . at ( ID ) ;
2014-04-19 21:44:21 +04:00
if ( t - > hasBuilt ( ID ) ) //already built
return EBuildingState : : ALREADY_PRESENT ;
//can we build it?
if ( vstd : : contains ( t - > forbiddenBuildings , ID ) )
return EBuildingState : : FORBIDDEN ; //forbidden
2023-03-14 00:26:44 +03:00
auto possiblyNotBuiltTest = [ & ] ( const BuildingID & id ) - > bool
2016-09-12 22:28:11 +02:00
{
return ( ( id = = BuildingID : : CAPITOL ) ? true : ! t - > hasBuilt ( id ) ) ;
} ;
2016-09-10 19:38:49 +02:00
2023-03-14 00:26:44 +03:00
std : : function < bool ( BuildingID id ) > allowedTest = [ & ] ( const BuildingID & id ) - > bool
2016-09-10 19:38:49 +02:00
{
2016-10-15 04:19:47 +03:00
return ! vstd : : contains ( t - > forbiddenBuildings , id ) ;
2016-09-10 19:38:49 +02:00
} ;
if ( ! t - > genBuildingRequirements ( ID , true ) . satisfiable ( allowedTest , possiblyNotBuiltTest ) )
return EBuildingState : : FORBIDDEN ;
2014-04-19 21:44:21 +04:00
if ( ID = = BuildingID : : CAPITOL )
{
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 17:58:30 +03:00
const PlayerState * ps = getPlayerState ( t - > tempOwner , false ) ;
2014-04-19 21:44:21 +04:00
if ( ps )
{
2024-08-24 22:21:26 +00:00
for ( const CGTownInstance * town : ps - > getTowns ( ) )
2014-04-19 21:44:21 +04:00
{
2018-10-29 16:56:14 +01:00
if ( town - > hasBuilt ( BuildingID : : CAPITOL ) )
2014-04-19 21:44:21 +04:00
{
return EBuildingState : : HAVE_CAPITAL ; //no more than one capitol
}
}
}
}
else if ( ID = = BuildingID : : SHIPYARD )
{
const TerrainTile * tile = getTile ( t - > bestLocation ( ) , false ) ;
2024-07-13 18:37:13 +00:00
if ( ! tile | | ! tile - > isWater ( ) )
2014-04-19 21:44:21 +04:00
return EBuildingState : : NO_WATER ; //lack of water
}
2023-03-14 00:26:44 +03:00
auto buildTest = [ & ] ( const BuildingID & id ) - > bool
2014-04-19 21:44:21 +04:00
{
2014-08-07 19:40:22 +03:00
return t - > hasBuilt ( id ) ;
2014-04-19 21:44:21 +04:00
} ;
2014-08-07 19:40:22 +03:00
if ( ! t - > genBuildingRequirements ( ID ) . test ( buildTest ) )
2014-04-19 21:44:21 +04:00
return EBuildingState : : PREREQUIRES ;
2024-08-31 11:00:36 +00:00
if ( t - > built > = getSettings ( ) . getInteger ( EGameSettings : : TOWNS_BUILDINGS_PER_TURN_CAP ) )
2014-07-29 09:49:50 +02:00
return EBuildingState : : CANT_BUILD_TODAY ; //building limit
2014-04-19 21:44:21 +04:00
//checking resources
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 17:58:30 +03:00
if ( ! building - > resources . canBeAfforded ( getPlayerState ( t - > tempOwner ) - > resources ) )
2014-04-19 21:44:21 +04:00
return EBuildingState : : NO_RESOURCES ; //lack of res
return EBuildingState : : ALLOWED ;
}
const CMapHeader * CGameInfoCallback : : getMapHeader ( ) const
{
2025-04-19 14:14:12 +03:00
return & gameState ( ) . getMap ( ) ;
2014-04-19 21:44:21 +04:00
}
2023-04-16 20:42:56 +03:00
bool CGameInfoCallback : : hasAccess ( std : : optional < PlayerColor > playerId ) const
2014-04-19 21:44:21 +04:00
{
2025-04-19 14:14:12 +03:00
return ! getPlayerID ( ) | | getPlayerID ( ) - > isSpectator ( ) | | gameState ( ) . getPlayerRelations ( * playerId , * getPlayerID ( ) ) ! = PlayerRelations : : ENEMIES ;
2014-04-19 21:44:21 +04:00
}
2023-08-19 21:43:50 +03:00
EPlayerStatus CGameInfoCallback : : getPlayerStatus ( PlayerColor player , bool verbose ) const
2014-04-19 21:44:21 +04:00
{
2025-04-19 14:14:12 +03:00
const PlayerState * ps = gameState ( ) . getPlayerState ( player , verbose ) ;
2014-04-19 21:44:21 +04:00
ERROR_VERBOSE_OR_NOT_RET_VAL_IF ( ! ps , verbose , " No such player! " , EPlayerStatus : : WRONG ) ;
return ps - > status ;
}
2015-11-30 17:51:28 +03:00
std : : string CGameInfoCallback : : getTavernRumor ( const CGObjectInstance * townOrTavern ) const
2014-04-19 21:44:21 +04:00
{
2023-09-27 23:22:45 +02:00
MetaString text ;
text . appendLocalString ( EMetaText : : GENERAL_TXT , 216 ) ;
2023-03-14 00:26:44 +03:00
std : : string extraText ;
2025-04-19 14:14:12 +03:00
if ( gameState ( ) . currentRumor . type = = RumorState : : TYPE_NONE )
2023-09-27 23:22:45 +02:00
return text . toString ( ) ;
2015-11-30 20:52:15 +03:00
2025-04-19 14:14:12 +03:00
auto rumor = gameState ( ) . currentRumor . last . at ( gameState ( ) . currentRumor . type ) ;
switch ( gameState ( ) . currentRumor . type )
2015-11-30 20:52:15 +03:00
{
2015-12-04 22:58:14 +03:00
case RumorState : : TYPE_SPECIAL :
2023-09-27 23:22:45 +02:00
text . replaceLocalString ( EMetaText : : GENERAL_TXT , rumor . first ) ;
2015-12-04 22:58:14 +03:00
if ( rumor . first = = RumorState : : RUMOR_GRAIL )
2023-10-11 00:58:32 +02:00
text . replaceTextID ( TextIdentifier ( " core " , " arraytxt " , 158 + rumor . second ) . get ( ) ) ;
2015-12-01 04:57:52 +03:00
else
2023-10-11 00:58:32 +02:00
text . replaceTextID ( TextIdentifier ( " core " , " plcolors " , rumor . second ) . get ( ) ) ;
2015-12-01 04:57:52 +03:00
break ;
2015-12-04 22:58:14 +03:00
case RumorState : : TYPE_MAP :
2025-04-19 14:14:12 +03:00
text . replaceRawString ( gameState ( ) . getMap ( ) . rumors [ rumor . first ] . text . toString ( ) ) ;
2015-12-01 00:44:58 +03:00
break ;
2015-11-30 20:52:15 +03:00
2015-12-04 22:58:14 +03:00
case RumorState : : TYPE_RAND :
2023-10-11 00:58:32 +02:00
text . replaceTextID ( TextIdentifier ( " core " , " randtvrn " , rumor . first ) . get ( ) ) ;
2015-11-30 20:52:15 +03:00
break ;
}
2023-09-27 23:22:45 +02:00
return text . toString ( ) ;
2014-04-19 21:44:21 +04:00
}
2023-08-19 21:43:50 +03:00
PlayerRelations CGameInfoCallback : : getPlayerRelations ( PlayerColor color1 , PlayerColor color2 ) const
2014-04-19 21:44:21 +04:00
{
2025-04-19 14:14:12 +03:00
return gameState ( ) . getPlayerRelations ( color1 , color2 ) ;
2014-04-19 21:44:21 +04:00
}
bool CGameInfoCallback : : canGetFullInfo ( const CGObjectInstance * obj ) const
{
return ! obj | | hasAccess ( obj - > tempOwner ) ;
}
int CGameInfoCallback : : getHeroCount ( PlayerColor player , bool includeGarrisoned ) const
{
int ret = 0 ;
2025-04-19 14:14:12 +03:00
const PlayerState * p = gameState ( ) . getPlayerState ( player ) ;
2014-04-19 21:44:21 +04:00
ERROR_RET_VAL_IF ( ! p , " No such player! " , - 1 ) ;
if ( includeGarrisoned )
2024-08-24 22:21:26 +00:00
return static_cast < int > ( p - > getHeroes ( ) . size ( ) ) ;
2014-04-19 21:44:21 +04:00
else
2024-08-24 22:21:26 +00:00
for ( const auto & elem : p - > getHeroes ( ) )
2025-03-09 21:51:33 +00:00
if ( ! elem - > isGarrisoned ( ) )
2014-04-19 21:44:21 +04:00
ret + + ;
return ret ;
}
2023-08-25 01:08:48 +03:00
bool CGameInfoCallback : : isPlayerMakingTurn ( PlayerColor player ) const
2014-04-19 21:44:21 +04:00
{
2025-04-19 14:14:12 +03:00
return gameState ( ) . actingPlayers . count ( player ) ;
2014-04-19 21:44:21 +04:00
}
const TeamState * CGameInfoCallback : : getTeam ( TeamID teamID ) const
{
2015-08-30 21:42:19 +02:00
//rewritten by hand, AI calls this function a lot
2025-04-19 14:14:12 +03:00
auto team = gameState ( ) . teams . find ( teamID ) ;
if ( team ! = gameState ( ) . teams . end ( ) )
2015-08-30 21:42:19 +02:00
{
const TeamState * ret = & team - > second ;
2023-08-30 22:07:02 +03:00
if ( ! getPlayerID ( ) . has_value ( ) ) //neutral (or invalid) player
2015-08-30 21:42:19 +02:00
return ret ;
else
{
2023-08-30 22:07:02 +03:00
if ( vstd : : contains ( ret - > players , * getPlayerID ( ) ) ) //specific player
2015-08-30 21:42:19 +02:00
return ret ;
else
{
2016-08-12 11:36:24 +03:00
logGlobal - > error ( " Illegal attempt to access team data! " ) ;
2015-08-30 21:42:19 +02:00
return nullptr ;
}
}
}
else
{
2016-08-12 19:20:57 +03:00
logGlobal - > error ( " Cannot find info for team %d " , teamID ) ;
2015-08-30 21:42:19 +02:00
return nullptr ;
}
2014-04-19 21:44:21 +04:00
}
const TeamState * CGameInfoCallback : : getPlayerTeam ( PlayerColor color ) const
{
2025-04-19 14:14:12 +03:00
auto player = gameState ( ) . players . find ( color ) ;
if ( player ! = gameState ( ) . players . end ( ) )
2015-08-30 21:42:19 +02:00
{
return getTeam ( player - > second . team ) ;
}
else
{
return nullptr ;
}
2014-04-19 21:44:21 +04:00
}
bool CGameInfoCallback : : isInTheMap ( const int3 & pos ) const
{
2025-04-19 14:14:12 +03:00
return gameState ( ) . getMap ( ) . isInTheMap ( pos ) ;
2014-04-19 21:44:21 +04:00
}
2023-04-16 01:48:49 +03:00
void CGameInfoCallback : : getVisibleTilesInRange ( std : : unordered_set < int3 > & tiles , int3 pos , int radious , int3 : : EDistanceFormula distanceFormula ) const
2017-09-13 03:35:58 +03:00
{
2025-04-19 14:14:12 +03:00
gameState ( ) . getTilesInRange ( tiles , pos , radious , ETileVisibility : : REVEALED , * getPlayerID ( ) , distanceFormula ) ;
2017-09-13 03:35:58 +03:00
}
2025-01-23 14:39:56 +00:00
void CGameInfoCallback : : calculatePaths ( const std : : shared_ptr < PathfinderConfig > & config ) const
2018-08-12 14:31:31 +03:00
{
2025-04-19 14:14:12 +03:00
gameState ( ) . calculatePaths ( config ) ;
2018-08-12 14:31:31 +03:00
}
2014-04-19 21:44:21 +04:00
const CArtifactInstance * CGameInfoCallback : : getArtInstance ( ArtifactInstanceID aid ) const
{
2025-04-19 14:14:12 +03:00
return gameState ( ) . getMap ( ) . getArtifactInstance ( aid ) ;
2014-04-19 21:44:21 +04:00
}
const CGObjectInstance * CGameInfoCallback : : getObjInstance ( ObjectInstanceID oid ) const
{
2025-04-19 14:14:12 +03:00
return gameState ( ) . getMap ( ) . getObject ( ( oid ) ) ;
2014-04-19 21:44:21 +04:00
}
2024-02-01 10:43:16 +02:00
const CArtifactSet * CGameInfoCallback : : getArtSet ( const ArtifactLocation & loc ) const
2023-10-23 19:37:18 +03:00
{
2025-04-19 14:14:12 +03:00
auto & gs = const_cast < CGameState & > ( gameState ( ) ) ;
return gs . getArtSet ( loc ) ;
2023-10-23 19:37:18 +03:00
}
2015-03-09 05:10:31 +03:00
std : : vector < ObjectInstanceID > CGameInfoCallback : : getVisibleTeleportObjects ( std : : vector < ObjectInstanceID > ids , PlayerColor player ) const
2015-03-08 16:21:14 +03:00
{
2023-03-14 00:26:44 +03:00
vstd : : erase_if ( ids , [ & ] ( const ObjectInstanceID & id ) - > bool
2015-03-08 16:21:14 +03:00
{
2023-03-14 00:26:44 +03:00
const auto * obj = getObj ( id , false ) ;
2025-05-14 15:50:13 +03:00
return player ! = PlayerColor : : UNFLAGGABLE & & ( ! obj | | ! isVisibleFor ( obj - > visitablePos ( ) , player ) ) ;
2015-03-09 05:10:31 +03:00
} ) ;
return ids ;
2015-03-08 16:21:14 +03:00
}
2024-06-24 03:23:26 +02:00
std : : vector < ObjectInstanceID > CGameInfoCallback : : getTeleportChannelEntrances ( TeleportChannelID id , PlayerColor player ) const
2015-03-08 16:21:14 +03:00
{
2025-04-19 14:14:12 +03:00
return getVisibleTeleportObjects ( gameState ( ) . getMap ( ) . teleportChannels . at ( id ) - > entrances , player ) ;
2015-03-09 05:10:31 +03:00
}
2015-03-08 16:21:14 +03:00
2015-03-09 14:20:34 +03:00
std : : vector < ObjectInstanceID > CGameInfoCallback : : getTeleportChannelExits ( TeleportChannelID id , PlayerColor player ) const
2015-03-09 05:10:31 +03:00
{
2025-04-19 14:14:12 +03:00
return getVisibleTeleportObjects ( gameState ( ) . getMap ( ) . teleportChannels . at ( id ) - > exits , player ) ;
2015-03-08 16:21:14 +03:00
}
2015-03-09 02:01:24 +03:00
ETeleportChannelType CGameInfoCallback : : getTeleportChannelType ( TeleportChannelID id , PlayerColor player ) const
2015-03-08 16:21:14 +03:00
{
2024-06-24 03:23:26 +02:00
std : : vector < ObjectInstanceID > entrances = getTeleportChannelEntrances ( id , player ) ;
2015-03-09 14:20:34 +03:00
std : : vector < ObjectInstanceID > exits = getTeleportChannelExits ( id , player ) ;
2023-03-14 00:26:44 +03:00
if ( ( entrances . empty ( ) | | exits . empty ( ) ) // impassable if exits or entrances list are empty
| | ( entrances . size ( ) = = 1 & & entrances = = exits ) ) // impassable if only entrance and only exit is same object. e.g bidirectional monolith
2015-03-08 16:21:14 +03:00
{
return ETeleportChannelType : : IMPASSABLE ;
}
auto intersection = vstd : : intersection ( entrances , exits ) ;
if ( intersection . size ( ) = = entrances . size ( ) & & intersection . size ( ) = = exits . size ( ) )
return ETeleportChannelType : : BIDIRECTIONAL ;
2023-03-14 00:26:44 +03:00
else if ( intersection . empty ( ) )
2015-03-08 16:21:14 +03:00
return ETeleportChannelType : : UNIDIRECTIONAL ;
else
return ETeleportChannelType : : MIXED ;
}
2015-03-09 02:01:24 +03:00
bool CGameInfoCallback : : isTeleportChannelImpassable ( TeleportChannelID id , PlayerColor player ) const
2015-03-08 16:21:14 +03:00
{
2015-03-09 02:01:24 +03:00
return ETeleportChannelType : : IMPASSABLE = = getTeleportChannelType ( id , player ) ;
}
bool CGameInfoCallback : : isTeleportChannelBidirectional ( TeleportChannelID id , PlayerColor player ) const
{
return ETeleportChannelType : : BIDIRECTIONAL = = getTeleportChannelType ( id , player ) ;
}
bool CGameInfoCallback : : isTeleportChannelUnidirectional ( TeleportChannelID id , PlayerColor player ) const
{
return ETeleportChannelType : : UNIDIRECTIONAL = = getTeleportChannelType ( id , player ) ;
}
bool CGameInfoCallback : : isTeleportEntrancePassable ( const CGTeleport * obj , PlayerColor player ) const
{
return obj & & obj - > isEntrance ( ) & & ! isTeleportChannelImpassable ( obj - > channel , player ) ;
2015-03-08 16:21:14 +03:00
}
2022-07-26 16:07:42 +03:00
2025-05-14 13:39:37 +03:00
void CGameInfoCallback : : getFreeTiles ( std : : vector < int3 > & tiles ) const
{
std : : vector < int > floors ;
floors . reserve ( gameState ( ) . getMap ( ) . levels ( ) ) ;
for ( int b = 0 ; b < gameState ( ) . getMap ( ) . levels ( ) ; + + b )
{
floors . push_back ( b ) ;
}
const TerrainTile * tinfo = nullptr ;
for ( auto zd : floors )
{
for ( int xd = 0 ; xd < gameState ( ) . getMap ( ) . width ; xd + + )
{
for ( int yd = 0 ; yd < gameState ( ) . getMap ( ) . height ; yd + + )
{
tinfo = getTile ( int3 ( xd , yd , zd ) ) ;
if ( tinfo - > isLand ( ) & & tinfo - > getTerrain ( ) - > isPassable ( ) & & ! tinfo - > blocked ( ) ) //land and free
tiles . emplace_back ( xd , yd , zd ) ;
}
}
}
}
void CGameInfoCallback : : getTilesInRange ( std : : unordered_set < int3 > & tiles ,
const int3 & pos ,
int radious ,
ETileVisibility mode ,
std : : optional < PlayerColor > player ,
int3 : : EDistanceFormula distanceFormula ) const
{
if ( player . has_value ( ) & & ! player - > isValidPlayer ( ) )
{
logGlobal - > error ( " Illegal call to getTilesInRange! " ) ;
return ;
}
if ( radious = = CBuilding : : HEIGHT_SKYSHIP ) //reveal entire map
getAllTiles ( tiles , player , - 1 , [ ] ( auto * tile ) { return true ; } ) ;
else
{
const TeamState * team = ! player ? nullptr : gameState ( ) . getPlayerTeam ( * player ) ;
for ( int xd = std : : max < int > ( pos . x - radious , 0 ) ; xd < = std : : min < int > ( pos . x + radious , gameState ( ) . getMap ( ) . width - 1 ) ; xd + + )
{
for ( int yd = std : : max < int > ( pos . y - radious , 0 ) ; yd < = std : : min < int > ( pos . y + radious , gameState ( ) . getMap ( ) . height - 1 ) ; yd + + )
{
int3 tilePos ( xd , yd , pos . z ) ;
int distance = pos . dist ( tilePos , distanceFormula ) ;
if ( distance < = radious )
{
if ( ! player
| | ( mode = = ETileVisibility : : HIDDEN & & team - > fogOfWarMap [ pos . z ] [ xd ] [ yd ] = = 0 )
| | ( mode = = ETileVisibility : : REVEALED & & team - > fogOfWarMap [ pos . z ] [ xd ] [ yd ] = = 1 )
)
tiles . insert ( int3 ( xd , yd , pos . z ) ) ;
}
}
}
}
}
void CGameInfoCallback : : getAllTiles ( std : : unordered_set < int3 > & tiles , std : : optional < PlayerColor > Player , int level , std : : function < bool ( const TerrainTile * ) > filter ) const
{
if ( Player . has_value ( ) & & ! Player - > isValidPlayer ( ) )
{
logGlobal - > error ( " Illegal call to getAllTiles ! " ) ;
return ;
}
std : : vector < int > floors ;
if ( level = = - 1 )
{
for ( int b = 0 ; b < gameState ( ) . getMap ( ) . levels ( ) ; + + b )
{
floors . push_back ( b ) ;
}
}
else
floors . push_back ( level ) ;
for ( auto zd : floors )
{
for ( int xd = 0 ; xd < gameState ( ) . getMap ( ) . width ; xd + + )
{
for ( int yd = 0 ; yd < gameState ( ) . getMap ( ) . height ; yd + + )
{
int3 coordinates ( xd , yd , zd ) ;
if ( filter ( getTile ( coordinates ) ) )
tiles . insert ( coordinates ) ;
}
}
}
}
void CGameInfoCallback : : pickAllowedArtsSet ( std : : vector < ArtifactID > & out , vstd : : RNG & rand )
{
for ( int j = 0 ; j < 3 ; j + + )
out . push_back ( gameState ( ) . pickRandomArtifact ( rand , EArtifactClass : : ART_TREASURE ) ) ;
for ( int j = 0 ; j < 3 ; j + + )
out . push_back ( gameState ( ) . pickRandomArtifact ( rand , EArtifactClass : : ART_MINOR ) ) ;
out . push_back ( gameState ( ) . pickRandomArtifact ( rand , EArtifactClass : : ART_MAJOR ) ) ;
}
void CGameInfoCallback : : getAllowedSpells ( std : : vector < SpellID > & out , std : : optional < ui16 > level )
{
for ( auto const & spellID : gameState ( ) . getMap ( ) . allowedSpells )
{
const auto * spell = spellID . toEntity ( LIBRARY ) ;
if ( ! isAllowed ( spellID ) )
continue ;
if ( level . has_value ( ) & & spell - > getLevel ( ) ! = level )
continue ;
out . push_back ( spellID ) ;
}
}
# if SCRIPTING_ENABLED
scripting : : Pool * CGameInfoCallback : : getGlobalContextPool ( ) const
{
return nullptr ; // TODO
}
# endif
2022-07-26 16:07:42 +03:00
VCMI_LIB_NAMESPACE_END