| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 | 
							- /*
 
-  * Bonus.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 "Bonus.h"
 
- #include "CBonusSystemNode.h"
 
- #include "Limiters.h"
 
- #include "Updaters.h"
 
- #include "Propagators.h"
 
- #include "../VCMI_Lib.h"
 
- #include "../spells/CSpellHandler.h"
 
- #include "../CCreatureHandler.h"
 
- #include "../CCreatureSet.h"
 
- #include "../CHeroHandler.h"
 
- #include "../CTownHandler.h"
 
- #include "../CGeneralTextHandler.h"
 
- #include "../CSkillHandler.h"
 
- #include "../CArtHandler.h"
 
- #include "../TerrainHandler.h"
 
- #include "../constants/StringConstants.h"
 
- #include "../battle/BattleInfo.h"
 
- #include "../modding/ModUtility.h"
 
- VCMI_LIB_NAMESPACE_BEGIN
 
- //This constructor should be placed here to avoid side effects
 
- CAddInfo::CAddInfo() = default;
 
- CAddInfo::CAddInfo(si32 value)
 
- {
 
- 	if(value != CAddInfo::NONE)
 
- 		push_back(value);
 
- }
 
- bool CAddInfo::operator==(si32 value) const
 
- {
 
- 	switch(size())
 
- 	{
 
- 	case 0:
 
- 		return value == CAddInfo::NONE;
 
- 	case 1:
 
- 		return operator[](0) == value;
 
- 	default:
 
- 		return false;
 
- 	}
 
- }
 
- bool CAddInfo::operator!=(si32 value) const
 
- {
 
- 	return !operator==(value);
 
- }
 
- si32 & CAddInfo::operator[](size_type pos)
 
- {
 
- 	if(pos >= size())
 
- 		resize(pos + 1, CAddInfo::NONE);
 
- 	return vector::operator[](pos);
 
- }
 
- si32 CAddInfo::operator[](size_type pos) const
 
- {
 
- 	return pos < size() ? vector::operator[](pos) : CAddInfo::NONE;
 
- }
 
- std::string CAddInfo::toString() const
 
- {
 
- 	return toJsonNode().toJson(true);
 
- }
 
- JsonNode CAddInfo::toJsonNode() const
 
- {
 
- 	if(size() < 2)
 
- 	{
 
- 		return JsonUtils::intNode(operator[](0));
 
- 	}
 
- 	else
 
- 	{
 
- 		JsonNode node(JsonNode::JsonType::DATA_VECTOR);
 
- 		for(si32 value : *this)
 
- 			node.Vector().push_back(JsonUtils::intNode(value));
 
- 		return node;
 
- 	}
 
- }
 
- std::string Bonus::Description(std::optional<si32> customValue) const
 
- {
 
- 	std::string str;
 
- 	if(description.empty())
 
- 	{
 
- 		if(stacking.empty() || stacking == "ALWAYS")
 
- 		{
 
- 			switch(source)
 
- 			{
 
- 			case BonusSource::ARTIFACT:
 
- 				str = sid.as<ArtifactID>().toEntity(VLC)->getNameTranslated();
 
- 				break;
 
- 			case BonusSource::SPELL_EFFECT:
 
- 				str = sid.as<SpellID>().toEntity(VLC)->getNameTranslated();
 
- 				break;
 
- 			case BonusSource::CREATURE_ABILITY:
 
- 				str = sid.as<CreatureID>().toEntity(VLC)->getNamePluralTranslated();
 
- 				break;
 
- 			case BonusSource::SECONDARY_SKILL:
 
- 				str = VLC->skills()->getById(sid.as<SecondarySkill>())->getNameTranslated();
 
- 				break;
 
- 			case BonusSource::HERO_SPECIAL:
 
- 				str = VLC->heroTypes()->getById(sid.as<HeroTypeID>())->getNameTranslated();
 
- 				break;
 
- 			default:
 
- 				//todo: handle all possible sources
 
- 				str = "Unknown";
 
- 				break;
 
- 			}
 
- 		}
 
- 		else
 
- 			str = stacking;
 
- 	}
 
- 	else
 
- 	{
 
- 		str = description;
 
- 	}
 
- 	if(auto value = customValue.value_or(val)) {
 
- 		//arraytxt already contains +-value
 
- 		std::string valueString = boost::str(boost::format(" %+d") % value);
 
- 		if(!boost::algorithm::ends_with(str, valueString))
 
- 			str += valueString;
 
- 	}
 
- 	return str;
 
- }
 
- static JsonNode additionalInfoToJson(BonusType type, CAddInfo addInfo)
 
- {
 
- 	switch(type)
 
- 	{
 
- 	case BonusType::SPECIAL_UPGRADE:
 
- 		return JsonUtils::stringNode(ModUtility::makeFullIdentifier("", "creature", CreatureID::encode(addInfo[0])));
 
- 	default:
 
- 		return addInfo.toJsonNode();
 
- 	}
 
- }
 
- JsonNode Bonus::toJsonNode() const
 
- {
 
- 	JsonNode root(JsonNode::JsonType::DATA_STRUCT);
 
- 	// only add values that might reasonably be found in config files
 
- 	root["type"].String() = vstd::findKey(bonusNameMap, type);
 
- 	if(subtype != BonusSubtypeID())
 
- 		root["subtype"].String() = subtype.toString();
 
- 	if(additionalInfo != CAddInfo::NONE)
 
- 		root["addInfo"] = additionalInfoToJson(type, additionalInfo);
 
- 	if(source != BonusSource::OTHER)
 
- 		root["sourceType"].String() = vstd::findKey(bonusSourceMap, source);
 
- 	if(targetSourceType != BonusSource::OTHER)
 
- 		root["targetSourceType"].String() = vstd::findKey(bonusSourceMap, targetSourceType);
 
- 	if(sid != BonusSourceID())
 
- 		root["sourceID"].String() = sid.toString();
 
- 	if(val != 0)
 
- 		root["val"].Integer() = val;
 
- 	if(valType != BonusValueType::ADDITIVE_VALUE)
 
- 		root["valueType"].String() = vstd::findKey(bonusValueMap, valType);
 
- 	if(!stacking.empty())
 
- 		root["stacking"].String() = stacking;
 
- 	if(!description.empty())
 
- 		root["description"].String() = description;
 
- 	if(effectRange != BonusLimitEffect::NO_LIMIT)
 
- 		root["effectRange"].String() = vstd::findKey(bonusLimitEffect, effectRange);
 
- 	if(duration != BonusDuration::PERMANENT)
 
- 		root["duration"] = BonusDuration::toJson(duration);
 
- 	if(turnsRemain)
 
- 		root["turns"].Integer() = turnsRemain;
 
- 	if(limiter)
 
- 		root["limiters"] = limiter->toJsonNode();
 
- 	if(updater)
 
- 		root["updater"] = updater->toJsonNode();
 
- 	if(propagator)
 
- 		root["propagator"].String() = vstd::findKey(bonusPropagatorMap, propagator);
 
- 	return root;
 
- }
 
- Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID ID)
 
- 	: Bonus(Duration, Type, Src, Val, ID, BonusSubtypeID(), std::string())
 
- {}
 
- Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID ID, std::string Desc)
 
- 	: Bonus(Duration, Type, Src, Val, ID, BonusSubtypeID(), Desc)
 
- {}
 
- Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID ID, BonusSubtypeID Subtype)
 
- 	: Bonus(Duration, Type, Src, Val, ID, Subtype, std::string())
 
- {}
 
- Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID ID, BonusSubtypeID Subtype, std::string Desc):
 
- 	duration(Duration),
 
- 	type(Type),
 
- 	subtype(Subtype),
 
- 	source(Src),
 
- 	val(Val),
 
- 	sid(ID),
 
- 	description(std::move(Desc))
 
- {
 
- 	boost::algorithm::trim(description);
 
- 	targetSourceType = BonusSource::OTHER;
 
- }
 
- Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID ID, BonusSubtypeID Subtype, BonusValueType ValType):
 
- 	duration(Duration),
 
- 	type(Type),
 
- 	subtype(Subtype),
 
- 	source(Src),
 
- 	val(Val),
 
- 	sid(ID),
 
- 	valType(ValType)
 
- {
 
- 	turnsRemain = 0;
 
- 	effectRange = BonusLimitEffect::NO_LIMIT;
 
- 	targetSourceType = BonusSource::OTHER;
 
- }
 
- std::shared_ptr<Bonus> Bonus::addPropagator(const TPropagatorPtr & Propagator)
 
- {
 
- 	propagator = Propagator;
 
- 	return this->shared_from_this();
 
- }
 
- DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus)
 
- {
 
- 	for(const auto & i : bonusNameMap)
 
- 	if(i.second == bonus.type)
 
- 		out << "\tType: " << i.first << " \t";
 
- #define printField(field) out << "\t" #field ": " << (int)bonus.field << "\n"
 
- 	printField(val);
 
- 	out << "\tSubtype: " << bonus.subtype.toString() << "\n";
 
- 	printField(duration.to_ulong());
 
- 	printField(source);
 
- 	out << "\tSource ID: " << bonus.sid.toString() << "\n";
 
- 	if(bonus.additionalInfo != CAddInfo::NONE)
 
- 		out << "\taddInfo: " << bonus.additionalInfo.toString() << "\n";
 
- 	printField(turnsRemain);
 
- 	printField(valType);
 
- 	if(!bonus.stacking.empty())
 
- 		out << "\tstacking: \"" << bonus.stacking << "\"\n";
 
- 	printField(effectRange);
 
- #undef printField
 
- 	if(bonus.limiter)
 
- 		out << "\tLimiter: " << bonus.limiter->toString() << "\n";
 
- 	if(bonus.updater)
 
- 		out << "\tUpdater: " << bonus.updater->toString() << "\n";
 
- 	return out;
 
- }
 
- std::shared_ptr<Bonus> Bonus::addLimiter(const TLimiterPtr & Limiter)
 
- {
 
- 	if (limiter)
 
- 	{
 
- 		//If we already have limiter list, retrieve it
 
- 		auto limiterList = std::dynamic_pointer_cast<AllOfLimiter>(limiter);
 
- 		if(!limiterList)
 
- 		{
 
- 			//Create a new limiter list with old limiter and the new one will be pushed later
 
- 			limiterList = std::make_shared<AllOfLimiter>();
 
- 			limiterList->add(limiter);
 
- 			limiter = limiterList;
 
- 		}
 
- 		limiterList->add(Limiter);
 
- 	}
 
- 	else
 
- 	{
 
- 		limiter = Limiter;
 
- 	}
 
- 	return this->shared_from_this();
 
- }
 
- // Updaters
 
- std::shared_ptr<Bonus> Bonus::addUpdater(const TUpdaterPtr & Updater)
 
- {
 
- 	updater = Updater;
 
- 	return this->shared_from_this();
 
- }
 
- VCMI_LIB_NAMESPACE_END
 
 
  |