2023-06-08 17:29:29 +03:00
/*
* DwellingInstanceConstructor . 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
*
*/
# include "StdInc.h"
# include "DwellingInstanceConstructor.h"
# include "../CCreatureHandler.h"
2024-07-20 12:55:17 +00:00
# include "../texts/CGeneralTextHandler.h"
2024-02-11 23:09:01 +02:00
# include "../json/JsonRandom.h"
2025-02-14 16:23:37 +00:00
# include "../GameLibrary.h"
2023-06-08 17:29:29 +03:00
# include "../mapObjects/CGDwelling.h"
2025-05-12 17:50:36 +03:00
# include "../mapObjects/ObjectTemplate.h"
2023-07-30 20:12:25 +03:00
# include "../modding/IdentifierStorage.h"
2025-05-12 17:50:36 +03:00
# include "../CConfigHandler.h"
2023-06-08 17:29:29 +03:00
VCMI_LIB_NAMESPACE_BEGIN
bool DwellingInstanceConstructor : : hasNameTextID ( ) const
{
return true ;
}
void DwellingInstanceConstructor : : initTypeData ( const JsonNode & input )
{
if ( input . Struct ( ) . count ( " name " ) = = 0 )
logMod - > warn ( " Dwelling %s missing name! " , getJsonKey ( ) ) ;
2025-02-14 16:23:37 +00:00
LIBRARY - > generaltexth - > registerString ( input . getModScope ( ) , getNameTextID ( ) , input [ " name " ] ) ;
2023-06-08 17:29:29 +03:00
const JsonVector & levels = input [ " creatures " ] . Vector ( ) ;
const auto totalLevels = levels . size ( ) ;
availableCreatures . resize ( totalLevels ) ;
2024-01-20 18:40:03 +02:00
for ( int currentLevel = 0 ; currentLevel < totalLevels ; currentLevel + + )
2023-06-08 17:29:29 +03:00
{
const JsonVector & creaturesOnLevel = levels [ currentLevel ] . Vector ( ) ;
const auto creaturesNumber = creaturesOnLevel . size ( ) ;
availableCreatures [ currentLevel ] . resize ( creaturesNumber ) ;
2024-01-20 18:40:03 +02:00
for ( int currentCreature = 0 ; currentCreature < creaturesNumber ; currentCreature + + )
2023-06-08 17:29:29 +03:00
{
2025-02-14 16:23:37 +00:00
LIBRARY - > identifiers ( ) - > requestIdentifier ( " creature " , creaturesOnLevel [ currentCreature ] , [ this , currentLevel , currentCreature ] ( si32 index )
2023-06-08 17:29:29 +03:00
{
2024-01-25 16:23:13 +02:00
availableCreatures . at ( currentLevel ) . at ( currentCreature ) = CreatureID ( index ) . toCreature ( ) ;
2023-06-08 17:29:29 +03:00
} ) ;
}
assert ( ! availableCreatures [ currentLevel ] . empty ( ) ) ;
}
guards = input [ " guards " ] ;
2024-04-22 12:35:55 +03:00
bannedForRandomDwelling = input [ " bannedForRandomDwelling " ] . Bool ( ) ;
2025-05-12 17:50:36 +03:00
for ( const auto & mapTemplate : getTemplates ( ) )
onTemplateAdded ( mapTemplate ) ;
}
void DwellingInstanceConstructor : : onTemplateAdded ( const std : : shared_ptr < const ObjectTemplate > mapTemplate )
{
if ( bannedForRandomDwelling | | settings [ " mods " ] [ " validation " ] . String ( ) = = " off " )
return ;
bool invalidForRandomDwelling = false ;
int3 corner = mapTemplate - > getCornerOffset ( ) ;
for ( const auto & tile : mapTemplate - > getBlockedOffsets ( ) )
invalidForRandomDwelling | = ( tile . x ! = - corner . x & & tile . x ! = - corner . x - 1 ) | | ( tile . y ! = - corner . y & & tile . y ! = - corner . y - 1 ) ;
for ( const auto & tile : { mapTemplate - > getVisitableOffset ( ) } )
invalidForRandomDwelling | = ( tile . x ! = corner . x & & tile . x ! = corner . x + 1 ) | | tile . y ! = corner . y ;
invalidForRandomDwelling | = ! mapTemplate - > isBlockedAt ( corner . x + 0 , corner . y ) & & ! mapTemplate - > isVisibleAt ( corner . x + 0 , corner . y ) ;
invalidForRandomDwelling | = ! mapTemplate - > isBlockedAt ( corner . x + 1 , corner . y ) & & ! mapTemplate - > isVisibleAt ( corner . x + 1 , corner . y ) ;
if ( invalidForRandomDwelling )
logMod - > warn ( " Dwelling %s has template %s which is not valid for a random dwelling! Dwellings must not block tiles outside 2x2 range and must be visitable in bottom row. Change dwelling mask or mark dwelling as 'bannedForRandomDwelling' " , getJsonKey ( ) , mapTemplate - > animationFile . getOriginalName ( ) ) ;
2024-04-22 12:35:55 +03:00
}
bool DwellingInstanceConstructor : : isBannedForRandomDwelling ( ) const
{
return bannedForRandomDwelling ;
2023-06-08 17:29:29 +03:00
}
bool DwellingInstanceConstructor : : objectFilter ( const CGObjectInstance * obj , std : : shared_ptr < const ObjectTemplate > tmpl ) const
{
return false ;
}
void DwellingInstanceConstructor : : initializeObject ( CGDwelling * obj ) const
{
obj - > creatures . resize ( availableCreatures . size ( ) ) ;
for ( const auto & entry : availableCreatures )
{
for ( const CCreature * cre : entry )
obj - > creatures . back ( ) . second . push_back ( cre - > getId ( ) ) ;
}
}
2024-06-01 15:28:17 +00:00
void DwellingInstanceConstructor : : randomizeObject ( CGDwelling * dwelling , vstd : : RNG & rng ) const
2023-06-08 17:29:29 +03:00
{
2024-01-01 16:37:48 +02:00
JsonRandom randomizer ( dwelling - > cb ) ;
2023-06-08 17:29:29 +03:00
dwelling - > creatures . clear ( ) ;
dwelling - > creatures . reserve ( availableCreatures . size ( ) ) ;
for ( const auto & entry : availableCreatures )
{
dwelling - > creatures . resize ( dwelling - > creatures . size ( ) + 1 ) ;
for ( const CCreature * cre : entry )
dwelling - > creatures . back ( ) . second . push_back ( cre - > getId ( ) ) ;
}
2024-11-17 13:51:36 +00:00
bool guarded = false ;
2023-06-08 17:29:29 +03:00
2024-11-17 13:51:36 +00:00
if ( guards . getType ( ) = = JsonNode : : JsonType : : DATA_BOOL )
2023-06-08 17:29:29 +03:00
{
2024-11-17 13:51:36 +00:00
//simple switch
2023-06-08 17:29:29 +03:00
if ( guards . Bool ( ) )
{
guarded = true ;
}
}
2024-11-17 13:51:36 +00:00
else if ( guards . getType ( ) = = JsonNode : : JsonType : : DATA_VECTOR )
2023-06-08 17:29:29 +03:00
{
2024-11-17 13:51:36 +00:00
//custom guards (eg. Elemental Conflux)
2023-09-30 18:47:47 +03:00
JsonRandom : : Variables emptyVariables ;
2024-01-01 16:37:48 +02:00
for ( auto & stack : randomizer . loadCreatures ( guards , rng , emptyVariables ) )
2023-06-08 17:29:29 +03:00
{
2025-05-01 13:41:48 +03:00
dwelling - > putStack ( SlotID ( dwelling - > stacksCount ( ) ) , std : : make_unique < CStackInstance > ( dwelling - > cb , stack . getId ( ) , stack . getCount ( ) ) ) ;
2023-06-08 17:29:29 +03:00
}
}
2024-11-17 13:51:36 +00:00
else if ( dwelling - > ID = = Obj : : CREATURE_GENERATOR1 | | dwelling - > ID = = Obj : : CREATURE_GENERATOR4 )
2023-06-08 17:29:29 +03:00
{
2024-11-17 13:51:36 +00:00
//default condition - this is dwelling with creatures of level 5 or higher
2023-06-08 17:29:29 +03:00
for ( auto creatureEntry : availableCreatures )
{
if ( creatureEntry . at ( 0 ) - > getLevel ( ) > = 5 )
{
guarded = true ;
break ;
}
}
}
if ( guarded )
{
for ( auto creatureEntry : availableCreatures )
{
const CCreature * crea = creatureEntry . at ( 0 ) ;
2025-03-18 23:30:06 +00:00
dwelling - > putStack ( SlotID ( dwelling - > stacksCount ( ) ) , std : : make_unique < CStackInstance > ( dwelling - > cb , crea - > getId ( ) , crea - > getGrowth ( ) * 3 ) ) ;
2023-06-08 17:29:29 +03:00
}
}
}
bool DwellingInstanceConstructor : : producesCreature ( const CCreature * crea ) const
{
for ( const auto & entry : availableCreatures )
{
for ( const CCreature * cre : entry )
if ( crea = = cre )
return true ;
}
return false ;
}
std : : vector < const CCreature * > DwellingInstanceConstructor : : getProducedCreatures ( ) const
{
std : : vector < const CCreature * > creatures ; //no idea why it's 2D, to be honest
for ( const auto & entry : availableCreatures )
{
for ( const CCreature * cre : entry )
creatures . push_back ( cre ) ;
}
return creatures ;
}
VCMI_LIB_NAMESPACE_END