/* * Limiter.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */ #include "StdInc.h" #include "Limiter.h" #include "../IGameCallback.h" #include "../CPlayerState.h" #include "../mapObjects/CGHeroInstance.h" #include "../serializer/JsonSerializeFormat.h" #include "../constants/StringConstants.h" #include "../CHeroHandler.h" #include "../CSkillHandler.h" #include "../ArtifactUtils.h" VCMI_LIB_NAMESPACE_BEGIN Rewardable::Limiter::Limiter() : dayOfWeek(0) , daysPassed(0) , heroExperience(0) , heroLevel(-1) , manaPercentage(0) , manaPoints(0) , primary(GameConstants::PRIMARY_SKILLS, 0) { } Rewardable::Limiter::~Limiter() = default; bool Rewardable::Limiter::empty() const { if(dayOfWeek != 0 || daysPassed != 0 || heroLevel > 0 || heroExperience > 0 || manaPoints > 0 || manaPercentage > 0 || !secondary.empty() || !creatures.empty() || !spells.empty() || !artifacts.empty() || !players.empty() || !heroes.empty() || !heroClasses.empty() || resources.nonZero() || std::find_if(primary.begin(), primary.end(), [](si32 i){return i != 0;}) != primary.end()) return false; for(const auto & sub : {noneOf, allOf, anyOf}) { for(const auto & sublimiter : sub) { if(!sublimiter->empty()) return false; } } return true; } bool Rewardable::Limiter::heroAllowed(const CGHeroInstance * hero) const { if(dayOfWeek != 0) { if (IObjectInterface::cb->getDate(Date::DAY_OF_WEEK) != dayOfWeek) return false; } if(daysPassed != 0) { if (IObjectInterface::cb->getDate(Date::DAY) < daysPassed) return false; } for(const auto & reqStack : creatures) { size_t count = 0; for(const auto & slot : hero->Slots()) { const CStackInstance * heroStack = slot.second; if (heroStack->type == reqStack.type) count += heroStack->count; } if (count < reqStack.count) //not enough creatures of this kind return false; } if(!IObjectInterface::cb->getPlayerState(hero->tempOwner)->resources.canAfford(resources)) return false; if(heroLevel > static_cast(hero->level)) return false; if(static_cast(heroExperience) > hero->exp) return false; if(manaPoints > hero->mana) return false; if(manaPercentage > 100 * hero->mana / hero->manaLimit()) return false; for(size_t i=0; i hero->getPrimSkillLevel(static_cast(i))) return false; } for(const auto & skill : secondary) { if (skill.second > hero->getSecSkillLevel(skill.first)) return false; } for(const auto & spell : spells) { if (!hero->spellbookContainsSpell(spell)) return false; } { std::unordered_map artifactsRequirements; // artifact ID -> required count for(const auto & art : artifacts) ++artifactsRequirements[art]; size_t reqSlots = 0; for(const auto & elem : artifactsRequirements) { // check required amount of artifacts if(hero->getArtPosCount(elem.first, false, true, true) < elem.second) return false; if(!hero->hasArt(elem.first)) reqSlots += hero->getAssemblyByConstituent(elem.first)->getPartsInfo().size() - 2; } if(!ArtifactUtils::isBackpackFreeSlots(hero, reqSlots)) return false; } if(!players.empty() && !vstd::contains(players, hero->getOwner())) return false; if(!heroes.empty() && !vstd::contains(heroes, hero->type->getId())) return false; if(!heroClasses.empty() && !vstd::contains(heroClasses, hero->type->heroClass->getId())) return false; for(const auto & sublimiter : noneOf) { if (sublimiter->heroAllowed(hero)) return false; } for(const auto & sublimiter : allOf) { if (!sublimiter->heroAllowed(hero)) return false; } if(anyOf.empty()) return true; for(const auto & sublimiter : anyOf) { if (sublimiter->heroAllowed(hero)) return true; } return false; } void Rewardable::Limiter::loadComponents(std::vector & comps, const CGHeroInstance * h) const { if (heroExperience) comps.emplace_back(Component::EComponentType::EXPERIENCE, 0, static_cast(h->calculateXp(heroExperience)), 0); if (heroLevel) comps.emplace_back(Component::EComponentType::EXPERIENCE, 1, heroLevel, 0); if (manaPoints || manaPercentage > 0) { int absoluteMana = h->manaLimit() ? (manaPercentage * h->mana / h->manaLimit() / 100) : 0; comps.emplace_back(Component::EComponentType::PRIM_SKILL, 5, absoluteMana + manaPoints, 0); } for (size_t i=0; i(i), primary[i], 0); } for(const auto & entry : secondary) comps.emplace_back(Component::EComponentType::SEC_SKILL, entry.first, entry.second, 0); for(const auto & entry : artifacts) comps.emplace_back(Component::EComponentType::ARTIFACT, entry, 1, 0); for(const auto & entry : spells) comps.emplace_back(Component::EComponentType::SPELL, entry, 1, 0); for(const auto & entry : creatures) comps.emplace_back(Component::EComponentType::CREATURE, entry.type->getId(), entry.count, 0); for(const auto & entry : players) comps.emplace_back(Component::EComponentType::FLAG, entry, 0, 0); //FIXME: portrait may not match hero, if custom portrait was set in map editor for(const auto & entry : heroes) comps.emplace_back(Component::EComponentType::HERO_PORTRAIT, VLC->heroTypes()->getById(entry)->getIconIndex(), 0, 0); for(const auto & entry : heroClasses) comps.emplace_back(Component::EComponentType::HERO_PORTRAIT, VLC->heroClasses()->getById(entry)->getIconIndex(), 0, 0); for (size_t i=0; i(i), resources[i], 0); } } void Rewardable::Limiter::serializeJson(JsonSerializeFormat & handler) { handler.serializeInt("dayOfWeek", dayOfWeek); handler.serializeInt("daysPassed", daysPassed); resources.serializeJson(handler, "resources"); handler.serializeInt("manaPercentage", manaPercentage); handler.serializeInt("heroExperience", heroExperience); handler.serializeInt("heroLevel", heroLevel); handler.serializeIdArray("heroes", heroes); handler.serializeIdArray("heroClasses", heroClasses); handler.serializeIdArray("colors", players); handler.serializeInt("manaPoints", manaPoints); handler.serializeIdArray("artifacts", artifacts); handler.enterArray("creatures").serializeStruct(creatures); handler.enterArray("primary").serializeArray(primary); { auto a = handler.enterArray("secondary"); std::vector> fieldValue(secondary.begin(), secondary.end()); a.serializeStruct>(fieldValue, [](JsonSerializeFormat & h, std::pair & e) { h.serializeId("skill", e.first, SecondarySkill{}, VLC->skillh->decodeSkill, VLC->skillh->encodeSkill); h.serializeId("level", e.second, 0, [](const std::string & i){return vstd::find_pos(NSecondarySkill::levels, i);}, [](si32 i){return NSecondarySkill::levels.at(i);}); }); a.syncSize(fieldValue); secondary = std::map(fieldValue.begin(), fieldValue.end()); } //sublimiters auto serializeSublimitersList = [&handler](const std::string & field, LimitersList & container) { auto a = handler.enterArray(field); a.syncSize(container); for(int i = 0; i < container.size(); ++i) { if(!handler.saving) container[i] = std::make_shared(); auto e = a.enterStruct(i); container[i]->serializeJson(handler); } }; serializeSublimitersList("allOf", allOf); serializeSublimitersList("anyOf", anyOf); serializeSublimitersList("noneOf", noneOf); } VCMI_LIB_NAMESPACE_END