mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-10 22:31:40 +02:00
Add new rewards for configurable objects
This commit is contained in:
@@ -265,9 +265,9 @@ uint64_t RewardEvaluator::getArmyReward(
|
||||
|
||||
auto rewardValue = 0;
|
||||
|
||||
if(!info.reward.artifacts.empty())
|
||||
if(!info.reward.grantedArtifacts.empty())
|
||||
{
|
||||
for(auto artID : info.reward.artifacts)
|
||||
for(auto artID : info.reward.grantedArtifacts)
|
||||
{
|
||||
const auto * art = artID.toArtifact();
|
||||
|
||||
@@ -283,7 +283,7 @@ uint64_t RewardEvaluator::getArmyReward(
|
||||
}
|
||||
}
|
||||
|
||||
totalValue += rewardValue > 0 ? rewardValue / (info.reward.artifacts.size() + info.reward.creatures.size()) : 0;
|
||||
totalValue += rewardValue > 0 ? rewardValue / (info.reward.grantedArtifacts.size() + info.reward.creatures.size()) : 0;
|
||||
}
|
||||
|
||||
return totalValue;
|
||||
|
@@ -47,6 +47,15 @@ std::shared_ptr<CGObjectInstance> CRewardableConstructor::create(IGameCallback *
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CRewardableConstructor::assignBonuses(std::vector<Bonus> & bonuses, MapObjectID objectID) const
|
||||
{
|
||||
for (auto & bonus : bonuses)
|
||||
{
|
||||
bonus.source = BonusSource::OBJECT_TYPE;
|
||||
bonus.sid = BonusSourceID(objectID);
|
||||
}
|
||||
}
|
||||
|
||||
Rewardable::Configuration CRewardableConstructor::generateConfiguration(IGameCallback * cb, vstd::RNG & rand, MapObjectID objectID, const std::map<std::string, JsonNode> & presetVariables) const
|
||||
{
|
||||
Rewardable::Configuration result;
|
||||
@@ -62,11 +71,8 @@ Rewardable::Configuration CRewardableConstructor::generateConfiguration(IGameCal
|
||||
|
||||
for(auto & rewardInfo : result.info)
|
||||
{
|
||||
for (auto & bonus : rewardInfo.reward.bonuses)
|
||||
{
|
||||
bonus.source = BonusSource::OBJECT_TYPE;
|
||||
bonus.sid = BonusSourceID(objectID);
|
||||
}
|
||||
assignBonuses(rewardInfo.reward.heroBonuses, objectID);
|
||||
assignBonuses(rewardInfo.reward.playerBonuses, objectID);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@@ -14,10 +14,13 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct Bonus;
|
||||
|
||||
class DLL_LINKAGE CRewardableConstructor : public AObjectTypeHandler
|
||||
{
|
||||
Rewardable::Info objectInfo;
|
||||
|
||||
void assignBonuses(std::vector<Bonus> & bonuses, MapObjectID objectID) const;
|
||||
void initTypeData(const JsonNode & config) override;
|
||||
|
||||
bool blockVisit = false;
|
||||
|
@@ -83,7 +83,7 @@ void CGPandoraBox::grantRewardWithMessage(const CGHeroInstance * h, int index, b
|
||||
temp.heroLevel = vi.reward.heroLevel;
|
||||
temp.primary = vi.reward.primary;
|
||||
temp.secondary = vi.reward.secondary;
|
||||
temp.bonuses = vi.reward.bonuses;
|
||||
temp.heroBonuses = vi.reward.heroBonuses;
|
||||
temp.manaDiff = vi.reward.manaDiff;
|
||||
temp.manaPercentage = vi.reward.manaPercentage;
|
||||
|
||||
@@ -106,7 +106,7 @@ void CGPandoraBox::grantRewardWithMessage(const CGHeroInstance * h, int index, b
|
||||
if(vi.reward.manaDiff || vi.reward.manaPercentage >= 0)
|
||||
txt = setText(temp.manaDiff > 0, 177, 176, h);
|
||||
|
||||
for(auto b : vi.reward.bonuses)
|
||||
for(auto b : vi.reward.heroBonuses)
|
||||
{
|
||||
if(b.val && b.type == BonusType::MORALE)
|
||||
txt = setText(b.val > 0, 179, 178, h);
|
||||
@@ -122,7 +122,7 @@ void CGPandoraBox::grantRewardWithMessage(const CGHeroInstance * h, int index, b
|
||||
|
||||
//artifacts message
|
||||
temp = Rewardable::Reward{};
|
||||
temp.artifacts = vi.reward.artifacts;
|
||||
temp.grantedArtifacts = vi.reward.grantedArtifacts;
|
||||
sendInfoWindow(setText(true, 183, 183, h), temp);
|
||||
|
||||
//creatures message
|
||||
@@ -160,8 +160,8 @@ void CGPandoraBox::grantRewardWithMessage(const CGHeroInstance * h, int index, b
|
||||
temp.manaPercentage = -1;
|
||||
temp.spells.clear();
|
||||
temp.creatures.clear();
|
||||
temp.bonuses.clear();
|
||||
temp.artifacts.clear();
|
||||
temp.heroBonuses.clear();
|
||||
temp.grantedArtifacts.clear();
|
||||
sendInfoWindow(setText(true, 175, 175, h), temp);
|
||||
|
||||
// grant reward afterwards. Note that it may remove object
|
||||
@@ -229,11 +229,11 @@ void CGPandoraBox::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
int val = 0;
|
||||
handler.serializeInt("morale", val, 0);
|
||||
if(val)
|
||||
vinfo.reward.bonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id));
|
||||
vinfo.reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id));
|
||||
|
||||
handler.serializeInt("luck", val, 0);
|
||||
if(val)
|
||||
vinfo.reward.bonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id));
|
||||
vinfo.reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id));
|
||||
|
||||
vinfo.reward.resources.serializeJson(handler, "resources");
|
||||
{
|
||||
@@ -246,7 +246,7 @@ void CGPandoraBox::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
}
|
||||
}
|
||||
|
||||
handler.serializeIdArray("artifacts", vinfo.reward.artifacts);
|
||||
handler.serializeIdArray("artifacts", vinfo.reward.grantedArtifacts);
|
||||
handler.serializeIdArray("spells", vinfo.reward.spells);
|
||||
handler.enterArray("creatures").serializeStruct(vinfo.reward.creatures);
|
||||
|
||||
@@ -279,8 +279,8 @@ void CGPandoraBox::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
|| vinfo.reward.heroExperience
|
||||
|| vinfo.reward.manaDiff
|
||||
|| vinfo.reward.resources.nonZero()
|
||||
|| !vinfo.reward.artifacts.empty()
|
||||
|| !vinfo.reward.bonuses.empty()
|
||||
|| !vinfo.reward.grantedArtifacts.empty()
|
||||
|| !vinfo.reward.heroBonuses.empty()
|
||||
|| !vinfo.reward.creatures.empty()
|
||||
|| !vinfo.reward.secondary.empty();
|
||||
|
||||
|
@@ -714,9 +714,9 @@ void CGSeerHut::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
if(metaTypeName == "mana")
|
||||
reward.manaDiff = val;
|
||||
if(metaTypeName == "morale")
|
||||
reward.bonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id));
|
||||
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id));
|
||||
if(metaTypeName == "luck")
|
||||
reward.bonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id));
|
||||
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(id));
|
||||
if(metaTypeName == "resource")
|
||||
{
|
||||
auto rawId = *LIBRARY->identifiers()->getIdentifier(ModScope::scopeMap(), fullIdentifier, false);
|
||||
@@ -735,7 +735,7 @@ void CGSeerHut::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
if(metaTypeName == "artifact")
|
||||
{
|
||||
auto rawId = *LIBRARY->identifiers()->getIdentifier(ModScope::scopeMap(), fullIdentifier, false);
|
||||
reward.artifacts.push_back(rawId);
|
||||
reward.grantedArtifacts.push_back(rawId);
|
||||
}
|
||||
if(metaTypeName == "spell")
|
||||
{
|
||||
|
@@ -72,6 +72,25 @@ TownRewardableBuildingInstance::TownRewardableBuildingInstance(CGTownInstance *
|
||||
configuration = generateConfiguration(rand);
|
||||
}
|
||||
|
||||
void TownRewardableBuildingInstance::assignBonuses(std::vector<Bonus> & bonuses) const
|
||||
{
|
||||
const auto & building = town->getTown()->buildings.at(getBuildingType());
|
||||
|
||||
for (auto & bonus : bonuses)
|
||||
{
|
||||
if (building->mapObjectLikeBonuses.hasValue())
|
||||
{
|
||||
bonus.source = BonusSource::OBJECT_TYPE;
|
||||
bonus.sid = BonusSourceID(building->mapObjectLikeBonuses);
|
||||
}
|
||||
else
|
||||
{
|
||||
bonus.source = BonusSource::TOWN_STRUCTURE;
|
||||
bonus.sid = BonusSourceID(building->getUniqueTypeID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rewardable::Configuration TownRewardableBuildingInstance::generateConfiguration(vstd::RNG & rand) const
|
||||
{
|
||||
Rewardable::Configuration result;
|
||||
@@ -82,19 +101,8 @@ Rewardable::Configuration TownRewardableBuildingInstance::generateConfiguration(
|
||||
building->rewardableObjectInfo.configureObject(result, rand, cb);
|
||||
for(auto & rewardInfo : result.info)
|
||||
{
|
||||
for (auto & bonus : rewardInfo.reward.bonuses)
|
||||
{
|
||||
if (building->mapObjectLikeBonuses.hasValue())
|
||||
{
|
||||
bonus.source = BonusSource::OBJECT_TYPE;
|
||||
bonus.sid = BonusSourceID(building->mapObjectLikeBonuses);
|
||||
}
|
||||
else
|
||||
{
|
||||
bonus.source = BonusSource::TOWN_STRUCTURE;
|
||||
bonus.sid = BonusSourceID(building->getUniqueTypeID());
|
||||
}
|
||||
}
|
||||
assignBonuses(rewardInfo.reward.heroBonuses);
|
||||
assignBonuses(rewardInfo.reward.playerBonuses);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@@ -58,6 +58,7 @@ class DLL_LINKAGE TownRewardableBuildingInstance : public TownBuildingInstance,
|
||||
bool wasVisitedBefore(const CGHeroInstance * contextHero) const override;
|
||||
void grantReward(ui32 rewardID, const CGHeroInstance * hero) const override;
|
||||
Rewardable::Configuration generateConfiguration(vstd::RNG & rand) const;
|
||||
void assignBonuses(std::vector<Bonus> & bonuses) const;
|
||||
|
||||
const IObjectInterface * getObject() const override;
|
||||
bool wasVisited(PlayerColor player) const override;
|
||||
|
@@ -1111,9 +1111,9 @@ void CMapLoaderH3M::readBoxContent(CGPandoraBox * object, const int3 & mapPositi
|
||||
reward.heroExperience = reader->readUInt32();
|
||||
reward.manaDiff = reader->readInt32();
|
||||
if(auto val = reader->readInt8Checked(-3, 3))
|
||||
reward.bonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(idToBeGiven));
|
||||
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(idToBeGiven));
|
||||
if(auto val = reader->readInt8Checked(-3, 3))
|
||||
reward.bonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(idToBeGiven));
|
||||
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(idToBeGiven));
|
||||
|
||||
reader->readResources(reward.resources);
|
||||
for(int x = 0; x < GameConstants::PRIMARY_SKILLS; ++x)
|
||||
@@ -1130,11 +1130,11 @@ void CMapLoaderH3M::readBoxContent(CGPandoraBox * object, const int3 & mapPositi
|
||||
size_t gart = reader->readUInt8(); //number of gained artifacts
|
||||
for(size_t oo = 0; oo < gart; ++oo)
|
||||
{
|
||||
reward.artifacts.push_back(reader->readArtifact());
|
||||
reward.grantedArtifacts.push_back(reader->readArtifact());
|
||||
if (features.levelHOTA5)
|
||||
{
|
||||
SpellID scrollSpell = reader->readSpell16();
|
||||
if (reward.artifacts.back() == ArtifactID::SPELL_SCROLL)
|
||||
if (reward.grantedArtifacts.back() == ArtifactID::SPELL_SCROLL)
|
||||
logGlobal->warn("Map '%s': Pandora/Event at %s Option to give spell scroll (%s) via event or pandora is not implemented!", mapName, mapPosition.toString(), scrollSpell.toEntity(LIBRARY)->getJsonKey());
|
||||
}
|
||||
}
|
||||
@@ -2300,12 +2300,12 @@ void CMapLoaderH3M::readSeerHutQuest(CGSeerHut * hut, const int3 & position, con
|
||||
}
|
||||
case ESeerHutRewardType::MORALE:
|
||||
{
|
||||
reward.bonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, reader->readInt8Checked(-3, 3), BonusSourceID(idToBeGiven));
|
||||
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT_INSTANCE, reader->readInt8Checked(-3, 3), BonusSourceID(idToBeGiven));
|
||||
break;
|
||||
}
|
||||
case ESeerHutRewardType::LUCK:
|
||||
{
|
||||
reward.bonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, reader->readInt8Checked(-3, 3), BonusSourceID(idToBeGiven));
|
||||
reward.heroBonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT_INSTANCE, reader->readInt8Checked(-3, 3), BonusSourceID(idToBeGiven));
|
||||
break;
|
||||
}
|
||||
case ESeerHutRewardType::RESOURCES:
|
||||
@@ -2334,11 +2334,11 @@ void CMapLoaderH3M::readSeerHutQuest(CGSeerHut * hut, const int3 & position, con
|
||||
}
|
||||
case ESeerHutRewardType::ARTIFACT:
|
||||
{
|
||||
reward.artifacts.push_back(reader->readArtifact());
|
||||
reward.grantedArtifacts.push_back(reader->readArtifact());
|
||||
if (features.levelHOTA5)
|
||||
{
|
||||
SpellID scrollSpell = reader->readSpell16();
|
||||
if (reward.artifacts.back() == ArtifactID::SPELL_SCROLL)
|
||||
if (reward.grantedArtifacts.back() == ArtifactID::SPELL_SCROLL)
|
||||
logGlobal->warn("Map '%s': Seer Hut at %s: Option to give spell scroll (%s) as a reward is not implemented!", mapName, position.toString(), scrollSpell.toEntity(LIBRARY)->getJsonKey());
|
||||
|
||||
}
|
||||
|
@@ -408,6 +408,7 @@ struct DLL_LINKAGE SetAvailableHero : public CPackForClient
|
||||
|
||||
struct DLL_LINKAGE GiveBonus : public CPackForClient
|
||||
{
|
||||
using VariantType = VariantIdentifier<ObjectInstanceID, PlayerColor, BattleID>;
|
||||
enum class ETarget : int8_t { OBJECT, PLAYER, BATTLE };
|
||||
|
||||
explicit GiveBonus(ETarget Who = ETarget::OBJECT)
|
||||
@@ -415,10 +416,17 @@ struct DLL_LINKAGE GiveBonus : public CPackForClient
|
||||
{
|
||||
}
|
||||
|
||||
GiveBonus(ETarget who, const VariantType & id, const Bonus & bonus)
|
||||
: who(who)
|
||||
, id(id)
|
||||
, bonus(bonus)
|
||||
{
|
||||
}
|
||||
|
||||
void applyGs(CGameState * gs) override;
|
||||
|
||||
ETarget who = ETarget::OBJECT;
|
||||
VariantIdentifier<ObjectInstanceID, PlayerColor, BattleID> id;
|
||||
VariantType id;
|
||||
Bonus bonus;
|
||||
|
||||
void visitTyped(ICPackVisitor & visitor) override;
|
||||
|
@@ -29,7 +29,8 @@ enum EVisitMode
|
||||
VISIT_HERO, // every hero can visit object once
|
||||
VISIT_BONUS, // can be visited by any hero that don't have bonus from this object
|
||||
VISIT_LIMITER, // can be visited by heroes that don't fulfill provided limiter
|
||||
VISIT_PLAYER // every player can visit object once
|
||||
VISIT_PLAYER, // every player can visit object once
|
||||
VISIT_PLAYER_GLOBAL // every player can visit object once. All objects of the same type will be considered as visited
|
||||
};
|
||||
|
||||
/// controls selection of reward granted to player
|
||||
@@ -70,6 +71,9 @@ struct DLL_LINKAGE ResetInfo
|
||||
/// if true - re-randomize rewards on a new week
|
||||
bool rewards;
|
||||
|
||||
/// Reset object after visit by a hero, whether hero accepted reward or not
|
||||
bool resetAfterVisit = false;
|
||||
|
||||
void serializeJson(JsonSerializeFormat & handler);
|
||||
|
||||
template <typename Handler> void serialize(Handler &h)
|
||||
@@ -77,6 +81,8 @@ struct DLL_LINKAGE ResetInfo
|
||||
h & period;
|
||||
h & visitors;
|
||||
h & rewards;
|
||||
if (h.version >= Handler::Version::REWARDABLE_EXTENSIONS)
|
||||
h & resetAfterVisit;
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -174,14 +174,15 @@ void Rewardable::Info::configureReward(Rewardable::Configuration & object, vstd:
|
||||
reward.movePercentage = randomizer.loadValue(source["movePercentage"], rng, variables, -1);
|
||||
|
||||
reward.removeObject = source["removeObject"].Bool();
|
||||
reward.bonuses = randomizer.loadBonuses(source["bonuses"]);
|
||||
reward.heroBonuses = randomizer.loadBonuses(source["bonuses"]);
|
||||
reward.playerBonuses = randomizer.loadBonuses(source["playerBonuses"]);
|
||||
|
||||
reward.guards = randomizer.loadCreatures(source["guards"], rng, variables);
|
||||
|
||||
reward.primary = randomizer.loadPrimaries(source["primary"], rng, variables);
|
||||
reward.secondary = randomizer.loadSecondaries(source["secondary"], rng, variables);
|
||||
|
||||
reward.artifacts = randomizer.loadArtifacts(source["artifacts"], rng, variables);
|
||||
reward.grantedArtifacts = randomizer.loadArtifacts(source["artifacts"], rng, variables);
|
||||
reward.spells = randomizer.loadSpells(source["spells"], rng, variables);
|
||||
reward.creatures = randomizer.loadCreatures(source["creatures"], rng, variables);
|
||||
if(!source["spellCast"].isNull() && source["spellCast"].isStruct())
|
||||
@@ -293,7 +294,7 @@ void Rewardable::Info::replaceTextPlaceholders(MetaString & target, const Variab
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto & artifact : info.reward.artifacts )
|
||||
for (const auto & artifact : info.reward.grantedArtifacts )
|
||||
{
|
||||
loot.appendRawString("%s");
|
||||
loot.replaceName(artifact);
|
||||
@@ -315,7 +316,7 @@ void Rewardable::Info::replaceTextPlaceholders(MetaString & target, const Variab
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto & artifact : info.reward.artifacts )
|
||||
for (const auto & artifact : info.reward.grantedArtifacts )
|
||||
target.replaceName(artifact);
|
||||
|
||||
for (const auto & spell : info.reward.spells )
|
||||
|
@@ -151,16 +151,19 @@ void Rewardable::Interface::grantRewardAfterLevelup(const Rewardable::VisitInfo
|
||||
cb->setMovePoints(&smp);
|
||||
}
|
||||
|
||||
for(const Bonus & bonus : info.reward.bonuses)
|
||||
for(const Bonus & bonus : info.reward.heroBonuses)
|
||||
{
|
||||
GiveBonus gb;
|
||||
gb.who = GiveBonus::ETarget::OBJECT;
|
||||
gb.bonus = bonus;
|
||||
gb.id = hero->id;
|
||||
GiveBonus gb(GiveBonus::ETarget::OBJECT, hero->id, bonus);
|
||||
cb->giveHeroBonus(&gb);
|
||||
}
|
||||
|
||||
for(const ArtifactID & art : info.reward.artifacts)
|
||||
for(const Bonus & bonus : info.reward.playerBonuses)
|
||||
{
|
||||
GiveBonus gb(GiveBonus::ETarget::PLAYER, hero->getOwner(), bonus);
|
||||
cb->giveHeroBonus(&gb);
|
||||
}
|
||||
|
||||
for(const ArtifactID & art : info.reward.grantedArtifacts)
|
||||
cb->giveHeroNewArtifact(hero, art, ArtifactPosition::FIRST_AVAILABLE);
|
||||
|
||||
if(!info.reward.spells.empty())
|
||||
|
@@ -48,6 +48,9 @@ struct DLL_LINKAGE Limiter final : public Serializeable
|
||||
/// Number of free secondary slots that hero needs to have
|
||||
bool canLearnSkills;
|
||||
|
||||
/// Hero has commander, and commander is currently alive
|
||||
bool commanderAlive;
|
||||
|
||||
/// resources player needs to have in order to trigger reward
|
||||
TResources resources;
|
||||
|
||||
@@ -59,6 +62,12 @@ struct DLL_LINKAGE Limiter final : public Serializeable
|
||||
/// checks for artifacts copies if same artifact id is included multiple times
|
||||
std::vector<ArtifactID> artifacts;
|
||||
|
||||
/// artifact slots that hero needs to have available (not locked and without any artifact) to pass the limiter
|
||||
std::vector<ArtifactPosition> availableSlots;
|
||||
|
||||
/// Spell scrolls that hero must have in inventory (equipped or in backpack)
|
||||
std::vector<SpellID> scrolls;
|
||||
|
||||
/// Spells that hero must have in the spellbook
|
||||
std::vector<SpellID> spells;
|
||||
|
||||
@@ -102,10 +111,17 @@ struct DLL_LINKAGE Limiter final : public Serializeable
|
||||
h & manaPoints;
|
||||
h & manaPercentage;
|
||||
h & canLearnSkills;
|
||||
if (h.version >= Handler::Version::REWARDABLE_EXTENSIONS)
|
||||
h & commanderAlive;
|
||||
h & resources;
|
||||
h & primary;
|
||||
h & secondary;
|
||||
h & artifacts;
|
||||
if (h.version >= Handler::Version::REWARDABLE_EXTENSIONS)
|
||||
{
|
||||
h & availableSlots;
|
||||
h & scrolls;
|
||||
}
|
||||
h & spells;
|
||||
h & canLearnSpells;
|
||||
h & creatures;
|
||||
|
@@ -79,7 +79,7 @@ void Rewardable::Reward::loadComponents(std::vector<Component> & comps, const CG
|
||||
for (auto comp : extraComponents)
|
||||
comps.push_back(comp);
|
||||
|
||||
for (auto & bonus : bonuses)
|
||||
for (auto & bonus : heroBonuses)
|
||||
{
|
||||
if (bonus.type == BonusType::MORALE)
|
||||
comps.emplace_back(ComponentType::MORALE, bonus.val);
|
||||
@@ -111,7 +111,7 @@ void Rewardable::Reward::loadComponents(std::vector<Component> & comps, const CG
|
||||
comps.emplace_back(ComponentType::SEC_SKILL, entry.first, finalLevel);
|
||||
}
|
||||
|
||||
for(const auto & entry : artifacts)
|
||||
for(const auto & entry : grantedArtifacts)
|
||||
comps.emplace_back(ComponentType::ARTIFACT, entry);
|
||||
|
||||
for(const auto & entry : spells)
|
||||
@@ -141,7 +141,7 @@ void Rewardable::Reward::serializeJson(JsonSerializeFormat & handler)
|
||||
handler.serializeInt("manaDiff", manaDiff);
|
||||
handler.serializeInt("manaOverflowFactor", manaOverflowFactor);
|
||||
handler.serializeInt("movePoints", movePoints);
|
||||
handler.serializeIdArray("artifacts", artifacts);
|
||||
handler.serializeIdArray("artifacts", grantedArtifacts);
|
||||
handler.serializeIdArray("spells", spells);
|
||||
handler.enterArray("creatures").serializeStruct(creatures);
|
||||
handler.enterArray("primary").serializeArray(primary);
|
||||
|
@@ -65,6 +65,8 @@ struct DLL_LINKAGE Reward final
|
||||
|
||||
/// received experience
|
||||
si32 heroExperience;
|
||||
si32 commanderExperience;
|
||||
si32 unitsExperience;
|
||||
/// received levels (converted into XP during grant)
|
||||
si32 heroLevel;
|
||||
|
||||
@@ -86,7 +88,8 @@ struct DLL_LINKAGE Reward final
|
||||
std::vector<CStackBasicDescriptor> guards;
|
||||
|
||||
/// list of bonuses, e.g. morale/luck
|
||||
std::vector<Bonus> bonuses;
|
||||
std::vector<Bonus> heroBonuses;
|
||||
std::vector<Bonus> playerBonuses;
|
||||
|
||||
/// skills that hero may receive or lose
|
||||
std::vector<si32> primary;
|
||||
@@ -96,7 +99,10 @@ struct DLL_LINKAGE Reward final
|
||||
std::map<CreatureID, CreatureID> creaturesChange;
|
||||
|
||||
/// objects that hero may receive
|
||||
std::vector<ArtifactID> artifacts;
|
||||
std::vector<ArtifactID> grantedArtifacts;
|
||||
std::vector<ArtifactID> takenArtifacts;
|
||||
std::vector<ArtifactPosition> takenArtifactSlots;
|
||||
std::vector<SpellID> scrolls;
|
||||
std::vector<SpellID> spells;
|
||||
std::vector<CStackBasicDescriptor> creatures;
|
||||
|
||||
@@ -131,14 +137,29 @@ struct DLL_LINKAGE Reward final
|
||||
h & movePercentage;
|
||||
h & guards;
|
||||
h & heroExperience;
|
||||
if (h.version >= Handler::Version::REWARDABLE_EXTENSIONS)
|
||||
{
|
||||
h & commanderExperience;
|
||||
h & unitsExperience;
|
||||
}
|
||||
h & heroLevel;
|
||||
h & manaDiff;
|
||||
h & manaOverflowFactor;
|
||||
h & movePoints;
|
||||
h & primary;
|
||||
h & secondary;
|
||||
h & bonuses;
|
||||
h & artifacts;
|
||||
h & heroBonuses;
|
||||
if (h.version >= Handler::Version::REWARDABLE_EXTENSIONS)
|
||||
{
|
||||
h & playerBonuses;
|
||||
}
|
||||
h & grantedArtifacts;
|
||||
if (h.version >= Handler::Version::REWARDABLE_EXTENSIONS)
|
||||
{
|
||||
h & takenArtifacts;
|
||||
h & takenArtifactSlots;
|
||||
h & scrolls;
|
||||
}
|
||||
h & spells;
|
||||
h & creatures;
|
||||
h & creaturesChange;
|
||||
|
@@ -39,9 +39,9 @@ enum class ESerializationVersion : int32_t
|
||||
STACK_INSTANCE_EXPERIENCE_FIX, // stack experience is stored as total, not as average
|
||||
STACK_INSTANCE_ARMY_FIX, // remove serialization of army that owns stack instance
|
||||
STORE_UID_COUNTER_IN_CMAP, // fix crash caused by conflicting instanceName after loading game
|
||||
REWARDABLE_EXTENSIONS, // new functionality for rewardable objects
|
||||
|
||||
|
||||
CURRENT = STORE_UID_COUNTER_IN_CMAP,
|
||||
CURRENT = REWARDABLE_EXTENSIONS,
|
||||
};
|
||||
|
||||
static_assert(ESerializationVersion::MINIMAL <= ESerializationVersion::CURRENT, "Invalid serialization version definition!");
|
||||
|
@@ -297,11 +297,11 @@ void RewardsWidget::saveCurrentVisitInfo(int index)
|
||||
vinfo.reward.resources[i] = widget->value();
|
||||
}
|
||||
|
||||
vinfo.reward.artifacts.clear();
|
||||
vinfo.reward.grantedArtifacts.clear();
|
||||
for(int i = 0; i < ui->rArtifacts->count(); ++i)
|
||||
{
|
||||
if(ui->rArtifacts->item(i)->checkState() == Qt::Checked)
|
||||
vinfo.reward.artifacts.push_back(LIBRARY->artifacts()->getByIndex(i)->getId());
|
||||
vinfo.reward.grantedArtifacts.push_back(LIBRARY->artifacts()->getByIndex(i)->getId());
|
||||
}
|
||||
vinfo.reward.spells.clear();
|
||||
for(int i = 0; i < ui->rSpells->count(); ++i)
|
||||
@@ -336,13 +336,13 @@ void RewardsWidget::saveCurrentVisitInfo(int index)
|
||||
vinfo.reward.spellCast.second = ui->castLevel->currentIndex();
|
||||
}
|
||||
|
||||
vinfo.reward.bonuses.clear();
|
||||
vinfo.reward.heroBonuses.clear();
|
||||
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 val = ui->bonuses->item(i, 2)->data(Qt::UserRole).toInt();
|
||||
vinfo.reward.bonuses.emplace_back(dur, typ, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(object.id));
|
||||
vinfo.reward.heroBonuses.emplace_back(dur, typ, BonusSource::OBJECT_INSTANCE, val, BonusSourceID(object.id));
|
||||
}
|
||||
|
||||
vinfo.limiter.dayOfWeek = ui->lDayOfWeek->currentIndex();
|
||||
@@ -452,7 +452,7 @@ void RewardsWidget::loadCurrentVisitInfo(int index)
|
||||
widget->setValue(vinfo.reward.resources[i]);
|
||||
}
|
||||
|
||||
for(auto i : vinfo.reward.artifacts)
|
||||
for(auto i : vinfo.reward.grantedArtifacts)
|
||||
ui->rArtifacts->item(LIBRARY->artifacts()->getById(i)->getIndex())->setCheckState(Qt::Checked);
|
||||
for(auto i : vinfo.reward.spells)
|
||||
ui->rArtifacts->item(LIBRARY->spells()->getById(i)->getIndex())->setCheckState(Qt::Checked);
|
||||
@@ -478,7 +478,7 @@ void RewardsWidget::loadCurrentVisitInfo(int index)
|
||||
ui->castLevel->setCurrentIndex(vinfo.reward.spellCast.second);
|
||||
}
|
||||
|
||||
for(auto & i : vinfo.reward.bonuses)
|
||||
for(auto & i : vinfo.reward.heroBonuses)
|
||||
{
|
||||
auto dur = vstd::findKey(bonusDurationMap, i.duration);
|
||||
for(int i = 0; i < ui->bonusDuration->count(); ++i)
|
||||
@@ -786,7 +786,7 @@ void RewardsDelegate::updateModelData(QAbstractItemModel * model, const QModelIn
|
||||
}
|
||||
textList += QObject::tr("Resources: %1").arg(resourcesList.join(", "));
|
||||
QStringList artifactsList;
|
||||
for (auto artifact : vinfo.reward.artifacts)
|
||||
for (auto artifact : vinfo.reward.grantedArtifacts)
|
||||
{
|
||||
artifactsList += QString::fromStdString(LIBRARY->artifacts()->getById(artifact)->getNameTranslated());
|
||||
}
|
||||
@@ -814,7 +814,7 @@ void RewardsDelegate::updateModelData(QAbstractItemModel * model, const QModelIn
|
||||
textList += QObject::tr("Spell Cast: %1 (%2)").arg(QString::fromStdString(LIBRARY->spells()->getById(vinfo.reward.spellCast.first)->getNameTranslated())).arg(vinfo.reward.spellCast.second);
|
||||
}
|
||||
QStringList bonusesList;
|
||||
for (auto & bonus : vinfo.reward.bonuses)
|
||||
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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user