1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-25 22:42:04 +02:00

- Parsing propagators and limiters

- Experimental support for chaining limiters
- Added missing abilities, propagators and limiters to artifacts
- Sketch of Calculator for bonuses, ignore it for now
This commit is contained in:
DjWarmonger
2013-01-16 13:02:01 +00:00
parent 53b684180d
commit d7c9377843
5 changed files with 1348 additions and 1172 deletions

View File

@@ -1189,10 +1189,18 @@
"id" : 82, "id" : 82,
"type" : ["HERO"] "type" : ["HERO"]
}, },
"recantersCloak": //TODO: implement? "recantersCloak":
{ {
"id" : 83, "id" : 83,
"type" : ["HERO"] "type" : ["HERO"],
"bonuses": [
{
"type" : "BLOCK_MAGIC_ABOVE",
"val" : 2,
"valueType" : "INDEPENDENT_MIN",
"propagator": "BATTLE_WIDE"
}
]
}, },
"spiritOfOppression": "spiritOfOppression":
{ {
@@ -1283,14 +1291,14 @@
{ {
"bonuses" : [ "bonuses" : [
{ {
"limiter" : "SHOOTER_ONLY", "limiters" : ["SHOOTER_ONLY"],
"subtype" : 0, "subtype" : 0,
"type" : "NO_DISTANCE_PENALTY", "type" : "NO_DISTANCE_PENALTY",
"val" : 0, "val" : 0,
"valueType" : "ADDITIVE_VALUE" "valueType" : "ADDITIVE_VALUE"
}, },
{ {
"limiter" : "SHOOTER_ONLY", "limiters" : ["SHOOTER_ONLY"],
"subtype" : 0, "subtype" : 0,
"type" : "NO_WALL_PENALTY", "type" : "NO_WALL_PENALTY",
"val" : 0, "val" : 0,
@@ -1453,7 +1461,7 @@
{ {
"bonuses" : [ "bonuses" : [
{ {
"limiter" : "IS_UNDEAD", "limiters" : ["IS_UNDEAD"],
"subtype" : "spell.destroyUndead", "subtype" : "spell.destroyUndead",
"type" : "SPELL_IMMUNITY", "type" : "SPELL_IMMUNITY",
"val" : 0, "val" : 0,
@@ -1642,30 +1650,70 @@
"id" : 117, "id" : 117,
"type" : ["HERO"] "type" : ["HERO"]
}, },
"legsOfLegion": //TODO: implement "legsOfLegion":
{ {
"id" : 118, "id" : 118,
"type" : ["HERO"] "type" : ["HERO"],
"bonuses" : [
{
"type" : "CREATURE_GROWTH",
"subtype" : 2,
"val" : 5,
"propagator": "VISITED_TOWN_AND_VISITOR"
}
]
}, },
"loinsOfLegion": "loinsOfLegion":
{ {
"id" : 119, "id" : 119,
"type" : ["HERO"] "type" : ["HERO"],
"bonuses" : [
{
"type" : "CREATURE_GROWTH",
"subtype" : 3,
"val" : 4,
"propagator": "VISITED_TOWN_AND_VISITOR"
}
]
}, },
"torsoOfLegion": "torsoOfLegion":
{ {
"id" : 120, "id" : 120,
"type" : ["HERO"] "type" : ["HERO"],
"bonuses" : [
{
"type" : "CREATURE_GROWTH",
"subtype" : 4,
"val" : 3,
"propagator": "VISITED_TOWN_AND_VISITOR"
}
]
}, },
"armsOfLegion": "armsOfLegion":
{ {
"id" : 121, "id" : 121,
"type" : ["HERO"] "type" : ["HERO"],
"bonuses" : [
{
"type" : "CREATURE_GROWTH",
"subtype" : 5,
"val" : 2,
"propagator": "VISITED_TOWN_AND_VISITOR"
}
]
}, },
"headOfLegion": "headOfLegion":
{ {
"id" : 122, "id" : 122,
"type" : ["HERO"] "type" : ["HERO"],
"bonuses" : [
{
"type" : "CREATURE_GROWTH",
"subtype" : 6,
"val" : 1,
"propagator": "VISITED_TOWN_AND_VISITOR"
}
]
}, },
"seaCaptainsHat": "seaCaptainsHat":
{ {
@@ -1709,28 +1757,40 @@
"id" : 124, "id" : 124,
"type" : ["HERO"] "type" : ["HERO"]
}, },
"shacklesOfWar": //TODO: implement "shacklesOfWar":
{ {
"id" : 125, "id" : 125,
"type" : ["HERO"] "type" : ["HERO"],
"bonuses" : [
{
"type" : "BATTLE_NO_FLEEING",
"propagator": "BATTLE_WIDE"
}
]
}, },
"orbOfInhibition": //TODO: implement "orbOfInhibition":
{ {
"id" : 126, "id" : 126,
"type" : ["HERO"] "type" : ["HERO"],
"bonuses" : [
{
"type" : "BLOCK_ALL_MAGIC",
"propagator": "BATTLE_WIDE"
}
]
}, },
"vialOfDragonBlood": //TODO: limiter "vialOfDragonBlood":
{ {
"bonuses" : [ "bonuses" : [
{ {
"limiter" : "DRAGON_NATURE", "limiters" : ["DRAGON_NATURE"],
"subtype" : 0, "subtype" : 0,
"type" : "PRIMARY_SKILL", "type" : "PRIMARY_SKILL",
"val" : 5, "val" : 5,
"valueType" : "BASE_NUMBER" "valueType" : "BASE_NUMBER"
}, },
{ {
"limiter" : "DRAGON_NATURE", "limiters" : ["DRAGON_NATURE"],
"subtype" : 1, "subtype" : 1,
"type" : "PRIMARY_SKILL", "type" : "PRIMARY_SKILL",
"val" : 5, "val" : 5,
@@ -1889,7 +1949,7 @@
"ribCage" "ribCage"
] ]
}, },
"statueOfLegion": //TODO: implement "statueOfLegion":
{ {
"id" : 133, "id" : 133,
"type" : ["HERO"], "type" : ["HERO"],
@@ -1900,19 +1960,50 @@
"torsoOfLegion", "torsoOfLegion",
"armsOfLegion", "armsOfLegion",
"headOfLegion" "headOfLegion"
],
"bonuses" : [
{
"type" : "CREATURE_GROWTH_PERCENT",
"val" : 50,
"propagator": "PLAYER_PROPAGATOR"
}
] ]
}, },
"powerOfTheDragonFather": //TODO: add stat bonus "powerOfTheDragonFather":
{ {
"id" : 134,
"type" : ["HERO"],
"bonuses" : [ "bonuses" : [
{ {
"type" : "LEVEL_SPELL_IMMUNITY", "type" : "LEVEL_SPELL_IMMUNITY",
"val" : 4, "val" : 4,
"valueType" : "INDEPENDENT_MAX" "valueType" : "INDEPENDENT_MAX"
},
{
"subtype" : 0,
"type" : "PRIMARY_SKILL",
"val" : 6,
"valueType" : "BASE_NUMBER"
},
{
"subtype" : 1,
"type" : "PRIMARY_SKILL",
"val" : 6,
"valueType" : "BASE_NUMBER"
},
{
"subtype" : 2,
"type" : "PRIMARY_SKILL",
"val" : 6,
"valueType" : "BASE_NUMBER"
},
{
"subtype" : 3,
"type" : "PRIMARY_SKILL",
"val" : 6,
"valueType" : "BASE_NUMBER"
} }
], ],
"id" : 134,
"type" : ["HERO"],
"components": "components":
[ [
"quietEyeOfTheDragon", "quietEyeOfTheDragon",
@@ -1963,25 +2054,27 @@
"seaCaptainsHat" "seaCaptainsHat"
] ]
}, },
"bowOfTheSharpshooter": //TODO: limiters "bowOfTheSharpshooter":
{ {
"bonuses" : [ "bonuses" : [
{ {
"limiter" : "SHOOTER_ONLY", "limiters" : [
"SHOOTER_ONLY",
],
"subtype" : 0, "subtype" : 0,
"type" : "NO_DISTANCE_PENALTY", "type" : "NO_DISTANCE_PENALTY",
"val" : 0, "val" : 0,
"valueType" : "ADDITIVE_VALUE" "valueType" : "ADDITIVE_VALUE"
}, },
{ {
"limiter" : "SHOOTER_ONLY", "limiters" : ["SHOOTER_ONLY"],
"subtype" : 0, "subtype" : 0,
"type" : "NO_WALL_PENALTY", "type" : "NO_WALL_PENALTY",
"val" : 0, "val" : 0,
"valueType" : "ADDITIVE_VALUE" "valueType" : "ADDITIVE_VALUE"
}, },
{ {
"limiter" : "SHOOTER_ONLY", "limiters" : ["SHOOTER_ONLY"],
"subtype" : 0, "subtype" : 0,
"type" : "FREE_SHOOTING", "type" : "FREE_SHOOTING",
"val" : 0, "val" : 0,

View File

@@ -65,7 +65,8 @@ const bmap<std::string, TLimiterPtr> bonusLimiterMap = boost::assign::map_list_o
const bmap<std::string, TPropagatorPtr> bonusPropagatorMap = boost::assign::map_list_of const bmap<std::string, TPropagatorPtr> bonusPropagatorMap = boost::assign::map_list_of
("BATTLE_WIDE", make_shared<CPropagatorNodeType>(CBonusSystemNode::BATTLE)) ("BATTLE_WIDE", make_shared<CPropagatorNodeType>(CBonusSystemNode::BATTLE))
("VISITED_TOWN_AND_VISITOR", make_shared<CPropagatorNodeType>(CBonusSystemNode::TOWN_AND_VISITOR)); ("VISITED_TOWN_AND_VISITOR", make_shared<CPropagatorNodeType>(CBonusSystemNode::TOWN_AND_VISITOR))
("PLAYER_PROPAGATOR", make_shared<CPropagatorNodeType>(CBonusSystemNode::PLAYER));
#define BONUS_LOG_LINE(x) tlog5 << x << std::endl #define BONUS_LOG_LINE(x) tlog5 << x << std::endl
@@ -95,6 +96,7 @@ BonusList& BonusList::operator=(const BonusList &bonusList)
int BonusList::totalValue() const int BonusList::totalValue() const
{ {
int tempVal = 0;
int base = 0; int base = 0;
int percentToBase = 0; int percentToBase = 0;
int percentToAll = 0; int percentToAll = 0;
@@ -108,6 +110,15 @@ int BonusList::totalValue() const
{ {
Bonus *b = bonuses[i]; Bonus *b = bonuses[i];
if (b->calculator)
{
assert (false);
BonusCalculationContext bcc = {b, CBonusSystemNode()};
tempVal = b->calculator->val (bcc);
}
else
tempVal = b->val;
switch(b->valType) switch(b->valType)
{ {
case Bonus::BASE_NUMBER: case Bonus::BASE_NUMBER:
@@ -1156,12 +1167,6 @@ Bonus::~Bonus()
{ {
} }
Bonus * Bonus::addLimiter(TLimiterPtr Limiter)
{
limiter = Limiter;
return this;
}
Bonus * Bonus::addPropagator(TPropagatorPtr Propagator) Bonus * Bonus::addPropagator(TPropagatorPtr Propagator)
{ {
propagator = Propagator; propagator = Propagator;
@@ -1314,6 +1319,21 @@ DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus)
return out; return out;
} }
Bonus * Bonus::addLimiter(TLimiterPtr Limiter)
{
if (next) //insert at the beginning of list
{
TLimiterPtr temp = next;
next = Limiter;
next->next = temp;
}
else
{
next = Limiter;
}
return this;
}
int LimiterDecorator::limit(const BonusLimitationContext &context) const /*return true to drop the bonus */ int LimiterDecorator::limit(const BonusLimitationContext &context) const /*return true to drop the bonus */
{ {

View File

@@ -18,13 +18,16 @@ struct Bonus;
class CBonusSystemNode; class CBonusSystemNode;
class ILimiter; class ILimiter;
class IPropagator; class IPropagator;
class ICalculator;
class BonusList; class BonusList;
class LimiterDecorator; class LimiterDecorator;
struct BonusLimitationContext; struct BonusLimitationContext;
struct BonusCalculationContext;
typedef shared_ptr<BonusList> TBonusListPtr; typedef shared_ptr<BonusList> TBonusListPtr;
typedef shared_ptr<ILimiter> TLimiterPtr; typedef shared_ptr<ILimiter> TLimiterPtr;
typedef shared_ptr<IPropagator> TPropagatorPtr; typedef shared_ptr<IPropagator> TPropagatorPtr;
typedef shared_ptr<ICalculator> TCalculatorPtr;
typedef std::vector<std::pair<int,std::string> > TModDescr; //modifiers values and their descriptions typedef std::vector<std::pair<int,std::string> > TModDescr; //modifiers values and their descriptions
typedef std::set<CBonusSystemNode*> TNodes; typedef std::set<CBonusSystemNode*> TNodes;
typedef std::set<const CBonusSystemNode*> TCNodes; typedef std::set<const CBonusSystemNode*> TCNodes;
@@ -277,6 +280,7 @@ struct DLL_LINKAGE Bonus : public LimiterDecorator
TLimiterPtr limiter; TLimiterPtr limiter;
TPropagatorPtr propagator; TPropagatorPtr propagator;
TCalculatorPtr calculator;
std::string description; std::string description;
@@ -354,7 +358,7 @@ struct DLL_LINKAGE Bonus : public LimiterDecorator
std::string Description() const; std::string Description() const;
Bonus *addLimiter(TLimiterPtr Limiter); //returns this for convenient chain-calls Bonus * addLimiter(TLimiterPtr Limiter);
Bonus * addPropagator(TPropagatorPtr Propagator); //returns this for convenient chain-calls Bonus * addPropagator(TPropagatorPtr Propagator); //returns this for convenient chain-calls
int limit(const BonusLimitationContext &context) const; //for backward compatibility int limit(const BonusLimitationContext &context) const; //for backward compatibility
}; };
@@ -500,6 +504,13 @@ struct BonusLimitationContext
const BonusList &alreadyAccepted; const BonusList &alreadyAccepted;
}; };
struct BonusCalculationContext
{
const Bonus *b;
const CBonusSystemNode &node;
};
class DLL_LINKAGE ILimiter : public LimiterDecorator class DLL_LINKAGE ILimiter : public LimiterDecorator
{ {
public: public:
@@ -895,6 +906,18 @@ extern DLL_LINKAGE const std::map<std::string, int> bonusNameMap, bonusValueMap,
extern DLL_LINKAGE const bmap<std::string, TLimiterPtr> bonusLimiterMap; extern DLL_LINKAGE const bmap<std::string, TLimiterPtr> bonusLimiterMap;
extern DLL_LINKAGE const bmap<std::string, TPropagatorPtr> bonusPropagatorMap; extern DLL_LINKAGE const bmap<std::string, TPropagatorPtr> bonusPropagatorMap;
class DLL_LINKAGE ICalculator //calculate value of bonus on-the-fly
{
public:
enum EDecision {ACCEPT, DISCARD, NOT_SURE};
virtual si32 val(const BonusCalculationContext &context) const {return 0;};
virtual ~ICalculator(){};
template <typename Handler> void serialize(Handler &h, const int version)
{}
};
// BonusList template that requires full interface of CBonusSystemNode // BonusList template that requires full interface of CBonusSystemNode
template <class InputIterator> template <class InputIterator>
void BonusList::insert(const int position, InputIterator first, InputIterator last) void BonusList::insert(const int position, InputIterator first, InputIterator last)

View File

@@ -903,25 +903,6 @@ Bonus * JsonUtils::parseBonus (const JsonVector &ability_vec) //TODO: merge with
b->turnsRemain = 0; b->turnsRemain = 0;
return b; return b;
} }
template <typename T>
const T & parseByMapStr(const std::map<std::string, T> & map, const std::string & val, std::string err)
{
static T defaultValue;
auto it = map.find(val);
if (it == map.end())
{
tlog1 << "Error: invalid " << err << val << std::endl;
return defaultValue;
}
else
{
return it->second;
}
}
template <typename T> template <typename T>
const T & parseByMap(const std::map<std::string, T> & map, const JsonNode * val, std::string err) const T & parseByMap(const std::map<std::string, T> & map, const JsonNode * val, std::string err)
{ {
@@ -929,11 +910,20 @@ const T & parseByMap(const std::map<std::string, T> & map, const JsonNode * val,
if (!val->isNull()) if (!val->isNull())
{ {
std::string type = val->String(); std::string type = val->String();
return parseByMapStr(map, type, err); auto it = map.find(type);
if (it == map.end())
{
tlog1 << "Error: invalid " << err << type << std::endl;
return defaultValue;
}
else
{
return it->second;
}
} }
else else
return defaultValue; return defaultValue;
} };
void JsonUtils::resolveIdentifier (si32 &var, const JsonNode &node, std::string name) void JsonUtils::resolveIdentifier (si32 &var, const JsonNode &node, std::string name)
{ {
@@ -958,6 +948,24 @@ void JsonUtils::resolveIdentifier (si32 &var, const JsonNode &node, std::string
} }
} }
void JsonUtils::resolveIdentifier (const JsonNode &node, si32 &var)
{
switch (node.getType())
{
case JsonNode::DATA_FLOAT:
var = node.Float();
break;
case JsonNode::DATA_STRING:
VLC->modh->identifiers.requestIdentifier (node.String(), [&](si32 identifier)
{
var = identifier;
});
break;
default:
tlog2 << "Error! Wrong indentifier used for identifier!";
}
}
Bonus * JsonUtils::parseBonus (const JsonNode &ability) Bonus * JsonUtils::parseBonus (const JsonNode &ability)
{ {
@@ -1004,25 +1012,56 @@ Bonus * JsonUtils::parseBonus (const JsonNode &ability)
b->valType = parseByMap(bonusLimitEffect, value, "effect range "); b->valType = parseByMap(bonusLimitEffect, value, "effect range ");
value = &ability["duration"]; value = &ability["duration"];
if (!value->isNull()) if (!value->isNull())
{ b->valType = parseByMap(bonusDurationMap, value, "duration type ");
int dur = 0;
std::vector<std::string> strs;
boost::split(strs, value->String(), boost::is_any_of("\t "));
BOOST_FOREACH(auto s, strs)
{
dur |=parseByMapStr(bonusDurationMap, s, "duration type ");
}
b->duration = dur;
}
value = &ability["source"]; value = &ability["source"];
if (!value->isNull()) if (!value->isNull())
b->valType = parseByMap(bonusSourceMap, value, "source type "); b->valType = parseByMap(bonusSourceMap, value, "source type ");
value = &ability["limiter"]; value = &ability["limiters"];
if (!value->isNull()) if (!value->isNull())
b->limiter = parseByMap(bonusLimiterMap, value, "limiter type "); {
BOOST_FOREACH (const JsonNode & limiter, value->Vector())
{
switch (limiter.getType())
{
case JsonNode::DATA_STRING: //pre-defined limiters
b->limiter = parseByMap(bonusLimiterMap, &limiter, "limiter type ");
break;
case JsonNode::DATA_STRUCT: //customisable limiters
{
shared_ptr<ILimiter> l;
if (limiter["type"].String() == "CREATURE_TYPE_LIMITER")
{
//continue;
//l = make_shared<CCreatureTypeLimiter>(); //TODO: How the hell resolve pointer to creature?
}
if (limiter["type"].String() == "HAS_ANOTHER_BONUS_LIMITER")
{
shared_ptr<HasAnotherBonusLimiter> l2 = make_shared<HasAnotherBonusLimiter>();
const JsonVector vec = limiter["parameters"].Vector();
std::string anotherBonusType = vec[0].String();
auto it = bonusNameMap.find (anotherBonusType);
if (it == bonusNameMap.end())
{
tlog1 << "Error: invalid ability type " << anotherBonusType << std::endl;
continue;
}
l2->type = it->second;
if (vec.size() > 1 )
{
resolveIdentifier (vec[1], l2->subtype);
l2->isSubtypeRelevant = true;
}
l = l2;
}
b->addLimiter(l);
}
break;
}
}
}
value = &ability["propagator"]; value = &ability["propagator"];
if (!value->isNull()) if (!value->isNull())

View File

@@ -118,6 +118,7 @@ namespace JsonUtils
DLL_LINKAGE Bonus * parseBonus (const JsonNode &bonus); DLL_LINKAGE Bonus * parseBonus (const JsonNode &bonus);
DLL_LINKAGE void unparseBonus (JsonNode &node, const Bonus * bonus); DLL_LINKAGE void unparseBonus (JsonNode &node, const Bonus * bonus);
DLL_LINKAGE void resolveIdentifier (si32 &var, const JsonNode &node, std::string name); DLL_LINKAGE void resolveIdentifier (si32 &var, const JsonNode &node, std::string name);
DLL_LINKAGE void resolveIdentifier (const JsonNode &node, si32 &var);
/// recursivly merges source into dest, replacing identical fields /// recursivly merges source into dest, replacing identical fields
/// struct : recursively calls this function /// struct : recursively calls this function