mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-28 08:48:48 +02:00
Extend Bonus.addInfo to integer vector (#427)
* changed Bonus::additionalInfo to integer vector * fixed deserialization for old savegames * removed newline from JsonNode::toJson() * updated bonus schema; SPELL_AFTER_ATTACK and SPELL_BEFORE_ATTACK use new addInfo format * removed unnecessary init in Bonus constructor
This commit is contained in:
parent
83c6ffbda0
commit
7f76648a7c
@ -183,7 +183,7 @@
|
||||
"type" : "SPELL_AFTER_ATTACK",
|
||||
"subtype" : "spell.stoneGaze",
|
||||
"val" : 20,
|
||||
"addInfo" : 2000 // FIXME: replace with range field?
|
||||
"addInfo" : [0,2]
|
||||
}
|
||||
},
|
||||
"upgrades": ["medusaQueen"],
|
||||
@ -217,7 +217,7 @@
|
||||
"type" : "SPELL_AFTER_ATTACK",
|
||||
"subtype" : "spell.stoneGaze",
|
||||
"val" : 20,
|
||||
"addInfo" : 2000 // FIXME: replace with range?
|
||||
"addInfo" : [0,2]
|
||||
}
|
||||
},
|
||||
"graphics" :
|
||||
|
@ -10,7 +10,16 @@
|
||||
"addInfo": {
|
||||
"anyOf" : [
|
||||
{ "type" : "string" },
|
||||
{ "type" : "number" }
|
||||
{ "type" : "number" },
|
||||
{
|
||||
"type" : "array",
|
||||
"items" : {
|
||||
"anyof" : [
|
||||
{ "type" : "string" },
|
||||
{ "type" : "number" }
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "addInfo"
|
||||
},
|
||||
|
@ -1890,7 +1890,7 @@ UpgradeInfo CGameState::getUpgradeInfo(const CStackInstance &stack)
|
||||
TBonusListPtr lista = h->getBonuses(Selector::typeSubtype(Bonus::SPECIAL_UPGRADE, base->idNumber));
|
||||
for(const std::shared_ptr<Bonus> it : *lista)
|
||||
{
|
||||
auto nid = CreatureID(it->additionalInfo);
|
||||
auto nid = CreatureID(it->additionalInfo[0]);
|
||||
if (nid != base->idNumber) //in very specific case the upgrade is available by default (?)
|
||||
{
|
||||
ret.newID.push_back(nid);
|
||||
|
@ -150,6 +150,59 @@ const BonusList * CBonusProxy::operator->() const
|
||||
return get().get();
|
||||
}
|
||||
|
||||
CAddInfo::CAddInfo()
|
||||
{
|
||||
}
|
||||
|
||||
CAddInfo::CAddInfo(si32 value)
|
||||
{
|
||||
if(value != CAddInfo::NONE)
|
||||
push_back(value);
|
||||
}
|
||||
|
||||
bool CAddInfo::operator==(si32 value) const
|
||||
{
|
||||
switch(size())
|
||||
{
|
||||
case 0:
|
||||
return value == CAddInfo::NONE;
|
||||
case 1:
|
||||
return operator[](0) == value;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CAddInfo::operator!=(si32 value) const
|
||||
{
|
||||
return !operator==(value);
|
||||
}
|
||||
|
||||
si32 CAddInfo::operator[](size_type pos) const
|
||||
{
|
||||
return pos < size() ? vector::operator[](pos) : CAddInfo::NONE;
|
||||
}
|
||||
|
||||
std::string CAddInfo::toString() const
|
||||
{
|
||||
return toJsonNode().toJson(true);
|
||||
}
|
||||
|
||||
JsonNode CAddInfo::toJsonNode() const
|
||||
{
|
||||
if(size() < 2)
|
||||
{
|
||||
return JsonUtils::intNode(operator[](0));
|
||||
}
|
||||
else
|
||||
{
|
||||
JsonNode node(JsonNode::JsonType::DATA_VECTOR);
|
||||
for(si32 value : *this)
|
||||
node.Vector().push_back(JsonUtils::intNode(value));
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
std::atomic<int32_t> CBonusSystemNode::treeChanged(1);
|
||||
const bool CBonusSystemNode::cachingEnabled = true;
|
||||
|
||||
@ -1189,14 +1242,24 @@ JsonNode subtypeToJson(Bonus::BonusType type, int subtype)
|
||||
}
|
||||
}
|
||||
|
||||
JsonNode additionalInfoToJson(Bonus::BonusType type, int addInfo)
|
||||
JsonNode additionalInfoToJson(Bonus::BonusType type, CAddInfo addInfo)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case Bonus::SPECIAL_UPGRADE:
|
||||
return JsonUtils::stringNode("creature." + CreatureID::encode(addInfo));
|
||||
return JsonUtils::stringNode("creature." + CreatureID::encode(addInfo[0]));
|
||||
default:
|
||||
return JsonUtils::intNode(addInfo);
|
||||
if(addInfo.size() <= 1)
|
||||
{
|
||||
return JsonUtils::intNode(addInfo[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
JsonNode vecNode(JsonNode::JsonType::DATA_VECTOR);
|
||||
for(si32 value : addInfo)
|
||||
vecNode.Vector().push_back(JsonUtils::intNode(value));
|
||||
return vecNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1207,7 +1270,7 @@ JsonNode Bonus::toJsonNode() const
|
||||
root["type"].String() = vstd::findKey(bonusNameMap, type);
|
||||
if(subtype != -1)
|
||||
root["subtype"] = subtypeToJson(type, subtype);
|
||||
if(additionalInfo != -1)
|
||||
if(additionalInfo != CAddInfo::NONE)
|
||||
root["addInfo"] = additionalInfoToJson(type, additionalInfo);
|
||||
if(val != 0)
|
||||
root["val"].Integer() = val;
|
||||
@ -1235,7 +1298,7 @@ std::string Bonus::nameForBonus() const
|
||||
case Bonus::SPECIAL_PECULIAR_ENCHANT:
|
||||
return (*VLC->spellh)[SpellID::ESpellID(subtype)]->identifier;
|
||||
case Bonus::SPECIAL_UPGRADE:
|
||||
return CreatureID::encode(subtype) + "2" + CreatureID::encode(additionalInfo);
|
||||
return CreatureID::encode(subtype) + "2" + CreatureID::encode(additionalInfo[0]);
|
||||
case Bonus::GENERATE_RESOURCE:
|
||||
return GameConstants::RESOURCE_NAMES[subtype];
|
||||
case Bonus::STACKS_SPEED:
|
||||
@ -1248,7 +1311,6 @@ std::string Bonus::nameForBonus() const
|
||||
Bonus::Bonus(ui16 Dur, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype)
|
||||
: duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), sid(ID), description(Desc)
|
||||
{
|
||||
additionalInfo = -1;
|
||||
turnsRemain = 0;
|
||||
valType = ADDITIVE_VALUE;
|
||||
effectRange = NO_LIMIT;
|
||||
@ -1258,7 +1320,6 @@ Bonus::Bonus(ui16 Dur, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::
|
||||
Bonus::Bonus(ui16 Dur, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype, ValueType ValType)
|
||||
: duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), sid(ID), valType(ValType)
|
||||
{
|
||||
additionalInfo = -1;
|
||||
turnsRemain = 0;
|
||||
effectRange = NO_LIMIT;
|
||||
}
|
||||
@ -1269,7 +1330,6 @@ Bonus::Bonus()
|
||||
turnsRemain = 0;
|
||||
type = NONE;
|
||||
subtype = -1;
|
||||
additionalInfo = -1;
|
||||
|
||||
valType = ADDITIVE_VALUE;
|
||||
effectRange = NO_LIMIT;
|
||||
@ -1288,7 +1348,7 @@ namespace Selector
|
||||
{
|
||||
DLL_LINKAGE CSelectFieldEqual<Bonus::BonusType> type(&Bonus::type);
|
||||
DLL_LINKAGE CSelectFieldEqual<TBonusSubtype> subtype(&Bonus::subtype);
|
||||
DLL_LINKAGE CSelectFieldEqual<si32> info(&Bonus::additionalInfo);
|
||||
DLL_LINKAGE CSelectFieldEqual<CAddInfo> info(&Bonus::additionalInfo);
|
||||
DLL_LINKAGE CSelectFieldEqual<Bonus::BonusSource> sourceType(&Bonus::source);
|
||||
DLL_LINKAGE CSelectFieldEqual<Bonus::LimitEffect> effectRange(&Bonus::effectRange);
|
||||
DLL_LINKAGE CWillLastTurns turns;
|
||||
@ -1299,11 +1359,11 @@ namespace Selector
|
||||
return type(Type).And(subtype(Subtype));
|
||||
}
|
||||
|
||||
CSelector DLL_LINKAGE typeSubtypeInfo(Bonus::BonusType type, TBonusSubtype subtype, si32 info)
|
||||
CSelector DLL_LINKAGE typeSubtypeInfo(Bonus::BonusType type, TBonusSubtype subtype, CAddInfo info)
|
||||
{
|
||||
return CSelectFieldEqual<Bonus::BonusType>(&Bonus::type)(type)
|
||||
.And(CSelectFieldEqual<TBonusSubtype>(&Bonus::subtype)(subtype))
|
||||
.And(CSelectFieldEqual<si32>(&Bonus::additionalInfo)(info));
|
||||
.And(CSelectFieldEqual<CAddInfo>(&Bonus::additionalInfo)(info));
|
||||
}
|
||||
|
||||
CSelector DLL_LINKAGE source(Bonus::BonusSource source, ui32 sourceID)
|
||||
@ -1403,7 +1463,8 @@ DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus)
|
||||
printField(duration);
|
||||
printField(source);
|
||||
printField(sid);
|
||||
printField(additionalInfo);
|
||||
if(bonus.additionalInfo != CAddInfo::NONE)
|
||||
out << "\taddInfo: " << bonus.additionalInfo.toString() << "\n";
|
||||
printField(turnsRemain);
|
||||
printField(valType);
|
||||
printField(effectRange);
|
||||
|
@ -87,6 +87,24 @@ private:
|
||||
mutable TBonusListPtr data;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CAddInfo : public std::vector<si32>
|
||||
{
|
||||
public:
|
||||
static const si32 NONE = -1;
|
||||
|
||||
CAddInfo();
|
||||
CAddInfo(si32 value);
|
||||
|
||||
bool operator==(si32 value) const;
|
||||
bool operator!=(si32 value) const;
|
||||
|
||||
using std::vector<si32>::operator[];
|
||||
si32 operator[](size_type pos) const;
|
||||
|
||||
std::string toString() const;
|
||||
JsonNode toJsonNode() const;
|
||||
};
|
||||
|
||||
#define BONUS_TREE_DESERIALIZATION_FIX if(!h.saving && h.smartPointerSerialization) deserializationFix();
|
||||
|
||||
#define BONUS_LIST \
|
||||
@ -147,8 +165,8 @@ private:
|
||||
BONUS_NAME(MAGIC_RESISTANCE) /*in % (value)*/ \
|
||||
BONUS_NAME(CHANGES_SPELL_COST_FOR_ALLY) /*in mana points (value) , eg. mage*/ \
|
||||
BONUS_NAME(CHANGES_SPELL_COST_FOR_ENEMY) /*in mana points (value) , eg. pegasus */ \
|
||||
BONUS_NAME(SPELL_AFTER_ATTACK) /* subtype - spell id, value - chance %, additional info % 1000 - level, (additional info)/1000 -> [0 - all attacks, 1 - shot only, 2 - melee only*/ \
|
||||
BONUS_NAME(SPELL_BEFORE_ATTACK) /* subtype - spell id, value - chance %, additional info % 1000 - level, (additional info)/1000 -> [0 - all attacks, 1 - shot only, 2 - melee only*/ \
|
||||
BONUS_NAME(SPELL_AFTER_ATTACK) /* subtype - spell id, value - chance %, addInfo[0] - level, addInfo[1] -> [0 - all attacks, 1 - shot only, 2 - melee only] */ \
|
||||
BONUS_NAME(SPELL_BEFORE_ATTACK) /* subtype - spell id, value - chance %, addInfo[0] - level, addInfo[1] -> [0 - all attacks, 1 - shot only, 2 - melee only] */ \
|
||||
BONUS_NAME(SPELL_RESISTANCE_AURA) /*eg. unicorns, value - resistance bonus in % for adjacent creatures*/ \
|
||||
BONUS_NAME(LEVEL_SPELL_IMMUNITY) /*creature is immune to all spell with level below or equal to value of this bonus */ \
|
||||
BONUS_NAME(BLOCK_MAGIC_ABOVE) /*blocks casting spells of the level > value */ \
|
||||
@ -338,7 +356,7 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
|
||||
ui32 sid; //source id: id of object/artifact/spell
|
||||
ValueType valType;
|
||||
|
||||
si32 additionalInfo;
|
||||
CAddInfo additionalInfo;
|
||||
LimitEffect effectRange; //if not NO_LIMIT, bonus will be omitted by default
|
||||
|
||||
TLimiterPtr limiter;
|
||||
@ -360,7 +378,15 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
|
||||
h & val;
|
||||
h & sid;
|
||||
h & description;
|
||||
h & additionalInfo;
|
||||
if(version >= 783)
|
||||
{
|
||||
h & additionalInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
additionalInfo.resize(1, -1);
|
||||
h & additionalInfo[0];
|
||||
}
|
||||
h & turnsRemain;
|
||||
h & valType;
|
||||
h & effectRange;
|
||||
@ -980,14 +1006,14 @@ namespace Selector
|
||||
{
|
||||
extern DLL_LINKAGE CSelectFieldEqual<Bonus::BonusType> type;
|
||||
extern DLL_LINKAGE CSelectFieldEqual<TBonusSubtype> subtype;
|
||||
extern DLL_LINKAGE CSelectFieldEqual<si32> info;
|
||||
extern DLL_LINKAGE CSelectFieldEqual<CAddInfo> info;
|
||||
extern DLL_LINKAGE CSelectFieldEqual<Bonus::BonusSource> sourceType;
|
||||
extern DLL_LINKAGE CSelectFieldEqual<Bonus::LimitEffect> effectRange;
|
||||
extern DLL_LINKAGE CWillLastTurns turns;
|
||||
extern DLL_LINKAGE CWillLastDays days;
|
||||
|
||||
CSelector DLL_LINKAGE typeSubtype(Bonus::BonusType Type, TBonusSubtype Subtype);
|
||||
CSelector DLL_LINKAGE typeSubtypeInfo(Bonus::BonusType type, TBonusSubtype subtype, si32 info);
|
||||
CSelector DLL_LINKAGE typeSubtypeInfo(Bonus::BonusType type, TBonusSubtype subtype, CAddInfo info);
|
||||
CSelector DLL_LINKAGE source(Bonus::BonusSource source, ui32 sourceID);
|
||||
CSelector DLL_LINKAGE sourceTypeSel(Bonus::BonusSource source);
|
||||
CSelector DLL_LINKAGE valueType(Bonus::ValueType valType);
|
||||
|
@ -418,7 +418,6 @@ std::string JsonNode::toJson(bool compact) const
|
||||
std::ostringstream out;
|
||||
JsonWriter writer(out, compact);
|
||||
writer.writeNode(*this);
|
||||
out << "\n";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
@ -496,6 +495,57 @@ void JsonUtils::resolveIdentifier(si32 &var, const JsonNode &node, std::string n
|
||||
}
|
||||
}
|
||||
|
||||
void JsonUtils::resolveAddInfo(CAddInfo & var, const JsonNode & node)
|
||||
{
|
||||
const JsonNode & value = node["addInfo"];
|
||||
if (!value.isNull())
|
||||
{
|
||||
switch (value.getType())
|
||||
{
|
||||
case JsonNode::JsonType::DATA_INTEGER:
|
||||
var = value.Integer();
|
||||
break;
|
||||
case JsonNode::JsonType::DATA_FLOAT:
|
||||
var = value.Float();
|
||||
break;
|
||||
case JsonNode::JsonType::DATA_STRING:
|
||||
VLC->modh->identifiers.requestIdentifier(value, [&](si32 identifier)
|
||||
{
|
||||
var = identifier;
|
||||
});
|
||||
break;
|
||||
case JsonNode::JsonType::DATA_VECTOR:
|
||||
{
|
||||
const JsonVector & vec = value.Vector();
|
||||
var.resize(vec.size());
|
||||
for(int i = 0; i < vec.size(); i++)
|
||||
{
|
||||
switch(vec[i].getType())
|
||||
{
|
||||
case JsonNode::JsonType::DATA_INTEGER:
|
||||
var[i] = vec[i].Integer();
|
||||
break;
|
||||
case JsonNode::JsonType::DATA_FLOAT:
|
||||
var[i] = vec[i].Float();
|
||||
break;
|
||||
case JsonNode::JsonType::DATA_STRING:
|
||||
VLC->modh->identifiers.requestIdentifier(vec[i], [&var,i](si32 identifier)
|
||||
{
|
||||
var[i] = identifier;
|
||||
});
|
||||
break;
|
||||
default:
|
||||
logMod->error("Error! Wrong identifier used for value of addInfo[%d].", i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
logMod->error("Error! Wrong identifier used for value of addInfo.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JsonUtils::resolveIdentifier(const JsonNode &node, si32 &var)
|
||||
{
|
||||
switch (node.getType())
|
||||
@ -548,7 +598,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
|
||||
if (!value->isNull())
|
||||
b->valType = static_cast<Bonus::ValueType>(parseByMap(bonusValueMap, value, "value type "));
|
||||
|
||||
resolveIdentifier(b->additionalInfo, ability, "addInfo");
|
||||
resolveAddInfo(b->additionalInfo, ability);
|
||||
|
||||
b->turnsRemain = ability["turns"].Float();
|
||||
|
||||
@ -698,7 +748,7 @@ void JsonUtils::unparseBonus( JsonNode &node, const std::shared_ptr<Bonus>& bonu
|
||||
node["subtype"].Float() = bonus->subtype;
|
||||
node["val"].Float() = bonus->val;
|
||||
node["valueType"].String() = reverseMapFirst<std::string, Bonus::ValueType>(bonus->valType, bonusValueMap);
|
||||
node["additionalInfo"].Float() = bonus->additionalInfo;
|
||||
node["additionalInfo"] = bonus->additionalInfo.toJsonNode();
|
||||
node["turns"].Float() = bonus->turnsRemain;
|
||||
node["sourceID"].Float() = bonus->source;
|
||||
node["description"].String() = bonus->description;
|
||||
|
@ -15,6 +15,7 @@ typedef std::vector <JsonNode> JsonVector;
|
||||
|
||||
struct Bonus;
|
||||
class ResourceID;
|
||||
class CAddInfo;
|
||||
|
||||
class DLL_LINKAGE JsonNode
|
||||
{
|
||||
@ -170,6 +171,7 @@ namespace JsonUtils
|
||||
DLL_LINKAGE void unparseBonus (JsonNode &node, const std::shared_ptr<Bonus>& bonus);
|
||||
DLL_LINKAGE void resolveIdentifier(si32 &var, const JsonNode &node, std::string name);
|
||||
DLL_LINKAGE void resolveIdentifier(const JsonNode &node, si32 &var);
|
||||
DLL_LINKAGE void resolveAddInfo(CAddInfo & var, const JsonNode & node);
|
||||
|
||||
/**
|
||||
* @brief recursively merges source into dest, replacing identical fields
|
||||
|
@ -797,7 +797,7 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo & info)
|
||||
TBonusListPtr blessEffects = attackerBonuses->getBonuses(selectorForcedMaxDamage, cachingStrForcedMaxDamage);
|
||||
|
||||
int curseBlessAdditiveModifier = blessEffects->totalValue() - curseEffects->totalValue();
|
||||
double curseMultiplicativePenalty = curseEffects->size() ? (*std::max_element(curseEffects->begin(), curseEffects->end(), &Bonus::compareByAdditionalInfo<std::shared_ptr<Bonus>>))->additionalInfo : 0;
|
||||
double curseMultiplicativePenalty = curseEffects->size() ? (*std::max_element(curseEffects->begin(), curseEffects->end(), &Bonus::compareByAdditionalInfo<std::shared_ptr<Bonus>>))->additionalInfo[0] : 0;
|
||||
|
||||
if(curseMultiplicativePenalty) //curse handling (partial, the rest is below)
|
||||
{
|
||||
@ -1738,12 +1738,12 @@ SpellID CBattleInfoCallback::getRandomCastedSpell(CRandomGenerator & rand,const
|
||||
int totalWeight = 0;
|
||||
for(auto b : *bl)
|
||||
{
|
||||
totalWeight += std::max(b->additionalInfo, 1); //minimal chance to cast is 1
|
||||
totalWeight += std::max(b->additionalInfo[0], 1); //minimal chance to cast is 1
|
||||
}
|
||||
int randomPos = rand.nextInt(totalWeight - 1);
|
||||
for(auto b : *bl)
|
||||
{
|
||||
randomPos -= std::max(b->additionalInfo, 1);
|
||||
randomPos -= std::max(b->additionalInfo[0], 1);
|
||||
if(randomPos < 0)
|
||||
{
|
||||
return SpellID(b->subtype);
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "../ConstTransitivePtr.h"
|
||||
#include "../GameConstants.h"
|
||||
|
||||
const ui32 SERIALIZATION_VERSION = 782;
|
||||
const ui32 SERIALIZATION_VERSION = 783;
|
||||
const ui32 MINIMAL_SERIALIZATION_VERSION = 753;
|
||||
const std::string SAVEGAME_MAGIC = "VCMISVG";
|
||||
|
||||
|
@ -181,7 +181,7 @@ void Timed::prepareEffects(SetStackEffect & sse, const Mechanics * m, const Effe
|
||||
const auto tier = std::max(affected->creatureLevel(), 1); //don't divide by 0 for certain creatures (commanders, war machines)
|
||||
if(bonus)
|
||||
{
|
||||
switch(bonus->additionalInfo)
|
||||
switch(bonus->additionalInfo[0])
|
||||
{
|
||||
case 0: //normal
|
||||
switch(tier)
|
||||
|
@ -4731,9 +4731,9 @@ void CGameHandler::stackTurnTrigger(const CStack *st)
|
||||
|
||||
for (auto b : bl)
|
||||
{
|
||||
if(b->additionalInfo >= 0)
|
||||
if(b->additionalInfo != CAddInfo::NONE)
|
||||
{
|
||||
const CStack * stack = gs->curB->battleGetStackByID(b->additionalInfo); //binding stack must be alive and adjacent
|
||||
const CStack * stack = gs->curB->battleGetStackByID(b->additionalInfo[0]); //binding stack must be alive and adjacent
|
||||
if(stack)
|
||||
{
|
||||
if(vstd::contains(adjacent, stack)) //binding stack is still present
|
||||
@ -4840,7 +4840,7 @@ void CGameHandler::stackTurnTrigger(const CStack *st)
|
||||
{
|
||||
cast = true;
|
||||
|
||||
int cooldown = bonus->additionalInfo;
|
||||
int cooldown = bonus->additionalInfo[0];
|
||||
BattleSetStackProperty ssp;
|
||||
ssp.which = BattleSetStackProperty::ENCHANTER_COUNTER;
|
||||
ssp.absolute = false;
|
||||
@ -5483,8 +5483,18 @@ void CGameHandler::attackCasting(bool ranged, Bonus::BonusType attackMode, const
|
||||
TBonusListPtr spellsByType = attacker->getBonuses(Selector::typeSubtype(attackMode, spellID));
|
||||
for(const std::shared_ptr<Bonus> sf : *spellsByType)
|
||||
{
|
||||
vstd::amax(spellLevel, sf->additionalInfo % 1000); //pick highest level
|
||||
int meleeRanged = sf->additionalInfo / 1000;
|
||||
int meleeRanged;
|
||||
if(sf->additionalInfo.size() < 2)
|
||||
{
|
||||
// legacy format
|
||||
vstd::amax(spellLevel, sf->additionalInfo[0] % 1000);
|
||||
meleeRanged = sf->additionalInfo[0] / 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
vstd::amax(spellLevel, sf->additionalInfo[0]);
|
||||
meleeRanged = sf->additionalInfo[1];
|
||||
}
|
||||
if (meleeRanged == 0 || (meleeRanged == 1 && ranged) || (meleeRanged == 2 && !ranged))
|
||||
castMe = true;
|
||||
}
|
||||
@ -5569,7 +5579,7 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
|
||||
TBonusListPtr acidBreath = attacker->getBonuses(Selector::type(Bonus::ACID_BREATH));
|
||||
for(const std::shared_ptr<Bonus> b : *acidBreath)
|
||||
{
|
||||
if(b->additionalInfo > getRandomGenerator().nextInt(99))
|
||||
if(b->additionalInfo[0] > getRandomGenerator().nextInt(99))
|
||||
acidDamage += b->val;
|
||||
}
|
||||
|
||||
@ -5597,10 +5607,10 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
|
||||
if(getRandomGenerator().getDoubleRange(0, 1)() > chanceToTrigger)
|
||||
return;
|
||||
|
||||
int bonusAdditionalInfo = attacker->getBonus(Selector::type(Bonus::TRANSMUTATION))->additionalInfo;
|
||||
int bonusAdditionalInfo = attacker->getBonus(Selector::type(Bonus::TRANSMUTATION))->additionalInfo[0];
|
||||
|
||||
if(defender->getCreature()->idNumber == bonusAdditionalInfo ||
|
||||
(bonusAdditionalInfo == -1 && defender->getCreature()->idNumber == attacker->getCreature()->idNumber))
|
||||
(bonusAdditionalInfo == CAddInfo::NONE && defender->getCreature()->idNumber == attacker->getCreature()->idNumber))
|
||||
return;
|
||||
|
||||
battle::UnitInfo resurrectInfo;
|
||||
@ -5609,7 +5619,7 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
|
||||
resurrectInfo.position = defender->getPosition();
|
||||
resurrectInfo.side = defender->unitSide();
|
||||
|
||||
if(bonusAdditionalInfo != -1)
|
||||
if(bonusAdditionalInfo != CAddInfo::NONE)
|
||||
resurrectInfo.type = CreatureID(bonusAdditionalInfo);
|
||||
else
|
||||
resurrectInfo.type = attacker->creatureId();
|
||||
@ -5639,13 +5649,13 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
|
||||
if(attacker->hasBonusOfType(Bonus::DESTRUCTION, 0)) //killing by percentage
|
||||
{
|
||||
chanceToTrigger = attacker->valOfBonuses(Bonus::DESTRUCTION, 0) / 100.0f;
|
||||
int percentageToDie = attacker->getBonus(Selector::type(Bonus::DESTRUCTION).And(Selector::subtype(0)))->additionalInfo;
|
||||
int percentageToDie = attacker->getBonus(Selector::type(Bonus::DESTRUCTION).And(Selector::subtype(0)))->additionalInfo[0];
|
||||
amountToDie = defender->getCount() * percentageToDie * 0.01f;
|
||||
}
|
||||
else if(attacker->hasBonusOfType(Bonus::DESTRUCTION, 1)) //killing by count
|
||||
{
|
||||
chanceToTrigger = attacker->valOfBonuses(Bonus::DESTRUCTION, 1) / 100.0f;
|
||||
amountToDie = attacker->getBonus(Selector::type(Bonus::DESTRUCTION).And(Selector::subtype(1)))->additionalInfo;
|
||||
amountToDie = attacker->getBonus(Selector::type(Bonus::DESTRUCTION).And(Selector::subtype(1)))->additionalInfo[0];
|
||||
}
|
||||
|
||||
vstd::amin(chanceToTrigger, 1); //cap trigger chance at 100%
|
||||
|
Loading…
Reference in New Issue
Block a user