diff --git a/AI/Nullkiller/Engine/PriorityEvaluator.cpp b/AI/Nullkiller/Engine/PriorityEvaluator.cpp index 91c72bca9..c68a60884 100644 --- a/AI/Nullkiller/Engine/PriorityEvaluator.cpp +++ b/AI/Nullkiller/Engine/PriorityEvaluator.cpp @@ -206,6 +206,11 @@ int getDwellingArmyCost(const CGObjectInstance * target) return cost; } +static uint64_t evaluateSpellScrollArmyValue(const SpellID &) +{ + return 1500; +} + static uint64_t evaluateArtifactArmyValue(const CArtifact * art) { if(art->getId() == ArtifactID::SPELL_SCROLL) @@ -265,23 +270,14 @@ uint64_t RewardEvaluator::getArmyReward( auto rewardValue = 0; - if(!info.reward.grantedArtifacts.empty()) - { - for(auto artID : info.reward.grantedArtifacts) - { - const auto * art = artID.toArtifact(); + for(auto artID : info.reward.grantedArtifacts) + rewardValue += evaluateArtifactArmyValue(artID.toArtifact()); - rewardValue += evaluateArtifactArmyValue(art); - } - } + for(auto scroll : info.reward.scrolls) + rewardValue += evaluateSpellScrollArmyValue(scroll); - if(!info.reward.creatures.empty()) - { - for(const auto & stackInfo : info.reward.creatures) - { - rewardValue += stackInfo.getType()->getAIValue() * stackInfo.getCount(); - } - } + for(const auto & stackInfo : info.reward.creatures) + rewardValue += stackInfo.getType()->getAIValue() * stackInfo.getCount(); totalValue += rewardValue > 0 ? rewardValue / (info.reward.grantedArtifacts.size() + info.reward.creatures.size()) : 0; } diff --git a/lib/mapping/MapFormatH3M.cpp b/lib/mapping/MapFormatH3M.cpp index 4650e9d4f..e98acc0d1 100644 --- a/lib/mapping/MapFormatH3M.cpp +++ b/lib/mapping/MapFormatH3M.cpp @@ -1130,13 +1130,16 @@ 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.grantedArtifacts.push_back(reader->readArtifact()); + ArtifactID grantedArtifact = reader->readArtifact(); + if (features.levelHOTA5) { SpellID scrollSpell = reader->readSpell16(); - 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()); + if (grantedArtifact == ArtifactID::SPELL_SCROLL) + reward.scrolls.push_back(scrollSpell); } + else + reward.grantedArtifacts.push_back(grantedArtifact); } size_t gspel = reader->readUInt8(); //number of gained spells @@ -2334,15 +2337,15 @@ void CMapLoaderH3M::readSeerHutQuest(CGSeerHut * hut, const int3 & position, con } case ESeerHutRewardType::ARTIFACT: { - reward.grantedArtifacts.push_back(reader->readArtifact()); + ArtifactID grantedArtifact = reader->readArtifact(); if (features.levelHOTA5) { SpellID scrollSpell = reader->readSpell16(); - 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()); - + if (grantedArtifact == ArtifactID::SPELL_SCROLL) + reward.scrolls.push_back(scrollSpell); } - + else + reward.grantedArtifacts.push_back(grantedArtifact); break; } case ESeerHutRewardType::SPELL: diff --git a/lib/rewardable/Info.cpp b/lib/rewardable/Info.cpp index 07a12c30f..d9c2faad4 100644 --- a/lib/rewardable/Info.cpp +++ b/lib/rewardable/Info.cpp @@ -183,6 +183,7 @@ void Rewardable::Info::configureReward(Rewardable::Configuration & object, vstd: reward.secondary = randomizer.loadSecondaries(source["secondary"], rng, variables); reward.grantedArtifacts = randomizer.loadArtifacts(source["artifacts"], rng, variables); + reward.scrolls = randomizer.loadSpells(source["scrolls"], 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()) @@ -300,6 +301,12 @@ void Rewardable::Info::replaceTextPlaceholders(MetaString & target, const Variab loot.replaceName(artifact); } + for (const auto & scroll : info.reward.scrolls ) + { + loot.appendRawString("%s"); + loot.replaceName(scroll); + } + for (const auto & spell : info.reward.spells ) { loot.appendRawString("%s"); @@ -319,6 +326,9 @@ void Rewardable::Info::replaceTextPlaceholders(MetaString & target, const Variab for (const auto & artifact : info.reward.grantedArtifacts ) target.replaceName(artifact); + for (const auto & scroll : info.reward.scrolls ) + target.replaceName(scroll); + for (const auto & spell : info.reward.spells ) target.replaceName(spell); diff --git a/lib/rewardable/Interface.cpp b/lib/rewardable/Interface.cpp index 824b9d923..ff2be48ca 100644 --- a/lib/rewardable/Interface.cpp +++ b/lib/rewardable/Interface.cpp @@ -166,6 +166,9 @@ void Rewardable::Interface::grantRewardAfterLevelup(const Rewardable::VisitInfo for(const ArtifactID & art : info.reward.grantedArtifacts) cb->giveHeroNewArtifact(hero, art, ArtifactPosition::FIRST_AVAILABLE); + for(const SpellID & spell : info.reward.scrolls) + cb->giveHeroNewScroll(hero, spell, ArtifactPosition::FIRST_AVAILABLE); + if(!info.reward.spells.empty()) { std::set spellsToGive; diff --git a/lib/rewardable/Reward.cpp b/lib/rewardable/Reward.cpp index c1758f1fc..4c7bba434 100644 --- a/lib/rewardable/Reward.cpp +++ b/lib/rewardable/Reward.cpp @@ -114,6 +114,9 @@ void Rewardable::Reward::loadComponents(std::vector & comps, const CG for(const auto & entry : grantedArtifacts) comps.emplace_back(ComponentType::ARTIFACT, entry); + for(const SpellID & spell : scrolls) + comps.emplace_back(ComponentType::SPELL, spell); + for(const auto & entry : spells) { bool learnable = !h || h->canLearnSpell(entry.toEntity(LIBRARY), true); @@ -142,6 +145,7 @@ void Rewardable::Reward::serializeJson(JsonSerializeFormat & handler) handler.serializeInt("manaOverflowFactor", manaOverflowFactor); handler.serializeInt("movePoints", movePoints); handler.serializeIdArray("artifacts", grantedArtifacts); + handler.serializeIdArray("scrolls", scrolls); handler.serializeIdArray("spells", spells); handler.enterArray("creatures").serializeStruct(creatures); handler.enterArray("primary").serializeArray(primary);