浏览代码

HeroBonus: split BonusList

Konstantin 2 年之前
父节点
当前提交
29c76fb9bf

+ 2 - 0
cmake_modules/VCMI_lib.cmake

@@ -27,6 +27,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
 		${MAIN_LIB_DIR}/battle/SiegeInfo.cpp
 		${MAIN_LIB_DIR}/battle/Unit.cpp
 
+		${MAIN_LIB_DIR}/bonuses/BonusList.cpp
 		${MAIN_LIB_DIR}/bonuses/BonusParams.cpp
 		${MAIN_LIB_DIR}/bonuses/CBonusProxy.cpp
 		${MAIN_LIB_DIR}/bonuses/CBonusSystemNode.cpp
@@ -308,6 +309,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
 		${MAIN_LIB_DIR}/battle/SiegeInfo.h
 		${MAIN_LIB_DIR}/battle/Unit.h
 
+		${MAIN_LIB_DIR}/bonuses/BonusList.h
 		${MAIN_LIB_DIR}/bonuses/BonusParams.h
 		${MAIN_LIB_DIR}/bonuses/CBonusProxy.h
 		${MAIN_LIB_DIR}/bonuses/CBonusSystemNode.h

+ 1 - 0
lib/BasicTypes.cpp

@@ -12,6 +12,7 @@
 
 #include "VCMI_Lib.h"
 #include "GameConstants.h"
+#include "bonuses/BonusList.h"
 #include "bonuses/HeroBonus.h"
 #include "bonuses/IBonusBearer.h"
 

+ 1 - 0
lib/CHeroHandler.h

@@ -17,6 +17,7 @@
 #include "../lib/ConstTransitivePtr.h"
 #include "GameConstants.h"
 #include "bonuses/HeroBonus.h"
+#include "bonuses/BonusList.h"
 #include "IHandlerBase.h"
 
 VCMI_LIB_NAMESPACE_BEGIN

+ 1 - 0
lib/CTownHandler.h

@@ -20,6 +20,7 @@
 #include "LogicalExpression.h"
 #include "battle/BattleHex.h"
 #include "bonuses/HeroBonus.h"
+#include "bonuses/BonusList.h"
 #include "Point.h"
 
 VCMI_LIB_NAMESPACE_BEGIN

+ 276 - 0
lib/bonuses/BonusList.cpp

@@ -0,0 +1,276 @@
+/*
+ * BonusList.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 "CBonusSystemNode.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+BonusList::BonusList(bool BelongsToTree) : belongsToTree(BelongsToTree)
+{
+}
+
+BonusList::BonusList(const BonusList & bonusList): belongsToTree(false)
+{
+	bonuses.resize(bonusList.size());
+	std::copy(bonusList.begin(), bonusList.end(), bonuses.begin());
+}
+
+BonusList::BonusList(BonusList && other) noexcept: belongsToTree(false)
+{
+	std::swap(belongsToTree, other.belongsToTree);
+	std::swap(bonuses, other.bonuses);
+}
+
+BonusList& BonusList::operator=(const BonusList &bonusList)
+{
+	bonuses.resize(bonusList.size());
+	std::copy(bonusList.begin(), bonusList.end(), bonuses.begin());
+	belongsToTree = false;
+	return *this;
+}
+
+void BonusList::changed() const
+{
+    if(belongsToTree)
+		CBonusSystemNode::treeHasChanged();
+}
+
+void BonusList::stackBonuses()
+{
+	boost::sort(bonuses, [](const std::shared_ptr<Bonus> & b1, const std::shared_ptr<Bonus> & b2) -> bool
+	{
+		if(b1 == b2)
+			return false;
+#define COMPARE_ATT(ATT) if(b1->ATT != b2->ATT) return b1->ATT < b2->ATT
+		COMPARE_ATT(stacking);
+		COMPARE_ATT(type);
+		COMPARE_ATT(subtype);
+		COMPARE_ATT(valType);
+#undef COMPARE_ATT
+		return b1->val > b2->val;
+	});
+	// remove non-stacking
+	size_t next = 1;
+	while(next < bonuses.size())
+	{
+		bool remove = false;
+		std::shared_ptr<Bonus> last = bonuses[next-1];
+		std::shared_ptr<Bonus> current = bonuses[next];
+
+		if(current->stacking.empty())
+			remove = current == last;
+		else if(current->stacking == "ALWAYS")
+			remove = false;
+		else
+			remove = current->stacking == last->stacking
+				&& current->type == last->type
+				&& current->subtype == last->subtype
+				&& current->valType == last->valType;
+
+		if(remove)
+			bonuses.erase(bonuses.begin() + next);
+		else
+			next++;
+	}
+}
+
+int BonusList::totalValue() const
+{
+	struct BonusCollection
+	{
+		int base = 0;
+		int percentToBase = 0;
+		int percentToAll = 0;
+		int additive = 0;
+		int percentToSource = 0;
+		int indepMin = std::numeric_limits<int>::max();
+		int indepMax = std::numeric_limits<int>::min();
+	};
+
+	auto percent = [](int64_t base, int64_t percent) -> int {
+		return static_cast<int>(std::clamp<int64_t>((base * (100 + percent)) / 100, std::numeric_limits<int>::min(), std::numeric_limits<int>::max()));
+	};
+	std::array <BonusCollection, Bonus::BonusSource::NUM_BONUS_SOURCE> sources = {};
+	BonusCollection any;
+	bool hasIndepMax = false;
+	bool hasIndepMin = false;
+
+	for(const auto & b : bonuses)
+	{
+		switch(b->valType)
+		{
+		case Bonus::BASE_NUMBER:
+			sources[b->source].base += b->val;
+			break;
+		case Bonus::PERCENT_TO_ALL:
+			sources[b->source].percentToAll += b->val;
+			break;
+		case Bonus::PERCENT_TO_BASE:
+			sources[b->source].percentToBase += b->val;
+			break;
+		case Bonus::PERCENT_TO_SOURCE:
+			sources[b->source].percentToSource += b->val;
+			break;
+		case Bonus::PERCENT_TO_TARGET_TYPE:
+			sources[b->targetSourceType].percentToSource += b->val;
+			break;
+		case Bonus::ADDITIVE_VALUE:
+			sources[b->source].additive += b->val;
+			break;
+		case Bonus::INDEPENDENT_MAX:
+			hasIndepMax = true;
+			vstd::amax(sources[b->source].indepMax, b->val);
+			break;
+		case Bonus::INDEPENDENT_MIN:
+			hasIndepMin = true;
+			vstd::amin(sources[b->source].indepMin, b->val);
+			break;
+		}
+	}
+	for(const auto & src : sources)
+	{
+		any.base += percent(src.base, src.percentToSource);
+		any.percentToBase += percent(src.percentToBase, src.percentToSource);
+		any.percentToAll += percent(src.percentToAll, src.percentToSource);
+		any.additive += percent(src.additive, src.percentToSource);
+		if(hasIndepMin)
+			vstd::amin(any.indepMin, percent(src.indepMin, src.percentToSource));
+		if(hasIndepMax)
+			vstd::amax(any.indepMax, percent(src.indepMax, src.percentToSource));
+	}
+	any.base = percent(any.base, any.percentToBase);
+	any.base += any.additive;
+	auto valFirst = percent(any.base ,any.percentToAll);
+
+	if(hasIndepMin && hasIndepMax && any.indepMin < any.indepMax)
+		any.indepMax = any.indepMin;
+
+	const int notIndepBonuses = static_cast<int>(std::count_if(bonuses.cbegin(), bonuses.cend(), [](const std::shared_ptr<Bonus>& b)
+	{
+		return b->valType != Bonus::INDEPENDENT_MAX && b->valType != Bonus::INDEPENDENT_MIN;
+	}));
+
+	if(notIndepBonuses)
+		return std::clamp(valFirst, any.indepMax, any.indepMin);
+
+	return hasIndepMin ? any.indepMin : hasIndepMax ? any.indepMax : 0;
+}
+
+std::shared_ptr<Bonus> BonusList::getFirst(const CSelector &select)
+{
+	for (auto & b : bonuses)
+	{
+		if(select(b.get()))
+			return b;
+	}
+	return nullptr;
+}
+
+std::shared_ptr<const Bonus> BonusList::getFirst(const CSelector &selector) const
+{
+	for(const auto & b : bonuses)
+	{
+		if(selector(b.get()))
+			return b;
+	}
+	return nullptr;
+}
+
+void BonusList::getBonuses(BonusList & out, const CSelector &selector, const CSelector &limit) const
+{
+	out.reserve(bonuses.size());
+	for(const auto & b : bonuses)
+	{
+		//add matching bonuses that matches limit predicate or have NO_LIMIT if no given predicate
+		auto noFightLimit = b->effectRange == Bonus::NO_LIMIT;
+		if(selector(b.get()) && ((!limit && noFightLimit) || ((bool)limit && limit(b.get()))))
+			out.push_back(b);
+	}
+}
+
+void BonusList::getAllBonuses(BonusList &out) const
+{
+	for(const auto & b : bonuses)
+		out.push_back(b);
+}
+
+int BonusList::valOfBonuses(const CSelector &select) const
+{
+	BonusList ret;
+	CSelector limit = nullptr;
+	getBonuses(ret, select, limit);
+	return ret.totalValue();
+}
+
+JsonNode BonusList::toJsonNode() const
+{
+	JsonNode node(JsonNode::JsonType::DATA_VECTOR);
+	for(const std::shared_ptr<Bonus> & b : bonuses)
+		node.Vector().push_back(b->toJsonNode());
+	return node;
+}
+
+void BonusList::push_back(const std::shared_ptr<Bonus> & x)
+{
+	bonuses.push_back(x);
+	changed();
+}
+
+BonusList::TInternalContainer::iterator BonusList::erase(const int position)
+{
+	changed();
+	return bonuses.erase(bonuses.begin() + position);
+}
+
+void BonusList::clear()
+{
+	bonuses.clear();
+	changed();
+}
+
+std::vector<BonusList *>::size_type BonusList::operator-=(const std::shared_ptr<Bonus> & i)
+{
+	auto itr = std::find(bonuses.begin(), bonuses.end(), i);
+	if(itr == bonuses.end())
+		return false;
+	bonuses.erase(itr);
+	changed();
+	return true;
+}
+
+void BonusList::resize(BonusList::TInternalContainer::size_type sz, const std::shared_ptr<Bonus> & c)
+{
+	bonuses.resize(sz, c);
+	changed();
+}
+
+void BonusList::reserve(TInternalContainer::size_type sz)
+{
+	bonuses.reserve(sz);
+}
+
+void BonusList::insert(BonusList::TInternalContainer::iterator position, BonusList::TInternalContainer::size_type n, const std::shared_ptr<Bonus> & x)
+{
+	bonuses.insert(position, n, x);
+	changed();
+}
+
+DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const BonusList &bonusList)
+{
+	for (ui32 i = 0; i < bonusList.size(); i++)
+	{
+		const auto & b = bonusList[i];
+		out << "Bonus " << i << "\n" << *b << std::endl;
+	}
+	return out;
+}
+
+VCMI_LIB_NAMESPACE_END

+ 113 - 0
lib/bonuses/BonusList.h

@@ -0,0 +1,113 @@
+/*
+ * BonusList.h, 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
+ *
+ */
+#pragma once
+
+#include "HeroBonus.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+class DLL_LINKAGE BonusList
+{
+public:
+	using TInternalContainer = std::vector<std::shared_ptr<Bonus>>;
+
+private:
+	TInternalContainer bonuses;
+	bool belongsToTree;
+	void changed() const;
+
+public:
+	using const_reference = TInternalContainer::const_reference;
+	using value_type = TInternalContainer::value_type;
+
+	using const_iterator = TInternalContainer::const_iterator;
+	using iterator = TInternalContainer::iterator;
+
+	BonusList(bool BelongsToTree = false);
+	BonusList(const BonusList &bonusList);
+	BonusList(BonusList && other) noexcept;
+	BonusList& operator=(const BonusList &bonusList);
+
+	// wrapper functions of the STL vector container
+	TInternalContainer::size_type size() const { return bonuses.size(); }
+	void push_back(const std::shared_ptr<Bonus> & x);
+	TInternalContainer::iterator erase (const int position);
+	void clear();
+	bool empty() const { return bonuses.empty(); }
+	void resize(TInternalContainer::size_type sz, const std::shared_ptr<Bonus> & c = nullptr);
+	void reserve(TInternalContainer::size_type sz);
+	TInternalContainer::size_type capacity() const { return bonuses.capacity(); }
+	STRONG_INLINE std::shared_ptr<Bonus> &operator[] (TInternalContainer::size_type n) { return bonuses[n]; }
+	STRONG_INLINE const std::shared_ptr<Bonus> &operator[] (TInternalContainer::size_type n) const { return bonuses[n]; }
+	std::shared_ptr<Bonus> &back() { return bonuses.back(); }
+	std::shared_ptr<Bonus> &front() { return bonuses.front(); }
+	const std::shared_ptr<Bonus> &back() const { return bonuses.back(); }
+	const std::shared_ptr<Bonus> &front() const { return bonuses.front(); }
+
+	// There should be no non-const access to provide solid,robust bonus caching
+	TInternalContainer::const_iterator begin() const { return bonuses.begin(); }
+	TInternalContainer::const_iterator end() const { return bonuses.end(); }
+	TInternalContainer::size_type operator-=(const std::shared_ptr<Bonus> & i);
+
+	// BonusList functions
+	void stackBonuses();
+	int totalValue() const;
+	void getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit = nullptr) const;
+	void getAllBonuses(BonusList &out) const;
+
+	//special find functions
+	std::shared_ptr<Bonus> getFirst(const CSelector &select);
+	std::shared_ptr<const Bonus> getFirst(const CSelector &select) const;
+	int valOfBonuses(const CSelector &select) const;
+
+	// conversion / output
+	JsonNode toJsonNode() const;
+
+	// remove_if implementation for STL vector types
+	template <class Predicate>
+	void remove_if(Predicate pred)
+	{
+		BonusList newList;
+		for(const auto & b : bonuses)
+		{
+			if (!pred(b.get()))
+				newList.push_back(b);
+		}
+		bonuses.clear();
+		bonuses.resize(newList.size());
+		std::copy(newList.begin(), newList.end(), bonuses.begin());
+	}
+
+	template <class InputIterator>
+	void insert(const int position, InputIterator first, InputIterator last);
+	void insert(TInternalContainer::iterator position, TInternalContainer::size_type n, const std::shared_ptr<Bonus> & x);
+
+	template <typename Handler>
+	void serialize(Handler &h, const int version)
+	{
+		h & static_cast<TInternalContainer&>(bonuses);
+	}
+
+	// C++ for range support
+	auto begin () -> decltype (bonuses.begin())
+	{
+		return bonuses.begin();
+	}
+
+	auto end () -> decltype (bonuses.end())
+	{
+		return bonuses.end();
+	}
+};
+
+DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const BonusList &bonusList);
+
+
+VCMI_LIB_NAMESPACE_END

+ 1 - 0
lib/bonuses/CBonusProxy.cpp

@@ -9,6 +9,7 @@
  */
 
 #include "StdInc.h"
+#include "BonusList.h"
 #include "CBonusProxy.h"
 #include "IBonusBearer.h"
 

+ 1 - 0
lib/bonuses/CBonusSystemNode.h

@@ -9,6 +9,7 @@
  */
 #pragma once
 
+#include "BonusList.h"
 #include "IBonusBearer.h"
 
 VCMI_LIB_NAMESPACE_BEGIN

+ 0 - 262
lib/bonuses/HeroBonus.cpp

@@ -147,258 +147,6 @@ JsonNode CAddInfo::toJsonNode() const
 		return node;
 	}
 }
-
-BonusList::BonusList(bool BelongsToTree) : belongsToTree(BelongsToTree)
-{
-
-}
-
-BonusList::BonusList(const BonusList & bonusList): belongsToTree(false)
-{
-	bonuses.resize(bonusList.size());
-	std::copy(bonusList.begin(), bonusList.end(), bonuses.begin());
-}
-
-BonusList::BonusList(BonusList && other) noexcept: belongsToTree(false)
-{
-	std::swap(belongsToTree, other.belongsToTree);
-	std::swap(bonuses, other.bonuses);
-}
-
-BonusList& BonusList::operator=(const BonusList &bonusList)
-{
-	bonuses.resize(bonusList.size());
-	std::copy(bonusList.begin(), bonusList.end(), bonuses.begin());
-	belongsToTree = false;
-	return *this;
-}
-
-void BonusList::changed() const
-{
-    if(belongsToTree)
-		CBonusSystemNode::treeHasChanged();
-}
-
-void BonusList::stackBonuses()
-{
-	boost::sort(bonuses, [](const std::shared_ptr<Bonus> & b1, const std::shared_ptr<Bonus> & b2) -> bool
-	{
-		if(b1 == b2)
-			return false;
-#define COMPARE_ATT(ATT) if(b1->ATT != b2->ATT) return b1->ATT < b2->ATT
-		COMPARE_ATT(stacking);
-		COMPARE_ATT(type);
-		COMPARE_ATT(subtype);
-		COMPARE_ATT(valType);
-#undef COMPARE_ATT
-		return b1->val > b2->val;
-	});
-	// remove non-stacking
-	size_t next = 1;
-	while(next < bonuses.size())
-	{
-		bool remove = false;
-		std::shared_ptr<Bonus> last = bonuses[next-1];
-		std::shared_ptr<Bonus> current = bonuses[next];
-
-		if(current->stacking.empty())
-			remove = current == last;
-		else if(current->stacking == "ALWAYS")
-			remove = false;
-		else
-			remove = current->stacking == last->stacking
-				&& current->type == last->type
-				&& current->subtype == last->subtype
-				&& current->valType == last->valType;
-
-		if(remove)
-			bonuses.erase(bonuses.begin() + next);
-		else
-			next++;
-	}
-}
-
-int BonusList::totalValue() const
-{
-	struct BonusCollection
-	{
-		int base = 0;
-		int percentToBase = 0;
-		int percentToAll = 0;
-		int additive = 0;
-		int percentToSource = 0;
-		int indepMin = std::numeric_limits<int>::max();
-		int indepMax = std::numeric_limits<int>::min();
-	};
-
-	auto percent = [](int64_t base, int64_t percent) -> int {
-		return static_cast<int>(std::clamp<int64_t>((base * (100 + percent)) / 100, std::numeric_limits<int>::min(), std::numeric_limits<int>::max()));
-	};
-	std::array <BonusCollection, Bonus::BonusSource::NUM_BONUS_SOURCE> sources = {};
-	BonusCollection any;
-	bool hasIndepMax = false;
-	bool hasIndepMin = false;
-
-	for(const auto & b : bonuses)
-	{
-		switch(b->valType)
-		{
-		case Bonus::BASE_NUMBER:
-			sources[b->source].base += b->val;
-			break;
-		case Bonus::PERCENT_TO_ALL:
-			sources[b->source].percentToAll += b->val;
-			break;
-		case Bonus::PERCENT_TO_BASE:
-			sources[b->source].percentToBase += b->val;
-			break;
-		case Bonus::PERCENT_TO_SOURCE:
-			sources[b->source].percentToSource += b->val;
-			break;
-		case Bonus::PERCENT_TO_TARGET_TYPE:
-			sources[b->targetSourceType].percentToSource += b->val;
-			break;
-		case Bonus::ADDITIVE_VALUE:
-			sources[b->source].additive += b->val;
-			break;
-		case Bonus::INDEPENDENT_MAX:
-			hasIndepMax = true;
-			vstd::amax(sources[b->source].indepMax, b->val);
-			break;
-		case Bonus::INDEPENDENT_MIN:
-			hasIndepMin = true;
-			vstd::amin(sources[b->source].indepMin, b->val);
-			break;
-		}
-	}
-	for(const auto & src : sources)
-	{
-		any.base += percent(src.base, src.percentToSource);
-		any.percentToBase += percent(src.percentToBase, src.percentToSource);
-		any.percentToAll += percent(src.percentToAll, src.percentToSource);
-		any.additive += percent(src.additive, src.percentToSource);
-		if(hasIndepMin)
-			vstd::amin(any.indepMin, percent(src.indepMin, src.percentToSource));
-		if(hasIndepMax)
-			vstd::amax(any.indepMax, percent(src.indepMax, src.percentToSource));
-	}
-	any.base = percent(any.base, any.percentToBase);
-	any.base += any.additive;
-	auto valFirst = percent(any.base ,any.percentToAll);
-
-	if(hasIndepMin && hasIndepMax && any.indepMin < any.indepMax)
-		any.indepMax = any.indepMin;
-
-	const int notIndepBonuses = static_cast<int>(std::count_if(bonuses.cbegin(), bonuses.cend(), [](const std::shared_ptr<Bonus>& b)
-	{
-		return b->valType != Bonus::INDEPENDENT_MAX && b->valType != Bonus::INDEPENDENT_MIN;
-	}));
-
-	if(notIndepBonuses)
-		return std::clamp(valFirst, any.indepMax, any.indepMin);
-	
-	return hasIndepMin ? any.indepMin : hasIndepMax ? any.indepMax : 0;
-}
-
-std::shared_ptr<Bonus> BonusList::getFirst(const CSelector &select)
-{
-	for (auto & b : bonuses)
-	{
-		if(select(b.get()))
-			return b;
-	}
-	return nullptr;
-}
-
-std::shared_ptr<const Bonus> BonusList::getFirst(const CSelector &selector) const
-{
-	for(const auto & b : bonuses)
-	{
-		if(selector(b.get()))
-			return b;
-	}
-	return nullptr;
-}
-
-void BonusList::getBonuses(BonusList & out, const CSelector &selector, const CSelector &limit) const
-{
-	out.reserve(bonuses.size());
-	for(const auto & b : bonuses)
-	{
-		//add matching bonuses that matches limit predicate or have NO_LIMIT if no given predicate
-		auto noFightLimit = b->effectRange == Bonus::NO_LIMIT;
-		if(selector(b.get()) && ((!limit && noFightLimit) || ((bool)limit && limit(b.get()))))
-			out.push_back(b);
-	}
-}
-
-void BonusList::getAllBonuses(BonusList &out) const
-{
-	for(const auto & b : bonuses)
-		out.push_back(b);
-}
-
-int BonusList::valOfBonuses(const CSelector &select) const
-{
-	BonusList ret;
-	CSelector limit = nullptr;
-	getBonuses(ret, select, limit);
-	return ret.totalValue();
-}
-
-JsonNode BonusList::toJsonNode() const
-{
-	JsonNode node(JsonNode::JsonType::DATA_VECTOR);
-	for(const std::shared_ptr<Bonus> & b : bonuses)
-		node.Vector().push_back(b->toJsonNode());
-	return node;
-}
-
-void BonusList::push_back(const std::shared_ptr<Bonus> & x)
-{
-	bonuses.push_back(x);
-	changed();
-}
-
-BonusList::TInternalContainer::iterator BonusList::erase(const int position)
-{
-	changed();
-	return bonuses.erase(bonuses.begin() + position);
-}
-
-void BonusList::clear()
-{
-	bonuses.clear();
-	changed();
-}
-
-std::vector<BonusList *>::size_type BonusList::operator-=(const std::shared_ptr<Bonus> & i)
-{
-	auto itr = std::find(bonuses.begin(), bonuses.end(), i);
-	if(itr == bonuses.end())
-		return false;
-	bonuses.erase(itr);
-	changed();
-	return true;
-}
-
-void BonusList::resize(BonusList::TInternalContainer::size_type sz, const std::shared_ptr<Bonus> & c)
-{
-	bonuses.resize(sz, c);
-	changed();
-}
-
-void BonusList::reserve(TInternalContainer::size_type sz)
-{
-	bonuses.reserve(sz);
-}
-
-void BonusList::insert(BonusList::TInternalContainer::iterator position, BonusList::TInternalContainer::size_type n, const std::shared_ptr<Bonus> & x)
-{
-	bonuses.insert(position, n, x);
-	changed();
-}
-
 std::string Bonus::Description(std::optional<si32> customValue) const
 {
 	std::ostringstream str;
@@ -679,16 +427,6 @@ namespace Selector
 	DLL_LINKAGE CSelector none([](const Bonus * b){return false;});
 }
 
-DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const BonusList &bonusList)
-{
-	for (ui32 i = 0; i < bonusList.size(); i++)
-	{
-		const auto & b = bonusList[i];
-		out << "Bonus " << i << "\n" << *b << std::endl;
-	}
-	return out;
-}
-
 DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus)
 {
 	for(const auto & i : bonusNameMap)

+ 0 - 102
lib/bonuses/HeroBonus.h

@@ -464,100 +464,6 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
 
 DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus);
 
-class DLL_LINKAGE BonusList
-{
-public:
-	using TInternalContainer = std::vector<std::shared_ptr<Bonus>>;
-
-private:
-	TInternalContainer bonuses;
-	bool belongsToTree;
-	void changed() const;
-
-public:
-	using const_reference = TInternalContainer::const_reference;
-	using value_type = TInternalContainer::value_type;
-
-	using const_iterator = TInternalContainer::const_iterator;
-	using iterator = TInternalContainer::iterator;
-
-	BonusList(bool BelongsToTree = false);
-	BonusList(const BonusList &bonusList);
-	BonusList(BonusList && other) noexcept;
-	BonusList& operator=(const BonusList &bonusList);
-
-	// wrapper functions of the STL vector container
-	TInternalContainer::size_type size() const { return bonuses.size(); }
-	void push_back(const std::shared_ptr<Bonus> & x);
-	TInternalContainer::iterator erase (const int position);
-	void clear();
-	bool empty() const { return bonuses.empty(); }
-	void resize(TInternalContainer::size_type sz, const std::shared_ptr<Bonus> & c = nullptr);
-	void reserve(TInternalContainer::size_type sz);
-	TInternalContainer::size_type capacity() const { return bonuses.capacity(); }
-	STRONG_INLINE std::shared_ptr<Bonus> &operator[] (TInternalContainer::size_type n) { return bonuses[n]; }
-	STRONG_INLINE const std::shared_ptr<Bonus> &operator[] (TInternalContainer::size_type n) const { return bonuses[n]; }
-	std::shared_ptr<Bonus> &back() { return bonuses.back(); }
-	std::shared_ptr<Bonus> &front() { return bonuses.front(); }
-	const std::shared_ptr<Bonus> &back() const { return bonuses.back(); }
-	const std::shared_ptr<Bonus> &front() const { return bonuses.front(); }
-
-	// There should be no non-const access to provide solid,robust bonus caching
-	TInternalContainer::const_iterator begin() const { return bonuses.begin(); }
-	TInternalContainer::const_iterator end() const { return bonuses.end(); }
-	TInternalContainer::size_type operator-=(const std::shared_ptr<Bonus> & i);
-
-	// BonusList functions
-	void stackBonuses();
-	int totalValue() const;
-	void getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit = nullptr) const;
-	void getAllBonuses(BonusList &out) const;
-
-	//special find functions
-	std::shared_ptr<Bonus> getFirst(const CSelector &select);
-	std::shared_ptr<const Bonus> getFirst(const CSelector &select) const;
-	int valOfBonuses(const CSelector &select) const;
-
-	// conversion / output
-	JsonNode toJsonNode() const;
-
-	// remove_if implementation for STL vector types
-	template <class Predicate>
-	void remove_if(Predicate pred)
-	{
-		BonusList newList;
-		for(const auto & b : bonuses)
-		{
-			if (!pred(b.get()))
-				newList.push_back(b);
-		}
-		bonuses.clear();
-		bonuses.resize(newList.size());
-		std::copy(newList.begin(), newList.end(), bonuses.begin());
-	}
-
-	template <class InputIterator>
-	void insert(const int position, InputIterator first, InputIterator last);
-	void insert(TInternalContainer::iterator position, TInternalContainer::size_type n, const std::shared_ptr<Bonus> & x);
-
-	template <typename Handler>
-	void serialize(Handler &h, const int version)
-	{
-		h & static_cast<TInternalContainer&>(bonuses);
-	}
-
-	// C++ for range support
-	auto begin () -> decltype (bonuses.begin())
-	{
-		return bonuses.begin();
-	}
-
-	auto end () -> decltype (bonuses.end())
-	{
-		return bonuses.end();
-	}
-};
-
 DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const BonusList &bonusList);
 
 template<typename T>
@@ -662,12 +568,4 @@ extern DLL_LINKAGE const std::map<std::string, ui16> bonusDurationMap;
 extern DLL_LINKAGE const std::map<std::string, Bonus::LimitEffect> bonusLimitEffect;
 extern DLL_LINKAGE const std::set<std::string> deprecatedBonusSet;
 
-// BonusList template that requires full interface of CBonusSystemNode
-template <class InputIterator>
-void BonusList::insert(const int position, InputIterator first, InputIterator last)
-{
-	bonuses.insert(bonuses.begin() + position, first, last);
-	changed();
-}
-
 VCMI_LIB_NAMESPACE_END

+ 1 - 0
lib/bonuses/IBonusBearer.cpp

@@ -11,6 +11,7 @@
 #include "StdInc.h"
 
 #include "CBonusSystemNode.h"
+#include "BonusList.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 

+ 1 - 0
lib/spells/TargetCondition.cpp

@@ -16,6 +16,7 @@
 #include "../battle/CBattleInfoCallback.h"
 #include "../battle/Unit.h"
 #include "../bonuses/BonusParams.h"
+#include "../bonuses/BonusList.h"
 
 #include "../serializer/JsonSerializeFormat.h"
 #include "../VCMI_Lib.h"

+ 1 - 0
scripting/lua/api/BonusSystem.cpp

@@ -11,6 +11,7 @@
 
 #include "BonusSystem.h"
 
+#include "../../../lib/bonuses/BonusList.h"
 #include "../../../lib/bonuses/HeroBonus.h"
 #include "../../../lib/bonuses/IBonusBearer.h"
 

+ 1 - 0
test/mock/mock_BonusBearer.h

@@ -10,6 +10,7 @@
 
 #pragma once
 
+#include "../../lib/bonuses/BonusList.h"
 #include "../../lib/bonuses/HeroBonus.h"
 #include "../../lib/bonuses/IBonusBearer.h"