1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Bonus: complex duration as bitset

Fixes #2125
This commit is contained in:
Konstantin P 2023-05-05 12:56:53 +03:00
parent e9a90a8cbf
commit 8764765dcf
9 changed files with 105 additions and 38 deletions

View File

@ -975,7 +975,15 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
switch (value->getType())
{
case JsonNode::JsonType::DATA_STRING:
b->duration = static_cast<BonusDuration>(parseByMap(bonusDurationMap, value, "duration type "));
b->duration = parseByMap(bonusDurationMap, value, "duration type ");
break;
case JsonNode::JsonType::DATA_VECTOR:
{
BonusDuration::Type dur = 0;
for (const JsonNode & d : value->Vector())
dur |= parseByMapN(bonusDurationMap, &d, "duration type ");
b->duration = dur;
}
break;
default:
logMod->error("Error! Wrong bonus duration format.");

View File

@ -154,7 +154,7 @@ std::string Bonus::Description(std::optional<si32> customValue) const
return str.str();
}
JsonNode subtypeToJson(BonusType type, int subtype)
static JsonNode subtypeToJson(BonusType type, int subtype)
{
switch(type)
{
@ -177,7 +177,7 @@ JsonNode subtypeToJson(BonusType type, int subtype)
}
}
JsonNode additionalInfoToJson(BonusType type, CAddInfo addInfo)
static JsonNode additionalInfoToJson(BonusType type, CAddInfo addInfo)
{
switch(type)
{
@ -216,7 +216,7 @@ JsonNode Bonus::toJsonNode() const
if(effectRange != BonusLimitEffect::NO_LIMIT)
root["effectRange"].String() = vstd::findKey(bonusLimitEffect, effectRange);
if(duration != BonusDuration::PERMANENT)
root["duration"].String() = vstd::findKey(bonusDurationMap, duration);
root["duration"] = BonusDuration::toJson(duration);
if(turnsRemain)
root["turns"].Integer() = turnsRemain;
if(limiter)
@ -228,7 +228,7 @@ JsonNode Bonus::toJsonNode() const
return root;
}
Bonus::Bonus(BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype):
Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype):
duration(Duration),
type(Type),
subtype(Subtype),
@ -241,7 +241,7 @@ Bonus::Bonus(BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val,
targetSourceType = BonusSource::OTHER;
}
Bonus::Bonus(BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype, BonusValueType ValType):
Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype, BonusValueType ValType):
duration(Duration),
type(Type),
subtype(Subtype),
@ -270,7 +270,7 @@ DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus)
#define printField(field) out << "\t" #field ": " << (int)bonus.field << "\n"
printField(val);
printField(subtype);
printField(duration);
printField(duration.to_ulong());
printField(source);
printField(sid);
if(bonus.additionalInfo != CAddInfo::NONE)

View File

@ -10,7 +10,6 @@
#pragma once
#include "BonusEnum.h"
#include "../JsonNode.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -52,7 +51,7 @@ public:
/// Struct for handling bonuses of several types. Can be transferred to any hero
struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
{
BonusDuration duration = BonusDuration::PERMANENT; //uses BonusDuration values
BonusDuration::Type duration = BonusDuration::PERMANENT; //uses BonusDuration values
si16 turnsRemain = 0; //used if duration is N_TURNS, N_DAYS or ONE_WEEK
BonusType type = BonusType::NONE; //uses BonusType values - says to what is this bonus - 1 byte
@ -75,8 +74,8 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
std::string description;
Bonus(BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype=-1);
Bonus(BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype=-1, BonusValueType ValType = BonusValueType::ADDITIVE_VALUE);
Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype=-1);
Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype=-1, BonusValueType ValType = BonusValueType::ADDITIVE_VALUE);
Bonus() = default;
template <typename Handler> void serialize(Handler &h, const int version)
@ -107,43 +106,53 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
}
static bool NDays(const Bonus *hb)
{
return hb->duration == BonusDuration::N_DAYS;
auto set = hb->duration & BonusDuration::N_DAYS;
return set.any();
}
static bool NTurns(const Bonus *hb)
{
return hb->duration == BonusDuration::N_TURNS;
auto set = hb->duration & BonusDuration::N_TURNS;
return set.any();
}
static bool OneDay(const Bonus *hb)
{
return hb->duration == BonusDuration::ONE_DAY;
auto set = hb->duration & BonusDuration::ONE_DAY;
return set.any();
}
static bool OneWeek(const Bonus *hb)
{
return hb->duration == BonusDuration::ONE_WEEK;
auto set = hb->duration & BonusDuration::ONE_WEEK;
return set.any();
}
static bool OneBattle(const Bonus *hb)
{
return hb->duration == BonusDuration::ONE_BATTLE;
auto set = hb->duration & BonusDuration::ONE_BATTLE;
return set.any();
}
static bool Permanent(const Bonus *hb)
{
return hb->duration == BonusDuration::PERMANENT;
auto set = hb->duration & BonusDuration::PERMANENT;
return set.any();
}
static bool UntilGetsTurn(const Bonus *hb)
{
return hb->duration == BonusDuration::STACK_GETS_TURN;
auto set = hb->duration & BonusDuration::STACK_GETS_TURN;
return set.any();
}
static bool UntilAttack(const Bonus *hb)
{
return hb->duration == BonusDuration::UNTIL_ATTACK;
auto set = hb->duration & BonusDuration::UNTIL_ATTACK;
return set.any();
}
static bool UntilBeingAttacked(const Bonus *hb)
{
return hb->duration == BonusDuration::UNTIL_BEING_ATTACKED;
auto set = hb->duration & BonusDuration::UNTIL_BEING_ATTACKED;
return set.any();
}
static bool UntilCommanderKilled(const Bonus *hb)
{
return hb->duration == BonusDuration::COMMANDER_KILLED;
auto set = hb->duration & BonusDuration::COMMANDER_KILLED;
return set.any();
}
inline bool operator == (const BonusType & cf) const
{

View File

@ -30,7 +30,7 @@ VCMI_LIB_NAMESPACE_BEGIN
#undef BONUS_SOURCE
#define BONUS_ITEM(x) { #x, BonusDuration::x },
const std::map<std::string, BonusDuration> bonusDurationMap =
const std::map<std::string, BonusDuration::Type> bonusDurationMap =
{
BONUS_ITEM(PERMANENT)
BONUS_ITEM(ONE_BATTLE)
@ -55,4 +55,28 @@ const std::map<std::string, BonusLimitEffect> bonusLimitEffect =
};
#undef BONUS_ITEM
namespace BonusDuration
{
JsonNode toJson(const Type & duration)
{
std::vector<std::string> durationNames;
for(auto durBit = 0; durBit < duration.size(); durBit++)
{
if(duration[durBit])
durationNames.push_back(vstd::findKey(bonusDurationMap, duration & Type().set(durBit)));
}
if(durationNames.size() == 1)
{
return JsonUtils::stringNode(durationNames[0]);
}
else
{
JsonNode node(JsonNode::JsonType::DATA_VECTOR);
for(const std::string & dur : durationNames)
node.Vector().push_back(JsonUtils::stringNode(dur));
return node;
}
}
}
VCMI_LIB_NAMESPACE_END

View File

@ -12,6 +12,8 @@
VCMI_LIB_NAMESPACE_BEGIN
#include "../JsonNode.h"
#define BONUS_LIST \
BONUS_NAME(NONE) \
BONUS_NAME(LEVEL_COUNTER) /* for commander artifacts*/ \
@ -220,18 +222,20 @@ enum class BonusType
BONUS_LIST
#undef BONUS_NAME
};
enum class BonusDuration : uint16_t //when bonus is automatically removed
namespace BonusDuration //when bonus is automatically removed
{
PERMANENT = 1,
ONE_BATTLE = 2, //at the end of battle
ONE_DAY = 4, //at the end of day
ONE_WEEK = 8, //at the end of week (bonus lasts till the end of week, thats NOT 7 days
N_TURNS = 16, //used during battles, after battle bonus is always removed
N_DAYS = 32,
UNTIL_BEING_ATTACKED = 64, /*removed after attack and counterattacks are performed*/
UNTIL_ATTACK = 128, /*removed after attack and counterattacks are performed*/
STACK_GETS_TURN = 256, /*removed when stack gets its turn - used for defensive stance*/
COMMANDER_KILLED = 512
using Type = std::bitset<10>;
extern JsonNode toJson(const Type & duration);
constexpr Type PERMANENT = 1 << 0;
constexpr Type ONE_BATTLE = 1 << 1; //at the end of battle
constexpr Type ONE_DAY = 1 << 2; //at the end of day
constexpr Type ONE_WEEK = 1 << 3; //at the end of week (bonus lasts till the end of week, thats NOT 7 days
constexpr Type N_TURNS = 1 << 4; //used during battles, after battle bonus is always removed
constexpr Type N_DAYS = 1 << 5;
constexpr Type UNTIL_BEING_ATTACKED = 1 << 6; /*removed after attack and counterattacks are performed*/
constexpr Type UNTIL_ATTACK = 1 << 7; /*removed after attack and counterattacks are performed*/
constexpr Type STACK_GETS_TURN = 1 << 8; /*removed when stack gets its turn - used for defensive stance*/
constexpr Type COMMANDER_KILLED = 1 << 9;
};
enum class BonusSource
{
@ -257,7 +261,7 @@ enum class BonusValueType
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> bonusDurationMap;
extern DLL_LINKAGE const std::map<std::string, BonusDuration::Type> bonusDurationMap;
extern DLL_LINKAGE const std::map<std::string, BonusLimitEffect> bonusLimitEffect;
VCMI_LIB_NAMESPACE_END

View File

@ -272,7 +272,7 @@ int3 CGObjectInstance::getVisitableOffset() const
return appearance->getVisitableOffset();
}
void CGObjectInstance::giveDummyBonus(const ObjectInstanceID & heroID, BonusDuration duration) const
void CGObjectInstance::giveDummyBonus(const ObjectInstanceID & heroID, BonusDuration::Type duration) const
{
GiveBonus gbonus;
gbonus.bonus.type = BonusType::NONE;

View File

@ -232,7 +232,7 @@ protected:
virtual void setPropertyDer(ui8 what, ui32 val);
/// Gives dummy bonus from this object to hero. Can be used to track visited state
void giveDummyBonus(const ObjectInstanceID & heroID, BonusDuration duration = BonusDuration::ONE_DAY) const;
void giveDummyBonus(const ObjectInstanceID & heroID, BonusDuration::Type duration = BonusDuration::ONE_DAY) const;
///Serialize object-type specific options
virtual void serializeJsonOptions(JsonSerializeFormat & handler);

View File

@ -351,6 +351,14 @@ public:
return 1;
}
template<std::size_t T>
static int quickRetInt(lua_State * L, const std::bitset<T> & value)
{
lua_settop(L, 0);
lua_pushinteger(L, static_cast<int32_t>(value.to_ulong()));
return 1;
}
static int quickRetStr(lua_State * L, const std::string & value)
{
lua_settop(L, 0);

View File

@ -155,8 +155,8 @@ int BonusProxy::toJsonNode(lua_State * L)
return 1;
}
template <typename T>
static void publishMap(lua_State * L, const T & map)
template <typename T, typename N>
static void publishMap(lua_State * L, const std::map<T , N> & map)
{
for(auto & p : map)
{
@ -169,6 +169,20 @@ static void publishMap(lua_State * L, const T & map)
}
}
template <typename T, std::size_t N>
static void publishMap(lua_State * L, const std::map<T , std::bitset<N>> & map)
{
for(auto & p : map)
{
const std::string & name = p.first;
auto id = static_cast<int32_t>(p.second.to_ulong());
lua_pushstring(L, name.c_str());
lua_pushinteger(L, id);
lua_rawset(L, -3);
}
}
void BonusProxy::adjustStaticTable(lua_State * L) const
{
publishMap(L, bonusNameMap);