1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-21 00:19:29 +02:00

Use bonus only as shared_ptr to avoid memory corruption

This commit is contained in:
Ivan Savenko
2025-06-16 16:22:21 +03:00
parent 4044e03c0a
commit 463c404a83
19 changed files with 62 additions and 67 deletions

View File

@ -142,15 +142,10 @@ std::shared_ptr<CArtifact> CArtHandler::loadFromJson(const std::string & scope,
if(!node["growing"].isNull()) if(!node["growing"].isNull())
{ {
for(auto bonus : node["growing"]["bonusesPerLevel"].Vector()) for(auto bonus : node["growing"]["bonusesPerLevel"].Vector())
{ art->bonusesPerLevel.emplace_back(static_cast<ui16>(bonus["level"].Float()), JsonUtils::parseBonus(bonus["bonus"]));
art->bonusesPerLevel.emplace_back(static_cast<ui16>(bonus["level"].Float()), Bonus());
JsonUtils::parseBonus(bonus["bonus"], &art->bonusesPerLevel.back().second);
}
for(auto bonus : node["growing"]["thresholdBonuses"].Vector()) for(auto bonus : node["growing"]["thresholdBonuses"].Vector())
{ art->thresholdBonuses.emplace_back(static_cast<ui16>(bonus["level"].Float()), JsonUtils::parseBonus(bonus["bonus"]));
art->thresholdBonuses.emplace_back(static_cast<ui16>(bonus["level"].Float()), Bonus());
JsonUtils::parseBonus(bonus["bonus"], &art->thresholdBonuses.back().second);
}
} }
art->id = ArtifactID(index); art->id = ArtifactID(index);

View File

@ -59,22 +59,22 @@ bool CGrowingArtifact::isGrowing() const
return !bonusesPerLevel.empty() || !thresholdBonuses.empty(); return !bonusesPerLevel.empty() || !thresholdBonuses.empty();
} }
std::vector <std::pair<ui16, Bonus>> & CGrowingArtifact::getBonusesPerLevel() std::vector <std::pair<ui16, std::shared_ptr<Bonus>>> & CGrowingArtifact::getBonusesPerLevel()
{ {
return bonusesPerLevel; return bonusesPerLevel;
} }
const std::vector <std::pair<ui16, Bonus>> & CGrowingArtifact::getBonusesPerLevel() const const std::vector <std::pair<ui16, std::shared_ptr<Bonus>>> & CGrowingArtifact::getBonusesPerLevel() const
{ {
return bonusesPerLevel; return bonusesPerLevel;
} }
std::vector <std::pair<ui16, Bonus>> & CGrowingArtifact::getThresholdBonuses() std::vector <std::pair<ui16, std::shared_ptr<Bonus>>> & CGrowingArtifact::getThresholdBonuses()
{ {
return thresholdBonuses; return thresholdBonuses;
} }
const std::vector <std::pair<ui16, Bonus>> & CGrowingArtifact::getThresholdBonuses() const const std::vector <std::pair<ui16, std::shared_ptr<Bonus>>> & CGrowingArtifact::getThresholdBonuses() const
{ {
return thresholdBonuses; return thresholdBonuses;
} }

View File

@ -54,15 +54,15 @@ class DLL_LINKAGE CGrowingArtifact
protected: protected:
CGrowingArtifact() = default; CGrowingArtifact() = default;
std::vector<std::pair<ui16, Bonus>> bonusesPerLevel; // Bonus given each n levels std::vector<std::pair<ui16, std::shared_ptr<Bonus>>> bonusesPerLevel; // Bonus given each n levels
std::vector<std::pair<ui16, Bonus>> thresholdBonuses; // After certain level they will be added once std::vector<std::pair<ui16, std::shared_ptr<Bonus>>> thresholdBonuses; // After certain level they will be added once
public: public:
bool isGrowing() const; bool isGrowing() const;
std::vector<std::pair<ui16, Bonus>> & getBonusesPerLevel(); std::vector<std::pair<ui16, std::shared_ptr<Bonus>>> & getBonusesPerLevel();
const std::vector<std::pair<ui16, Bonus>> & getBonusesPerLevel() const; const std::vector<std::pair<ui16, std::shared_ptr<Bonus>>> & getBonusesPerLevel() const;
std::vector<std::pair<ui16, Bonus>> & getThresholdBonuses(); std::vector<std::pair<ui16, std::shared_ptr<Bonus>>> & getThresholdBonuses();
const std::vector<std::pair<ui16, Bonus>> & getThresholdBonuses() const; const std::vector<std::pair<ui16, std::shared_ptr<Bonus>>> & getThresholdBonuses() const;
}; };
class DLL_LINKAGE CChargedArtifact class DLL_LINKAGE CChargedArtifact

View File

@ -109,7 +109,7 @@ void CGrowingArtifactInstance::growingUp()
// Every n levels // Every n levels
if(artInst->valOfBonuses(BonusType::ARTIFACT_GROWING) % bonus.first == 0) if(artInst->valOfBonuses(BonusType::ARTIFACT_GROWING) % bonus.first == 0)
{ {
artInst->accumulateBonus(std::make_shared<Bonus>(bonus.second)); artInst->accumulateBonus(std::make_shared<Bonus>(*bonus.second));
} }
} }
for(const auto & bonus : artType->getThresholdBonuses()) for(const auto & bonus : artType->getThresholdBonuses())
@ -117,7 +117,7 @@ void CGrowingArtifactInstance::growingUp()
// At n level // At n level
if(artInst->valOfBonuses(BonusType::ARTIFACT_GROWING) == bonus.first) if(artInst->valOfBonuses(BonusType::ARTIFACT_GROWING) == bonus.first)
{ {
artInst->addNewBonus(std::make_shared<Bonus>(bonus.second)); artInst->addNewBonus(std::make_shared<Bonus>(*bonus.second));
} }
} }

View File

@ -580,13 +580,13 @@ JsonRandom::JsonRandom(IGameInfoCallback * cb, IGameRandomizer & gameRandomizer)
return ret; return ret;
} }
std::vector<Bonus> JsonRandom::loadBonuses(const JsonNode & value) std::vector<std::shared_ptr<Bonus>> JsonRandom::loadBonuses(const JsonNode & value)
{ {
std::vector<Bonus> ret; std::vector<std::shared_ptr<Bonus>> ret;
for (const JsonNode & entry : value.Vector()) for (const JsonNode & entry : value.Vector())
{ {
if(auto bonus = JsonUtils::parseBonus(entry)) if(auto bonus = JsonUtils::parseBonus(entry))
ret.push_back(*bonus); ret.push_back(bonus);
} }
return ret; return ret;
} }

View File

@ -91,7 +91,7 @@ public:
std::vector<HeroTypeID> loadHeroes(const JsonNode & value); std::vector<HeroTypeID> loadHeroes(const JsonNode & value);
std::vector<HeroClassID> loadHeroClasses(const JsonNode & value); std::vector<HeroClassID> loadHeroClasses(const JsonNode & value);
static std::vector<Bonus> loadBonuses(const JsonNode & value); static std::vector<std::shared_ptr<Bonus>> loadBonuses(const JsonNode & value);
}; };
VCMI_LIB_NAMESPACE_END VCMI_LIB_NAMESPACE_END

View File

@ -46,12 +46,12 @@ std::shared_ptr<CGObjectInstance> CRewardableConstructor::create(IGameInfoCallba
return ret; return ret;
} }
void CRewardableConstructor::assignBonuses(std::vector<Bonus> & bonuses, MapObjectID objectID) const void CRewardableConstructor::assignBonuses(std::vector<std::shared_ptr<Bonus>> & bonuses, MapObjectID objectID) const
{ {
for (auto & bonus : bonuses) for (auto & bonus : bonuses)
{ {
bonus.source = BonusSource::OBJECT_TYPE; bonus->source = BonusSource::OBJECT_TYPE;
bonus.sid = BonusSourceID(objectID); bonus->sid = BonusSourceID(objectID);
} }
} }

View File

@ -20,7 +20,7 @@ class DLL_LINKAGE CRewardableConstructor : public AObjectTypeHandler
{ {
Rewardable::Info objectInfo; Rewardable::Info objectInfo;
void assignBonuses(std::vector<Bonus> & bonuses, MapObjectID objectID) const; void assignBonuses(std::vector<std::shared_ptr<Bonus>> & bonuses, MapObjectID objectID) const;
void initTypeData(const JsonNode & config) override; void initTypeData(const JsonNode & config) override;
bool blockVisit = false; bool blockVisit = false;

View File

@ -269,7 +269,7 @@ void BoatInstanceConstructor::initializeObject(CGBoat * boat) const
boat->onboardAssaultAllowed = onboardAssaultAllowed; boat->onboardAssaultAllowed = onboardAssaultAllowed;
boat->onboardVisitAllowed = onboardVisitAllowed; boat->onboardVisitAllowed = onboardVisitAllowed;
for(auto & b : bonuses) for(auto & b : bonuses)
boat->addNewBonus(std::make_shared<Bonus>(b)); boat->addNewBonus(b);
} }
AnimationPath BoatInstanceConstructor::getBoatAnimationName() const AnimationPath BoatInstanceConstructor::getBoatAnimationName() const

View File

@ -110,7 +110,7 @@ class DLL_LINKAGE BoatInstanceConstructor : public CDefaultObjectTypeHandler<CGB
protected: protected:
void initTypeData(const JsonNode & config) override; void initTypeData(const JsonNode & config) override;
std::vector<Bonus> bonuses; std::vector<std::shared_ptr<Bonus>> bonuses;
EPathfindingLayer layer; EPathfindingLayer layer;
bool onboardAssaultAllowed; //if true, hero can attack units from transport bool onboardAssaultAllowed; //if true, hero can attack units from transport
bool onboardVisitAllowed; //if true, hero can visit objects from transport bool onboardVisitAllowed; //if true, hero can visit objects from transport

View File

@ -109,10 +109,10 @@ void CGPandoraBox::grantRewardWithMessage(IGameEventCallback & gameEvents, const
for(auto b : vi.reward.heroBonuses) for(auto b : vi.reward.heroBonuses)
{ {
if(b.val && b.type == BonusType::MORALE) if(b->val && b->type == BonusType::MORALE)
txt = setText(b.val > 0, 179, 178, h); txt = setText(b->val > 0, 179, 178, h);
if(b.val && b.type == BonusType::LUCK) if(b->val && b->type == BonusType::LUCK)
txt = setText(b.val > 0, 181, 180, h); txt = setText(b->val > 0, 181, 180, h);
} }
sendInfoWindow(txt, temp); sendInfoWindow(txt, temp);
@ -229,11 +229,11 @@ void CGPandoraBox::serializeJsonOptions(JsonSerializeFormat & handler)
int val = 0; int val = 0;
handler.serializeInt("morale", val, 0); handler.serializeInt("morale", val, 0);
if(val) if(val)
vinfo.reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id)); vinfo.reward.heroBonuses.push_back(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id)));
handler.serializeInt("luck", val, 0); handler.serializeInt("luck", val, 0);
if(val) if(val)
vinfo.reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id)); vinfo.reward.heroBonuses.push_back(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id)));
vinfo.reward.resources.serializeJson(handler, "resources"); vinfo.reward.resources.serializeJson(handler, "resources");
{ {

View File

@ -703,9 +703,9 @@ void CGSeerHut::serializeJsonOptions(JsonSerializeFormat & handler)
if(metaTypeName == "mana") if(metaTypeName == "mana")
reward.manaDiff = val; reward.manaDiff = val;
if(metaTypeName == "morale") if(metaTypeName == "morale")
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id)); reward.heroBonuses.push_back(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id)));
if(metaTypeName == "luck") if(metaTypeName == "luck")
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id)); reward.heroBonuses.push_back(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id)));
if(metaTypeName == "resource") if(metaTypeName == "resource")
{ {
auto rawId = *LIBRARY->identifiers()->getIdentifier(ModScope::scopeMap(), fullIdentifier, false); auto rawId = *LIBRARY->identifiers()->getIdentifier(ModScope::scopeMap(), fullIdentifier, false);

View File

@ -73,7 +73,7 @@ TownRewardableBuildingInstance::TownRewardableBuildingInstance(CGTownInstance *
configuration = generateConfiguration(gameRandomizer); configuration = generateConfiguration(gameRandomizer);
} }
void TownRewardableBuildingInstance::assignBonuses(std::vector<Bonus> & bonuses) const void TownRewardableBuildingInstance::assignBonuses(std::vector<std::shared_ptr<Bonus>> & bonuses) const
{ {
const auto & building = town->getTown()->buildings.at(getBuildingType()); const auto & building = town->getTown()->buildings.at(getBuildingType());
@ -81,13 +81,13 @@ void TownRewardableBuildingInstance::assignBonuses(std::vector<Bonus> & bonuses)
{ {
if (building->mapObjectLikeBonuses.hasValue()) if (building->mapObjectLikeBonuses.hasValue())
{ {
bonus.source = BonusSource::OBJECT_TYPE; bonus->source = BonusSource::OBJECT_TYPE;
bonus.sid = BonusSourceID(building->mapObjectLikeBonuses); bonus->sid = BonusSourceID(building->mapObjectLikeBonuses);
} }
else else
{ {
bonus.source = BonusSource::TOWN_STRUCTURE; bonus->source = BonusSource::TOWN_STRUCTURE;
bonus.sid = BonusSourceID(building->getUniqueTypeID()); bonus->sid = BonusSourceID(building->getUniqueTypeID());
} }
} }
} }

View File

@ -58,7 +58,7 @@ class DLL_LINKAGE TownRewardableBuildingInstance : public TownBuildingInstance,
bool wasVisitedBefore(const CGHeroInstance * contextHero) const override; bool wasVisitedBefore(const CGHeroInstance * contextHero) const override;
void grantReward(IGameEventCallback & gameEvents, ui32 rewardID, const CGHeroInstance * hero) const override; void grantReward(IGameEventCallback & gameEvents, ui32 rewardID, const CGHeroInstance * hero) const override;
Rewardable::Configuration generateConfiguration(IGameRandomizer & gameRandomizer) const; Rewardable::Configuration generateConfiguration(IGameRandomizer & gameRandomizer) const;
void assignBonuses(std::vector<Bonus> & bonuses) const; void assignBonuses(std::vector<std::shared_ptr<Bonus>> & bonuses) const;
const IObjectInterface * getObject() const override; const IObjectInterface * getObject() const override;
bool wasVisited(PlayerColor player) const override; bool wasVisited(PlayerColor player) const override;

View File

@ -1083,9 +1083,9 @@ void CMapLoaderH3M::readBoxContent(CGPandoraBox * object, const int3 & mapPositi
reward.heroExperience = reader->readUInt32(); reward.heroExperience = reader->readUInt32();
reward.manaDiff = reader->readInt32(); reward.manaDiff = reader->readInt32();
if(auto val = reader->readInt8Checked(-3, 3)) if(auto val = reader->readInt8Checked(-3, 3))
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(idToBeGiven)); reward.heroBonuses.push_back(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(idToBeGiven)));
if(auto val = reader->readInt8Checked(-3, 3)) if(auto val = reader->readInt8Checked(-3, 3))
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(idToBeGiven)); reward.heroBonuses.push_back(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(idToBeGiven)));
reader->readResources(reward.resources); reader->readResources(reward.resources);
for(int x = 0; x < GameConstants::PRIMARY_SKILLS; ++x) for(int x = 0; x < GameConstants::PRIMARY_SKILLS; ++x)
@ -2275,12 +2275,12 @@ void CMapLoaderH3M::readSeerHutQuest(CGSeerHut * hut, const int3 & position, con
} }
case ESeerHutRewardType::MORALE: case ESeerHutRewardType::MORALE:
{ {
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, reader->readInt8Checked(-3, 3), BonusSourceID(idToBeGiven)); reward.heroBonuses.push_back(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, reader->readInt8Checked(-3, 3), BonusSourceID(idToBeGiven)));
break; break;
} }
case ESeerHutRewardType::LUCK: case ESeerHutRewardType::LUCK:
{ {
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, reader->readInt8Checked(-3, 3), BonusSourceID(idToBeGiven)); reward.heroBonuses.push_back(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, reader->readInt8Checked(-3, 3), BonusSourceID(idToBeGiven)));
break; break;
} }
case ESeerHutRewardType::RESOURCES: case ESeerHutRewardType::RESOURCES:

View File

@ -152,24 +152,24 @@ void Rewardable::Interface::grantRewardAfterLevelup(IGameEventCallback & gameEve
gameEvents.setMovePoints(&smp); gameEvents.setMovePoints(&smp);
} }
for(const Bonus & bonus : info.reward.heroBonuses) for(const auto & bonus : info.reward.heroBonuses)
{ {
GiveBonus gb(GiveBonus::ETarget::OBJECT, hero->id, bonus); GiveBonus gb(GiveBonus::ETarget::OBJECT, hero->id, *bonus);
gameEvents.giveHeroBonus(&gb); gameEvents.giveHeroBonus(&gb);
} }
if (hero->getCommander()) if (hero->getCommander())
{ {
for(const Bonus & bonus : info.reward.commanderBonuses) for(const auto & bonus : info.reward.commanderBonuses)
{ {
GiveBonus gb(GiveBonus::ETarget::HERO_COMMANDER, hero->id, bonus); GiveBonus gb(GiveBonus::ETarget::HERO_COMMANDER, hero->id, *bonus);
gameEvents.giveHeroBonus(&gb); gameEvents.giveHeroBonus(&gb);
} }
} }
for(const Bonus & bonus : info.reward.playerBonuses) for(const auto & bonus : info.reward.playerBonuses)
{ {
GiveBonus gb(GiveBonus::ETarget::PLAYER, hero->getOwner(), bonus); GiveBonus gb(GiveBonus::ETarget::PLAYER, hero->getOwner(), *bonus);
gameEvents.giveHeroBonus(&gb); gameEvents.giveHeroBonus(&gb);
} }

View File

@ -81,10 +81,10 @@ void Rewardable::Reward::loadComponents(std::vector<Component> & comps, const CG
for (auto & bonus : heroBonuses) for (auto & bonus : heroBonuses)
{ {
if (bonus.type == BonusType::MORALE) if (bonus->type == BonusType::MORALE)
comps.emplace_back(ComponentType::MORALE, bonus.val); comps.emplace_back(ComponentType::MORALE, bonus->val);
if (bonus.type == BonusType::LUCK) if (bonus->type == BonusType::LUCK)
comps.emplace_back(ComponentType::LUCK, bonus.val); comps.emplace_back(ComponentType::LUCK, bonus->val);
} }
if (heroExperience) if (heroExperience)

View File

@ -86,9 +86,9 @@ struct DLL_LINKAGE Reward final
std::vector<CStackBasicDescriptor> guards; std::vector<CStackBasicDescriptor> guards;
/// list of bonuses, e.g. morale/luck /// list of bonuses, e.g. morale/luck
std::vector<Bonus> heroBonuses; std::vector<std::shared_ptr<Bonus>> heroBonuses;
std::vector<Bonus> commanderBonuses; std::vector<std::shared_ptr<Bonus>> commanderBonuses;
std::vector<Bonus> playerBonuses; std::vector<std::shared_ptr<Bonus>> playerBonuses;
/// skills that hero may receive or lose /// skills that hero may receive or lose
std::vector<si32> primary; std::vector<si32> primary;

View File

@ -345,7 +345,7 @@ void RewardsWidget::saveCurrentVisitInfo(int index)
auto dur = bonusDurationMap.at(ui->bonuses->item(i, 0)->text().toStdString()); auto dur = bonusDurationMap.at(ui->bonuses->item(i, 0)->text().toStdString());
auto typ = static_cast<BonusType>(*LIBRARY->identifiers()->getIdentifier(ModScope::scopeBuiltin(), "bonus", ui->bonuses->item(i, 1)->text().toStdString())); auto typ = static_cast<BonusType>(*LIBRARY->identifiers()->getIdentifier(ModScope::scopeBuiltin(), "bonus", ui->bonuses->item(i, 1)->text().toStdString()));
auto val = ui->bonuses->item(i, 2)->data(Qt::UserRole).toInt(); 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)); vinfo.reward.heroBonuses.push_back(std::make_shared<Bonus>(dur, typ, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(object.id)));
} }
vinfo.limiter.dayOfWeek = ui->lDayOfWeek->currentIndex(); vinfo.limiter.dayOfWeek = ui->lDayOfWeek->currentIndex();
@ -483,7 +483,7 @@ void RewardsWidget::loadCurrentVisitInfo(int index)
for(auto & i : vinfo.reward.heroBonuses) for(auto & i : vinfo.reward.heroBonuses)
{ {
auto dur = vstd::findKey(bonusDurationMap, i.duration); auto dur = vstd::findKey(bonusDurationMap, i->duration);
for(int i = 0; i < ui->bonusDuration->count(); ++i) for(int i = 0; i < ui->bonusDuration->count(); ++i)
{ {
if(ui->bonusDuration->itemText(i) == QString::fromStdString(dur)) if(ui->bonusDuration->itemText(i) == QString::fromStdString(dur))
@ -493,7 +493,7 @@ void RewardsWidget::loadCurrentVisitInfo(int index)
} }
} }
std::string typ = LIBRARY->bth->bonusToString(i.type); std::string typ = LIBRARY->bth->bonusToString(i->type);
for(int i = 0; i < ui->bonusType->count(); ++i) for(int i = 0; i < ui->bonusType->count(); ++i)
{ {
if(ui->bonusType->itemText(i) == QString::fromStdString(typ)) if(ui->bonusType->itemText(i) == QString::fromStdString(typ))
@ -503,7 +503,7 @@ void RewardsWidget::loadCurrentVisitInfo(int index)
} }
} }
ui->bonusValue->setValue(i.val); ui->bonusValue->setValue(i->val);
on_bonusAdd_clicked(); on_bonusAdd_clicked();
} }
@ -819,8 +819,8 @@ void RewardsDelegate::updateModelData(QAbstractItemModel * model, const QModelIn
QStringList bonusesList; QStringList bonusesList;
for (auto & bonus : vinfo.reward.heroBonuses) for (auto & bonus : vinfo.reward.heroBonuses)
{ {
std::string bonusName = LIBRARY->bth->bonusToString(bonus.type); 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); 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(", ")); textList += QObject::tr("Bonuses: %1").arg(bonusesList.join(", "));
} }