1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-09-16 09:26:28 +02:00

Preparation for user-defined bonus types

This commit is contained in:
Ivan Savenko
2025-06-09 11:40:21 +03:00
parent 527885de21
commit 51832c4fb9
13 changed files with 72 additions and 123 deletions

View File

@@ -45,14 +45,19 @@ CBonusTypeHandler::CBonusTypeHandler()
{
//register predefined bonus types
#define BONUS_NAME(x) \
#define BONUS_NAME(x) { #x },
bonusNames = {
BONUS_LIST
};
#undef BONUS_NAME
#define BONUS_NAME(x) \
do { \
bonusTypes.push_back(CBonusType()); \
} while(0);
BONUS_LIST;
#undef BONUS_NAME
#undef BONUS_NAME
}
CBonusTypeHandler::~CBonusTypeHandler() = default;
@@ -117,19 +122,12 @@ std::vector<JsonNode> CBonusTypeHandler::loadLegacyData()
void CBonusTypeHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
{
auto it = bonusNameMap.find(name);
BonusType bonus = stringToBonus(name);
if(it == bonusNameMap.end())
{
logBonus->warn("Unrecognized bonus name! (%s)", name);
}
else
{
CBonusType & bt = bonusTypes[vstd::to_underlying(it->second)];
CBonusType & bt = bonusTypes[vstd::to_underlying(bonus)];
loadItem(data, bt, name);
logBonus->trace("Loaded bonus type %s", name);
}
loadItem(data, bt, name);
logBonus->trace("Loaded bonus type %s", name);
}
void CBonusTypeHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
@@ -185,4 +183,27 @@ void CBonusTypeHandler::loadItem(const JsonNode & source, CBonusType & dest, con
}
}
BonusType CBonusTypeHandler::stringToBonus(const std::string & name) const
{
auto it = boost::range::find(bonusNames, name);
if (it != bonusNames.end())
return static_cast<BonusType>(it - bonusNames.begin());
return BonusType::NONE;
}
const std::string CBonusTypeHandler::bonusToString(BonusType bonus) const
{
return bonusNames.at(static_cast<int>(bonus));
}
std::vector<BonusType> CBonusTypeHandler::getAllObjets() const
{
std::vector<BonusType> ret;
for (int i = 0; i < bonusNames.size(); ++i)
ret.push_back(static_cast<BonusType>(i));
return ret;
}
VCMI_LIB_NAMESPACE_END

View File

@@ -41,6 +41,7 @@ private:
class DLL_LINKAGE CBonusTypeHandler : public IBonusTypeHandler
{
std::vector<std::string> bonusNames;
public:
CBonusTypeHandler();
virtual ~CBonusTypeHandler();
@@ -52,6 +53,10 @@ public:
void loadObject(std::string scope, std::string name, const JsonNode & data) override;
void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;
BonusType stringToBonus(const std::string & name) const;
const std::string bonusToString(BonusType bonus) const;
std::vector<BonusType> getAllObjets() const;
private:
void loadItem(const JsonNode & source, CBonusType & dest, const std::string & name) const;

View File

@@ -14,6 +14,7 @@
#include "Updaters.h"
#include "Propagators.h"
#include "../CBonusTypeHandler.h"
#include "../CCreatureHandler.h"
#include "../CCreatureSet.h"
#include "../CSkillHandler.h"
@@ -172,7 +173,7 @@ JsonNode Bonus::toJsonNode() const
{
JsonNode root;
// only add values that might reasonably be found in config files
root["type"].String() = vstd::findKey(bonusNameMap, type);
root["type"].String() = LIBRARY->bth->bonusToString(type);
if(subtype != BonusSubtypeID())
root["subtype"].String() = subtype.toString();
if(additionalInfo != CAddInfo::NONE)
@@ -243,9 +244,7 @@ std::shared_ptr<Bonus> Bonus::addPropagator(const TPropagatorPtr & Propagator)
DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus)
{
for(const auto & i : bonusNameMap)
if(i.second == bonus.type)
out << "\tType: " << i.first << " \t";
out << "\tType: " << LIBRARY->bth->bonusToString(bonus.type) << " \t";
#define printField(field) out << "\t" #field ": " << (int)bonus.field << "\n"
printField(val);

View File

@@ -65,9 +65,8 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>, public Se
BonusValueType valType = BonusValueType::ADDITIVE_VALUE; // 1 byte
BonusSource source = BonusSource::OTHER; //source type" uses BonusSource values - what gave that bonus - 1 byte
BonusSource targetSourceType = BonusSource::OTHER;//Bonuses of what origin this amplifies, uses BonusSource values. Needed for PERCENT_TO_TARGET_TYPE. - 1 byte
BonusType type = BonusType::NONE; //uses BonusType values - says to what is this bonus - 1 byte
BonusLimitEffect effectRange = BonusLimitEffect::NO_LIMIT; // 1 byte
// 1 bytes padding
BonusType type = BonusType::NONE; //uses BonusType values - says to what is this bonus - 2 bytes
BonusSubtypeID subtype;
BonusSourceID sid; //source id: id of object/artifact/spell

View File

@@ -14,12 +14,6 @@
VCMI_LIB_NAMESPACE_BEGIN
#define BONUS_NAME(x) { #x, BonusType::x },
const std::map<std::string, BonusType> bonusNameMap = {
BONUS_LIST
};
#undef BONUS_NAME
#define BONUS_VALUE(x) { #x, BonusValueType::x },
const std::map<std::string, BonusValueType> bonusValueMap = { BONUS_VALUE_LIST };
#undef BONUS_VALUE

View File

@@ -224,11 +224,12 @@ class JsonNode;
BONUS_VALUE(INDEPENDENT_MIN) //used for SECONDARY_SKILL_PREMY bonus
enum class BonusType : uint8_t
enum class BonusType : uint16_t
{
#define BONUS_NAME(x) x,
BONUS_LIST
#undef BONUS_NAME
BUILTIN_BONUSES_COUNT
};
namespace BonusDuration //when bonus is automatically removed
{
@@ -273,7 +274,6 @@ enum class BonusValueType : uint8_t
#undef BONUS_VALUE
};
extern DLL_LINKAGE const std::map<std::string, BonusType> bonusNameMap;
extern DLL_LINKAGE const std::map<std::string, BonusValueType> bonusValueMap;
extern DLL_LINKAGE const std::map<std::string, BonusSource> bonusSourceMap;
extern DLL_LINKAGE const std::map<std::string, BonusDuration::Type> bonusDurationMap;

View File

@@ -12,6 +12,7 @@
#include "Limiters.h"
#include "Updaters.h"
#include "../CBonusTypeHandler.h"
#include "../GameLibrary.h"
#include "../entities/faction/CFaction.h"
#include "../entities/faction/CTownHandler.h"
@@ -189,7 +190,7 @@ ILimiter::EDecision HasAnotherBonusLimiter::limit(const BonusLimitationContext &
std::string HasAnotherBonusLimiter::toString() const
{
std::string typeName = vstd::findKey(bonusNameMap, type);
std::string typeName = LIBRARY->bth->bonusToString(type);
if(isSubtypeRelevant)
{
boost::format fmt("HasAnotherBonusLimiter(type=%s, subtype=%s)");
@@ -207,7 +208,7 @@ std::string HasAnotherBonusLimiter::toString() const
JsonNode HasAnotherBonusLimiter::toJsonNode() const
{
JsonNode root;
std::string typeName = vstd::findKey(bonusNameMap, type);
std::string typeName = LIBRARY->bth->bonusToString(type);
auto sourceTypeName = vstd::findKey(bonusSourceMap, source);
root["type"].String() = "HAS_ANOTHER_BONUS_LIMITER";

View File

@@ -78,12 +78,8 @@ public:
class DLL_LINKAGE TimesStackLevelUpdater : public IUpdater
{
std::shared_ptr<Bonus> apply(const std::shared_ptr<Bonus> & b, int level) const;
public:
template <typename Handler> void serialize(Handler & h)
{
h & static_cast<IUpdater &>(*this);
}
public:
std::shared_ptr<Bonus> createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context) const override;
std::string toString() const override;
JsonNode toJsonNode() const override;
@@ -92,12 +88,8 @@ public:
class DLL_LINKAGE DivideStackLevelUpdater : public IUpdater
{
std::shared_ptr<Bonus> apply(const std::shared_ptr<Bonus> & b, int level) const;
public:
template <typename Handler> void serialize(Handler & h)
{
h & static_cast<IUpdater &>(*this);
}
public:
std::shared_ptr<Bonus> createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context) const override;
std::string toString() const override;
JsonNode toJsonNode() const override;
@@ -125,11 +117,6 @@ public:
class DLL_LINKAGE OwnerUpdater : public IUpdater
{
public:
template <typename Handler> void serialize(Handler& h)
{
h & static_cast<IUpdater &>(*this);
}
std::shared_ptr<Bonus> createUpdatedBonus(const std::shared_ptr<Bonus>& b, const CBonusSystemNode& context) const override;
std::string toString() const override;
JsonNode toJsonNode() const override;

View File

@@ -9,6 +9,7 @@
*/
#include "StdInc.h"
#include "CBonusTypeHandler.h"
#include "JsonBonus.h"
#include "JsonValidator.h"
@@ -184,10 +185,10 @@ static void loadBonusSubtype(BonusSubtypeID & subtype, BonusType type, const Jso
break;
}
default:
for(const auto & i : bonusNameMap)
if(i.second == type)
logMod->warn("Bonus type %s does not supports subtypes!", i.first );
{
logMod->warn("Bonus type %s does not supports subtypes!", LIBRARY->bth->bonusToString(type));
subtype = BonusSubtypeID();
}
}
}
@@ -258,10 +259,7 @@ static void loadBonusAddInfo(CAddInfo & var, BonusType type, const JsonNode & no
}
break;
default:
for(const auto & i : bonusNameMap)
if(i.second == type)
logMod->warn("Bonus type %s does not supports addInfo!", i.first );
logMod->warn("Bonus type %s does not supports addInfo!", LIBRARY->bth->bonusToString(type) );
}
}
@@ -414,14 +412,8 @@ std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonVector & ability_vec)
{
auto b = std::make_shared<Bonus>();
std::string type = ability_vec[0].String();
auto it = bonusNameMap.find(type);
if (it == bonusNameMap.end())
{
logMod->error("Error: invalid ability type %s.", type);
return b;
}
b->type = it->second;
b->type = LIBRARY->bth->stringToBonus(type);
b->val = static_cast<si32>(ability_vec[1].Float());
loadBonusSubtype(b->subtype, b->type, ability_vec[2]);
b->additionalInfo = static_cast<si32>(ability_vec[3].Float());
@@ -505,15 +497,7 @@ std::shared_ptr<const ILimiter> JsonUtils::parseLimiter(const JsonNode & limiter
if (!parameters[0].isNull())
{
std::string anotherBonusType = parameters[0].String();
auto it = bonusNameMap.find(anotherBonusType);
if(it != bonusNameMap.end())
{
bonusLimiter->type = it->second;
}
else
{
logMod->error("Error: invalid ability type %s.", anotherBonusType);
}
bonusLimiter->type = LIBRARY->bth->stringToBonus(anotherBonusType);
}
auto findSource = [&](const JsonNode & parameter)
@@ -627,15 +611,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b, const TextIdentifi
{
const JsonNode * value = nullptr;
std::string type = ability["type"].String();
auto it = bonusNameMap.find(type);
if (it == bonusNameMap.end())
{
logMod->error("Error: invalid ability type %s.", type);
return false;
}
else
b->type = it->second;
b->type = LIBRARY->bth->stringToBonus(ability["type"].String());
loadBonusSubtype(b->subtype, b->type, ability["subtype"]);
@@ -771,12 +747,7 @@ CSelector JsonUtils::parseSelector(const JsonNode & ability)
value = &ability["type"];
if(value->isString())
{
auto it = bonusNameMap.find(value->String());
if(it != bonusNameMap.end())
{
type = it->second;
ret = ret.And(Selector::type()(it->second));
}
ret = ret.And(Selector::type()(LIBRARY->bth->stringToBonus(value->String())));
}
value = &ability["subtype"];
if(!value->isNull() && type != BonusType::NONE)

View File

@@ -12,6 +12,7 @@
#include <cctype>
#include "CBonusTypeHandler.h"
#include "CSpellHandler.h"
#include "Problem.h"
@@ -473,26 +474,14 @@ JsonNode CSpell::convertTargetCondition(const BTVector & immunity, const BTVecto
static const std::string CONDITION_NORMAL = "normal";
static const std::string CONDITION_ABSOLUTE = "absolute";
#define BONUS_NAME(x) { BonusType::x, #x },
static const std::map<BonusType, std::string> bonusNameRMap = { BONUS_LIST };
#undef BONUS_NAME
JsonNode res;
auto convertVector = [&](const std::string & targetName, const BTVector & source, const std::string & value)
{
for(auto bonusType : source)
{
auto iter = bonusNameRMap.find(bonusType);
if(iter != bonusNameRMap.end())
{
auto fullId = ModUtility::makeFullIdentifier("", "bonus", iter->second);
res[targetName][fullId].String() = value;
}
else
{
logGlobal->error("Invalid bonus type %d", static_cast<int32_t>(bonusType));
}
std::string bonusName = LIBRARY->bth->bonusToString(bonusType);
res[targetName][bonusName].String() = value;
}
};
@@ -886,19 +875,6 @@ std::shared_ptr<CSpell> CSpellHandler::loadFromJson(const std::string & scope, c
spell->onlyOnWaterMap = json["onlyOnWaterMap"].Bool();
auto findBonus = [&](const std::string & name, std::vector<BonusType> & vec)
{
auto it = bonusNameMap.find(name);
if(it == bonusNameMap.end())
{
logMod->error("Spell %s: invalid bonus name %s", spell->getNameTranslated(), name);
}
else
{
vec.push_back(static_cast<BonusType>(it->second));
}
};
auto readBonusStruct = [&](const std::string & name, std::vector<BonusType> & vec)
{
for(auto bonusData: json[name].Struct())
@@ -907,7 +883,7 @@ std::shared_ptr<CSpell> CSpellHandler::loadFromJson(const std::string & scope, c
const bool flag = bonusData.second.Bool();
if(flag)
findBonus(bonusId, vec);
vec.push_back(LIBRARY->bth->stringToBonus(bonusId));
}
};

View File

@@ -355,12 +355,7 @@ public:
{
if(type == "bonus")
{
//TODO: support custom bonus types
auto it = bonusNameMap.find(identifier);
if(it != bonusNameMap.end())
return std::make_shared<SelectorCondition>(Selector::type()(it->second));
logMod->error("Invalid bonus type %s in spell target condition.", identifier);
return std::make_shared<SelectorCondition>(Selector::type()(LIBRARY->bth->stringToBonus(identifier)));
}
else if(type == "creature")
{

View File

@@ -8,6 +8,7 @@
*
*/
#include "StdInc.h"
#include "CBonusTypeHandler.h"
#include "rewardswidget.h"
#include "ui_rewardswidget.h"
#include "../lib/GameLibrary.h"
@@ -183,8 +184,8 @@ RewardsWidget::RewardsWidget(CMap & m, CRewardableObject & p, QWidget *parent) :
//fill bonuses
for(auto & s : bonusDurationMap)
ui->bonusDuration->addItem(QString::fromStdString(s.first));
for(auto & s : bonusNameMap)
ui->bonusType->addItem(QString::fromStdString(s.first));
for(auto & s : LIBRARY->bth->getAllObjets())
ui->bonusType->addItem(QString::fromStdString(LIBRARY->bth->bonusToString(s)));
//set default values
if(dynamic_cast<CGPandoraBox*>(&object))
@@ -340,7 +341,7 @@ void RewardsWidget::saveCurrentVisitInfo(int index)
for(int i = 0; i < ui->bonuses->rowCount(); ++i)
{
auto dur = bonusDurationMap.at(ui->bonuses->item(i, 0)->text().toStdString());
auto typ = bonusNameMap.at(ui->bonuses->item(i, 1)->text().toStdString());
auto typ = LIBRARY->bth->stringToBonus(ui->bonuses->item(i, 1)->text().toStdString());
auto val = ui->bonuses->item(i, 2)->data(Qt::UserRole).toInt();
vinfo.reward.heroBonuses.emplace_back(dur, typ, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(object.id));
}
@@ -490,7 +491,7 @@ void RewardsWidget::loadCurrentVisitInfo(int index)
}
}
auto typ = vstd::findKey(bonusNameMap, i.type);
std::string typ = LIBRARY->bth->bonusToString(i.type);
for(int i = 0; i < ui->bonusType->count(); ++i)
{
if(ui->bonusType->itemText(i) == QString::fromStdString(typ))
@@ -816,7 +817,8 @@ void RewardsDelegate::updateModelData(QAbstractItemModel * model, const QModelIn
QStringList bonusesList;
for (auto & bonus : vinfo.reward.heroBonuses)
{
bonusesList += QString("%1 %2 (%3)").arg(QString::fromStdString(vstd::findKey(bonusDurationMap, bonus.duration))).arg(QString::fromStdString(vstd::findKey(bonusNameMap, bonus.type))).arg(bonus.val);
std::string bonusName = LIBRARY->bth->bonusToString(bonus.type);
bonusesList += QString("%1 %2 (%3)").arg(QString::fromStdString(vstd::findKey(bonusDurationMap, bonus.duration))).arg(QString::fromStdString(bonusName)).arg(bonus.val);
}
textList += QObject::tr("Bonuses: %1").arg(bonusesList.join(", "));
}

View File

@@ -187,7 +187,6 @@ static void publishMap(lua_State * L, const std::map<T , std::bitset<N>> & map)
void BonusProxy::adjustStaticTable(lua_State * L) const
{
publishMap(L, bonusNameMap);
publishMap(L, bonusValueMap);
publishMap(L, bonusSourceMap);
publishMap(L, bonusDurationMap);