1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +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()) switch (value->getType())
{ {
case JsonNode::JsonType::DATA_STRING: 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; break;
default: default:
logMod->error("Error! Wrong bonus duration format."); 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(); return str.str();
} }
JsonNode subtypeToJson(BonusType type, int subtype) static JsonNode subtypeToJson(BonusType type, int subtype)
{ {
switch(type) 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) switch(type)
{ {
@ -216,7 +216,7 @@ JsonNode Bonus::toJsonNode() const
if(effectRange != BonusLimitEffect::NO_LIMIT) if(effectRange != BonusLimitEffect::NO_LIMIT)
root["effectRange"].String() = vstd::findKey(bonusLimitEffect, effectRange); root["effectRange"].String() = vstd::findKey(bonusLimitEffect, effectRange);
if(duration != BonusDuration::PERMANENT) if(duration != BonusDuration::PERMANENT)
root["duration"].String() = vstd::findKey(bonusDurationMap, duration); root["duration"] = BonusDuration::toJson(duration);
if(turnsRemain) if(turnsRemain)
root["turns"].Integer() = turnsRemain; root["turns"].Integer() = turnsRemain;
if(limiter) if(limiter)
@ -228,7 +228,7 @@ JsonNode Bonus::toJsonNode() const
return root; 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), duration(Duration),
type(Type), type(Type),
subtype(Subtype), subtype(Subtype),
@ -241,7 +241,7 @@ Bonus::Bonus(BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val,
targetSourceType = BonusSource::OTHER; 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), duration(Duration),
type(Type), type(Type),
subtype(Subtype), 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" #define printField(field) out << "\t" #field ": " << (int)bonus.field << "\n"
printField(val); printField(val);
printField(subtype); printField(subtype);
printField(duration); printField(duration.to_ulong());
printField(source); printField(source);
printField(sid); printField(sid);
if(bonus.additionalInfo != CAddInfo::NONE) if(bonus.additionalInfo != CAddInfo::NONE)

View File

@ -10,7 +10,6 @@
#pragma once #pragma once
#include "BonusEnum.h" #include "BonusEnum.h"
#include "../JsonNode.h"
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
@ -52,7 +51,7 @@ public:
/// Struct for handling bonuses of several types. Can be transferred to any hero /// Struct for handling bonuses of several types. Can be transferred to any hero
struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus> 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 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 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; std::string description;
Bonus(BonusDuration 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, 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, si32 Subtype=-1, BonusValueType ValType = BonusValueType::ADDITIVE_VALUE);
Bonus() = default; Bonus() = default;
template <typename Handler> void serialize(Handler &h, const int version) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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 inline bool operator == (const BonusType & cf) const
{ {

View File

@ -30,7 +30,7 @@ VCMI_LIB_NAMESPACE_BEGIN
#undef BONUS_SOURCE #undef BONUS_SOURCE
#define BONUS_ITEM(x) { #x, BonusDuration::x }, #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(PERMANENT)
BONUS_ITEM(ONE_BATTLE) BONUS_ITEM(ONE_BATTLE)
@ -55,4 +55,28 @@ const std::map<std::string, BonusLimitEffect> bonusLimitEffect =
}; };
#undef BONUS_ITEM #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 VCMI_LIB_NAMESPACE_END

View File

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

View File

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

View File

@ -232,7 +232,7 @@ protected:
virtual void setPropertyDer(ui8 what, ui32 val); virtual void setPropertyDer(ui8 what, ui32 val);
/// Gives dummy bonus from this object to hero. Can be used to track visited state /// 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 ///Serialize object-type specific options
virtual void serializeJsonOptions(JsonSerializeFormat & handler); virtual void serializeJsonOptions(JsonSerializeFormat & handler);

View File

@ -351,6 +351,14 @@ public:
return 1; 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) static int quickRetStr(lua_State * L, const std::string & value)
{ {
lua_settop(L, 0); lua_settop(L, 0);

View File

@ -155,8 +155,8 @@ int BonusProxy::toJsonNode(lua_State * L)
return 1; return 1;
} }
template <typename T> template <typename T, typename N>
static void publishMap(lua_State * L, const T & map) static void publishMap(lua_State * L, const std::map<T , N> & map)
{ {
for(auto & p : 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 void BonusProxy::adjustStaticTable(lua_State * L) const
{ {
publishMap(L, bonusNameMap); publishMap(L, bonusNameMap);