Skip to content

Commit 4000346

Browse files
committed
Check if building's dependencies are allowed
1 parent 6747555 commit 4000346

File tree

4 files changed

+173
-5
lines changed

4 files changed

+173
-5
lines changed

lib/CGameInfoCallback.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,28 @@ EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTow
520520
if(vstd::contains(t->forbiddenBuildings, ID))
521521
return EBuildingState::FORBIDDEN; //forbidden
522522

523+
std::function<bool(BuildingID id)> allowedTest;
524+
std::function<bool(BuildingID id)> possiblyNotBuiltTest;
525+
526+
allowedTest = [&](BuildingID id) -> bool
527+
{
528+
if (vstd::contains(t->forbiddenBuildings, id))
529+
{
530+
return false;
531+
}
532+
533+
return t->genBuildingRequirements(id, true).satisfiable(allowedTest, possiblyNotBuiltTest);
534+
};
535+
536+
possiblyNotBuiltTest = [&](BuildingID id) -> bool
537+
{
538+
//TODO consider destroing
539+
return !t->hasBuilt(id);
540+
};
541+
542+
if (!t->genBuildingRequirements(ID, true).satisfiable(allowedTest, possiblyNotBuiltTest))
543+
return EBuildingState::FORBIDDEN;
544+
523545
if(ID == BuildingID::CAPITOL)
524546
{
525547
const PlayerState *ps = getPlayer(t->tempOwner, false);

lib/LogicalExpression.h

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,123 @@ namespace LogicalExpressionDetail
9999
}
100100
};
101101

102+
template <typename ContainedClass>
103+
class FalsifiabilityVisitor;
104+
105+
/// Visitor to test whether expression's value can be true
106+
template <typename ContainedClass>
107+
class SatisfiabilityVisitor : public boost::static_visitor<bool>
108+
{
109+
typedef ExpressionBase<ContainedClass> Base;
110+
111+
std::function<bool(const typename Base::Value &)> satisfiabilityTest;
112+
FalsifiabilityVisitor<ContainedClass> *falsifiabilityVisitor;
113+
114+
size_t countSatisfiable(const std::vector<typename Base::Variant> & element) const
115+
{
116+
return boost::range::count_if(element, [&](const typename Base::Variant & expr)
117+
{
118+
return boost::apply_visitor(*this, expr);
119+
});
120+
}
121+
122+
size_t countFalsifiable(const std::vector<typename Base::Variant> & element) const
123+
{
124+
return boost::range::count_if(element, [&](const typename Base::Variant & expr)
125+
{
126+
return boost::apply_visitor(*falsifiabilityVisitor, expr);
127+
});
128+
}
129+
130+
public:
131+
SatisfiabilityVisitor(std::function<bool (const typename Base::Value &)> satisfiabilityTest):
132+
satisfiabilityTest(satisfiabilityTest),
133+
falsifiabilityVisitor(nullptr)
134+
{}
135+
136+
void setFalsifiabilityVisitor(FalsifiabilityVisitor<ContainedClass> *falsifiabilityVisitor)
137+
{
138+
this->falsifiabilityVisitor = falsifiabilityVisitor;
139+
}
140+
141+
bool operator()(const typename Base::OperatorAny & element) const
142+
{
143+
return countSatisfiable(element.expressions) != 0;
144+
}
145+
146+
bool operator()(const typename Base::OperatorAll & element) const
147+
{
148+
return countSatisfiable(element.expressions) == element.expressions.size();
149+
}
150+
151+
bool operator()(const typename Base::OperatorNone & element) const
152+
{
153+
return countFalsifiable(element.expressions) == element.expressions.size();
154+
}
155+
156+
bool operator()(const typename Base::Value & element) const
157+
{
158+
return satisfiabilityTest(element);
159+
}
160+
};
161+
162+
/// Visitor to test whether expression's value can be false
163+
template <typename ContainedClass>
164+
class FalsifiabilityVisitor : public boost::static_visitor<bool>
165+
{
166+
typedef ExpressionBase<ContainedClass> Base;
167+
168+
std::function<bool(const typename Base::Value &)> falsifiabilityTest;
169+
SatisfiabilityVisitor<ContainedClass> *satisfiabilityVisitor;
170+
171+
size_t countSatisfiable(const std::vector<typename Base::Variant> & element) const
172+
{
173+
return boost::range::count_if(element, [&](const typename Base::Variant & expr)
174+
{
175+
return boost::apply_visitor(*satisfiabilityVisitor, expr);
176+
});
177+
}
178+
179+
size_t countFalsifiable(const std::vector<typename Base::Variant> & element) const
180+
{
181+
return boost::range::count_if(element, [&](const typename Base::Variant & expr)
182+
{
183+
return boost::apply_visitor(*this, expr);
184+
});
185+
}
186+
187+
public:
188+
FalsifiabilityVisitor(std::function<bool (const typename Base::Value &)> falsifiabilityTest):
189+
falsifiabilityTest(falsifiabilityTest),
190+
satisfiabilityVisitor(nullptr)
191+
{}
192+
193+
void setFalsifiabilityVisitor(SatisfiabilityVisitor<ContainedClass> *satisfiabilityVisitor)
194+
{
195+
this->satisfiabilityVisitor = satisfiabilityVisitor;
196+
}
197+
198+
bool operator()(const typename Base::OperatorAny & element) const
199+
{
200+
return countFalsifiable(element.expressions) == element.expressions.size();
201+
}
202+
203+
bool operator()(const typename Base::OperatorAll & element) const
204+
{
205+
return countFalsifiable(element.expressions) != 0;
206+
}
207+
208+
bool operator()(const typename Base::OperatorNone & element) const
209+
{
210+
return countSatisfiable(element.expressions) != 0;
211+
}
212+
213+
bool operator()(const typename Base::Value & element) const
214+
{
215+
return falsifiabilityTest(element);
216+
}
217+
};
218+
102219
/// visitor that is trying to generates candidates that must be fulfilled
103220
/// to complete this expression
104221
template <typename ContainedClass>
@@ -436,6 +553,30 @@ class LogicalExpression
436553
return boost::apply_visitor(testVisitor, data);
437554
}
438555

556+
/// calculates if expression can evaluate to "true".
557+
bool satisfiable (std::function<bool(const Value &)> satisfiabilityTest, std::function<bool(const Value &)> falsifiabilityTest) const
558+
{
559+
LogicalExpressionDetail::SatisfiabilityVisitor<Value> satisfiabilityVisitor(satisfiabilityTest);
560+
LogicalExpressionDetail::FalsifiabilityVisitor<Value> falsifiabilityVisitor(falsifiabilityTest);
561+
562+
satisfiabilityVisitor.setFalsifiabilityVisitor(&falsifiabilityVisitor);
563+
falsifiabilityVisitor.setFalsifiabilityVisitor(&satisfiabilityVisitor);
564+
565+
return boost::apply_visitor(satisfiabilityVisitor, data);
566+
}
567+
568+
/// calculates if expression can evaluate to "false".
569+
bool falsifiable(std::function<bool(const Value &)> satisfiabilityTest, std::function<bool(const Value &)> falsifiabilityTest) const
570+
{
571+
LogicalExpressionDetail::SatisfiabilityVisitor<Value> satisfiabilityVisitor(satisfiabilityTest);
572+
LogicalExpressionDetail::FalsifiabilityVisitor<Value> falsifiabilityVisitor(falsifiabilityTest);
573+
574+
satisfiabilityVisitor.setFalsifiabilityVisitor(&falsifiabilityVisitor);
575+
falsifiabilityVisitor.setFalsifiabilityVisitor(&satisfiabilityVisitor);
576+
577+
return boost::apply_visitor(falsifiabilityVisitor, data);
578+
}
579+
439580
/// generates list of candidates that can be fulfilled by caller (like AI)
440581
std::vector<Value> getFulfillmentCandidates(std::function<bool(const Value &)> toBool) const
441582
{

lib/mapObjects/CGTownInstance.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,25 +1126,30 @@ bool CGTownInstance::hasBuilt(BuildingID buildingID) const
11261126
return vstd::contains(builtBuildings, buildingID);
11271127
}
11281128

1129-
CBuilding::TRequired CGTownInstance::genBuildingRequirements(BuildingID buildID) const
1129+
CBuilding::TRequired CGTownInstance::genBuildingRequirements(BuildingID buildID, bool deep) const
11301130
{
11311131
const CBuilding * building = town->buildings.at(buildID);
11321132

11331133
std::function<CBuilding::TRequired::Variant(const BuildingID &)> dependTest =
11341134
[&](const BuildingID & id) -> CBuilding::TRequired::Variant
11351135
{
11361136
const CBuilding * build = town->buildings.at(id);
1137+
CBuilding::TRequired::OperatorAll requirements;
11371138

11381139
if (!hasBuilt(id))
1139-
return id;
1140+
{
1141+
requirements.expressions.push_back(id);
11401142

1141-
CBuilding::TRequired::OperatorAll requirements;
1143+
if (!deep)
1144+
{
1145+
return requirements;
1146+
}
1147+
}
11421148

11431149
if (build->upgrade != BuildingID::NONE)
11441150
requirements.expressions.push_back(dependTest(build->upgrade));
11451151

11461152
requirements.expressions.push_back(build->requirements.morph(dependTest));
1147-
11481153
return requirements;
11491154
};
11501155

lib/mapObjects/CGTownInstance.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ class DLL_LINKAGE CGTownInstance : public CGDwelling, public IShipyard, public I
238238
bool armedGarrison() const; //true if town has creatures in garrison or garrisoned hero
239239
int getTownLevel() const;
240240

241-
CBuilding::TRequired genBuildingRequirements(BuildingID build) const;
241+
CBuilding::TRequired genBuildingRequirements(BuildingID build, bool deep = false) const;
242242

243243
void mergeGarrisonOnSiege() const; // merge garrison into army of visiting hero
244244
void removeCapitols (PlayerColor owner) const;

0 commit comments

Comments
 (0)