1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-28 08:48:48 +02:00
vcmi/lib/mapObjectConstructors/DwellingInstanceConstructor.cpp
Ivan Savenko ffec4b9154 Explicitly ban 'large' dwellings from random selection
Old code was relying on specific sorting order leading to easy to break
logic
2024-04-22 12:35:55 +03:00

154 lines
4.2 KiB
C++

/*
* 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"
#include "../CGeneralTextHandler.h"
#include "../json/JsonRandom.h"
#include "../VCMI_Lib.h"
#include "../mapObjects/CGDwelling.h"
#include "../modding/IdentifierStorage.h"
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());
VLC->generaltexth->registerString( input.getModScope(), getNameTextID(), input["name"].String());
const JsonVector & levels = input["creatures"].Vector();
const auto totalLevels = levels.size();
availableCreatures.resize(totalLevels);
for(int currentLevel = 0; currentLevel < totalLevels; currentLevel++)
{
const JsonVector & creaturesOnLevel = levels[currentLevel].Vector();
const auto creaturesNumber = creaturesOnLevel.size();
availableCreatures[currentLevel].resize(creaturesNumber);
for(int currentCreature = 0; currentCreature < creaturesNumber; currentCreature++)
{
VLC->identifiers()->requestIdentifier("creature", creaturesOnLevel[currentCreature], [this, currentLevel, currentCreature] (si32 index)
{
availableCreatures.at(currentLevel).at(currentCreature) = CreatureID(index).toCreature();
});
}
assert(!availableCreatures[currentLevel].empty());
}
guards = input["guards"];
bannedForRandomDwelling = input["bannedForRandomDwelling"].Bool();
}
bool DwellingInstanceConstructor::isBannedForRandomDwelling() const
{
return bannedForRandomDwelling;
}
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());
}
}
void DwellingInstanceConstructor::randomizeObject(CGDwelling * dwelling, CRandomGenerator &rng) const
{
JsonRandom randomizer(dwelling->cb);
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());
}
bool guarded = false; //TODO: serialize for sanity
if(guards.getType() == JsonNode::JsonType::DATA_BOOL) //simple switch
{
if(guards.Bool())
{
guarded = true;
}
}
else if(guards.getType() == JsonNode::JsonType::DATA_VECTOR) //custom guards (eg. Elemental Conflux)
{
JsonRandom::Variables emptyVariables;
for(auto & stack : randomizer.loadCreatures(guards, rng, emptyVariables))
{
dwelling->putStack(SlotID(dwelling->stacksCount()), new CStackInstance(stack.type->getId(), stack.count));
}
}
else //default condition - creatures are of level 5 or higher
{
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);
dwelling->putStack(SlotID(dwelling->stacksCount()), new CStackInstance(crea->getId(), crea->getGrowth() * 3));
}
}
}
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