1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-29 23:07:48 +02:00

Replace bonus string description with metastring that can properly

handle translations
This commit is contained in:
Ivan Savenko
2024-04-07 19:57:49 +03:00
parent b0334b381e
commit 9e49587749
19 changed files with 98 additions and 146 deletions

View File

@@ -208,8 +208,7 @@ void StackWithBonuses::removeUnitBonus(const std::vector<Bonus> & bonus)
&& one.sid == b->sid && one.sid == b->sid
&& one.valType == b->valType && one.valType == b->valType
&& one.additionalInfo == b->additionalInfo && one.additionalInfo == b->additionalInfo
&& one.effectRange == b->effectRange && one.effectRange == b->effectRange;
&& one.description == b->description;
}); });
removeUnitBonus(selector); removeUnitBonus(selector);

View File

@@ -79,14 +79,14 @@
"type" : "MORALE", "type" : "MORALE",
"val" : 1, "val" : 1,
"valueType" : "BASE_NUMBER", "valueType" : "BASE_NUMBER",
"description" : "Creatures of good town alignment on Holly Ground", "description" : "core.arraytxt.123",
"limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["good"] }] "limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["good"] }]
}, },
{ {
"type" : "MORALE", "type" : "MORALE",
"val" : -1, "val" : -1,
"valueType" : "BASE_NUMBER", "valueType" : "BASE_NUMBER",
"description" : "Creatures of evil town alignment on Holly Ground", "description" : "core.arraytxt.124",
"limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["evil"] }] "limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["evil"] }]
} }
] ]
@@ -99,7 +99,7 @@
"type" : "LUCK", "type" : "LUCK",
"val" : 2, "val" : 2,
"valueType" : "BASE_NUMBER", "valueType" : "BASE_NUMBER",
"description" : "Creatures of neutral town alignment on Clover Field", "description" : "core.arraytxt.83",
"limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["neutral"] }] "limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["neutral"] }]
} }
] ]
@@ -112,14 +112,14 @@
"type" : "MORALE", "type" : "MORALE",
"val" : -1, "val" : -1,
"valueType" : "BASE_NUMBER", "valueType" : "BASE_NUMBER",
"description" : "Creatures of good town alignment on Evil Fog", "description" : "core.arraytxt.126",
"limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["good"] }] "limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["good"] }]
}, },
{ {
"type" : "MORALE", "type" : "MORALE",
"val" : 1, "val" : 1,
"valueType" : "BASE_NUMBER", "valueType" : "BASE_NUMBER",
"description" : "Creatures of evil town alignment on Evil Fog", "description" : "core.arraytxt.125",
"limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["evil"] }] "limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["evil"] }]
} }
] ]
@@ -132,13 +132,13 @@
"type" : "NO_MORALE", "type" : "NO_MORALE",
"val" : 0, "val" : 0,
"valueType" : "INDEPENDENT_MIN", "valueType" : "INDEPENDENT_MIN",
"description" : "Creatures on Cursed Ground" "description" : "core.arraytxt.112"
}, },
{ {
"type" : "NO_LUCK", "type" : "NO_LUCK",
"val" : 0, "val" : 0,
"valueType" : "INDEPENDENT_MIN", "valueType" : "INDEPENDENT_MIN",
"description" : "Creatures on Cursed Ground" "description" : "core.arraytxt.81"
}, },
{ {
"type" : "BLOCK_MAGIC_ABOVE", "type" : "BLOCK_MAGIC_ABOVE",

View File

@@ -294,7 +294,7 @@ void CArtifact::addNewBonus(const std::shared_ptr<Bonus>& b)
{ {
b->source = BonusSource::ARTIFACT; b->source = BonusSource::ARTIFACT;
b->duration = BonusDuration::PERMANENT; b->duration = BonusDuration::PERMANENT;
b->description = getNameTranslated(); b->description.appendName(id);
CBonusSystemNode::addNewBonus(b); CBonusSystemNode::addNewBonus(b);
} }

View File

@@ -94,7 +94,7 @@ void CSkill::addNewBonus(const std::shared_ptr<Bonus> & b, int level)
b->source = BonusSource::SECONDARY_SKILL; b->source = BonusSource::SECONDARY_SKILL;
b->sid = BonusSourceID(id); b->sid = BonusSourceID(id);
b->duration = BonusDuration::PERMANENT; b->duration = BonusDuration::PERMANENT;
b->description = getNameTranslated(); b->description.appendTextID(getNameTextID());
levels[level-1].effects.push_back(b); levels[level-1].effects.push_back(b);
} }

View File

@@ -575,20 +575,9 @@ std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, BonusType ty
std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, BonusType type, int val, BonusSubtypeID subtype, const TPropagatorPtr & prop) const std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, BonusType type, int val, BonusSubtypeID subtype, const TPropagatorPtr & prop) const
{ {
std::ostringstream descr; auto b = std::make_shared<Bonus>(BonusDuration::PERMANENT, type, BonusSource::TOWN_STRUCTURE, val, build->getUniqueTypeID(), subtype);
descr << build->getNameTranslated();
return createBonusImpl(build->bid, build->town->faction->getId(), type, val, prop, descr.str(), subtype);
}
std::shared_ptr<Bonus> CTownHandler::createBonusImpl(const BuildingID & building, b->description.appendTextID(build->getNameTextID());
const FactionID & faction,
BonusType type,
int val,
const TPropagatorPtr & prop,
const std::string & description,
BonusSubtypeID subtype) const
{
auto b = std::make_shared<Bonus>(BonusDuration::PERMANENT, type, BonusSource::TOWN_STRUCTURE, val, BuildingTypeUniqueID(faction, building), subtype, description);
if(prop) if(prop)
b->addPropagator(prop); b->addPropagator(prop);
@@ -600,12 +589,13 @@ void CTownHandler::loadSpecialBuildingBonuses(const JsonNode & source, BonusList
{ {
for(const auto & b : source.Vector()) for(const auto & b : source.Vector())
{ {
auto bonus = JsonUtils::parseBuildingBonus(b, building->town->faction->getId(), building->bid, building->getNameTranslated()); auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::NONE, BonusSource::TOWN_STRUCTURE, 0, BonusSourceID(building->getUniqueTypeID()));
if(bonus == nullptr) if(!JsonUtils::parseBonus(b, bonus.get()))
continue; continue;
bonus->sid = BonusSourceID(building->getUniqueTypeID()); bonus->description.appendTextID(building->getNameTextID());
//JsonUtils::parseBuildingBonus produces UNKNOWN type propagator instead of empty. //JsonUtils::parseBuildingBonus produces UNKNOWN type propagator instead of empty.
if(bonus->propagator != nullptr if(bonus->propagator != nullptr
&& bonus->propagator->getPropagatorType() == CBonusSystemNode::ENodeTypes::UNKNOWN) && bonus->propagator->getPropagatorType() == CBonusSystemNode::ENodeTypes::UNKNOWN)

View File

@@ -303,13 +303,6 @@ class DLL_LINKAGE CTownHandler : public CHandlerBase<FactionID, Faction, CFactio
std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val) const; std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val) const;
std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val, BonusSubtypeID subtype) const; std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val, BonusSubtypeID subtype) const;
std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val, BonusSubtypeID subtype, const TPropagatorPtr & prop) const; std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val, BonusSubtypeID subtype, const TPropagatorPtr & prop) const;
std::shared_ptr<Bonus> createBonusImpl(const BuildingID & building,
const FactionID & faction,
BonusType type,
int val,
const TPropagatorPtr & prop,
const std::string & description,
BonusSubtypeID subtype) const;
/// loads CStructure's into town /// loads CStructure's into town
void loadStructure(CTown & town, const std::string & stringID, const JsonNode & source) const; void loadStructure(CTown & town, const std::string & stringID, const JsonNode & source) const;

View File

@@ -917,8 +917,7 @@ void BattleInfo::removeUnitBonus(uint32_t id, const std::vector<Bonus> & bonus)
&& one.sid == b->sid && one.sid == b->sid
&& one.valType == b->valType && one.valType == b->valType
&& one.additionalInfo == b->additionalInfo && one.additionalInfo == b->additionalInfo
&& one.effectRange == b->effectRange && one.effectRange == b->effectRange;
&& one.description == b->description;
}; };
sta->removeBonusesRecursive(selector); sta->removeBonusesRecursive(selector);
} }

View File

@@ -90,7 +90,7 @@ JsonNode CAddInfo::toJsonNode() const
} }
std::string Bonus::Description(std::optional<si32> customValue) const std::string Bonus::Description(std::optional<si32> customValue) const
{ {
std::string str; MetaString descriptionHelper;
if(description.empty()) if(description.empty())
{ {
@@ -99,42 +99,43 @@ std::string Bonus::Description(std::optional<si32> customValue) const
switch(source) switch(source)
{ {
case BonusSource::ARTIFACT: case BonusSource::ARTIFACT:
str = sid.as<ArtifactID>().toEntity(VLC)->getNameTranslated(); descriptionHelper.appendName(sid.as<ArtifactID>());
break; break;
case BonusSource::SPELL_EFFECT: case BonusSource::SPELL_EFFECT:
str = sid.as<SpellID>().toEntity(VLC)->getNameTranslated(); descriptionHelper.appendName(sid.as<SpellID>());
break; break;
case BonusSource::CREATURE_ABILITY: case BonusSource::CREATURE_ABILITY:
str = sid.as<CreatureID>().toEntity(VLC)->getNamePluralTranslated(); descriptionHelper.appendNamePlural(sid.as<CreatureID>());
break; break;
case BonusSource::SECONDARY_SKILL: case BonusSource::SECONDARY_SKILL:
str = VLC->skills()->getById(sid.as<SecondarySkill>())->getNameTranslated(); descriptionHelper.appendTextID(sid.as<SecondarySkill>().toEntity(VLC)->getNameTextID());
break; break;
case BonusSource::HERO_SPECIAL: case BonusSource::HERO_SPECIAL:
str = VLC->heroTypes()->getById(sid.as<HeroTypeID>())->getNameTranslated(); descriptionHelper.appendTextID(sid.as<HeroTypeID>().toEntity(VLC)->getNameTextID());
break; break;
default: default:
//todo: handle all possible sources //todo: handle all possible sources
str = "Unknown"; descriptionHelper.appendRawString("Unknown");
break; break;
} }
} }
else else
str = stacking; descriptionHelper = MetaString::createFromRawString(stacking);
} }
else else
{ {
str = description; descriptionHelper = description;
} }
if(auto value = customValue.value_or(val)) { auto valueToShow = customValue.value_or(val);
//arraytxt already contains +-value
std::string valueString = boost::str(boost::format(" %+d") % value); if(valueToShow != 0)
if(!boost::algorithm::ends_with(str, valueString)) {
str += valueString; descriptionHelper.replaceNumber(valueToShow);
descriptionHelper.replacePositiveNumber(valueToShow);
} }
return str; return descriptionHelper.toString();
} }
static JsonNode additionalInfoToJson(BonusType type, CAddInfo addInfo) static JsonNode additionalInfoToJson(BonusType type, CAddInfo addInfo)
@@ -170,7 +171,7 @@ JsonNode Bonus::toJsonNode() const
if(!stacking.empty()) if(!stacking.empty())
root["stacking"].String() = stacking; root["stacking"].String() = stacking;
if(!description.empty()) if(!description.empty())
root["description"].String() = description; root["description"].String() = description.toString();
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)
@@ -187,27 +188,17 @@ JsonNode Bonus::toJsonNode() const
} }
Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID ID) Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID ID)
: Bonus(Duration, Type, Src, Val, ID, BonusSubtypeID(), std::string()) : Bonus(Duration, Type, Src, Val, ID, BonusSubtypeID())
{} {}
Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID ID, std::string Desc) Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID ID, BonusSubtypeID Subtype):
: Bonus(Duration, Type, Src, Val, ID, BonusSubtypeID(), Desc)
{}
Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID ID, BonusSubtypeID Subtype)
: Bonus(Duration, Type, Src, Val, ID, Subtype, std::string())
{}
Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID ID, BonusSubtypeID Subtype, std::string Desc):
duration(Duration), duration(Duration),
type(Type), type(Type),
subtype(Subtype), subtype(Subtype),
source(Src), source(Src),
val(Val), val(Val),
sid(ID), sid(ID)
description(std::move(Desc))
{ {
boost::algorithm::trim(description);
targetSourceType = BonusSource::OTHER; targetSourceType = BonusSource::OTHER;
} }

View File

@@ -13,6 +13,7 @@
#include "BonusCustomTypes.h" #include "BonusCustomTypes.h"
#include "../constants/VariantIdentifier.h" #include "../constants/VariantIdentifier.h"
#include "../constants/EntityIdentifiers.h" #include "../constants/EntityIdentifiers.h"
#include "../MetaString.h"
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
@@ -77,15 +78,15 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
TUpdaterPtr updater; TUpdaterPtr updater;
TUpdaterPtr propagationUpdater; TUpdaterPtr propagationUpdater;
std::string description; MetaString description;
Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID sourceID); Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID sourceID);
Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID sourceID, std::string Desc);
Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID sourceID, BonusSubtypeID subtype); Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID sourceID, BonusSubtypeID subtype);
Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID sourceID, BonusSubtypeID subtype, std::string Desc);
Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID sourceID, BonusSubtypeID subtype, BonusValueType ValType); Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID sourceID, BonusSubtypeID subtype, BonusValueType ValType);
Bonus() = default; Bonus() = default;
public:
template <typename Handler> void serialize(Handler &h) template <typename Handler> void serialize(Handler &h)
{ {
h & duration; h & duration;

View File

@@ -625,19 +625,6 @@ std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonNode &ability)
return b; return b;
} }
std::shared_ptr<Bonus> JsonUtils::parseBuildingBonus(const JsonNode & ability, const FactionID & faction, const BuildingID & building, const std::string & description)
{
/* duration = BonusDuration::PERMANENT
source = BonusSource::TOWN_STRUCTURE
bonusType, val, subtype - get from json
*/
auto b = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::NONE, BonusSource::TOWN_STRUCTURE, 0, BuildingTypeUniqueID(faction, building), description);
if(!parseBonus(ability, b.get()))
return nullptr;
return b;
}
bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b) bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
{ {
const JsonNode * value = nullptr; const JsonNode * value = nullptr;
@@ -682,9 +669,9 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
if(!ability["description"].isNull()) if(!ability["description"].isNull())
{ {
if (ability["description"].isString()) if (ability["description"].isString())
b->description = ability["description"].String(); b->description.appendTextID(ability["description"].String());
if (ability["description"].isNumber()) if (ability["description"].isNumber())
b->description = VLC->generaltexth->translate("core.arraytxt", ability["description"].Integer()); b->description.appendTextID("core.arraytxt." + std::to_string(ability["description"].Integer()));
} }
value = &ability["effectRange"]; value = &ability["effectRange"];

View File

@@ -23,7 +23,6 @@ namespace JsonUtils
{ {
std::shared_ptr<Bonus> parseBonus(const JsonVector & ability_vec); std::shared_ptr<Bonus> parseBonus(const JsonVector & ability_vec);
std::shared_ptr<Bonus> parseBonus(const JsonNode & ability); std::shared_ptr<Bonus> parseBonus(const JsonNode & ability);
std::shared_ptr<Bonus> parseBuildingBonus(const JsonNode & ability, const FactionID & faction, const BuildingID & building, const std::string & description);
bool parseBonus(const JsonNode & ability, Bonus * placement); bool parseBonus(const JsonNode & ability, Bonus * placement);
std::shared_ptr<ILimiter> parseLimiter(const JsonNode & limiter); std::shared_ptr<ILimiter> parseLimiter(const JsonNode & limiter);
CSelector parseSelector(const JsonNode &ability); CSelector parseSelector(const JsonNode &ability);

View File

@@ -101,28 +101,22 @@ void CArmedInstance::updateMoraleBonusFromArmy()
factionsInArmy -= mixableFactions - 1; factionsInArmy -= mixableFactions - 1;
} }
std::string description; MetaString bonusDescription;
if(factionsInArmy == 1) if(factionsInArmy == 1)
{ {
b->val = +1; b->val = +1;
description = VLC->generaltexth->arraytxt[115]; //All troops of one alignment +1 bonusDescription.appendTextID("core.arraytxt.115"); //All troops of one alignment +1
description = description.substr(0, description.size()-3);//trim "+1"
} }
else if (!factions.empty()) // no bonus from empty garrison else if (!factions.empty()) // no bonus from empty garrison
{ {
b->val = 2 - static_cast<si32>(factionsInArmy); b->val = 2 - static_cast<si32>(factionsInArmy);
MetaString formatter; bonusDescription.appendTextID("core.arraytxt.114"); //Troops of %d alignments %d
formatter.appendTextID("core.arraytxt.114"); //Troops of %d alignments %d bonusDescription.replaceNumber(factionsInArmy);
formatter.replaceNumber(factionsInArmy); bonusDescription.replaceNumber(b->val);
formatter.replaceNumber(b->val);
description = formatter.toString();
description = description.substr(0, description.size()-3);//trim value
} }
boost::algorithm::trim(description); b->description = bonusDescription;
b->description = description;
CBonusSystemNode::treeHasChanged(); CBonusSystemNode::treeHasChanged();
@@ -132,8 +126,8 @@ void CArmedInstance::updateMoraleBonusFromArmy()
{ {
if(!undeadModifier) if(!undeadModifier)
{ {
undeadModifier = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::MORALE, BonusSource::ARMY, -1, BonusCustomSource::undeadMoraleDebuff, VLC->generaltexth->arraytxt[116]); undeadModifier = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::MORALE, BonusSource::ARMY, -1, BonusCustomSource::undeadMoraleDebuff);
undeadModifier->description = undeadModifier->description.substr(0, undeadModifier->description.size()-2);//trim value undeadModifier->description.appendTextID("core.arraytxt.116");
addNewBonus(undeadModifier); addNewBonus(undeadModifier);
} }
} }

View File

@@ -225,15 +225,15 @@ void CBank::doVisit(const CGHeroInstance * hero) const
{ {
case Obj::SHIPWRECK: case Obj::SHIPWRECK:
textID = 123; textID = 123;
gbonus.bdescr.appendRawString(VLC->generaltexth->arraytxt[99]); gbonus.bonus.description.appendRawString(VLC->generaltexth->arraytxt[99]);
break; break;
case Obj::DERELICT_SHIP: case Obj::DERELICT_SHIP:
textID = 42; textID = 42;
gbonus.bdescr.appendRawString(VLC->generaltexth->arraytxt[101]); gbonus.bonus.description.appendRawString(VLC->generaltexth->arraytxt[101]);
break; break;
case Obj::CRYPT: case Obj::CRYPT:
textID = 120; textID = 120;
gbonus.bdescr.appendRawString(VLC->generaltexth->arraytxt[98]); gbonus.bonus.description.appendRawString(VLC->generaltexth->arraytxt[98]);
break; break;
} }
cb->giveHeroBonus(&gbonus); cb->giveHeroBonus(&gbonus);
@@ -244,7 +244,8 @@ void CBank::doVisit(const CGHeroInstance * hero) const
case Obj::PYRAMID: case Obj::PYRAMID:
{ {
GiveBonus gb; GiveBonus gb;
gb.bonus = Bonus(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, -2, BonusSourceID(id), VLC->generaltexth->arraytxt[70]); gb.bonus = Bonus(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, -2, BonusSourceID(id));
gb.bonus.description.appendTextID("core.arraytxt.70");
gb.id = hero->id; gb.id = hero->id;
cb->giveHeroBonus(&gb); cb->giveHeroBonus(&gb);
textID = 107; textID = 107;

View File

@@ -98,27 +98,33 @@ std::string CGTownBuilding::getCustomBonusGreeting(const Bonus & bonus) const
{ {
if(bonus.type == BonusType::TOWN_MAGIC_WELL) if(bonus.type == BonusType::TOWN_MAGIC_WELL)
{ {
auto bonusGreeting = std::string(VLC->generaltexth->translate("vcmi.townHall.greetingInTownMagicWell")); MetaString wellGreeting = MetaString::createFromTextID("vcmi.townHall.greetingInTownMagicWell");
auto buildingName = town->getTown()->getSpecialBuilding(bType)->getNameTranslated();
boost::algorithm::replace_first(bonusGreeting, "%s", buildingName); wellGreeting.replaceTextID(town->getTown()->getSpecialBuilding(bType)->getNameTextID());
return bonusGreeting; return wellGreeting.toString();
} }
auto bonusGreeting = std::string(VLC->generaltexth->translate("vcmi.townHall.greetingCustomBonus")); //"%s gives you +%d %s%s"
std::string param; MetaString greeting = MetaString::createFromTextID("vcmi.townHall.greetingCustomBonus");
std::string paramTextID;
std::string until; std::string until;
if(bonus.type == BonusType::MORALE) if(bonus.type == BonusType::MORALE)
param = VLC->generaltexth->allTexts[384]; paramTextID = "core.genrltxt.384"; // Morale
else if(bonus.type == BonusType::LUCK)
param = VLC->generaltexth->allTexts[385];
until = bonus.duration == BonusDuration::ONE_BATTLE if(bonus.type == BonusType::LUCK)
? VLC->generaltexth->translate("vcmi.townHall.greetingCustomUntil") paramTextID = "core.genrltxt.385"; // Luck
: ".";
boost::format fmt = boost::format(bonusGreeting) % bonus.description % bonus.val % param % until; // greeting.replaceTextID(bonus.descriptionTextID);
std::string greeting = fmt.str(); greeting.replaceNumber(bonus.val);
return greeting; greeting.replaceTextID(paramTextID);
if (bonus.duration == BonusDuration::ONE_BATTLE)
greeting.replaceTextID("vcmi.townHall.greetingCustomUntil");
else
greeting.replaceRawString(".");
return greeting.toString();
} }
COPWBonus::COPWBonus(IGameCallback *cb) COPWBonus::COPWBonus(IGameCallback *cb)
@@ -160,7 +166,7 @@ void COPWBonus::onHeroVisit (const CGHeroInstance * h) const
if(!h->hasBonusFrom(BonusSource::OBJECT_TYPE, BonusSourceID(Obj(Obj::STABLES)))) //does not stack with advMap Stables if(!h->hasBonusFrom(BonusSource::OBJECT_TYPE, BonusSourceID(Obj(Obj::STABLES)))) //does not stack with advMap Stables
{ {
GiveBonus gb; GiveBonus gb;
gb.bonus = Bonus(BonusDuration::ONE_WEEK, BonusType::MOVEMENT, BonusSource::OBJECT_TYPE, 600, BonusSourceID(Obj(Obj::STABLES)), BonusCustomSubtype::heroMovementLand, VLC->generaltexth->arraytxt[100]); gb.bonus = Bonus(BonusDuration::ONE_WEEK, BonusType::MOVEMENT, BonusSource::OBJECT_TYPE, 600, BonusSourceID(Obj(Obj::STABLES)), BonusCustomSubtype::heroMovementLand);
gb.id = heroID; gb.id = heroID;
cb->giveHeroBonus(&gb); cb->giveHeroBonus(&gb);

View File

@@ -1005,30 +1005,26 @@ void GiveBonus::applyGs(CGameState *gs)
auto b = std::make_shared<Bonus>(bonus); auto b = std::make_shared<Bonus>(bonus);
cbsn->addNewBonus(b); cbsn->addNewBonus(b);
std::string &descr = b->description;
if(!bdescr.empty()) if(b->description.empty())
{ {
descr = bdescr.toString(); if((bonus.type == BonusType::LUCK || bonus.type == BonusType::MORALE)
}
else if(!descr.empty())
{
//use preseet description
}
else if((bonus.type == BonusType::LUCK || bonus.type == BonusType::MORALE)
&& (bonus.source == BonusSource::OBJECT_TYPE || bonus.source == BonusSource::OBJECT_INSTANCE)) && (bonus.source == BonusSource::OBJECT_TYPE || bonus.source == BonusSource::OBJECT_INSTANCE))
{ {
//no description, use generic
//?could use allways when Type == BonusDuration::Type::ONE_BATTLE //?could use allways when Type == BonusDuration::Type::ONE_BATTLE
descr = VLC->generaltexth->arraytxt[bonus.val > 0 ? 110 : 109]; //+/-%d Temporary until next battle" if (bonus.val > 0)
b->description.appendTextID("core.arraytxt.110"); //+%d Temporary until next battle"
else
b->description.appendTextID("core.arraytxt.109"); //-%d Temporary until next battle"
} }
else else
{ {
logGlobal->debug("Empty bonus decription. Type=%d", (int) bonus.type); logGlobal->debug("Empty bonus decription. Type=%d", (int) bonus.type);
} }
}
// Some of(?) versions of H3 use " %s" here instead of %d. Try to replace both of them // Some of(?) versions of H3 use " %s" here instead of %d. Try to replace both of them
boost::replace_first(descr, "%d", std::to_string(std::abs(bonus.val))); // " +/-%d Temporary until next battle //boost::replace_first(descr, "%d", std::to_string(std::abs(bonus.val))); // " +/-%d Temporary until next battle
boost::replace_first(descr, " %s", boost::str(boost::format(" %+d") % bonus.val)); // " %s" in arraytxt.69, fountian of fortune //boost::replace_first(descr, " %s", boost::str(boost::format(" %+d") % bonus.val)); // " %s" in arraytxt.69, fountian of fortune
} }
void ChangeObjPos::applyGs(CGameState *gs) void ChangeObjPos::applyGs(CGameState *gs)

View File

@@ -382,7 +382,6 @@ struct DLL_LINKAGE GiveBonus : public CPackForClient
ETarget who = ETarget::OBJECT; ETarget who = ETarget::OBJECT;
VariantIdentifier<ObjectInstanceID, PlayerColor, BattleID> id; VariantIdentifier<ObjectInstanceID, PlayerColor, BattleID> id;
Bonus bonus; Bonus bonus;
MetaString bdescr;
void visitTyped(ICPackVisitor & visitor) override; void visitTyped(ICPackVisitor & visitor) override;
@@ -390,7 +389,6 @@ struct DLL_LINKAGE GiveBonus : public CPackForClient
{ {
h & bonus; h & bonus;
h & id; h & id;
h & bdescr;
h & who; h & who;
assert(id.getNum() != -1); assert(id.getNum() != -1);
} }

View File

@@ -207,8 +207,7 @@ void JsonUpdater::serializeBonuses(const std::string & fieldName, CBonusSystemNo
&& mask->sid == b->sid && mask->sid == b->sid
&& mask->valType == b->valType && mask->valType == b->valType
&& mask->additionalInfo == b->additionalInfo && mask->additionalInfo == b->additionalInfo
&& mask->effectRange == b->effectRange && mask->effectRange == b->effectRange;
&& mask->description == b->description;
}; };
value->removeBonuses(selector); value->removeBonuses(selector);

View File

@@ -32,9 +32,9 @@ BonusCaster::~BonusCaster() = default;
void BonusCaster::getCasterName(MetaString & text) const void BonusCaster::getCasterName(MetaString & text) const
{ {
if(!bonus->description.empty()) // if(!bonus->descriptionTextID.empty())
text.replaceRawString(bonus->description); // text.replaceTextID(bonus->descriptionTextID);
else // else
actualCaster->getCasterName(text); actualCaster->getCasterName(text);
} }

View File

@@ -33,8 +33,7 @@ bool operator==(const Bonus & b1, const Bonus & b2)
&& b1.sid == b2.sid && b1.sid == b2.sid
&& b1.valType == b2.valType && b1.valType == b2.valType
&& b1.additionalInfo == b2.additionalInfo && b1.additionalInfo == b2.additionalInfo
&& b1.effectRange == b2.effectRange && b1.effectRange == b2.effectRange;
&& b1.description == b2.description;
} }
namespace test namespace test