/* * 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 "../networkPacks/Component.h" #include "../serializer/JsonSerializeFormat.h" #include "../constants/StringConstants.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) , canLearnSkills(false) , primary(GameConstants::PRIMARY_SKILLS, 0) { } Rewardable::Limiter::~Limiter() = default; bool operator==(const Rewardable::Limiter & l, const Rewardable::Limiter & r) { return l.dayOfWeek == r.dayOfWeek && l.daysPassed == r.daysPassed && l.heroLevel == r.heroLevel && l.heroExperience == r.heroExperience && l.manaPoints == r.manaPoints && l.manaPercentage == r.manaPercentage && l.secondary == r.secondary && l.canLearnSkills == r.canLearnSkills && l.creatures == r.creatures && l.spells == r.spells && l.artifacts == r.artifacts && l.players == r.players && l.heroes == r.heroes && l.heroClasses == r.heroClasses && l.resources == r.resources && l.primary == r.primary && l.noneOf == r.noneOf && l.allOf == r.allOf && l.anyOf == r.anyOf; } bool operator!=(const Rewardable::Limiter & l, const Rewardable::Limiter & r) { return !(l == r); } bool Rewardable::Limiter::heroAllowed(const CGHeroInstance * hero) const { if(dayOfWeek != 0) { if (hero->cb->getDate(Date::DAY_OF_WEEK) != dayOfWeek) return false; } if(daysPassed != 0) { if (hero->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->getType() == reqStack.getType()) count += heroStack->count; } if (count < reqStack.count) //not enough creatures of this kind return false; } if(!hero->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 (canLearnSkills && !hero->canLearnSkill()) return false; if (hero->manaLimit() != 0 && 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; } for(const auto & spell : canLearnSpells) { if (!hero->canLearnSpell(spell.toEntity(VLC), true)) 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 size_t artCnt = 0; for(const auto & [slot, slotInfo] : hero->artifactsWorn) if(slotInfo.artifact->getTypeId() == elem.first) artCnt++; for(auto & slotInfo : hero->artifactsInBackpack) if(slotInfo.artifact->getTypeId() == elem.first) { artCnt++; } else if(slotInfo.artifact->isCombined()) { for(const auto & partInfo : slotInfo.artifact->getPartsInfo()) if(partInfo.art->getTypeId() == elem.first) artCnt++; } if(artCnt < elem.second) return false; // Check if art has no own slot. (As part of combined in backpack) if(hero->getArtPos(elem.first, false) == ArtifactPosition::PRE_FIRST) reqSlots += hero->getCombinedArtWithPart(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->getHeroTypeID())) return false; if(!heroClasses.empty() && !vstd::contains(heroClasses, hero->getHeroClassID())) 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(ComponentType::EXPERIENCE, static_cast(h ? h->calculateXp(heroExperience) : heroExperience)); if (heroLevel > 0) comps.emplace_back(ComponentType::EXPERIENCE, heroLevel); if (manaPoints || manaPercentage > 0) { int absoluteMana = (h && h->manaLimit()) ? (manaPercentage * h->mana / h->manaLimit() / 100) : 0; comps.emplace_back(ComponentType::MANA, absoluteMana + manaPoints); } for (size_t i=0; i> fieldValue(secondary.begin(), secondary.end()); a.serializeStruct>(fieldValue, [](JsonSerializeFormat & h, std::pair & e) { h.serializeId("skill", e.first, SecondarySkill(SecondarySkill::NONE)); 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