| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454 | 
							- #include "StdInc.h"
 
- #include "CommonConstructors.h"
 
- #include "CGTownInstance.h"
 
- #include "CGHeroInstance.h"
 
- #include "CBank.h"
 
- #include "../mapping/CMap.h"
 
- #include "../CHeroHandler.h"
 
- #include "../CCreatureHandler.h"
 
- #include "JsonRandom.h"
 
- #include "../CModHandler.h"
 
- #include "../IGameCallback.h"
 
- /*
 
-  * CommonConstructors.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
 
-  *
 
-  */
 
- CObstacleConstructor::CObstacleConstructor()
 
- {
 
- }
 
- bool CObstacleConstructor::isStaticObject()
 
- {
 
- 	return true;
 
- }
 
- CTownInstanceConstructor::CTownInstanceConstructor():
 
- 	faction(nullptr)
 
- {
 
- }
 
- void CTownInstanceConstructor::initTypeData(const JsonNode & input)
 
- {
 
- 	VLC->modh->identifiers.requestIdentifier("faction", input["faction"], [&](si32 index)
 
- 	{
 
- 		faction = VLC->townh->factions[index];
 
- 	});
 
- 	filtersJson = input["filters"];
 
- }
 
- void CTownInstanceConstructor::afterLoadFinalization()
 
- {
 
- 	assert(faction);
 
- 	for (auto entry : filtersJson.Struct())
 
- 	{
 
- 		filters[entry.first] = LogicalExpression<BuildingID>(entry.second, [this](const JsonNode & node)
 
- 		{
 
- 			return BuildingID(VLC->modh->identifiers.getIdentifier("building." + faction->identifier, node.Vector()[0]).get());
 
- 		});
 
- 	}
 
- }
 
- bool CTownInstanceConstructor::objectFilter(const CGObjectInstance * object, const ObjectTemplate & templ) const
 
- {
 
- 	auto town = dynamic_cast<const CGTownInstance *>(object);
 
- 	auto buildTest = [&](const BuildingID & id)
 
- 	{
 
- 		return town->hasBuilt(id);
 
- 	};
 
- 	if (filters.count(templ.stringID))
 
- 		return filters.at(templ.stringID).test(buildTest);
 
- 	return false;
 
- }
 
- CGObjectInstance * CTownInstanceConstructor::create(ObjectTemplate tmpl) const
 
- {
 
- 	CGTownInstance * obj = createTyped(tmpl);
 
- 	obj->town = faction->town;
 
- 	obj->tempOwner = PlayerColor::NEUTRAL;
 
- 	return obj;
 
- }
 
- void CTownInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const
 
- {
 
- 	auto templ = getOverride(object->cb->getTile(object->pos)->terType, object);
 
- 	if (templ)
 
- 		object->appearance = templ.get();
 
- }
 
- CHeroInstanceConstructor::CHeroInstanceConstructor()
 
- {
 
- }
 
- void CHeroInstanceConstructor::initTypeData(const JsonNode & input)
 
- {
 
- 	VLC->modh->identifiers.requestIdentifier("heroClass", input["heroClass"],
 
- 			[&](si32 index) { heroClass = VLC->heroh->classes.heroClasses[index]; });
 
- 	filtersJson = input["filters"];
 
- }
 
- void CHeroInstanceConstructor::afterLoadFinalization()
 
- {
 
- 	for (auto entry : filtersJson.Struct())
 
- 	{
 
- 		filters[entry.first] = LogicalExpression<HeroTypeID>(entry.second, [this](const JsonNode & node)
 
- 		{
 
- 			return HeroTypeID(VLC->modh->identifiers.getIdentifier("hero", node.Vector()[0]).get());
 
- 		});
 
- 	}
 
- }
 
- bool CHeroInstanceConstructor::objectFilter(const CGObjectInstance * object, const ObjectTemplate & templ) const
 
- {
 
- 	auto hero = dynamic_cast<const CGHeroInstance *>(object);
 
- 	auto heroTest = [&](const HeroTypeID & id)
 
- 	{
 
- 		return hero->type->ID == id;
 
- 	};
 
- 	if (filters.count(templ.stringID))
 
- 	{
 
- 		return filters.at(templ.stringID).test(heroTest);
 
- 	}
 
- 	return false;
 
- }
 
- CGObjectInstance * CHeroInstanceConstructor::create(ObjectTemplate tmpl) const
 
- {
 
- 	CGHeroInstance * obj = createTyped(tmpl);
 
- 	obj->type = nullptr; //FIXME: set to valid value. somehow.
 
- 	return obj;
 
- }
 
- void CHeroInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const
 
- {
 
- }
 
- CDwellingInstanceConstructor::CDwellingInstanceConstructor()
 
- {
 
- }
 
- void CDwellingInstanceConstructor::initTypeData(const JsonNode & input)
 
- {
 
- 	const JsonVector & levels = input["creatures"].Vector();
 
- 	availableCreatures.resize(levels.size());
 
- 	for (size_t i=0; i<levels.size(); i++)
 
- 	{
 
- 		const JsonVector & creatures = levels[i].Vector();
 
- 		availableCreatures[i].resize(creatures.size());
 
- 		for (size_t j=0; j<creatures.size(); j++)
 
- 		{
 
- 			VLC->modh->identifiers.requestIdentifier("creature", creatures[j], [=] (si32 index)
 
- 			{
 
- 				availableCreatures[i][j] = VLC->creh->creatures[index];
 
- 			});
 
- 		}
 
- 		assert(!availableCreatures[i].empty());
 
- 	}
 
- 	guards = input["guards"];
 
- }
 
- bool CDwellingInstanceConstructor::objectFilter(const CGObjectInstance *, const ObjectTemplate &) const
 
- {
 
- 	return false;
 
- }
 
- CGObjectInstance * CDwellingInstanceConstructor::create(ObjectTemplate tmpl) const
 
- {
 
- 	CGDwelling * obj = createTyped(tmpl);
 
- 	obj->creatures.resize(availableCreatures.size());
 
- 	for (auto & entry : availableCreatures)
 
- 	{
 
- 		for (const CCreature * cre : entry)
 
- 			obj->creatures.back().second.push_back(cre->idNumber);
 
- 	}
 
- 	return obj;
 
- }
 
- void CDwellingInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator &rng) const
 
- {
 
- 	CGDwelling * dwelling = dynamic_cast<CGDwelling*>(object);
 
- 	dwelling->creatures.clear();
 
- 	dwelling->creatures.reserve(availableCreatures.size());
 
- 	for (auto & entry : availableCreatures)
 
- 	{
 
- 		dwelling->creatures.resize(dwelling->creatures.size() + 1);
 
- 		for (const CCreature * cre : entry)
 
- 			dwelling->creatures.back().second.push_back(cre->idNumber);
 
- 	}
 
- 	bool guarded = false; //TODO: serialize for sanity
 
- 	if (guards.getType() == JsonNode::DATA_BOOL) //simple switch
 
- 	{
 
- 		if (guards.Bool())
 
- 		{
 
- 			guarded = true;
 
- 		}
 
- 	}
 
- 	else if (guards.getType() == JsonNode::DATA_VECTOR) //custom guards (eg. Elemental Conflux)
 
- 	{
 
- 		for (auto & stack : JsonRandom::loadCreatures(guards, rng))
 
- 		{
 
- 			dwelling->putStack(SlotID(dwelling->stacksCount()), new CStackInstance(stack.type->idNumber, stack.count));
 
- 		}
 
- 	}
 
- 	else //default condition - creatures are of level 5 or higher
 
- 	{
 
- 		for (auto creatureEntry : availableCreatures)
 
- 		{
 
- 			if (creatureEntry.at(0)->level >= 5)
 
- 			{
 
- 				guarded = true;
 
- 				break;
 
- 			}
 
- 		}
 
- 	}
 
- 	if (guarded)
 
- 	{
 
- 		for (auto creatureEntry : availableCreatures)
 
- 		{
 
- 			const CCreature * crea = creatureEntry.at(0);
 
- 			dwelling->putStack (SlotID(dwelling->stacksCount()), new CStackInstance(crea->idNumber, crea->growth * 3));
 
- 		}
 
- 	}
 
- }
 
- bool CDwellingInstanceConstructor::producesCreature(const CCreature * crea) const
 
- {
 
- 	for (auto & entry : availableCreatures)
 
- 	{
 
- 		for (const CCreature * cre : entry)
 
- 			if (crea == cre)
 
- 				return true;
 
- 	}
 
- 	return false;
 
- }
 
- std::vector<const CCreature *> CDwellingInstanceConstructor::getProducedCreatures() const
 
- {
 
- 	std::vector<const CCreature *> creatures; //no idea why it's 2D, to be honest
 
- 	for (auto & entry : availableCreatures)
 
- 	{
 
- 		for (const CCreature * cre : entry)
 
- 			creatures.push_back(cre);
 
- 	}
 
- 	return creatures;
 
- }
 
- CBankInstanceConstructor::CBankInstanceConstructor()
 
- {
 
- }
 
- void CBankInstanceConstructor::initTypeData(const JsonNode & input)
 
- {
 
- 	//TODO: name = input["name"].String();
 
- 	levels = input["levels"].Vector();
 
- 	bankResetDuration = input["resetDuration"].Float();
 
- }
 
- CGObjectInstance *CBankInstanceConstructor::create(ObjectTemplate tmpl) const
 
- {
 
- 	return createTyped(tmpl);
 
- }
 
- BankConfig CBankInstanceConstructor::generateConfig(const JsonNode & level, CRandomGenerator & rng) const
 
- {
 
- 	BankConfig bc;
 
- 	bc.chance = level["chance"].Float();
 
- 	bc.guards = JsonRandom::loadCreatures(level["guards"], rng);
 
- 	bc.upgradeChance = level["upgrade_chance"].Float();
 
- 	bc.combatValue = level["combat_value"].Float();
 
- 	std::vector<SpellID> spells;
 
- 	for (size_t i=0; i<6; i++)
 
- 		IObjectInterface::cb->getAllowedSpells(spells, i);
 
- 	bc.resources = Res::ResourceSet(level["reward"]["resources"]);
 
- 	bc.creatures = JsonRandom::loadCreatures(level["reward"]["creatures"], rng);
 
- 	bc.artifacts = JsonRandom::loadArtifacts(level["reward"]["artifacts"], rng);
 
- 	bc.spells    = JsonRandom::loadSpells(level["reward"]["spells"], rng, spells);
 
- 	bc.value = level["value"].Float();
 
- 	return bc;
 
- }
 
- void CBankInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const
 
- {
 
- 	//logGlobal->debugStream() << "Seed used to configure bank is " << rng.nextInt();
 
- 	auto bank = dynamic_cast<CBank*>(object);
 
- 	bank->resetDuration = bankResetDuration;
 
- 	si32 totalChance = 0;
 
- 	for (auto & node : levels)
 
- 		totalChance += node["chance"].Float();
 
- 	assert(totalChance != 0);
 
- 	si32 selectedChance = rng.nextInt(totalChance - 1);
 
- 	//logGlobal->debugStream() << "Selected chance for bank config is " << selectedChance;
 
- 	int cumulativeChance = 0;
 
- 	for (auto & node : levels)
 
- 	{
 
- 		cumulativeChance += node["chance"].Float();
 
- 		if (selectedChance < cumulativeChance)
 
- 		{
 
- 			 bank->setConfig(generateConfig(node, rng));
 
- 			 break;
 
- 		}
 
- 	}
 
- }
 
- CBankInfo::CBankInfo(const JsonVector & Config):
 
- 	config(Config)
 
- {
 
- 	assert(!Config.empty());
 
- }
 
- static void addStackToArmy(IObjectInfo::CArmyStructure & army, const CCreature * crea, si32 amount)
 
- {
 
- 	army.totalStrength += crea->fightValue * amount;
 
- 	bool walker = true;
 
- 	if (crea->hasBonusOfType(Bonus::SHOOTER))
 
- 	{
 
- 		army.shootersStrength += crea->fightValue * amount;
 
- 		walker = false;
 
- 	}
 
- 	if (crea->hasBonusOfType(Bonus::FLYING))
 
- 	{
 
- 		army.flyersStrength += crea->fightValue * amount;
 
- 		walker = false;
 
- 	}
 
- 	if (walker)
 
- 		army.walkersStrength += crea->fightValue * amount;
 
- }
 
- IObjectInfo::CArmyStructure CBankInfo::minGuards() const
 
- {
 
- 	std::vector<IObjectInfo::CArmyStructure> armies;
 
- 	for (auto configEntry : config)
 
- 	{
 
- 		auto stacks = JsonRandom::evaluateCreatures(configEntry["guards"]);
 
- 		IObjectInfo::CArmyStructure army;
 
- 		for (auto & stack : stacks)
 
- 		{
 
- 			assert(!stack.allowedCreatures.empty());
 
- 			auto weakest = boost::range::min_element(stack.allowedCreatures, [](const CCreature * a, const CCreature * b)
 
- 			{
 
- 				return a->fightValue < b->fightValue;
 
- 			});
 
- 			addStackToArmy(army, *weakest, stack.minAmount);
 
- 		}
 
- 		armies.push_back(army);
 
- 	}
 
- 	return *boost::range::min_element(armies);
 
- }
 
- IObjectInfo::CArmyStructure CBankInfo::maxGuards() const
 
- {
 
- 	std::vector<IObjectInfo::CArmyStructure> armies;
 
- 	for (auto configEntry : config)
 
- 	{
 
- 		auto stacks = JsonRandom::evaluateCreatures(configEntry["guards"]);
 
- 		IObjectInfo::CArmyStructure army;
 
- 		for (auto & stack : stacks)
 
- 		{
 
- 			assert(!stack.allowedCreatures.empty());
 
- 			auto strongest = boost::range::max_element(stack.allowedCreatures, [](const CCreature * a, const CCreature * b)
 
- 			{
 
- 				return a->fightValue < b->fightValue;
 
- 			});
 
- 			addStackToArmy(army, *strongest, stack.maxAmount);
 
- 		}
 
- 		armies.push_back(army);
 
- 	}
 
- 	return *boost::range::max_element(armies);
 
- }
 
- TPossibleGuards CBankInfo::getPossibleGuards() const
 
- {
 
- 	TPossibleGuards out;
 
- 	for (const JsonNode & configEntry : config)
 
- 	{
 
- 		const JsonNode & guardsInfo = configEntry["guards"];
 
- 		auto stacks = JsonRandom::evaluateCreatures(guardsInfo);
 
- 		IObjectInfo::CArmyStructure army;
 
- 		for (auto stack : stacks)
 
- 		{
 
- 			army.totalStrength += stack.allowedCreatures.front()->AIValue * (stack.minAmount + stack.maxAmount) / 2;
 
- 			//TODO: add fields for flyers, walkers etc...
 
- 		}
 
- 		ui8 chance = configEntry["chance"].Float();
 
- 		out.push_back(std::make_pair(chance, army));
 
- 	}
 
- 	return out;
 
- }
 
- bool CBankInfo::givesResources() const
 
- {
 
- 	for (const JsonNode & node : config)
 
- 		if (!node["reward"]["resources"].isNull())
 
- 			return true;
 
- 	return false;
 
- }
 
- bool CBankInfo::givesArtifacts() const
 
- {
 
- 	for (const JsonNode & node : config)
 
- 		if (!node["reward"]["artifacts"].isNull())
 
- 			return true;
 
- 	return false;
 
- }
 
- bool CBankInfo::givesCreatures() const
 
- {
 
- 	for (const JsonNode & node : config)
 
- 		if (!node["reward"]["creatures"].isNull())
 
- 			return true;
 
- 	return false;
 
- }
 
- bool CBankInfo::givesSpells() const
 
- {
 
- 	for (const JsonNode & node : config)
 
- 		if (!node["reward"]["spells"].isNull())
 
- 			return true;
 
- 	return false;
 
- }
 
- std::unique_ptr<IObjectInfo> CBankInstanceConstructor::getObjectInfo(ObjectTemplate tmpl) const
 
- {
 
- 	return std::unique_ptr<IObjectInfo>(new CBankInfo(levels));
 
- }
 
 
  |