/* * BonusSelector.h, 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 * */ #pragma once #include "Bonus.h" VCMI_LIB_NAMESPACE_BEGIN class CSelector : std::function { using TBase = std::function; public: CSelector() = default; template CSelector(const T &t, //SFINAE trick -> include this c-tor in overload resolution only if parameter is class //(includes functors, lambdas) or function. Without that VC is going mad about ambiguities. typename std::enable_if_t < std::is_class_v || std::is_function_v > *dummy = nullptr) : TBase(t) {} CSelector(std::nullptr_t) {} CSelector And(CSelector rhs) const { //lambda may likely outlive "this" (it can be even a temporary) => we copy the OBJECT (not pointer) auto thisCopy = *this; return [thisCopy, rhs](const Bonus *b) mutable { return thisCopy(b) && rhs(b); }; } CSelector Or(CSelector rhs) const { auto thisCopy = *this; return [thisCopy, rhs](const Bonus *b) mutable { return thisCopy(b) || rhs(b); }; } CSelector Not() const { auto thisCopy = *this; return [thisCopy](const Bonus *b) mutable { return !thisCopy(b); }; } bool operator()(const Bonus *b) const { return TBase::operator()(b); } operator bool() const { return !!static_cast(*this); } }; template class CSelectFieldEqual { T Bonus::*ptr; public: CSelectFieldEqual(T Bonus::*Ptr) : ptr(Ptr) { } CSelector operator()(const T &valueToCompareAgainst) const { auto ptr2 = ptr; //We need a COPY because we don't want to reference this (might be outlived by lambda) return [ptr2, valueToCompareAgainst](const Bonus *bonus) { return bonus->*ptr2 == valueToCompareAgainst; }; } }; class DLL_LINKAGE CWillLastTurns { int turnsRequested; public: CWillLastTurns(int turnsRequested): turnsRequested(turnsRequested) {} bool operator()(const Bonus *bonus) const { return turnsRequested <= 0 //every present effect will last zero (or "less") turns || !Bonus::NTurns(bonus) //so do every not expriing after N-turns effect || bonus->turnsRemain > turnsRequested; } }; class DLL_LINKAGE CWillLastDays { int daysRequested; public: CWillLastDays(int daysRequested): daysRequested(daysRequested) {} bool operator()(const Bonus *bonus) const { if(daysRequested <= 0 || Bonus::Permanent(bonus) || Bonus::OneBattle(bonus)) return true; else if(Bonus::OneDay(bonus)) return false; else if(Bonus::NDays(bonus) || Bonus::OneWeek(bonus)) { return bonus->turnsRemain > daysRequested; } return false; // TODO: ONE_WEEK need support for turnsRemain, but for now we'll exclude all unhandled durations } }; namespace Selector { extern DLL_LINKAGE const CSelectFieldEqual & type(); extern DLL_LINKAGE const CSelectFieldEqual & subtype(); extern DLL_LINKAGE const CSelectFieldEqual & info(); extern DLL_LINKAGE const CSelectFieldEqual & sourceType(); extern DLL_LINKAGE const CSelectFieldEqual & targetSourceType(); extern DLL_LINKAGE const CSelectFieldEqual & effectRange(); CWillLastTurns DLL_LINKAGE turns(int turns); CWillLastDays DLL_LINKAGE days(int days); CSelector DLL_LINKAGE typeSubtype(BonusType Type, BonusSubtypeID Subtype); CSelector DLL_LINKAGE typeSubtypeInfo(BonusType type, BonusSubtypeID subtype, const CAddInfo & info); CSelector DLL_LINKAGE source(BonusSource source, BonusSourceID sourceID); CSelector DLL_LINKAGE sourceTypeSel(BonusSource source); CSelector DLL_LINKAGE valueType(BonusValueType valType); CSelector DLL_LINKAGE typeSubtypeValueType(BonusType Type, BonusSubtypeID Subtype, BonusValueType valType); /** * Selects all bonuses * Usage example: Selector::all.And().And()...) */ extern DLL_LINKAGE CSelector all; /** * Selects nothing * Usage example: Selector::none.Or().Or()...) */ extern DLL_LINKAGE CSelector none; } VCMI_LIB_NAMESPACE_END