mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Check if building's dependencies are allowed
This commit is contained in:
parent
6747555339
commit
40003460ca
@ -520,6 +520,28 @@ EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTow
|
||||
if(vstd::contains(t->forbiddenBuildings, ID))
|
||||
return EBuildingState::FORBIDDEN; //forbidden
|
||||
|
||||
std::function<bool(BuildingID id)> allowedTest;
|
||||
std::function<bool(BuildingID id)> possiblyNotBuiltTest;
|
||||
|
||||
allowedTest = [&](BuildingID id) -> bool
|
||||
{
|
||||
if (vstd::contains(t->forbiddenBuildings, id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return t->genBuildingRequirements(id, true).satisfiable(allowedTest, possiblyNotBuiltTest);
|
||||
};
|
||||
|
||||
possiblyNotBuiltTest = [&](BuildingID id) -> bool
|
||||
{
|
||||
//TODO consider destroing
|
||||
return !t->hasBuilt(id);
|
||||
};
|
||||
|
||||
if (!t->genBuildingRequirements(ID, true).satisfiable(allowedTest, possiblyNotBuiltTest))
|
||||
return EBuildingState::FORBIDDEN;
|
||||
|
||||
if(ID == BuildingID::CAPITOL)
|
||||
{
|
||||
const PlayerState *ps = getPlayer(t->tempOwner, false);
|
||||
|
@ -99,6 +99,123 @@ namespace LogicalExpressionDetail
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ContainedClass>
|
||||
class FalsifiabilityVisitor;
|
||||
|
||||
/// Visitor to test whether expression's value can be true
|
||||
template <typename ContainedClass>
|
||||
class SatisfiabilityVisitor : public boost::static_visitor<bool>
|
||||
{
|
||||
typedef ExpressionBase<ContainedClass> Base;
|
||||
|
||||
std::function<bool(const typename Base::Value &)> satisfiabilityTest;
|
||||
FalsifiabilityVisitor<ContainedClass> *falsifiabilityVisitor;
|
||||
|
||||
size_t countSatisfiable(const std::vector<typename Base::Variant> & element) const
|
||||
{
|
||||
return boost::range::count_if(element, [&](const typename Base::Variant & expr)
|
||||
{
|
||||
return boost::apply_visitor(*this, expr);
|
||||
});
|
||||
}
|
||||
|
||||
size_t countFalsifiable(const std::vector<typename Base::Variant> & element) const
|
||||
{
|
||||
return boost::range::count_if(element, [&](const typename Base::Variant & expr)
|
||||
{
|
||||
return boost::apply_visitor(*falsifiabilityVisitor, expr);
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
SatisfiabilityVisitor(std::function<bool (const typename Base::Value &)> satisfiabilityTest):
|
||||
satisfiabilityTest(satisfiabilityTest),
|
||||
falsifiabilityVisitor(nullptr)
|
||||
{}
|
||||
|
||||
void setFalsifiabilityVisitor(FalsifiabilityVisitor<ContainedClass> *falsifiabilityVisitor)
|
||||
{
|
||||
this->falsifiabilityVisitor = falsifiabilityVisitor;
|
||||
}
|
||||
|
||||
bool operator()(const typename Base::OperatorAny & element) const
|
||||
{
|
||||
return countSatisfiable(element.expressions) != 0;
|
||||
}
|
||||
|
||||
bool operator()(const typename Base::OperatorAll & element) const
|
||||
{
|
||||
return countSatisfiable(element.expressions) == element.expressions.size();
|
||||
}
|
||||
|
||||
bool operator()(const typename Base::OperatorNone & element) const
|
||||
{
|
||||
return countFalsifiable(element.expressions) == element.expressions.size();
|
||||
}
|
||||
|
||||
bool operator()(const typename Base::Value & element) const
|
||||
{
|
||||
return satisfiabilityTest(element);
|
||||
}
|
||||
};
|
||||
|
||||
/// Visitor to test whether expression's value can be false
|
||||
template <typename ContainedClass>
|
||||
class FalsifiabilityVisitor : public boost::static_visitor<bool>
|
||||
{
|
||||
typedef ExpressionBase<ContainedClass> Base;
|
||||
|
||||
std::function<bool(const typename Base::Value &)> falsifiabilityTest;
|
||||
SatisfiabilityVisitor<ContainedClass> *satisfiabilityVisitor;
|
||||
|
||||
size_t countSatisfiable(const std::vector<typename Base::Variant> & element) const
|
||||
{
|
||||
return boost::range::count_if(element, [&](const typename Base::Variant & expr)
|
||||
{
|
||||
return boost::apply_visitor(*satisfiabilityVisitor, expr);
|
||||
});
|
||||
}
|
||||
|
||||
size_t countFalsifiable(const std::vector<typename Base::Variant> & element) const
|
||||
{
|
||||
return boost::range::count_if(element, [&](const typename Base::Variant & expr)
|
||||
{
|
||||
return boost::apply_visitor(*this, expr);
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
FalsifiabilityVisitor(std::function<bool (const typename Base::Value &)> falsifiabilityTest):
|
||||
falsifiabilityTest(falsifiabilityTest),
|
||||
satisfiabilityVisitor(nullptr)
|
||||
{}
|
||||
|
||||
void setFalsifiabilityVisitor(SatisfiabilityVisitor<ContainedClass> *satisfiabilityVisitor)
|
||||
{
|
||||
this->satisfiabilityVisitor = satisfiabilityVisitor;
|
||||
}
|
||||
|
||||
bool operator()(const typename Base::OperatorAny & element) const
|
||||
{
|
||||
return countFalsifiable(element.expressions) == element.expressions.size();
|
||||
}
|
||||
|
||||
bool operator()(const typename Base::OperatorAll & element) const
|
||||
{
|
||||
return countFalsifiable(element.expressions) != 0;
|
||||
}
|
||||
|
||||
bool operator()(const typename Base::OperatorNone & element) const
|
||||
{
|
||||
return countSatisfiable(element.expressions) != 0;
|
||||
}
|
||||
|
||||
bool operator()(const typename Base::Value & element) const
|
||||
{
|
||||
return falsifiabilityTest(element);
|
||||
}
|
||||
};
|
||||
|
||||
/// visitor that is trying to generates candidates that must be fulfilled
|
||||
/// to complete this expression
|
||||
template <typename ContainedClass>
|
||||
@ -436,6 +553,30 @@ public:
|
||||
return boost::apply_visitor(testVisitor, data);
|
||||
}
|
||||
|
||||
/// calculates if expression can evaluate to "true".
|
||||
bool satisfiable (std::function<bool(const Value &)> satisfiabilityTest, std::function<bool(const Value &)> falsifiabilityTest) const
|
||||
{
|
||||
LogicalExpressionDetail::SatisfiabilityVisitor<Value> satisfiabilityVisitor(satisfiabilityTest);
|
||||
LogicalExpressionDetail::FalsifiabilityVisitor<Value> falsifiabilityVisitor(falsifiabilityTest);
|
||||
|
||||
satisfiabilityVisitor.setFalsifiabilityVisitor(&falsifiabilityVisitor);
|
||||
falsifiabilityVisitor.setFalsifiabilityVisitor(&satisfiabilityVisitor);
|
||||
|
||||
return boost::apply_visitor(satisfiabilityVisitor, data);
|
||||
}
|
||||
|
||||
/// calculates if expression can evaluate to "false".
|
||||
bool falsifiable(std::function<bool(const Value &)> satisfiabilityTest, std::function<bool(const Value &)> falsifiabilityTest) const
|
||||
{
|
||||
LogicalExpressionDetail::SatisfiabilityVisitor<Value> satisfiabilityVisitor(satisfiabilityTest);
|
||||
LogicalExpressionDetail::FalsifiabilityVisitor<Value> falsifiabilityVisitor(falsifiabilityTest);
|
||||
|
||||
satisfiabilityVisitor.setFalsifiabilityVisitor(&falsifiabilityVisitor);
|
||||
falsifiabilityVisitor.setFalsifiabilityVisitor(&satisfiabilityVisitor);
|
||||
|
||||
return boost::apply_visitor(falsifiabilityVisitor, data);
|
||||
}
|
||||
|
||||
/// generates list of candidates that can be fulfilled by caller (like AI)
|
||||
std::vector<Value> getFulfillmentCandidates(std::function<bool(const Value &)> toBool) const
|
||||
{
|
||||
|
@ -1126,7 +1126,7 @@ bool CGTownInstance::hasBuilt(BuildingID buildingID) const
|
||||
return vstd::contains(builtBuildings, buildingID);
|
||||
}
|
||||
|
||||
CBuilding::TRequired CGTownInstance::genBuildingRequirements(BuildingID buildID) const
|
||||
CBuilding::TRequired CGTownInstance::genBuildingRequirements(BuildingID buildID, bool deep) const
|
||||
{
|
||||
const CBuilding * building = town->buildings.at(buildID);
|
||||
|
||||
@ -1134,17 +1134,22 @@ CBuilding::TRequired CGTownInstance::genBuildingRequirements(BuildingID buildID)
|
||||
[&](const BuildingID & id) -> CBuilding::TRequired::Variant
|
||||
{
|
||||
const CBuilding * build = town->buildings.at(id);
|
||||
CBuilding::TRequired::OperatorAll requirements;
|
||||
|
||||
if (!hasBuilt(id))
|
||||
return id;
|
||||
{
|
||||
requirements.expressions.push_back(id);
|
||||
|
||||
CBuilding::TRequired::OperatorAll requirements;
|
||||
if (!deep)
|
||||
{
|
||||
return requirements;
|
||||
}
|
||||
}
|
||||
|
||||
if (build->upgrade != BuildingID::NONE)
|
||||
requirements.expressions.push_back(dependTest(build->upgrade));
|
||||
|
||||
requirements.expressions.push_back(build->requirements.morph(dependTest));
|
||||
|
||||
return requirements;
|
||||
};
|
||||
|
||||
|
@ -238,7 +238,7 @@ public:
|
||||
bool armedGarrison() const; //true if town has creatures in garrison or garrisoned hero
|
||||
int getTownLevel() const;
|
||||
|
||||
CBuilding::TRequired genBuildingRequirements(BuildingID build) const;
|
||||
CBuilding::TRequired genBuildingRequirements(BuildingID build, bool deep = false) const;
|
||||
|
||||
void mergeGarrisonOnSiege() const; // merge garrison into army of visiting hero
|
||||
void removeCapitols (PlayerColor owner) const;
|
||||
|
Loading…
Reference in New Issue
Block a user