1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-17 01:32:21 +02:00

Fixed #484. Preliminary support for bonus limiters/

This commit is contained in:
Michał W. Urbańczyk
2010-07-12 10:20:25 +00:00
parent bb7615309f
commit fa4ee94cf9
10 changed files with 225 additions and 47 deletions

View File

@ -48,6 +48,7 @@
#ifdef _WIN32
#include "SDL_syswm.h"
#endif
#include <boost/foreach.hpp>
#if __MINGW32__
#undef main
@ -427,6 +428,19 @@ void processCommand(const std::string &message)
if(const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(adventureInt->selection))
tlog0 << h->movement << "; max: " << h->maxMovePoints(true) << "/" << h->maxMovePoints(false) << std::endl;
}
else if(cn == "bonuses")
{
tlog0 << "Bonuses of " << adventureInt->selection->getHoverText() << std::endl
<< adventureInt->selection->bonuses << std::endl;
tlog0 << "\nInherited bonuses:\n";
TCNodes parents;
adventureInt->selection->getParents(parents);
BOOST_FOREACH(const CBonusSystemNode *parent, parents)
{
tlog0 << "\nBonuses from " << typeid(*parent).name() << std::endl << parent->bonuses << std::endl;
}
}
else if(client && client->serv && client->serv->connected) //send to server
{
PlayerMessage pm(LOCPLINT->playerID,message);

View File

@ -128,6 +128,12 @@ void CCreature::addBonus(int val, int type, int subtype /*= -1*/)
bonuses.push_back(added);
}
bool CCreature::isMyUpgrade(const CCreature *anotherCre) const
{
//TODO upgrade of upgrade?
return vstd::contains(upgrades, anotherCre->idNumber);
}
int readNumber(int & befi, int & i, int andame, std::string & buf) //helper function for void CCreatureHandler::loadCreatures() and loadUnitAnimInfo()
{
befi=i;
@ -338,11 +344,6 @@ void CCreatureHandler::loadCreatures()
}
}
// Map types names
#define BONUS_NAME(x) ( #x, Bonus::x )
static const std::map<std::string, int> type_list = map_list_of BONUS_LIST;
#undef BONUS_NAME
////second part of reading cr_abils.txt////
bool contReading = true;
while(contReading) //main reading loop
@ -363,10 +364,10 @@ void CCreatureHandler::loadCreatures()
reader >> creatureID;
reader >> type;
std::map<std::string, int>::const_iterator it = type_list.find(type);
std::map<std::string, int>::const_iterator it = bonusNameMap.find(type);
CCreature *cre = creatures[creatureID];
if (it == type_list.end())
if (it == bonusNameMap.end())
{
if(type == "DOUBLE_WIDE")
cre->doubleWide = true;
@ -403,8 +404,8 @@ void CCreatureHandler::loadCreatures()
std::string type;
reader >> creatureID;
reader >> type;
std::map<std::string, int>::const_iterator it = type_list.find(type);
if (it == type_list.end())
std::map<std::string, int>::const_iterator it = bonusNameMap.find(type);
if (it == bonusNameMap.end())
{
if(type == "DOUBLE_WIDE")
creatures[creatureID]->doubleWide = false;

View File

@ -55,9 +55,11 @@ public:
bool isEvil () const;
si32 maxAmount(const std::vector<si32> &res) const; //how many creatures can be bought
static int getQuantityID(const int & quantity); //0 - a few, 1 - several, 2 - pack, 3 - lots, 4 - horde, 5 - throng, 6 - swarm, 7 - zounds, 8 - legion
bool isMyUpgrade(const CCreature *anotherCre) const;
void addBonus(int val, int type, int subtype = -1);
template<typename RanGen>
int getRandomAmount(RanGen &ranGen)
{

View File

@ -973,50 +973,60 @@ void CGHeroInstance::initObj()
{
case 1:// creature speciality
{
speciality.growthsWithLevel = true;
bonus.type = Bonus::SPECIAL_CREATURE_LEV; // general info to indicate type of growing bonus
bonus.additionalInfo = it->additionalinfo; //base creature ID
speciality.bonuses.push_back (bonus);
std::vector<CCreature*>* creatures = &VLC->creh->creatures;
int creLevel = (*creatures)[it->additionalinfo]->level;
const CCreature &specCreature = *VLC->creh->creatures[it->additionalinfo]; //creature in which we have specialty
int creLevel = specCreature.level;
if(!creLevel) //TODO: set fixed level for War Machines
{
if(it->additionalinfo == 146)
creLevel = 5; //treat ballista as 5-level
else
{
tlog2 << "Warning: unknown level of " << (*creatures)[it->additionalinfo]->namePl << std::endl;
tlog2 << "Warning: unknown level of " << specCreature.namePl << std::endl;
continue;
}
}
speciality.growthsWithLevel = true;
bonus.type = Bonus::PRIMARY_SKILL; //TODO: limit to specific creature type
bonus.valType = Bonus::ADDITIVE_VALUE;
bonus.subtype = 1; //attack
bonus.val = level * (*creatures)[it->additionalinfo]->attack / creLevel /20;
speciality.bonuses.push_back (bonus);
bonus.subtype = 2; //defense
bonus.val = level * (*creatures)[it->additionalinfo]->defence / creLevel /20;
speciality.bonuses.push_back (bonus);
bonus.type = Bonus::STACKS_SPEED;
bonus.val = 1; //+1 speed
speciality.bonuses.push_back (bonus);
for (std::set<ui32>::iterator i = (*creatures)[it->additionalinfo]->upgrades.begin();
i != VLC->creh->creatures[it->additionalinfo]->upgrades.end(); i++)
{
bonus.val = (*i); // for all direct upgrades of that creature
int levelFactor = level / creLevel; //round down
double primSkillModifier = levelFactor / 20.0;
bonus.limiter = new CCreatureTypeLimiter(specCreature);
bonus.type = Bonus::PRIMARY_SKILL;
bonus.subtype = 1; //attack
bonus.val = level * (*creatures)[*i]->attack / (*creatures)[*i]->level /20;
bonus.valType = Bonus::ADDITIVE_VALUE;
bonus.subtype = PrimarySkill::ATTACK;
bonus.val = std::ceil(primSkillModifier * specCreature.attack);
speciality.bonuses.push_back (bonus);
bonus.subtype = 2; //defense
bonus.val = level * (*creatures)[*i]->defence / (*creatures)[*i]->level /20;
bonus.subtype = PrimarySkill::DEFENSE;
bonus.val = std::ceil(primSkillModifier * specCreature.defence);
speciality.bonuses.push_back (bonus);
bonus.type = Bonus::STACKS_SPEED;
bonus.val = 1; //+1 speed
speciality.bonuses.push_back (bonus);
}
// for (std::set<ui32>::iterator i = (*creatures)[it->additionalinfo]->upgrades.begin();
// i != VLC->creh->creatures[it->additionalinfo]->upgrades.end(); i++)
// {
// bonus.val = (*i); // for all direct upgrades of that creature
// bonus.type = Bonus::PRIMARY_SKILL;
// bonus.subtype = 1; //attack
// bonus.val = level * (*creatures)[*i]->attack / (*creatures)[*i]->level /20;
// speciality.bonuses.push_back (bonus);
// bonus.subtype = 2; //defense
// bonus.val = level * (*creatures)[*i]->defence / (*creatures)[*i]->level /20;
// speciality.bonuses.push_back (bonus);
// bonus.type = Bonus::STACKS_SPEED;
// bonus.val = 1; //+1 speed
// speciality.bonuses.push_back (bonus);
// }
}
break;
case 2://secondary skill

View File

@ -252,6 +252,7 @@ void CStackInstance::init()
type = NULL;
idRand = -1;
armyObj = NULL;
nodeType = STACK;
}
int CStackInstance::getQuantityID() const

View File

@ -117,11 +117,11 @@ class CObjectCaller : public IObjectCaller
public:
void preInit()
{
T::preInit();
//T::preInit();
}
void postInit()
{
T::postInit();
//T::postInit();
}
};
@ -148,14 +148,14 @@ public:
void preInit()
{
for (size_t i = 0; i < apps.size(); i++)
apps[i]->preInit();
// for (size_t i = 0; i < apps.size(); i++)
// apps[i]->preInit();
}
void postInit()
{
for (size_t i = 0; i < apps.size(); i++)
apps[i]->postInit();
// for (size_t i = 0; i < apps.size(); i++)
// apps[i]->postInit();
}
} *objCaller = NULL;
@ -2365,7 +2365,7 @@ int3 CGameState::guardingCreaturePosition (int3 pos) const
if (map->isInTheMap(pos))
{
TerrainTile &tile = map->terrain[pos.x][pos.y][pos.z];
if (tile.visitable)
if (tile.visitable && (tile.tertype == TerrainTile::water) == (posTile.tertype == TerrainTile::water))
{
BOOST_FOREACH (CGObjectInstance* obj, tile.visitableObjects)
{

View File

@ -5,10 +5,16 @@
#include "../hch/CSpellHandler.h"
#include <sstream>
#include "../hch/CCreatureHandler.h"
#include <boost/assign/list_of.hpp>
#include "CCreatureSet.h"
#define FOREACH_CONST_PARENT(pname, source) TCNodes parents; getParents(parents, source); BOOST_FOREACH(const CBonusSystemNode *pname, parents)
#define FOREACH_PARENT(pname, source) TNodes parents; getParents(parents, source); BOOST_FOREACH(CBonusSystemNode *pname, parents)
#define BONUS_NAME(x) ( #x, Bonus::x )
DLL_EXPORT const std::map<std::string, int> bonusNameMap = boost::assign::map_list_of BONUS_LIST;
#undef BONUS_NAME
int DLL_EXPORT BonusList::totalValue() const
{
int base = 0;
@ -75,6 +81,19 @@ void DLL_EXPORT BonusList::getBonuses(BonusList &out, const CSelector &selector,
out.push_back(*i);
}
void BonusList::limit(const CBonusSystemNode &node)
{
for(const_iterator i = begin(); i != end(); i++)
{
if(i->limiter && i->limiter->limit(*i, node))
{
const_iterator toErase = i;
i--;
erase(toErase);
}
}
}
int CBonusSystemNode::valOfBonuses(Bonus::BonusType type, int subtype /*= -1*/) const
{
CSelector s = Selector::type(type);
@ -161,6 +180,9 @@ void CBonusSystemNode::getBonuses(BonusList &out, const CSelector &selector, con
bonuses.getBonuses(out, selector);
FOREACH_CONST_PARENT(p, root ? root : this)
p->getBonuses(out, selector, root ? root : this);
if(!root)
out.limit(*this);
}
BonusList CBonusSystemNode::getBonuses(const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const
@ -175,6 +197,9 @@ void CBonusSystemNode::getBonuses(BonusList &out, const CSelector &selector, con
bonuses.getBonuses(out, selector, limit);
FOREACH_CONST_PARENT(p, root ? root : this)
p->getBonuses(out, selector, limit, root ? root : this);
if(!root)
out.limit(*this);
}
BonusList CBonusSystemNode::getBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const
@ -245,6 +270,16 @@ ui16 CBonusSystemNode::MaxHealth() const
return valOfBonuses(Bonus::STACK_HEALTH);
}
CBonusSystemNode::CBonusSystemNode()
{
nodeType = UNKNOWN;
}
CBonusSystemNode::~CBonusSystemNode()
{
}
int NBonus::valOf(const CBonusSystemNode *obj, Bonus::BonusType type, int subtype /*= -1*/)
{
if(obj)
@ -347,3 +382,64 @@ namespace Selector
return sel(dummy);
}
}
DLL_EXPORT std::ostream & operator<<(std::ostream &out, const BonusList &bonusList)
{
int i = 0;
BOOST_FOREACH(const Bonus &b, bonusList)
{
out << "Bonus " << i++ << "\n" << b << std::endl;
}
return out;
}
DLL_EXPORT std::ostream & operator<<(std::ostream &out, const Bonus &bonus)
{
for(std::map<std::string, int>::const_iterator i = bonusNameMap.begin(); i != bonusNameMap.end(); i++)
if(i->second == bonus.type)
out << "\tType: " << i->first << " \t";
#define printField(field) out << "\t" #field ": " << (int)bonus.field << "\n"
printField(val);
printField(subtype);
printField(duration);
printField(source);
printField(id);
printField(additionalInfo);
printField(turnsRemain);
printField(valType);
printField(effectRange);
#undef printField
return out;
}
ILimiter::~ILimiter()
{
}
bool ILimiter::limit(const Bonus &b, const CBonusSystemNode &node) const /*return true to drop the bonus */
{
return false;
}
bool CCreatureTypeLimiter::limit(const Bonus &b, const CBonusSystemNode &node) const
{
if(node.nodeType != CBonusSystemNode::STACK)
return true;
const CCreature *c = (static_cast<const CStackInstance *>(&node))->type;
return c != creature && (!includeUpgrades || !creature->isMyUpgrade(c)); //drop bonus if it's not our creature and (we dont check upgrades or its not our upgrade)
}
CCreatureTypeLimiter::CCreatureTypeLimiter(const CCreature &Creature, ui8 IncludeUpgrades /*= true*/)
:creature(&Creature), includeUpgrades(IncludeUpgrades)
{
}
CCreatureTypeLimiter::CCreatureTypeLimiter()
{
creature = NULL;
includeUpgrades = false;
}

View File

@ -19,17 +19,17 @@
typedef ui8 TBonusType;
typedef si32 TBonusSubtype;
class CCreature;
class CSpell;
struct Bonus;
class CBonusSystemNode;
class ILimiter;
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;
typedef boost::function<bool(const Bonus&)> CSelector;
namespace PrimarySkill
{
enum { ATTACK, DEFENSE, SPELL_POWER, KNOWLEDGE};
@ -223,6 +223,8 @@ struct DLL_EXPORT Bonus
si32 additionalInfo;
ui8 effectRange; //if not NO_LIMIT, bonus will be ommitted by default
ILimiter *limiter;
std::string description;
Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype=-1)
@ -232,6 +234,7 @@ struct DLL_EXPORT Bonus
turnsRemain = 0;
valType = ADDITIVE_VALUE;
effectRange = NO_LIMIT;
limiter = NULL;
}
Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, si32 Subtype=-1, ui8 ValType = ADDITIVE_VALUE)
:duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), id(ID), valType(ValType)
@ -239,6 +242,7 @@ struct DLL_EXPORT Bonus
additionalInfo = -1;
turnsRemain = 0;
effectRange = NO_LIMIT;
limiter = NULL;
}
Bonus()
{
@ -247,6 +251,7 @@ struct DLL_EXPORT Bonus
turnsRemain = 0;
valType = ADDITIVE_VALUE;
effectRange = NO_LIMIT;
limiter = NULL;
}
// //comparison
@ -263,7 +268,7 @@ struct DLL_EXPORT Bonus
template <typename Handler> void serialize(Handler &h, const int version)
{
h & duration & type & subtype & source & val & id & description & additionalInfo & turnsRemain & valType & effectRange;
h & duration & type & subtype & source & val & id & description & additionalInfo & turnsRemain & valType & effectRange & limiter;
}
static bool OneDay(const Bonus &hb)
@ -307,6 +312,8 @@ struct DLL_EXPORT Bonus
std::string Description() const;
};
DLL_EXPORT std::ostream & operator<<(std::ostream &out, const Bonus &bonus);
class BonusList : public std::list<Bonus>
{
public:
@ -319,16 +326,35 @@ public:
DLL_EXPORT Bonus * getFirst(const CSelector &select);
DLL_EXPORT const Bonus * getFirst(const CSelector &select) const;
void limit(const CBonusSystemNode &node); //erases bonuses using limitor
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<std::list<Bonus>&>(*this);
}
};
DLL_EXPORT std::ostream & operator<<(std::ostream &out, const BonusList &bonusList);
class DLL_EXPORT ILimiter
{
public:
virtual ~ILimiter();
virtual bool limit(const Bonus &b, const CBonusSystemNode &node) const; //return true to drop the bonus
template <typename Handler> void serialize(Handler &h, const int version)
{}
};
class DLL_EXPORT CBonusSystemNode
{
public:
BonusList bonuses;
ui8 nodeType;
CBonusSystemNode();
virtual ~CBonusSystemNode();
//new bonusing node interface
// * selector is predicate that tests if HeroBonus matches our criteria
@ -366,8 +392,13 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & bonuses;
h & bonuses & nodeType;
}
enum ENodeTypes
{
UNKNOWN, STACK
};
};
namespace NBonus
@ -450,6 +481,23 @@ public:
}
};
class CCreatureTypeLimiter : public ILimiter //affect only stacks of given creature (and optionally it's upgrades)
{
public:
const CCreature *creature;
ui8 includeUpgrades;
CCreatureTypeLimiter();
CCreatureTypeLimiter(const CCreature &Creature, ui8 IncludeUpgrades = true);
bool limit(const Bonus &b, const CBonusSystemNode &node) const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & creature & includeUpgrades;
}
};
namespace Selector
{
extern DLL_EXPORT CSelectFieldEqual<TBonusType> type;
@ -466,3 +514,5 @@ namespace Selector
bool DLL_EXPORT matchesType(const CSelector &sel, TBonusType type);
bool DLL_EXPORT matchesTypeSubtype(const CSelector &sel, TBonusType type, TBonusSubtype subtype);
}
extern DLL_EXPORT const std::map<std::string, int> bonusNameMap;

View File

@ -20,6 +20,7 @@
template<typename Serializer> DLL_EXPORT
void registerTypes1(Serializer &s)
{
//map objects
s.template registerType<CGHeroPlaceholder>();
s.template registerType<CGHeroInstance>();
s.template registerType<CGTownInstance>();
@ -64,6 +65,9 @@ void registerTypes1(Serializer &s)
s.template registerType<CGLighthouse>();
s.template registerType<CGMarket>();
s.template registerType<CGBlackMarket>();
//end of objects
s.template registerType<ILimiter>();
s.template registerType<CCreatureTypeLimiter>();
}
template<typename Serializer> DLL_EXPORT