From d0e259864e35ea4f160b1a17296467b19c6cba1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20W=2E=20Urba=C5=84czyk?= Date: Tue, 6 Mar 2012 16:59:55 +0000 Subject: [PATCH] * 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. --- CCallback.cpp | 4 +- CCallback.h | 3 +- Global.h | 704 ++++++++++++++++++++------------------- client/CMusicHandler.h | 4 +- client/Client.cpp | 8 +- client/Client.h | 2 +- lib/BattleState.cpp | 12 +- lib/CCreatureHandler.cpp | 2 +- lib/CObjectHandler.cpp | 16 +- lib/CObjectHandler.h | 2 +- lib/Connection.h | 4 +- lib/HeroBonus.cpp | 265 ++++++++++----- lib/HeroBonus.h | 56 ++-- lib/NetPacksLib.cpp | 4 + 14 files changed, 598 insertions(+), 488 deletions(-) diff --git a/CCallback.cpp b/CCallback.cpp index 977282456..b17c4ce5b 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -232,9 +232,9 @@ void CBattleCallback::sendRequest(const CPack* request) if(waitTillRealize) { - std::unique_ptr unlocker; //optional, if flag set + unique_ptr unlocker; //optional, if flag set if(unlockGsWhenWaiting) - unlocker = vstd::make_unique(vstd::makeUnlockSharedGuard(getGsMutex())); + unlocker = make_unique(vstd::makeUnlockSharedGuard(getGsMutex())); cl->waitingRequest.waitWhileTrue(); } diff --git a/CCallback.h b/CCallback.h index 44f584839..21b3558b8 100644 --- a/CCallback.h +++ b/CCallback.h @@ -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 diff --git a/Global.h b/Global.h index 3d8a08bfe..053a0d633 100644 --- a/Global.h +++ b/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 -#include -#ifdef _WIN32 -#include -#else -#include "tchar_amigaos4.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -//filesystem version 3 causes problems (and it's default as of boost 1.46) -#define BOOST_FILESYSTEM_VERSION 2 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef ANDROID -#include -#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 -class bmap : public std::map -{ -public: - const ValT & operator[](KeyT key) const - { - return find(key)->second; - } - ValT & operator[](KeyT key) - { - return static_cast &>(*this)[key]; - } - template void serialize(Handler &h, const int version) - { - h & static_cast &>(*this); - } -}; - -namespace vstd -{ - //returns true if container c contains item i - template - 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 - bool contains(const std::map & c, const Item2 &i) - { - return c.find(i)!=c.end(); - } - - //returns true if bmap c contains item i - template - bool contains(const bmap & c, const Item2 &i) - { - return c.find(i)!=c.end(); - } - - //returns true if unordered set c contains item i - template - bool contains(const boost::unordered_set & 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 - int find_pos(const std::vector & 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 - int find_pos(const std::vector & 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::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::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::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 - 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 - t1 &amin(t1 &a, const t2 &b) - { - if(a <= b) - return a; - else - { - a = b; - return a; - } - } - - //makes a to fit the range - template - 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 - 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 - bool iswithin(const t1 &a, const t2 &b, const t3 &c) - { - return a >= b && a <= c; - } - - template - 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 - assigner assigno(t1 &a1, const t2 &a2) - { - return assigner(a1,a2); - } - - //deleted pointer and sets it to NULL - template - 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 +#include +#ifdef _WIN32 +#include +#else +#include "tchar_amigaos4.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +//filesystem version 3 causes problems (and it's default as of boost 1.46) +#define BOOST_FILESYSTEM_VERSION 2 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ANDROID +#include +#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 +class bmap : public std::map +{ +public: + const ValT & operator[](KeyT key) const + { + return find(key)->second; + } + ValT & operator[](KeyT key) + { + return static_cast &>(*this)[key]; + } + template void serialize(Handler &h, const int version) + { + h & static_cast &>(*this); + } +}; + +namespace vstd +{ + //returns true if container c contains item i + template + 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 + bool contains(const std::map & c, const Item2 &i) + { + return c.find(i)!=c.end(); + } + + //returns true if bmap c contains item i + template + bool contains(const bmap & c, const Item2 &i) + { + return c.find(i)!=c.end(); + } + + //returns true if unordered set c contains item i + template + bool contains(const boost::unordered_set & 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 + int find_pos(const std::vector & 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 + int find_pos(const std::vector & 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::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::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::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 + 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 + t1 &amin(t1 &a, const t2 &b) + { + if(a <= b) + return a; + else + { + a = b; + return a; + } + } + + //makes a to fit the range + template + 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 + 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 + bool iswithin(const t1 &a, const t2 &b, const t3 &c) + { + return a >= b && a <= c; + } + + template + 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 + assigner assigno(t1 &a1, const t2 &a2) + { + return assigner(a1,a2); + } + + //deleted pointer and sets it to NULL + template + void clear_pointer(T* &ptr) + { + delete ptr; + ptr = NULL; + } + template std::unique_ptr make_unique() { return std::unique_ptr(new T()); - } + } template std::unique_ptr make_unique(Arg1&& arg1) { return std::unique_ptr(new T(std::forward(arg1))); - } -} -using vstd::operator-=; - -// can be used for counting arrays -template 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 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" diff --git a/client/CMusicHandler.h b/client/CMusicHandler.h index f613edb30..b32844562 100644 --- a/client/CMusicHandler.h +++ b/client/CMusicHandler.h @@ -145,8 +145,8 @@ private: SettingsListener listener; void onVolumeChange(const JsonNode &volumeNode); - std::unique_ptr current; - std::unique_ptr next; + unique_ptr current; + unique_ptr next; void queueNext(MusicEntry *queued); public: diff --git a/client/Client.cpp b/client/Client.cpp index e15455e48..026c628e5 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -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(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(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(new CCallback(gs,pid,this)); + callbacks[pid] = make_shared(gs,pid,this); battleints[pid] = playerint[pid] = nInt; nInt->init(callbacks[pid].get()); nInt->serialize(h, version); diff --git a/client/Client.h b/client/Client.h index 279e6a3b9..b50603b94 100644 --- a/client/Client.h +++ b/client/Client.h @@ -61,7 +61,7 @@ class CClient : public IGameCallback { public: CCallback *cb; - std::map > callbacks; //callbacks given to player interfaces + std::map > callbacks; //callbacks given to player interfaces std::vector privilagedGameEventReceivers; //scripting modules, spectator interfaces std::vector privilagedBattleEventReceivers; //scripting modules, spectator interfaces std::map playerint; diff --git a/lib/BattleState.cpp b/lib/BattleState.cpp index 32ac57b8f..192c5b7a1 100644 --- a/lib/BattleState.cpp +++ b/lib/BattleState.cpp @@ -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(EAlignment::GOOD))); + curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)->addLimiter(make_shared(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(-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(EAlignment::GOOD))); + curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, +1, Bonus::TERRAIN_OVERLAY)->addLimiter(make_shared(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 nativeTerrain(new CreatureNativeTerrainLimiter(terrain)); + auto nativeTerrain = make_shared(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)); diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp index 41798148e..2f8676e53 100644 --- a/lib/CCreatureHandler.cpp +++ b/lib/CCreatureHandler.cpp @@ -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(CBonusSystemNode::HERO)); } if(boost::algorithm::find_first(ncre.abilityRefs, "const_lowers_morale")) { diff --git a/lib/CObjectHandler.cpp b/lib/CObjectHandler.cpp index a1a85eff8..0c15ed248 100644 --- a/lib/CObjectHandler.cpp +++ b/lib/CObjectHandler.cpp @@ -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(PLAYER)); //lighthouses + addBonusIfBuilt(26, Bonus::MORALE, +2, make_shared(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(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(PLAYER), CGHeroInstance::NECROMANCY); //necromancy amplifier + addBonusIfBuilt(26, Bonus::SECONDARY_SKILL_PREMY, +20, make_shared(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)) { diff --git a/lib/CObjectHandler.h b/lib/CObjectHandler.h index 5e13519b8..8f57c4bbe 100644 --- a/lib/CObjectHandler.h +++ b/lib/CObjectHandler.h @@ -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); diff --git a/lib/Connection.h b/lib/Connection.h index 68b6ccb9c..a0bb26730 100644 --- a/lib/Connection.h +++ b/lib/Connection.h @@ -495,7 +495,7 @@ public: const_cast(data).serialize(*this,version); } template - void saveSerializable(const boost::shared_ptr &data) + void saveSerializable(const shared_ptr &data) { T *internalPtr = data.get(); *this << internalPtr; @@ -762,7 +762,7 @@ public: template - void loadSerializable(boost::shared_ptr &data) + void loadSerializable(shared_ptr &data) { T *internalPtr; *this >> internalPtr; diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index 07e1275e6..d92ee1e49 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -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::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(); + 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(); + + // 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(); + 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(Limiter)); -} - -Bonus * Bonus::addLimiter(boost::shared_ptr Limiter) +Bonus * Bonus::addLimiter(TLimiterPtr Limiter) { limiter = Limiter; return this; } -Bonus * Bonus::addPropagator(IPropagator *Propagator) -{ - return addPropagator(boost::shared_ptr(Propagator)); -} - -Bonus * Bonus::addPropagator(boost::shared_ptr 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(type), subtype); - } - else - { - return !node.hasBonusOfType(static_cast(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; diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index dad8c8204..eb5252a94 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -22,7 +22,9 @@ class ILimiter; class IPropagator; class BonusList; -typedef boost::shared_ptr TBonusListPtr; +typedef shared_ptr TBonusListPtr; +typedef shared_ptr TLimiterPtr; +typedef shared_ptr TPropagatorPtr; typedef std::vector > TModDescr; //modifiers values and their descriptions typedef std::set TNodes; typedef std::set 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 limiter; - boost::shared_ptr 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 Limiter); //returns this for convenient chain-calls - Bonus *addPropagator(boost::shared_ptr 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 void serialize(Handler &h, const int version) {} @@ -527,13 +537,17 @@ private: // [property key]_[value] => only for selector mutable std::map 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 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 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 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 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 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 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 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 void serialize(Handler &h, const int version) { diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index b45d91280..2940baae1 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -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;