1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +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:
Michał W. Urbańczyk 2012-03-06 16:59:55 +00:00
parent 0ef1085555
commit d0e259864e
14 changed files with 598 additions and 488 deletions

View File

@ -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();
}

View File

@ -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
View File

@ -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"

View File

@ -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:

View File

@ -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);

View File

@ -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;

View File

@ -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));

View File

@ -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"))
{

View File

@ -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))
{

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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)
{

View File

@ -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;