mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	* Replaced boost::shared_ptr with std::shared_ptr.
* Brought shared_ptr and unique_ptr and their factories (make_shared, make_unique) to the global scope. * Removed excessive usage of shared_ptr in bonus system interface. * Fixed bonus system limiters/caching interactions. That covers #823, #859 and a number of rare edge-cases. * Implemented multiple-step limiters applying, fixing hasAnotherBonusLimiter and allowing transitional dependencies between bonuses. * Bonus system should be slightly faster, since we cache limited bonuses. Some rare usages (limiting query against a foreign node) however can't use caching.
This commit is contained in:
		| @@ -232,9 +232,9 @@ void CBattleCallback::sendRequest(const CPack* request) | ||||
|  | ||||
| 	if(waitTillRealize) | ||||
| 	{ | ||||
| 		std::unique_ptr<vstd::unlock_shared_guard> unlocker; //optional, if flag set | ||||
| 		unique_ptr<vstd::unlock_shared_guard> unlocker; //optional, if flag set | ||||
| 		if(unlockGsWhenWaiting) | ||||
| 			unlocker = vstd::make_unique<vstd::unlock_shared_guard>(vstd::makeUnlockSharedGuard(getGsMutex())); | ||||
| 			unlocker = make_unique<vstd::unlock_shared_guard>(vstd::makeUnlockSharedGuard(getGsMutex())); | ||||
|  | ||||
| 		cl->waitingRequest.waitWhileTrue(); | ||||
| 	} | ||||
|   | ||||
| @@ -100,11 +100,12 @@ public: | ||||
| class CCallback : public CPlayerSpecificInfoCallback, public IGameActionCallback, public CBattleCallback | ||||
| { | ||||
| private: | ||||
| 	CCallback(CGameState * GS, int Player, CClient *C); | ||||
|  | ||||
| 	void validatePaths(); //recalcualte paths if necessary | ||||
|  | ||||
| public: | ||||
| 	CCallback(CGameState * GS, int Player, CClient *C); | ||||
|  | ||||
| 	//client-specific functionalities (pathfinding) | ||||
| 	virtual bool getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath &ret); //DEPRACATED!!! | ||||
| 	virtual const CGPathNode *getPathInfo(int3 tile); //uses main, client pathfinder info | ||||
|   | ||||
							
								
								
									
										704
									
								
								Global.h
									
									
									
									
									
								
							
							
						
						
									
										704
									
								
								Global.h
									
									
									
									
									
								
							| @@ -1,357 +1,363 @@ | ||||
| #pragma once | ||||
|  | ||||
| // Standard include file | ||||
| // Contents: | ||||
| // Includes C/C++ libraries, STL libraries, IOStream and String libraries | ||||
| // Includes the most important boost headers | ||||
| // Defines the import + export, override and exception handling macros | ||||
| // Defines the vstd library | ||||
| // Includes the logger | ||||
|  | ||||
| // This file shouldn't be changed, except if there is a important header file missing which is shared among several projects. | ||||
|  | ||||
| /* | ||||
|  * Global.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 | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers | ||||
| #include <cstdio> | ||||
| #include <stdio.h> | ||||
| #ifdef _WIN32 | ||||
| #include <tchar.h> | ||||
| #else | ||||
| #include "tchar_amigaos4.h" | ||||
| #endif | ||||
|  | ||||
| #include <cmath> | ||||
| #include <cassert> | ||||
| #include <assert.h> | ||||
| #include <vector> | ||||
| #include <string> | ||||
| #include <map> | ||||
| #include <queue> | ||||
| #include <set> | ||||
| #include <utility> | ||||
| #include <numeric> | ||||
|  | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
| #include <sstream> | ||||
| #include <iomanip> | ||||
|  | ||||
| #include <algorithm> | ||||
| #include <memory> | ||||
| #include <cstdlib> | ||||
|  | ||||
| //filesystem version 3 causes problems (and it's default as of boost 1.46) | ||||
| #define BOOST_FILESYSTEM_VERSION 2 | ||||
|  | ||||
| #include <boost/algorithm/string.hpp> | ||||
| #include <boost/assert.hpp> | ||||
| #include <boost/assign.hpp> | ||||
| #include <boost/bind.hpp> | ||||
| #include <boost/cstdint.hpp> | ||||
| #include <boost/date_time/posix_time/posix_time.hpp> | ||||
| #include <boost/filesystem.hpp> | ||||
| #include <boost/foreach.hpp> | ||||
| #include <boost/format.hpp> | ||||
| #include <boost/function.hpp> | ||||
| #include <boost/lexical_cast.hpp> | ||||
| #include <boost/logic/tribool.hpp> | ||||
| #include <boost/program_options.hpp> | ||||
| #include <boost/thread.hpp> | ||||
| #include <boost/unordered_set.hpp> | ||||
|  | ||||
| #ifdef ANDROID | ||||
| #include <android/log.h> | ||||
| #endif | ||||
|  | ||||
| // Integral data types | ||||
| typedef boost::uint64_t ui64; //unsigned int 64 bits (8 bytes) | ||||
| typedef boost::uint32_t ui32;  //unsigned int 32 bits (4 bytes) | ||||
| typedef boost::uint16_t ui16; //unsigned int 16 bits (2 bytes) | ||||
| typedef boost::uint8_t ui8; //unsigned int 8 bits (1 byte) | ||||
| typedef boost::int64_t si64; //signed int 64 bits (8 bytes) | ||||
| typedef boost::int32_t si32; //signed int 32 bits (4 bytes) | ||||
| typedef boost::int16_t si16; //signed int 16 bits (2 bytes) | ||||
| typedef boost::int8_t si8; //signed int 8 bits (1 byte) | ||||
|  | ||||
| #ifdef __GNUC__ | ||||
| #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__ ) | ||||
| #endif | ||||
|  | ||||
| // Import + Export macro declarations | ||||
| #ifdef _WIN32 | ||||
| #define DLL_EXPORT __declspec(dllexport) | ||||
| #else | ||||
| #if defined(__GNUC__) && GCC_VERSION >= 400 | ||||
| #define DLL_EXPORT	__attribute__ ((visibility("default"))) | ||||
| #else | ||||
| #define DLL_EXPORT | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| #define DLL_IMPORT __declspec(dllimport) | ||||
| #else | ||||
| #if defined(__GNUC__) && GCC_VERSION >= 400 | ||||
| #define DLL_IMPORT	__attribute__ ((visibility("default"))) | ||||
| #else | ||||
| #define DLL_IMPORT | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #ifdef VCMI_DLL | ||||
| #define DLL_LINKAGE DLL_EXPORT | ||||
| #else | ||||
| #define DLL_LINKAGE DLL_IMPORT | ||||
| #endif | ||||
|  | ||||
| //defining available c++11 features | ||||
|  | ||||
| //initialization lists - only gcc-4.4 or later | ||||
| #if defined(__GNUC__) && (GCC_VERSION >= 404) | ||||
| #define CPP11_USE_INITIALIZERS_LIST | ||||
| #endif | ||||
|  | ||||
| //nullptr -  only msvc and gcc-4.6 or later, othervice define it  as NULL | ||||
| #if !defined(_MSC_VER) && !(defined(__GNUC__) && (GCC_VERSION >= 406)) | ||||
| #define nullptr NULL | ||||
| #endif | ||||
|  | ||||
| //override keyword - only msvc and gcc-4.7 or later. | ||||
| #if !defined(_MSC_VER) && !(defined(__GNUC__) && (GCC_VERSION >= 407)) | ||||
| #define override | ||||
| #endif | ||||
|  | ||||
| //workaround to support existing code | ||||
| #define OVERRIDE override | ||||
|  | ||||
| //a normal std::map with a const operator[] for sanity | ||||
| template<typename KeyT, typename ValT> | ||||
| class bmap : public std::map<KeyT, ValT> | ||||
| { | ||||
| public: | ||||
| 	const ValT & operator[](KeyT key) const | ||||
| 	{ | ||||
| 		return find(key)->second; | ||||
| 	} | ||||
| 	ValT & operator[](KeyT key) | ||||
| 	{ | ||||
| 		return static_cast<std::map<KeyT, ValT> &>(*this)[key]; | ||||
| 	} | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & static_cast<std::map<KeyT, ValT> &>(*this); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| namespace vstd | ||||
| { | ||||
| 	//returns true if container c contains item i | ||||
| 	template <typename Container, typename Item> | ||||
| 	bool contains(const Container & c, const Item &i) | ||||
| 	{ | ||||
| 		return std::find(c.begin(),c.end(),i) != c.end(); | ||||
| 	} | ||||
|  | ||||
| 	//returns true if map c contains item i | ||||
| 	template <typename V, typename Item, typename Item2> | ||||
| 	bool contains(const std::map<Item,V> & c, const Item2 &i) | ||||
| 	{ | ||||
| 		return c.find(i)!=c.end(); | ||||
| 	} | ||||
|  | ||||
| 	//returns true if bmap c contains item i | ||||
| 	template <typename V, typename Item, typename Item2> | ||||
| 	bool contains(const bmap<Item,V> & c, const Item2 &i) | ||||
| 	{ | ||||
| 		return c.find(i)!=c.end(); | ||||
| 	} | ||||
|  | ||||
| 	//returns true if unordered set c contains item i | ||||
| 	template <typename Item> | ||||
| 	bool contains(const boost::unordered_set<Item> & c, const Item &i) | ||||
| 	{ | ||||
| 		return c.find(i)!=c.end(); | ||||
| 	} | ||||
|  | ||||
| 	//returns position of first element in vector c equal to s, if there is no such element, -1 is returned | ||||
| 	template <typename T1, typename T2> | ||||
| 	int find_pos(const std::vector<T1> & c, const T2 &s) | ||||
| 	{ | ||||
| 		for(size_t i=0; i < c.size(); ++i) | ||||
| 			if(c[i] == s) | ||||
| 				return i; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	//Func(T1,T2) must say if these elements matches | ||||
| 	template <typename T1, typename T2, typename Func> | ||||
| 	int find_pos(const std::vector<T1> & c, const T2 &s, const Func &f) | ||||
| 	{ | ||||
| 		for(size_t i=0; i < c.size(); ++i) | ||||
| 			if(f(c[i],s)) | ||||
| 				return i; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	//returns iterator to the given element if present in container, end() if not | ||||
| 	template <typename Container, typename Item> | ||||
| 	typename Container::iterator find(Container & c, const Item &i) | ||||
| 	{ | ||||
| 		return std::find(c.begin(),c.end(),i); | ||||
| 	} | ||||
|  | ||||
| 	//returns const iterator to the given element if present in container, end() if not | ||||
| 	template <typename Container, typename Item> | ||||
| 	typename Container::const_iterator find(const Container & c, const Item &i) | ||||
| 	{ | ||||
| 		return std::find(c.begin(),c.end(),i); | ||||
| 	} | ||||
|  | ||||
| 	//removes element i from container c, returns false if c does not contain i | ||||
| 	template <typename Container, typename Item> | ||||
| 	typename Container::size_type operator-=(Container &c, const Item &i) | ||||
| 	{ | ||||
| 		typename Container::iterator itr = find(c,i); | ||||
| 		if(itr == c.end()) | ||||
| 			return false; | ||||
| 		c.erase(itr); | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	//assigns greater of (a, b) to a and returns maximum of (a, b) | ||||
| 	template <typename t1, typename t2> | ||||
| 	t1 &amax(t1 &a, const t2 &b) | ||||
| 	{ | ||||
| 		if(a >= b) | ||||
| 			return a; | ||||
| 		else | ||||
| 		{ | ||||
| 			a = b; | ||||
| 			return a; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	//assigns smaller of (a, b) to a and returns minimum of (a, b) | ||||
| 	template <typename t1, typename t2> | ||||
| 	t1 &amin(t1 &a, const t2 &b) | ||||
| 	{ | ||||
| 		if(a <= b) | ||||
| 			return a; | ||||
| 		else | ||||
| 		{ | ||||
| 			a = b; | ||||
| 			return a; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	//makes a to fit the range <b, c> | ||||
| 	template <typename t1, typename t2, typename t3> | ||||
| 	t1 &abetween(t1 &a, const t2 &b, const t3 &c) | ||||
| 	{ | ||||
| 		amax(a,b); | ||||
| 		amin(a,c); | ||||
| 		return a; | ||||
| 	} | ||||
|  | ||||
| 	//checks if a is between b and c | ||||
| 	template <typename t1, typename t2, typename t3> | ||||
| 	bool isbetween(const t1 &a, const t2 &b, const t3 &c) | ||||
| 	{ | ||||
| 		return a > b && a < c; | ||||
| 	} | ||||
|  | ||||
| 	//checks if a is within b and c | ||||
| 	template <typename t1, typename t2, typename t3> | ||||
| 	bool iswithin(const t1 &a, const t2 &b, const t3 &c) | ||||
| 	{ | ||||
| 		return a >= b && a <= c; | ||||
| 	} | ||||
|  | ||||
| 	template <typename t1, typename t2> | ||||
| 	struct assigner | ||||
| 	{ | ||||
| 	public: | ||||
| 		t1 &op1; | ||||
| 		t2 op2; | ||||
| 		assigner(t1 &a1, const t2 & a2) | ||||
| 			:op1(a1), op2(a2) | ||||
| 		{} | ||||
| 		void operator()() | ||||
| 		{ | ||||
| 			op1 = op2; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	// Assigns value a2 to a1. The point of time of the real operation can be controlled | ||||
| 	// with the () operator. | ||||
| 	template <typename t1, typename t2> | ||||
| 	assigner<t1,t2> assigno(t1 &a1, const t2 &a2) | ||||
| 	{ | ||||
| 		return assigner<t1,t2>(a1,a2); | ||||
| 	} | ||||
|  | ||||
| 	//deleted pointer and sets it to NULL | ||||
| 	template <typename T> | ||||
| 	void clear_pointer(T* &ptr) | ||||
| 	{ | ||||
| 		delete ptr; | ||||
| 		ptr = NULL; | ||||
| 	} | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| // Standard include file | ||||
| // Contents: | ||||
| // Includes C/C++ libraries, STL libraries, IOStream and String libraries | ||||
| // Includes the most important boost headers | ||||
| // Defines the import + export, override and exception handling macros | ||||
| // Defines the vstd library | ||||
| // Includes the logger | ||||
|  | ||||
| // This file shouldn't be changed, except if there is a important header file missing which is shared among several projects. | ||||
|  | ||||
| /* | ||||
|  * Global.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 | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers | ||||
| #include <cstdio> | ||||
| #include <stdio.h> | ||||
| #ifdef _WIN32 | ||||
| #include <tchar.h> | ||||
| #else | ||||
| #include "tchar_amigaos4.h" | ||||
| #endif | ||||
|  | ||||
| #include <cmath> | ||||
| #include <cassert> | ||||
| #include <assert.h> | ||||
| #include <vector> | ||||
| #include <string> | ||||
| #include <map> | ||||
| #include <queue> | ||||
| #include <set> | ||||
| #include <utility> | ||||
| #include <numeric> | ||||
|  | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
| #include <sstream> | ||||
| #include <iomanip> | ||||
|  | ||||
| #include <algorithm> | ||||
| #include <memory> | ||||
| #include <cstdlib> | ||||
|  | ||||
| //filesystem version 3 causes problems (and it's default as of boost 1.46) | ||||
| #define BOOST_FILESYSTEM_VERSION 2 | ||||
|  | ||||
| #include <boost/algorithm/string.hpp> | ||||
| #include <boost/assert.hpp> | ||||
| #include <boost/assign.hpp> | ||||
| #include <boost/bind.hpp> | ||||
| #include <boost/cstdint.hpp> | ||||
| #include <boost/date_time/posix_time/posix_time.hpp> | ||||
| #include <boost/filesystem.hpp> | ||||
| #include <boost/foreach.hpp> | ||||
| #include <boost/format.hpp> | ||||
| #include <boost/function.hpp> | ||||
| #include <boost/lexical_cast.hpp> | ||||
| #include <boost/logic/tribool.hpp> | ||||
| #include <boost/program_options.hpp> | ||||
| #include <boost/thread.hpp> | ||||
| #include <boost/unordered_set.hpp> | ||||
|  | ||||
| #ifdef ANDROID | ||||
| #include <android/log.h> | ||||
| #endif | ||||
|  | ||||
| // Integral data types | ||||
| typedef boost::uint64_t ui64; //unsigned int 64 bits (8 bytes) | ||||
| typedef boost::uint32_t ui32;  //unsigned int 32 bits (4 bytes) | ||||
| typedef boost::uint16_t ui16; //unsigned int 16 bits (2 bytes) | ||||
| typedef boost::uint8_t ui8; //unsigned int 8 bits (1 byte) | ||||
| typedef boost::int64_t si64; //signed int 64 bits (8 bytes) | ||||
| typedef boost::int32_t si32; //signed int 32 bits (4 bytes) | ||||
| typedef boost::int16_t si16; //signed int 16 bits (2 bytes) | ||||
| typedef boost::int8_t si8; //signed int 8 bits (1 byte) | ||||
|  | ||||
| #ifdef __GNUC__ | ||||
| #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__ ) | ||||
| #endif | ||||
|  | ||||
| // Import + Export macro declarations | ||||
| #ifdef _WIN32 | ||||
| #define DLL_EXPORT __declspec(dllexport) | ||||
| #else | ||||
| #if defined(__GNUC__) && GCC_VERSION >= 400 | ||||
| #define DLL_EXPORT	__attribute__ ((visibility("default"))) | ||||
| #else | ||||
| #define DLL_EXPORT | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| #define DLL_IMPORT __declspec(dllimport) | ||||
| #else | ||||
| #if defined(__GNUC__) && GCC_VERSION >= 400 | ||||
| #define DLL_IMPORT	__attribute__ ((visibility("default"))) | ||||
| #else | ||||
| #define DLL_IMPORT | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #ifdef VCMI_DLL | ||||
| #define DLL_LINKAGE DLL_EXPORT | ||||
| #else | ||||
| #define DLL_LINKAGE DLL_IMPORT | ||||
| #endif | ||||
|  | ||||
| //defining available c++11 features | ||||
|  | ||||
| //initialization lists - only gcc-4.4 or later | ||||
| #if defined(__GNUC__) && (GCC_VERSION >= 404) | ||||
| #define CPP11_USE_INITIALIZERS_LIST | ||||
| #endif | ||||
|  | ||||
| //nullptr -  only msvc and gcc-4.6 or later, othervice define it  as NULL | ||||
| #if !defined(_MSC_VER) && !(defined(__GNUC__) && (GCC_VERSION >= 406)) | ||||
| #define nullptr NULL | ||||
| #endif | ||||
|  | ||||
| //override keyword - only msvc and gcc-4.7 or later. | ||||
| #if !defined(_MSC_VER) && !(defined(__GNUC__) && (GCC_VERSION >= 407)) | ||||
| #define override | ||||
| #endif | ||||
|  | ||||
| //workaround to support existing code | ||||
| #define OVERRIDE override | ||||
|  | ||||
| //a normal std::map with a const operator[] for sanity | ||||
| template<typename KeyT, typename ValT> | ||||
| class bmap : public std::map<KeyT, ValT> | ||||
| { | ||||
| public: | ||||
| 	const ValT & operator[](KeyT key) const | ||||
| 	{ | ||||
| 		return find(key)->second; | ||||
| 	} | ||||
| 	ValT & operator[](KeyT key) | ||||
| 	{ | ||||
| 		return static_cast<std::map<KeyT, ValT> &>(*this)[key]; | ||||
| 	} | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & static_cast<std::map<KeyT, ValT> &>(*this); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| namespace vstd | ||||
| { | ||||
| 	//returns true if container c contains item i | ||||
| 	template <typename Container, typename Item> | ||||
| 	bool contains(const Container & c, const Item &i) | ||||
| 	{ | ||||
| 		return std::find(c.begin(),c.end(),i) != c.end(); | ||||
| 	} | ||||
|  | ||||
| 	//returns true if map c contains item i | ||||
| 	template <typename V, typename Item, typename Item2> | ||||
| 	bool contains(const std::map<Item,V> & c, const Item2 &i) | ||||
| 	{ | ||||
| 		return c.find(i)!=c.end(); | ||||
| 	} | ||||
|  | ||||
| 	//returns true if bmap c contains item i | ||||
| 	template <typename V, typename Item, typename Item2> | ||||
| 	bool contains(const bmap<Item,V> & c, const Item2 &i) | ||||
| 	{ | ||||
| 		return c.find(i)!=c.end(); | ||||
| 	} | ||||
|  | ||||
| 	//returns true if unordered set c contains item i | ||||
| 	template <typename Item> | ||||
| 	bool contains(const boost::unordered_set<Item> & c, const Item &i) | ||||
| 	{ | ||||
| 		return c.find(i)!=c.end(); | ||||
| 	} | ||||
|  | ||||
| 	//returns position of first element in vector c equal to s, if there is no such element, -1 is returned | ||||
| 	template <typename T1, typename T2> | ||||
| 	int find_pos(const std::vector<T1> & c, const T2 &s) | ||||
| 	{ | ||||
| 		for(size_t i=0; i < c.size(); ++i) | ||||
| 			if(c[i] == s) | ||||
| 				return i; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	//Func(T1,T2) must say if these elements matches | ||||
| 	template <typename T1, typename T2, typename Func> | ||||
| 	int find_pos(const std::vector<T1> & c, const T2 &s, const Func &f) | ||||
| 	{ | ||||
| 		for(size_t i=0; i < c.size(); ++i) | ||||
| 			if(f(c[i],s)) | ||||
| 				return i; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	//returns iterator to the given element if present in container, end() if not | ||||
| 	template <typename Container, typename Item> | ||||
| 	typename Container::iterator find(Container & c, const Item &i) | ||||
| 	{ | ||||
| 		return std::find(c.begin(),c.end(),i); | ||||
| 	} | ||||
|  | ||||
| 	//returns const iterator to the given element if present in container, end() if not | ||||
| 	template <typename Container, typename Item> | ||||
| 	typename Container::const_iterator find(const Container & c, const Item &i) | ||||
| 	{ | ||||
| 		return std::find(c.begin(),c.end(),i); | ||||
| 	} | ||||
|  | ||||
| 	//removes element i from container c, returns false if c does not contain i | ||||
| 	template <typename Container, typename Item> | ||||
| 	typename Container::size_type operator-=(Container &c, const Item &i) | ||||
| 	{ | ||||
| 		typename Container::iterator itr = find(c,i); | ||||
| 		if(itr == c.end()) | ||||
| 			return false; | ||||
| 		c.erase(itr); | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	//assigns greater of (a, b) to a and returns maximum of (a, b) | ||||
| 	template <typename t1, typename t2> | ||||
| 	t1 &amax(t1 &a, const t2 &b) | ||||
| 	{ | ||||
| 		if(a >= b) | ||||
| 			return a; | ||||
| 		else | ||||
| 		{ | ||||
| 			a = b; | ||||
| 			return a; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	//assigns smaller of (a, b) to a and returns minimum of (a, b) | ||||
| 	template <typename t1, typename t2> | ||||
| 	t1 &amin(t1 &a, const t2 &b) | ||||
| 	{ | ||||
| 		if(a <= b) | ||||
| 			return a; | ||||
| 		else | ||||
| 		{ | ||||
| 			a = b; | ||||
| 			return a; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	//makes a to fit the range <b, c> | ||||
| 	template <typename t1, typename t2, typename t3> | ||||
| 	t1 &abetween(t1 &a, const t2 &b, const t3 &c) | ||||
| 	{ | ||||
| 		amax(a,b); | ||||
| 		amin(a,c); | ||||
| 		return a; | ||||
| 	} | ||||
|  | ||||
| 	//checks if a is between b and c | ||||
| 	template <typename t1, typename t2, typename t3> | ||||
| 	bool isbetween(const t1 &a, const t2 &b, const t3 &c) | ||||
| 	{ | ||||
| 		return a > b && a < c; | ||||
| 	} | ||||
|  | ||||
| 	//checks if a is within b and c | ||||
| 	template <typename t1, typename t2, typename t3> | ||||
| 	bool iswithin(const t1 &a, const t2 &b, const t3 &c) | ||||
| 	{ | ||||
| 		return a >= b && a <= c; | ||||
| 	} | ||||
|  | ||||
| 	template <typename t1, typename t2> | ||||
| 	struct assigner | ||||
| 	{ | ||||
| 	public: | ||||
| 		t1 &op1; | ||||
| 		t2 op2; | ||||
| 		assigner(t1 &a1, const t2 & a2) | ||||
| 			:op1(a1), op2(a2) | ||||
| 		{} | ||||
| 		void operator()() | ||||
| 		{ | ||||
| 			op1 = op2; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	// Assigns value a2 to a1. The point of time of the real operation can be controlled | ||||
| 	// with the () operator. | ||||
| 	template <typename t1, typename t2> | ||||
| 	assigner<t1,t2> assigno(t1 &a1, const t2 &a2) | ||||
| 	{ | ||||
| 		return assigner<t1,t2>(a1,a2); | ||||
| 	} | ||||
|  | ||||
| 	//deleted pointer and sets it to NULL | ||||
| 	template <typename T> | ||||
| 	void clear_pointer(T* &ptr) | ||||
| 	{ | ||||
| 		delete ptr; | ||||
| 		ptr = NULL; | ||||
| 	} | ||||
|  | ||||
| 	template<typename T> | ||||
| 	std::unique_ptr<T> make_unique() | ||||
| 	{ | ||||
| 		return std::unique_ptr<T>(new T()); | ||||
| 	} | ||||
| 	} | ||||
| 	template<typename T, typename Arg1> | ||||
| 	std::unique_ptr<T> make_unique(Arg1&& arg1) | ||||
| 	{ | ||||
| 		return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1))); | ||||
| 	} | ||||
| } | ||||
| using vstd::operator-=; | ||||
|  | ||||
| // can be used for counting arrays | ||||
| template<typename T, size_t N> char (&_ArrayCountObj(const T (&)[N]))[N]; | ||||
| #define ARRAY_COUNT(arr)    (sizeof(_ArrayCountObj(arr))) | ||||
|  | ||||
| //XXX pls dont - 'debug macros' are usually more trouble than it's worth | ||||
| #define HANDLE_EXCEPTION  \ | ||||
| 	catch (const std::exception& e) {	\ | ||||
| 	tlog1 << e.what() << std::endl;		\ | ||||
| 	throw;								\ | ||||
| }									\ | ||||
| 	catch (const std::exception * e)	\ | ||||
| {									\ | ||||
| 	tlog1 << e->what()<< std::endl;	\ | ||||
| 	throw;							\ | ||||
| }									\ | ||||
| 	catch (const std::string& e) {		\ | ||||
| 	tlog1 << e << std::endl;		\ | ||||
| 	throw;							\ | ||||
| } | ||||
|  | ||||
| #define HANDLE_EXCEPTIONC(COMMAND)  \ | ||||
| 	catch (const std::exception& e) {	\ | ||||
| 	COMMAND;						\ | ||||
| 	tlog1 << e.what() << std::endl;	\ | ||||
| 	throw;							\ | ||||
| }									\ | ||||
| 	catch (const std::string &e)	\ | ||||
| {									\ | ||||
| 	COMMAND;						\ | ||||
| 	tlog1 << e << std::endl;	\ | ||||
| 	throw;							\ | ||||
| } | ||||
|  | ||||
|  | ||||
| #include "lib/CLogger.h" | ||||
| 	} | ||||
| } | ||||
|  | ||||
| using std::shared_ptr; | ||||
| using std::unique_ptr; | ||||
| using std::make_shared; | ||||
| using vstd::make_unique; | ||||
|  | ||||
| using vstd::operator-=; | ||||
|  | ||||
| // can be used for counting arrays | ||||
| template<typename T, size_t N> char (&_ArrayCountObj(const T (&)[N]))[N]; | ||||
| #define ARRAY_COUNT(arr)    (sizeof(_ArrayCountObj(arr))) | ||||
|  | ||||
| //XXX pls dont - 'debug macros' are usually more trouble than it's worth | ||||
| #define HANDLE_EXCEPTION  \ | ||||
| 	catch (const std::exception& e) {	\ | ||||
| 	tlog1 << e.what() << std::endl;		\ | ||||
| 	throw;								\ | ||||
| }									\ | ||||
| 	catch (const std::exception * e)	\ | ||||
| {									\ | ||||
| 	tlog1 << e->what()<< std::endl;	\ | ||||
| 	throw;							\ | ||||
| }									\ | ||||
| 	catch (const std::string& e) {		\ | ||||
| 	tlog1 << e << std::endl;		\ | ||||
| 	throw;							\ | ||||
| } | ||||
|  | ||||
| #define HANDLE_EXCEPTIONC(COMMAND)  \ | ||||
| 	catch (const std::exception& e) {	\ | ||||
| 	COMMAND;						\ | ||||
| 	tlog1 << e.what() << std::endl;	\ | ||||
| 	throw;							\ | ||||
| }									\ | ||||
| 	catch (const std::string &e)	\ | ||||
| {									\ | ||||
| 	COMMAND;						\ | ||||
| 	tlog1 << e << std::endl;	\ | ||||
| 	throw;							\ | ||||
| } | ||||
|  | ||||
|  | ||||
| #include "lib/CLogger.h" | ||||
|   | ||||
| @@ -145,8 +145,8 @@ private: | ||||
| 	SettingsListener listener; | ||||
| 	void onVolumeChange(const JsonNode &volumeNode); | ||||
|  | ||||
| 	std::unique_ptr<MusicEntry> current; | ||||
| 	std::unique_ptr<MusicEntry> next; | ||||
| 	unique_ptr<MusicEntry> current; | ||||
| 	unique_ptr<MusicEntry> next; | ||||
|  | ||||
| 	void queueNext(MusicEntry *queued); | ||||
| public: | ||||
|   | ||||
| @@ -367,7 +367,7 @@ void CClient::newGame( CConnection *con, StartInfo *si ) | ||||
|  | ||||
| 		if(si->mode != StartInfo::DUEL) | ||||
| 		{ | ||||
| 			CCallback *cb = new CCallback(gs,color,this); | ||||
| 			auto cb = make_shared<CCallback>(gs,color,this); | ||||
| 			if(!it->second.human)  | ||||
| 			{ | ||||
| 				std::string AItoGive = settings["server"]["playerAI"].String(); | ||||
| @@ -385,8 +385,8 @@ void CClient::newGame( CConnection *con, StartInfo *si ) | ||||
| 			} | ||||
| 			battleints[color] = playerint[color]; | ||||
|  | ||||
| 			playerint[color]->init(cb); | ||||
| 			callbacks[color] = boost::shared_ptr<CCallback>(cb); | ||||
| 			playerint[color]->init(cb.get()); | ||||
| 			callbacks[color] = cb; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| @@ -473,7 +473,7 @@ void CClient::serialize( Handler &h, const int version ) | ||||
| 			else | ||||
| 				nInt = new CPlayerInterface(pid); | ||||
|  | ||||
| 			callbacks[pid] = boost::shared_ptr<CCallback>(new CCallback(gs,pid,this)); | ||||
| 			callbacks[pid] = make_shared<CCallback>(gs,pid,this); | ||||
| 			battleints[pid] = playerint[pid] = nInt; | ||||
| 			nInt->init(callbacks[pid].get()); | ||||
| 			nInt->serialize(h, version); | ||||
|   | ||||
| @@ -61,7 +61,7 @@ class CClient : public IGameCallback | ||||
| { | ||||
| public: | ||||
| 	CCallback *cb; | ||||
| 	std::map<ui8,boost::shared_ptr<CCallback> > callbacks; //callbacks given to player interfaces | ||||
| 	std::map<ui8,shared_ptr<CCallback> > callbacks; //callbacks given to player interfaces | ||||
| 	std::vector<IGameEventsReceiver*> privilagedGameEventReceivers; //scripting modules, spectator interfaces | ||||
| 	std::vector<IBattleEventsReceiver*> privilagedBattleEventReceivers; //scripting modules, spectator interfaces | ||||
| 	std::map<ui8,CGameInterface *> playerint; | ||||
|   | ||||
| @@ -1727,19 +1727,19 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const | ||||
|  | ||||
| 	case 18: //holy ground | ||||
| 		{ | ||||
| 			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, +1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(EAlignment::GOOD))); | ||||
| 			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(EAlignment::EVIL))); | ||||
| 			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, +1, Bonus::TERRAIN_OVERLAY)->addLimiter(make_shared<CreatureAlignmentLimiter>(EAlignment::GOOD))); | ||||
| 			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)->addLimiter(make_shared<CreatureAlignmentLimiter>(EAlignment::EVIL))); | ||||
| 			break; | ||||
| 		} | ||||
| 	case 19: //clover field | ||||
| 		{ //+2 luck bonus for neutral creatures | ||||
| 			curB->addNewBonus(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, +2, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureFactionLimiter(-1))); | ||||
| 			curB->addNewBonus(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, +2, Bonus::TERRAIN_OVERLAY)->addLimiter(make_shared<CreatureFactionLimiter>(-1))); | ||||
| 			break; | ||||
| 		} | ||||
| 	case 20: //evil fog | ||||
| 		{ | ||||
| 			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(EAlignment::GOOD))); | ||||
| 			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, +1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(EAlignment::EVIL))); | ||||
| 			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)->addLimiter(make_shared<CreatureAlignmentLimiter>(EAlignment::GOOD))); | ||||
| 			curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, +1, Bonus::TERRAIN_OVERLAY)->addLimiter(make_shared<CreatureAlignmentLimiter>(EAlignment::EVIL))); | ||||
| 			break; | ||||
| 		} | ||||
| 	case 22: //cursed ground | ||||
| @@ -1758,7 +1758,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const | ||||
| 	if(town) //during siege always take premies for native terrain of faction | ||||
| 		terrain = VLC->heroh->nativeTerrains[town->town->typeID]; | ||||
|  | ||||
| 	boost::shared_ptr<ILimiter> nativeTerrain(new CreatureNativeTerrainLimiter(terrain)); | ||||
| 	auto nativeTerrain = make_shared<CreatureNativeTerrainLimiter>(terrain); | ||||
| 	curB->addNewBonus(makeFeature(Bonus::STACKS_SPEED, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain)); | ||||
| 	curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::ATTACK, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain)); | ||||
| 	curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::DEFENSE, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain)); | ||||
|   | ||||
| @@ -363,7 +363,7 @@ void CCreatureHandler::loadCreatures() | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "const_raises_morale")) | ||||
| 			{ | ||||
| 				ncre.addBonus(+1, Bonus::MORALE);; | ||||
| 				ncre.getBonusList().back()->addPropagator(new CPropagatorNodeType(CBonusSystemNode::HERO)); | ||||
| 				ncre.getBonusList().back()->addPropagator(make_shared<CPropagatorNodeType>(CBonusSystemNode::HERO)); | ||||
| 			} | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "const_lowers_morale")) | ||||
| 			{ | ||||
|   | ||||
| @@ -2274,9 +2274,9 @@ void CGTownInstance::deserializationFix() | ||||
|  | ||||
| void CGTownInstance::recreateBuildingsBonuses() | ||||
| { | ||||
| 	TBonusListPtr bl(new BonusList); | ||||
| 	BonusList bl; | ||||
| 	getExportedBonusList().getBonuses(bl, Selector::sourceType(Bonus::TOWN_STRUCTURE)); | ||||
| 	BOOST_FOREACH(Bonus *b, *bl) | ||||
| 	BOOST_FOREACH(Bonus *b, bl) | ||||
| 		removeBonus(b); | ||||
|  | ||||
|  | ||||
| @@ -2285,13 +2285,13 @@ void CGTownInstance::recreateBuildingsBonuses() | ||||
| 	 | ||||
| 	if(subID == 0) //castle | ||||
| 	{ | ||||
| 		addBonusIfBuilt(17, Bonus::SEA_MOVEMENT, +500, new CPropagatorNodeType(PLAYER)); //lighthouses | ||||
| 		addBonusIfBuilt(26, Bonus::MORALE, +2, new CPropagatorNodeType(PLAYER)); //colossus | ||||
| 		addBonusIfBuilt(17, Bonus::SEA_MOVEMENT, +500, make_shared<CPropagatorNodeType>(PLAYER)); //lighthouses | ||||
| 		addBonusIfBuilt(26, Bonus::MORALE, +2, make_shared<CPropagatorNodeType>(PLAYER)); //colossus | ||||
| 	} | ||||
| 	else if(subID == 1) //rampart | ||||
| 	{ | ||||
| 		addBonusIfBuilt(21, Bonus::LUCK, +2); //fountain of fortune | ||||
| 		addBonusIfBuilt(21, Bonus::LUCK, +2, new CPropagatorNodeType(PLAYER)); //guardian spirit | ||||
| 		addBonusIfBuilt(21, Bonus::LUCK, +2, make_shared<CPropagatorNodeType>(PLAYER)); //guardian spirit | ||||
| 	} | ||||
| 	else if(subID == 2) //tower | ||||
| 	{ | ||||
| @@ -2304,8 +2304,8 @@ void CGTownInstance::recreateBuildingsBonuses() | ||||
| 	else if(subID == 4) //necropolis | ||||
| 	{ | ||||
| 		addBonusIfBuilt(17, Bonus::DARKNESS, +20); | ||||
| 		addBonusIfBuilt(21, Bonus::SECONDARY_SKILL_PREMY, +10, new CPropagatorNodeType(PLAYER), CGHeroInstance::NECROMANCY); //necromancy amplifier | ||||
| 		addBonusIfBuilt(26, Bonus::SECONDARY_SKILL_PREMY, +20, new CPropagatorNodeType(PLAYER), CGHeroInstance::NECROMANCY); //Soul prison | ||||
| 		addBonusIfBuilt(21, Bonus::SECONDARY_SKILL_PREMY, +10, make_shared<CPropagatorNodeType>(PLAYER), CGHeroInstance::NECROMANCY); //necromancy amplifier | ||||
| 		addBonusIfBuilt(26, Bonus::SECONDARY_SKILL_PREMY, +20, make_shared<CPropagatorNodeType>(PLAYER), CGHeroInstance::NECROMANCY); //Soul prison | ||||
| 	} | ||||
| 	else if(subID == 5) //Dungeon | ||||
| 	{ | ||||
| @@ -2333,7 +2333,7 @@ bool CGTownInstance::addBonusIfBuilt(int building, int type, int val, int subtyp | ||||
| 	return addBonusIfBuilt(building, type, val, NULL, subtype); | ||||
| } | ||||
|  | ||||
| bool CGTownInstance::addBonusIfBuilt(int building, int type, int val, IPropagator *prop, int subtype /*= -1*/) | ||||
| bool CGTownInstance::addBonusIfBuilt(int building, int type, int val, TPropagatorPtr prop, int subtype /*= -1*/) | ||||
| { | ||||
| 	if(vstd::contains(builtBuildings, building)) | ||||
| 	{ | ||||
|   | ||||
| @@ -584,7 +584,7 @@ public: | ||||
| 	std::string nodeName() const OVERRIDE; | ||||
| 	void deserializationFix(); | ||||
| 	void recreateBuildingsBonuses(); | ||||
| 	bool addBonusIfBuilt(int building, int type, int val, IPropagator *prop, int subtype = -1); //returns true if building is built and bonus has been added | ||||
| 	bool addBonusIfBuilt(int building, int type, int val, TPropagatorPtr prop, int subtype = -1); //returns true if building is built and bonus has been added | ||||
| 	bool addBonusIfBuilt(int building, int type, int val, int subtype = -1); //convienence version of above | ||||
| 	void setVisitingHero(CGHeroInstance *h); | ||||
| 	void setGarrisonedHero(CGHeroInstance *h); | ||||
|   | ||||
| @@ -495,7 +495,7 @@ public: | ||||
| 		const_cast<T&>(data).serialize(*this,version); | ||||
| 	} | ||||
| 	template <typename T> | ||||
| 	void saveSerializable(const boost::shared_ptr<T> &data) | ||||
| 	void saveSerializable(const shared_ptr<T> &data) | ||||
| 	{ | ||||
| 		T *internalPtr = data.get(); | ||||
| 		*this << internalPtr; | ||||
| @@ -762,7 +762,7 @@ public: | ||||
|  | ||||
|  | ||||
| 	template <typename T> | ||||
| 	void loadSerializable(boost::shared_ptr<T> &data) | ||||
| 	void loadSerializable(shared_ptr<T> &data) | ||||
| 	{ | ||||
| 		T *internalPtr; | ||||
| 		*this >> internalPtr; | ||||
|   | ||||
| @@ -12,6 +12,7 @@ | ||||
| #include "GameConstants.h" | ||||
|  | ||||
| #define FOREACH_PARENT(pname) 	TNodes lparents; getParents(lparents); BOOST_FOREACH(CBonusSystemNode *pname, lparents) | ||||
| #define FOREACH_CPARENT(pname) 	TCNodes lparents; getParents(lparents); BOOST_FOREACH(const CBonusSystemNode *pname, lparents) | ||||
| #define FOREACH_RED_CHILD(pname) 	TNodes lchildren; getRedChildren(lchildren); BOOST_FOREACH(CBonusSystemNode *pname, lchildren) | ||||
| #define FOREACH_RED_PARENT(pname) 	TNodes lparents; getRedParents(lparents); BOOST_FOREACH(CBonusSystemNode *pname, lparents) | ||||
|  | ||||
| @@ -143,7 +144,7 @@ void BonusList::getModifiersWDescr(TModDescr &out) const | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void BonusList::getBonuses(TBonusListPtr out, const CSelector &selector) const | ||||
| void BonusList::getBonuses(BonusList & out, const CSelector &selector) const | ||||
| { | ||||
| // 	BOOST_FOREACH(Bonus *i, *this) | ||||
| // 		if(selector(i) && i->effectRange == Bonus::NO_LIMIT) | ||||
| @@ -152,31 +153,37 @@ void BonusList::getBonuses(TBonusListPtr out, const CSelector &selector) const | ||||
| 	getBonuses(out, selector, 0); | ||||
| } | ||||
|  | ||||
| void BonusList::getBonuses(TBonusListPtr out, const CSelector &selector, const CSelector &limit, const bool caching /*= false*/) const | ||||
| void BonusList::getBonuses(BonusList & out, const CSelector &selector, const CSelector &limit) const | ||||
| { | ||||
| 	for (ui32 i = 0; i < bonuses.size(); i++) | ||||
| 	{ | ||||
| 		Bonus *b = bonuses[i]; | ||||
|  | ||||
| 		//add matching bonuses that matches limit predicate or have NO_LIMIT if no given predicate | ||||
| 		if(caching || (selector(b) && ((!limit && b->effectRange == Bonus::NO_LIMIT) || (limit && limit(b))))) | ||||
| 			out->push_back(b); | ||||
| 		if(selector(b) && ((!limit && b->effectRange == Bonus::NO_LIMIT) || (limit && limit(b)))) | ||||
| 			out.push_back(b); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void BonusList::getAllBonuses(BonusList &out) const | ||||
| { | ||||
| 	BOOST_FOREACH(Bonus *b, bonuses) | ||||
| 		out.push_back(b); | ||||
| } | ||||
|  | ||||
| int BonusList::valOfBonuses(const CSelector &select) const | ||||
| { | ||||
| 	TBonusListPtr ret(new BonusList()); | ||||
| 	BonusList ret; | ||||
| 	CSelector limit = 0; | ||||
| 	getBonuses(ret, select, limit, false); | ||||
| 	ret->eliminateDuplicates(); | ||||
| 	return ret->totalValue(); | ||||
| 	getBonuses(ret, select, limit); | ||||
| 	ret.eliminateDuplicates(); | ||||
| 	return ret.totalValue(); | ||||
| } | ||||
|  | ||||
| void BonusList::limit(const CBonusSystemNode &node) | ||||
| { | ||||
| 	remove_if(boost::bind(&CBonusSystemNode::isLimitedOnUs, boost::ref(node), _1)); | ||||
| } | ||||
| // void BonusList::limit(const CBonusSystemNode &node) | ||||
| // { | ||||
| // 	remove_if(boost::bind(&CBonusSystemNode::isLimitedOnUs, boost::ref(node), _1)); | ||||
| // } | ||||
|  | ||||
|  | ||||
| void BonusList::eliminateDuplicates() | ||||
| @@ -464,20 +471,30 @@ void CBonusSystemNode::getParents(TNodes &out) | ||||
| 	}	 | ||||
| } | ||||
|  | ||||
| void CBonusSystemNode::getAllBonusesRec(TBonusListPtr out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/, const bool caching /*= false*/) const | ||||
| void CBonusSystemNode::getBonusesRec(BonusList &out, const CSelector &selector, const CSelector &limit) const | ||||
| { | ||||
| 	TCNodes lparents;  | ||||
| 	getParents(lparents);  | ||||
| 	BOOST_FOREACH(const CBonusSystemNode *p, lparents) | ||||
| 		p->getAllBonusesRec(out, selector, limit, root ? root : this, caching); | ||||
| 	 | ||||
| 	bonuses.getBonuses(out, selector, limit, caching); | ||||
| 	FOREACH_CPARENT(p) | ||||
| 	{ | ||||
| 		p->getBonusesRec(out, selector, limit); | ||||
| 	} | ||||
|  | ||||
| 	bonuses.getBonuses(out, selector, limit); | ||||
| } | ||||
|  | ||||
| void CBonusSystemNode::getAllBonusesRec(BonusList &out) const | ||||
| { | ||||
| 	FOREACH_CPARENT(p) | ||||
| 	{ | ||||
| 		p->getAllBonusesRec(out); | ||||
| 	} | ||||
|  | ||||
| 	bonuses.getAllBonuses(out); | ||||
| } | ||||
|  | ||||
| const TBonusListPtr CBonusSystemNode::getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/, const std::string &cachingStr /*= ""*/) const | ||||
| { | ||||
| 	TBonusListPtr ret(new BonusList()); | ||||
| 	if (CBonusSystemNode::cachingEnabled) | ||||
| 	bool limitOnUs = (!root || root == this); //caching won't work when we want to limit bonuses against an external node | ||||
| 	if (CBonusSystemNode::cachingEnabled && limitOnUs)  | ||||
| 	{ | ||||
| 		// Exclusive access for one thread | ||||
| 		static boost::mutex m; | ||||
| @@ -487,11 +504,14 @@ const TBonusListPtr CBonusSystemNode::getAllBonuses(const CSelector &selector, c | ||||
| 		// cache all bonus objects. Selector objects doesn't matter. | ||||
| 		if (cachedLast != treeChanged) | ||||
| 		{ | ||||
| 			getAllBonusesRec(ret, selector, limit, this, true); | ||||
| 			ret->eliminateDuplicates(); | ||||
| 			cachedBonuses = *ret; | ||||
| 			ret->clear(); | ||||
| 			cachedBonuses.clear(); | ||||
| 			cachedRequests.clear(); | ||||
|  | ||||
| 			BonusList allBonuses; | ||||
| 			getAllBonusesRec(allBonuses); | ||||
| 			allBonuses.eliminateDuplicates(); | ||||
| 			limitBonuses(allBonuses, cachedBonuses); | ||||
|  | ||||
| 			cachedLast = treeChanged; | ||||
| 		} | ||||
| 		 | ||||
| @@ -499,43 +519,70 @@ const TBonusListPtr CBonusSystemNode::getAllBonuses(const CSelector &selector, c | ||||
| 		// pre-calculated bonus results. Limiters can't be cached so they have to be calculated. | ||||
| 		if (cachingStr != "") | ||||
| 		{ | ||||
| 			std::map<std::string, TBonusListPtr >::iterator it(cachedRequests.find(cachingStr)); | ||||
| 			if (cachedRequests.size() > 0 && it != cachedRequests.end()) | ||||
| 			auto it = cachedRequests.find(cachingStr); | ||||
| 			if(it != cachedRequests.end()) | ||||
| 			{ | ||||
| 				ret = it->second; | ||||
| 				if (!root) | ||||
| 					ret->limit(*this); | ||||
|  | ||||
| 				return ret; | ||||
| 				//Cached list contains bonuses for our query with applied limiters | ||||
| 				return it->second; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Get the bonus results | ||||
| 		cachedBonuses.getBonuses(ret, selector, limit, false); | ||||
| 		 | ||||
| 		// Sets the results with the given caching string into the map | ||||
| 		if (cachingStr != "") | ||||
| 		//We still don't have the bonuses (didn't returned them from cache) | ||||
| 		//Perform bonus selection | ||||
| 		auto ret = make_shared<BonusList>(); | ||||
| 		cachedBonuses.getBonuses(*ret, selector, limit);  | ||||
|  | ||||
| 		// Save the results in the cache | ||||
| 		if(cachingStr != "") | ||||
| 			cachedRequests[cachingStr] = ret; | ||||
| 		 | ||||
| 		// Calculate limiters | ||||
| 		if (!root) | ||||
| 			ret->limit(*this); | ||||
|  | ||||
| 		return ret; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		// Get bonus results without caching enabled. | ||||
| 		getAllBonusesRec(ret, selector, limit, root, false); | ||||
| 		ret->eliminateDuplicates(); | ||||
|  | ||||
| 		if(!root) | ||||
| 			ret->limit(*this); | ||||
|  | ||||
| 		return ret; | ||||
| 		return getAllBonusesWithoutCaching(selector, limit, root); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| const TBonusListPtr CBonusSystemNode::getAllBonusesWithoutCaching(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const | ||||
| { | ||||
| 	auto ret = make_shared<BonusList>(); | ||||
|  | ||||
| 	// Get bonus results without caching enabled. | ||||
| 	BonusList beforeLimiting, afterLimiting; | ||||
| 	getAllBonusesRec(beforeLimiting); | ||||
| 	beforeLimiting.eliminateDuplicates(); | ||||
|  | ||||
| 	if(!root || root == this) | ||||
| 	{ | ||||
| 		limitBonuses(beforeLimiting, afterLimiting); | ||||
| 		afterLimiting.getBonuses(*ret, selector, limit); | ||||
| 	} | ||||
| 	else if(root) | ||||
| 	{ | ||||
| 		//We want to limit our query against an external node. We get all its bonuses,  | ||||
| 		// add the ones we're considering and see if they're cut out by limiters | ||||
| 		BonusList rootBonuses, limitedRootBonuses; | ||||
| 		getAllBonusesRec(rootBonuses); | ||||
|  | ||||
| 		BOOST_FOREACH(Bonus *b, beforeLimiting)  | ||||
| 			rootBonuses.push_back(b); | ||||
|  | ||||
| 		rootBonuses.eliminateDuplicates(); | ||||
| 		root->limitBonuses(rootBonuses, limitedRootBonuses); | ||||
|  | ||||
| 		BOOST_FOREACH(Bonus *b, beforeLimiting) | ||||
| 			if(vstd::contains(limitedRootBonuses, b)) | ||||
| 				afterLimiting.push_back(b); | ||||
|  | ||||
| 		afterLimiting.getBonuses(*ret, selector, limit); | ||||
| 	} | ||||
| 	else | ||||
| 		beforeLimiting.getBonuses(*ret, selector, limit); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| CBonusSystemNode::CBonusSystemNode() : bonuses(true), exportedBonuses(true), nodeType(UNKNOWN), cachedLast(0) | ||||
| { | ||||
| } | ||||
| @@ -585,9 +632,9 @@ void CBonusSystemNode::detachFrom(CBonusSystemNode *parent) | ||||
|  | ||||
| void CBonusSystemNode::popBonuses(const CSelector &s) | ||||
| { | ||||
| 	TBonusListPtr bl(new BonusList); | ||||
| 	BonusList bl; | ||||
| 	exportedBonuses.getBonuses(bl, s); | ||||
| 	BOOST_FOREACH(Bonus *b, *bl) | ||||
| 	BOOST_FOREACH(Bonus *b, bl) | ||||
| 		removeBonus(b); | ||||
|  | ||||
| 	BOOST_FOREACH(CBonusSystemNode *child, children) | ||||
| @@ -618,11 +665,6 @@ void CBonusSystemNode::removeBonus(Bonus *b) | ||||
| 	CBonusSystemNode::treeChanged++; | ||||
| } | ||||
|  | ||||
| bool CBonusSystemNode::isLimitedOnUs(Bonus *b) const | ||||
| { | ||||
| 	return b->limiter && b->limiter->limit(b, *this); | ||||
| } | ||||
|  | ||||
| bool CBonusSystemNode::actsAsBonusSourceOnly() const | ||||
| { | ||||
| 	switch(nodeType) | ||||
| @@ -852,6 +894,53 @@ void CBonusSystemNode::incrementTreeChangedNum() | ||||
| 	treeChanged++; | ||||
| } | ||||
|  | ||||
| void CBonusSystemNode::limitBonuses(const BonusList &allBonuses, BonusList &out) const | ||||
| { | ||||
| 	assert(&allBonuses != &out); //todo should it work in-place? | ||||
|  | ||||
| 	BonusList undecided = allBonuses,  | ||||
| 		&accepted = out; | ||||
|  | ||||
| 	while(true) | ||||
| 	{ | ||||
| 		int undecidedCount = undecided.size(); | ||||
| 		for(int i = 0; i < undecided.size(); i++) | ||||
| 		{ | ||||
| 			Bonus *b = undecided[i]; | ||||
| 			BonusLimitationContext context = {b, *this, out}; | ||||
| 			int decision = b->limiter ? b->limiter->limit(context) : ILimiter::ACCEPT; //bonuses without limiters will be accepted by default | ||||
| 			if(decision == ILimiter::DISCARD) | ||||
| 			{ | ||||
| 				undecided.erase(i); | ||||
| 				i--; continue;  | ||||
| 			} | ||||
| 			else if(decision == ILimiter::ACCEPT) | ||||
| 			{ | ||||
| 				accepted.push_back(b); | ||||
| 				undecided.erase(i); | ||||
| 				i--; continue;  | ||||
| 			} | ||||
| 			else | ||||
| 				assert(decision == ILimiter::NOT_SURE); | ||||
| 		} | ||||
|  | ||||
| 		if(undecided.size() == undecidedCount) //we haven't moved a single bonus -> limiters reached a stable state | ||||
| 			return; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| TBonusListPtr CBonusSystemNode::limitBonuses(const BonusList &allBonuses) const | ||||
| { | ||||
| 	auto ret = make_shared<BonusList>(); | ||||
| 	limitBonuses(allBonuses, *ret); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| void CBonusSystemNode::treeHasChanged() | ||||
| { | ||||
| 	treeChanged++; | ||||
| } | ||||
|  | ||||
| int NBonus::valOf(const CBonusSystemNode *obj, Bonus::BonusType type, int subtype /*= -1*/) | ||||
| { | ||||
| 	if(obj) | ||||
| @@ -944,23 +1033,13 @@ Bonus::~Bonus() | ||||
| { | ||||
| } | ||||
|  | ||||
| Bonus * Bonus::addLimiter(ILimiter *Limiter) | ||||
| { | ||||
| 	return addLimiter(boost::shared_ptr<ILimiter>(Limiter)); | ||||
| } | ||||
|  | ||||
| Bonus * Bonus::addLimiter(boost::shared_ptr<ILimiter> Limiter) | ||||
| Bonus * Bonus::addLimiter(TLimiterPtr Limiter) | ||||
| { | ||||
| 	limiter = Limiter; | ||||
| 	return this; | ||||
| } | ||||
|  | ||||
| Bonus * Bonus::addPropagator(IPropagator *Propagator) | ||||
| { | ||||
| 	return addPropagator(boost::shared_ptr<IPropagator>(Propagator)); | ||||
| } | ||||
|  | ||||
| Bonus * Bonus::addPropagator(boost::shared_ptr<IPropagator> Propagator) | ||||
| Bonus * Bonus::addPropagator(TPropagatorPtr Propagator) | ||||
| { | ||||
| 	propagator = Propagator; | ||||
| 	return this; | ||||
| @@ -1109,14 +1188,14 @@ ILimiter::~ILimiter() | ||||
| { | ||||
| } | ||||
|  | ||||
| bool ILimiter::limit(const Bonus *b, const CBonusSystemNode &node) const /*return true to drop the bonus */ | ||||
| int ILimiter::limit(const BonusLimitationContext &context) const /*return true to drop the bonus */ | ||||
| { | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| bool CCreatureTypeLimiter::limit(const Bonus *b, const CBonusSystemNode &node) const | ||||
| int CCreatureTypeLimiter::limit(const BonusLimitationContext &context) const | ||||
| { | ||||
| 	const CCreature *c = retrieveCreature(&node); | ||||
| 	const CCreature *c = retrieveCreature(&context.node); | ||||
| 	if(!c) | ||||
| 		return true; | ||||
| 	return c != creature   &&   (!includeUpgrades || !creature->isMyUpgrade(c)); | ||||
| @@ -1144,16 +1223,18 @@ HasAnotherBonusLimiter::HasAnotherBonusLimiter( TBonusType bonus, TBonusSubtype | ||||
| { | ||||
| } | ||||
|  | ||||
| bool HasAnotherBonusLimiter::limit( const Bonus *b, const CBonusSystemNode &node ) const | ||||
| int HasAnotherBonusLimiter::limit(const BonusLimitationContext &context) const | ||||
| { | ||||
| 	if(isSubtypeRelevant) | ||||
| 	{ | ||||
| 		return !node.hasBonusOfType(static_cast<Bonus::BonusType>(type), subtype); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		return !node.hasBonusOfType(static_cast<Bonus::BonusType>(type)); | ||||
| 	} | ||||
| 	CSelector mySelector = isSubtypeRelevant  | ||||
| 							? Selector::typeSubtype(type, subtype)  | ||||
| 							: Selector::type(type); | ||||
|  | ||||
| 	//if we have a bonus of required type accepted, limiter should accept also this bonus | ||||
| 	if(context.alreadyAccepted.getFirst(mySelector)) | ||||
| 		return ACCEPT; | ||||
|  | ||||
| 	//do not accept for now but it may change if more bonuses gets included | ||||
| 	return NOT_SURE; | ||||
| } | ||||
|  | ||||
| IPropagator::~IPropagator() | ||||
| @@ -1201,9 +1282,10 @@ CreatureNativeTerrainLimiter::CreatureNativeTerrainLimiter() | ||||
| { | ||||
|  | ||||
| } | ||||
| bool CreatureNativeTerrainLimiter::limit(const Bonus *b, const CBonusSystemNode &node) const | ||||
|  | ||||
| int CreatureNativeTerrainLimiter::limit(const BonusLimitationContext &context) const | ||||
| { | ||||
| 	const CCreature *c = retrieveCreature(&node); | ||||
| 	const CCreature *c = retrieveCreature(&context.node); | ||||
| 	return !c || !vstd::iswithin(c->faction, 0, 9) || VLC->heroh->nativeTerrains[c->faction] != terrainType; //drop bonus for non-creatures or non-native residents | ||||
| 	//TODO neutral creatues | ||||
| } | ||||
| @@ -1216,9 +1298,10 @@ CreatureFactionLimiter::CreatureFactionLimiter(int Faction) | ||||
| CreatureFactionLimiter::CreatureFactionLimiter() | ||||
| { | ||||
| } | ||||
| bool CreatureFactionLimiter::limit(const Bonus *b, const CBonusSystemNode &node) const | ||||
|  | ||||
| int CreatureFactionLimiter::limit(const BonusLimitationContext &context) const | ||||
| { | ||||
| 	const CCreature *c = retrieveCreature(&node); | ||||
| 	const CCreature *c = retrieveCreature(&context.node); | ||||
| 	return !c || c->faction != faction; //drop bonus for non-creatures or non-native residents | ||||
| } | ||||
|  | ||||
| @@ -1231,9 +1314,9 @@ CreatureAlignmentLimiter::CreatureAlignmentLimiter(si8 Alignment) | ||||
| { | ||||
| } | ||||
|  | ||||
| bool CreatureAlignmentLimiter::limit(const Bonus *b, const CBonusSystemNode &node) const | ||||
| int CreatureAlignmentLimiter::limit(const BonusLimitationContext &context) const | ||||
| { | ||||
| 	const CCreature *c = retrieveCreature(&node); | ||||
| 	const CCreature *c = retrieveCreature(&context.node); | ||||
| 	if(!c)  | ||||
| 		return true; | ||||
| 	switch(alignment) | ||||
| @@ -1260,21 +1343,21 @@ RankRangeLimiter::RankRangeLimiter() | ||||
| 	minRank = maxRank = -1; | ||||
| } | ||||
|  | ||||
| bool RankRangeLimiter::limit( const Bonus *b, const CBonusSystemNode &node ) const | ||||
| int RankRangeLimiter::limit(const BonusLimitationContext &context) const | ||||
| { | ||||
| 	const CStackInstance *csi = retreiveStackInstance(&node); | ||||
| 	const CStackInstance *csi = retreiveStackInstance(&context.node); | ||||
| 	if(csi) | ||||
| 		return csi->getExpRank() < minRank || csi->getExpRank() > maxRank; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool StackOwnerLimiter::limit(const Bonus *b, const CBonusSystemNode &node) const  | ||||
| int StackOwnerLimiter::limit(const BonusLimitationContext &context) const  | ||||
| { | ||||
| 	const CStack *s = retreiveStackBattle(&node); | ||||
| 	const CStack *s = retreiveStackBattle(&context.node); | ||||
| 	if(s) | ||||
| 		return s->owner != owner; | ||||
|  | ||||
|  	const CStackInstance *csi = retreiveStackInstance(&node); | ||||
|  	const CStackInstance *csi = retreiveStackInstance(&context.node); | ||||
|  	if(csi && csi->armyObj) | ||||
|  		return csi->armyObj->tempOwner != owner; | ||||
|  	return true; | ||||
|   | ||||
| @@ -22,7 +22,9 @@ class ILimiter; | ||||
| class IPropagator; | ||||
| class BonusList; | ||||
|  | ||||
| typedef boost::shared_ptr<BonusList> TBonusListPtr; | ||||
| typedef shared_ptr<BonusList> TBonusListPtr; | ||||
| typedef shared_ptr<ILimiter> TLimiterPtr; | ||||
| typedef shared_ptr<IPropagator> TPropagatorPtr; | ||||
| typedef std::vector<std::pair<int,std::string> > TModDescr; //modifiers values and their descriptions | ||||
| typedef std::set<CBonusSystemNode*> TNodes; | ||||
| typedef std::set<const CBonusSystemNode*> TCNodes; | ||||
| @@ -247,8 +249,8 @@ struct DLL_LINKAGE Bonus | ||||
| 	si32 additionalInfo; | ||||
| 	ui8 effectRange; //if not NO_LIMIT, bonus will be omitted by default | ||||
|  | ||||
| 	boost::shared_ptr<ILimiter> limiter; | ||||
| 	boost::shared_ptr<IPropagator> propagator; | ||||
| 	TLimiterPtr limiter; | ||||
| 	TPropagatorPtr propagator; | ||||
|  | ||||
| 	std::string description;  | ||||
|  | ||||
| @@ -322,10 +324,8 @@ struct DLL_LINKAGE Bonus | ||||
|  | ||||
| 	std::string Description() const; | ||||
|  | ||||
| 	Bonus *addLimiter(ILimiter *Limiter); //returns this for convenient chain-calls | ||||
| 	Bonus *addPropagator(IPropagator *Propagator); //returns this for convenient chain-calls | ||||
| 	Bonus *addLimiter(boost::shared_ptr<ILimiter> Limiter); //returns this for convenient chain-calls | ||||
| 	Bonus *addPropagator(boost::shared_ptr<IPropagator> Propagator); //returns this for convenient chain-calls | ||||
| 	Bonus *addLimiter(TLimiterPtr Limiter); //returns this for convenient chain-calls | ||||
| 	Bonus *addPropagator(TPropagatorPtr Propagator); //returns this for convenient chain-calls | ||||
| }; | ||||
|  | ||||
| DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus); | ||||
| @@ -363,17 +363,18 @@ public: | ||||
|  | ||||
| 	// BonusList functions | ||||
| 	int totalValue() const; //subtype -> subtype of bonus, if -1 then any | ||||
| 	void getBonuses(TBonusListPtr out, const CSelector &selector, const CSelector &limit, const bool caching = false) const; | ||||
| 	void getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit) const; | ||||
| 	void getAllBonuses(BonusList &out) const; | ||||
| 	void getModifiersWDescr(TModDescr &out) const; | ||||
|  | ||||
| 	void getBonuses(TBonusListPtr out, const CSelector &selector) const; | ||||
| 	void getBonuses(BonusList & out, const CSelector &selector) const; | ||||
|  | ||||
| 	//special find functions | ||||
| 	Bonus *getFirst(const CSelector &select); | ||||
| 	const Bonus *getFirst(const CSelector &select) const; | ||||
| 	int valOfBonuses(const CSelector &select) const; | ||||
|  | ||||
| 	void limit(const CBonusSystemNode &node); //erases bonuses using limitor | ||||
| 	//void limit(const CBonusSystemNode &node); //erases bonuses using limitor | ||||
| 	void eliminateDuplicates(); | ||||
| 	 | ||||
| 	// remove_if implementation for STL vector types | ||||
| @@ -454,13 +455,22 @@ public: | ||||
| 		h & nodeType; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| struct BonusLimitationContext | ||||
| { | ||||
| 	const Bonus *b; | ||||
| 	const CBonusSystemNode &node; | ||||
| 	const BonusList &alreadyAccepted; | ||||
| }; | ||||
| 	 | ||||
| class DLL_LINKAGE ILimiter | ||||
| { | ||||
| public: | ||||
| 	enum EDecision {ACCEPT, DISCARD, NOT_SURE}; | ||||
|  | ||||
| 	virtual ~ILimiter(); | ||||
|  | ||||
| 	virtual bool limit(const Bonus *b, const CBonusSystemNode &node) const; //return true to drop the bonus | ||||
| 	virtual int limit(const BonusLimitationContext &context) const; //0 - accept bonus; 1 - drop bonus; 2 - delay (drops eventually) | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{} | ||||
| @@ -527,13 +537,17 @@ private: | ||||
| 	// [property key]_[value] => only for selector | ||||
| 	mutable std::map<std::string, TBonusListPtr > cachedRequests; | ||||
|  | ||||
| 	void getAllBonusesRec(TBonusListPtr out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL, const bool caching = false) const; | ||||
| 	void getBonusesRec(BonusList &out, const CSelector &selector, const CSelector &limit) const; | ||||
| 	void getAllBonusesRec(BonusList &out) const; | ||||
| 	const TBonusListPtr getAllBonusesWithoutCaching(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const; | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	explicit CBonusSystemNode(); | ||||
| 	virtual ~CBonusSystemNode(); | ||||
| 	 | ||||
| 	void limitBonuses(const BonusList &allBonuses, BonusList &out) const; //out will bo populed with bonuses that are not limited here | ||||
| 	TBonusListPtr limitBonuses(const BonusList &allBonuses) const; //same as above, returns out by val for convienence | ||||
| 	const TBonusListPtr getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL, const std::string &cachingStr = "") const; | ||||
| 	void getParents(TCNodes &out) const;  //retrieves list of parent nodes (nodes to inherit bonuses from), | ||||
| 	const Bonus *getBonus(const CSelector &selector) const; | ||||
| @@ -563,7 +577,7 @@ public: | ||||
|  | ||||
| 	bool isIndependentNode() const; //node is independent when it has no parents nor children | ||||
| 	bool actsAsBonusSourceOnly() const; | ||||
| 	bool isLimitedOnUs(Bonus *b) const; //if bonus should be removed from list acquired from this node | ||||
| 	//bool isLimitedOnUs(Bonus *b) const; //if bonus should be removed from list acquired from this node | ||||
|  | ||||
| 	void popBonuses(const CSelector &s); | ||||
| 	virtual std::string bonusToString(Bonus *bonus, bool description) const {return "";}; //description or bonus name | ||||
| @@ -584,6 +598,8 @@ public: | ||||
| 	const std::string &getDescription() const; | ||||
| 	void setDescription(const std::string &description); | ||||
|  | ||||
| 	static void treeHasChanged(); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & /*bonuses & */nodeType; | ||||
| @@ -708,7 +724,7 @@ public: | ||||
| 	CCreatureTypeLimiter(); | ||||
| 	CCreatureTypeLimiter(const CCreature &Creature, ui8 IncludeUpgrades = true); | ||||
|  | ||||
| 	bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE; | ||||
| 	int limit(const BonusLimitationContext &context) const OVERRIDE; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| @@ -726,7 +742,7 @@ public: | ||||
| 	HasAnotherBonusLimiter(TBonusType bonus = Bonus::NONE); | ||||
| 	HasAnotherBonusLimiter(TBonusType bonus, TBonusSubtype _subtype); | ||||
|  | ||||
| 	bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE; | ||||
| 	int limit(const BonusLimitationContext &context) const OVERRIDE; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| @@ -741,7 +757,7 @@ public: | ||||
| 	CreatureNativeTerrainLimiter(); | ||||
| 	CreatureNativeTerrainLimiter(int TerrainType); | ||||
|  | ||||
| 	bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE; | ||||
| 	int limit(const BonusLimitationContext &context) const OVERRIDE; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| @@ -756,7 +772,7 @@ public: | ||||
| 	CreatureFactionLimiter(); | ||||
| 	CreatureFactionLimiter(int TerrainType); | ||||
|  | ||||
| 	bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE; | ||||
| 	int limit(const BonusLimitationContext &context) const OVERRIDE; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| @@ -771,7 +787,7 @@ public: | ||||
| 	CreatureAlignmentLimiter(); | ||||
| 	CreatureAlignmentLimiter(si8 Alignment); | ||||
|  | ||||
| 	bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE; | ||||
| 	int limit(const BonusLimitationContext &context) const OVERRIDE; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| @@ -786,7 +802,7 @@ public: | ||||
| 	StackOwnerLimiter(); | ||||
| 	StackOwnerLimiter(ui8 Owner); | ||||
|  | ||||
| 	bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE; | ||||
| 	int limit(const BonusLimitationContext &context) const OVERRIDE; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| @@ -801,7 +817,7 @@ public: | ||||
|  | ||||
| 	RankRangeLimiter(); | ||||
| 	RankRangeLimiter(ui8 Min, ui8 Max = 255); | ||||
| 	bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE; | ||||
| 	int limit(const BonusLimitationContext &context) const OVERRIDE; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
|   | ||||
| @@ -655,6 +655,8 @@ DLL_LINKAGE void RebalanceStacks::applyGs( CGameState *gs ) | ||||
| 				dst.army->setStackExp(dst.slot, src.army->getStackExperience(src.slot)); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	CBonusSystemNode::treeHasChanged(); | ||||
| } | ||||
|  | ||||
| DLL_LINKAGE void PutArtifact::applyGs( CGameState *gs ) | ||||
| @@ -941,6 +943,8 @@ void BattleResult::applyGs( CGameState *gs ) | ||||
| 			gs->curB->belligerents[0]->giveStackExp(exp[0]); | ||||
| 		if (exp[1]) | ||||
| 			gs->curB->belligerents[1]->giveStackExp(exp[1]); | ||||
|  | ||||
| 		CBonusSystemNode::treeHasChanged(); | ||||
| 	} | ||||
|  | ||||
| 	gs->curB->belligerents[0]->battle = gs->curB->belligerents[1]->battle = NULL; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user