mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Merge branch 'develop' into SpellsRefactoring8
This commit is contained in:
commit
d993710f8e
@ -115,15 +115,16 @@ void VCAI::heroMoved(const TryMoveHero & details)
|
||||
NET_EVENT_HANDLER;
|
||||
|
||||
validateObject(details.id); //enemy hero may have left visible area
|
||||
auto hero = cb->getHero(details.id);
|
||||
cachedSectorMaps.clear();
|
||||
|
||||
if(details.result == TryMoveHero::TELEPORTATION)
|
||||
{
|
||||
const int3 from = CGHeroInstance::convertPosition(details.start, false),
|
||||
to = CGHeroInstance::convertPosition(details.end, false);
|
||||
const CGObjectInstance *o1 = vstd::frontOrNull(cb->getVisitableObjs(from)),
|
||||
*o2 = vstd::frontOrNull(cb->getVisitableObjs(to));
|
||||
|
||||
if(details.result == TryMoveHero::TELEPORTATION)
|
||||
{
|
||||
auto t1 = dynamic_cast<const CGTeleport *>(o1);
|
||||
auto t2 = dynamic_cast<const CGTeleport *>(o2);
|
||||
if(t1 && t2)
|
||||
@ -139,6 +140,17 @@ void VCAI::heroMoved(const TryMoveHero & details)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(details.result == TryMoveHero::EMBARK && hero)
|
||||
{
|
||||
//make sure AI not attempt to visit used boat
|
||||
validateObject(hero->boat);
|
||||
}
|
||||
else if(details.result == TryMoveHero::DISEMBARK && o1)
|
||||
{
|
||||
auto boat = dynamic_cast<const CGBoat *>(o1);
|
||||
if(boat)
|
||||
addVisitableObj(boat);
|
||||
}
|
||||
}
|
||||
|
||||
void VCAI::stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute)
|
||||
@ -210,7 +222,7 @@ void VCAI::gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryL
|
||||
{
|
||||
LOG_TRACE_PARAMS(logAi, "victoryLossCheckResult '%s'", victoryLossCheckResult.messageToSelf);
|
||||
NET_EVENT_HANDLER;
|
||||
logAi->debug("Player %d: I heard that player %d %s.", playerID.getNum(), player.getNum(),(victoryLossCheckResult.victory() ? "won" : "lost"));
|
||||
logAi->debug("Player %d (%s): I heard that player %d (%s) %s.", playerID, playerID.getStr(), player, player.getStr(),(victoryLossCheckResult.victory() ? "won" : "lost"));
|
||||
if(player == playerID)
|
||||
{
|
||||
if(victoryLossCheckResult.victory())
|
||||
@ -220,7 +232,7 @@ void VCAI::gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryL
|
||||
}
|
||||
else
|
||||
{
|
||||
logAi->debug("VCAI: Player %d lost. It's me. What a disappointment! :(", player.getNum());
|
||||
logAi->debug("VCAI: Player %d (%s) lost. It's me. What a disappointment! :(", player, player.getStr());
|
||||
}
|
||||
|
||||
finish();
|
||||
@ -309,7 +321,7 @@ void VCAI::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, Q
|
||||
auto firstHero = cb->getHero(hero1);
|
||||
auto secondHero = cb->getHero(hero2);
|
||||
|
||||
status.addQuery(query, boost::str(boost::format("Exchange between heroes %s and %s") % firstHero->name % secondHero->name));
|
||||
status.addQuery(query, boost::str(boost::format("Exchange between heroes %s (%d) and %s (%d)") % firstHero->name % firstHero->tempOwner % secondHero->name % secondHero->tempOwner));
|
||||
|
||||
requestActionASAP([=]()
|
||||
{
|
||||
@ -328,9 +340,13 @@ void VCAI::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, Q
|
||||
this->pickBestArtifacts(h1, h2);
|
||||
};
|
||||
|
||||
if (goalpriority1 > goalpriority2)
|
||||
//Do not attempt army or artifacts exchange if we visited ally player
|
||||
//Visits can still be useful if hero have skills like Scholar
|
||||
if(firstHero->tempOwner != secondHero->tempOwner)
|
||||
logAi->debug("Heroes owned by different players. Do not exchange army or artifacts.");
|
||||
else if(goalpriority1 > goalpriority2)
|
||||
transferFrom2to1 (firstHero, secondHero);
|
||||
else if (goalpriority1 < goalpriority2)
|
||||
else if(goalpriority1 < goalpriority2)
|
||||
transferFrom2to1 (secondHero, firstHero);
|
||||
else //regular criteria
|
||||
{
|
||||
@ -405,6 +421,9 @@ void VCAI::objectRemoved(const CGObjectInstance *obj)
|
||||
{
|
||||
vstd::erase_if_present(visitableObjs, hero->boat);
|
||||
vstd::erase_if_present(alreadyVisited, hero->boat);
|
||||
|
||||
for (auto h : cb->getHeroesInfo())
|
||||
unreserveObject(h, hero->boat);
|
||||
}
|
||||
}
|
||||
|
||||
@ -524,16 +543,13 @@ void VCAI::objectPropertyChanged(const SetObjectProperty * sop)
|
||||
NET_EVENT_HANDLER;
|
||||
if(sop->what == ObjProperty::OWNER)
|
||||
{
|
||||
//we don't want to visit know object twice (do we really?)
|
||||
if(sop->val == playerID.getNum())
|
||||
vstd::erase_if_present(visitableObjs, myCb->getObj(sop->id));
|
||||
else if(myCb->getPlayerRelations(playerID, (PlayerColor)sop->val) == PlayerRelations::ENEMIES)
|
||||
if(myCb->getPlayerRelations(playerID, (PlayerColor)sop->val) == PlayerRelations::ENEMIES)
|
||||
{
|
||||
//we want to visit objects owned by oppponents
|
||||
auto obj = myCb->getObj(sop->id, false);
|
||||
if (obj)
|
||||
{
|
||||
addVisitableObj(obj);
|
||||
addVisitableObj(obj); // TODO: Remove once save compatability broken. In past owned objects were removed from this set
|
||||
vstd::erase_if_present(alreadyVisited, obj);
|
||||
}
|
||||
}
|
||||
@ -728,7 +744,7 @@ void makePossibleUpgrades(const CArmedInstance *obj)
|
||||
|
||||
void VCAI::makeTurn()
|
||||
{
|
||||
logGlobal->info("Player %d starting turn", playerID.getNum());
|
||||
logGlobal->info("Player %d (%s) starting turn", playerID, playerID.getStr());
|
||||
|
||||
MAKING_TURN;
|
||||
boost::shared_lock<boost::shared_mutex> gsLock(cb->getGsMutex());
|
||||
@ -1651,7 +1667,7 @@ void VCAI::battleEnd(const BattleResult *br)
|
||||
assert(status.getBattle() == ONGOING_BATTLE);
|
||||
status.setBattle(ENDING_BATTLE);
|
||||
bool won = br->winner == myCb->battleGetMySide();
|
||||
logAi->debug("Player %d: I %s the %s!", playerID.getNum(), (won ? "won" : "lost"), battlename);
|
||||
logAi->debug("Player %d (%s): I %s the %s!", playerID, playerID.getStr(), (won ? "won" : "lost"), battlename);
|
||||
battlename.clear();
|
||||
CAdventureAI::battleEnd(br);
|
||||
}
|
||||
@ -2233,7 +2249,7 @@ HeroPtr VCAI::primaryHero() const
|
||||
|
||||
void VCAI::endTurn()
|
||||
{
|
||||
logAi->info("Player %d ends turn", playerID.getNum());
|
||||
logAi->info("Player %d (%s) ends turn", playerID, playerID.getStr());
|
||||
if(!status.haveTurn())
|
||||
{
|
||||
logAi->error("Not having turn at the end of turn???");
|
||||
@ -2245,7 +2261,7 @@ void VCAI::endTurn()
|
||||
cb->endTurn();
|
||||
} while(status.haveTurn()); //for some reasons, our request may fail -> stop requesting end of turn only after we've received a confirmation that it's over
|
||||
|
||||
logGlobal->infoStream() << "Player %d ended turn", playerID.getNum();
|
||||
logGlobal->info("Player %d (%s) ended turn", playerID, playerID.getStr());
|
||||
}
|
||||
|
||||
void VCAI::striveToGoal(Goals::TSubgoal ultimateGoal)
|
||||
@ -2501,6 +2517,9 @@ void VCAI::performTypicalActions()
|
||||
{
|
||||
for(auto h : getUnblockedHeroes())
|
||||
{
|
||||
if(!h) //hero might be lost. getUnblockedHeroes() called once on start of turn
|
||||
continue;
|
||||
|
||||
logAi->debugStream() << boost::format("Looking into %s, MP=%d") % h->name.c_str() % h->movement;
|
||||
makePossibleUpgrades(*h);
|
||||
pickBestArtifacts(*h);
|
||||
|
4
Global.h
4
Global.h
@ -146,6 +146,10 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
|
||||
#define BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE 1
|
||||
#define BOOST_BIND_NO_PLACEHOLDERS
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER == 1900)
|
||||
#define BOOST_NO_CXX11_VARIADIC_TEMPLATES //Variadic templates are buggy in VS2015, so turn this off to avoid compile errors
|
||||
#endif
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/current_function.hpp>
|
||||
|
@ -240,6 +240,7 @@ int main(int argc, char** argv)
|
||||
("autoSkip", "automatically skip turns in GUI")
|
||||
("disable-video", "disable video player")
|
||||
("nointro,i", "skips intro movies")
|
||||
("donotstartserver,d","do not attempt to start server and just connect to it instead server")
|
||||
("loadserver","specifies we are the multiplayer server for loaded games")
|
||||
("loadnumplayers",po::value<int>(),"specifies the number of players connecting to a multiplayer game")
|
||||
("loadhumanplayerindices",po::value<std::vector<int>>(),"Indexes of human players (0=Red, etc.)")
|
||||
@ -277,6 +278,10 @@ int main(int argc, char** argv)
|
||||
gNoGUI = true;
|
||||
vm.insert(std::pair<std::string, po::variable_value>("onlyAI", po::variable_value()));
|
||||
}
|
||||
if(vm.count("donotstartserver"))
|
||||
{
|
||||
CServerHandler::DO_NOT_START_SERVER = true;
|
||||
}
|
||||
|
||||
// Have effect on X11 system only (Linux).
|
||||
// For whatever reason in fullscreen mode SDL takes "raw" mouse input from DGA X11 extension
|
||||
|
@ -719,6 +719,10 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
|
||||
else if(current)
|
||||
{
|
||||
SelectMap sm(*current);
|
||||
// FIXME: Super dirty hack to avoid crash on multiplayer game start.
|
||||
// There is some issues with TriggeredEvent serialization that cause it.
|
||||
// We'll look into them once refactored serializer fixed and merged
|
||||
sm.mapInfo->mapHeader->triggeredEvents.clear();
|
||||
*serv << &sm;
|
||||
|
||||
UpdateStartOptions uso(sInfo);
|
||||
|
@ -928,10 +928,15 @@ std::string CClient::aiNameForPlayer(const PlayerSettings &ps, bool battleAI)
|
||||
return goodAI;
|
||||
}
|
||||
|
||||
bool CServerHandler::DO_NOT_START_SERVER = false;
|
||||
|
||||
void CServerHandler::startServer()
|
||||
{
|
||||
if(DO_NOT_START_SERVER)
|
||||
return;
|
||||
|
||||
th.update();
|
||||
|
||||
serverThread = new boost::thread(&CServerHandler::callServer, this); //runs server executable;
|
||||
if(verbose)
|
||||
logNetwork->infoStream() << "Setting up thread calling server: " << th.getDiff();
|
||||
@ -939,6 +944,9 @@ void CServerHandler::startServer()
|
||||
|
||||
void CServerHandler::waitForServer()
|
||||
{
|
||||
if(DO_NOT_START_SERVER)
|
||||
return;
|
||||
|
||||
if(!serverThread)
|
||||
startServer();
|
||||
|
||||
|
@ -42,6 +42,8 @@ class CServerHandler
|
||||
private:
|
||||
void callServer(); //calls server via system(), should be called as thread
|
||||
public:
|
||||
static bool DO_NOT_START_SERVER;
|
||||
|
||||
CStopWatch th;
|
||||
boost::thread *serverThread; //thread that called system to run server
|
||||
SharedMem *shared; //interprocess memory (for waiting for server)
|
||||
|
@ -627,6 +627,8 @@ void CCastleBuildings::buildingClicked(BuildingID building)
|
||||
case BuildingID::SHIPYARD:
|
||||
if(town->shipyardStatus() == IBoatGenerator::GOOD)
|
||||
LOCPLINT->showShipyardDialog(town);
|
||||
else if(town->shipyardStatus() == IBoatGenerator::BOAT_ALREADY_BUILT)
|
||||
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[51]);
|
||||
break;
|
||||
|
||||
case BuildingID::FORT:
|
||||
|
@ -520,6 +520,24 @@ EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTow
|
||||
if(vstd::contains(t->forbiddenBuildings, ID))
|
||||
return EBuildingState::FORBIDDEN; //forbidden
|
||||
|
||||
auto possiblyNotBuiltTest = [&](BuildingID id) -> bool
|
||||
{
|
||||
return ((id == BuildingID::CAPITOL) ? true : !t->hasBuilt(id));
|
||||
};
|
||||
|
||||
std::function<bool(BuildingID id)> allowedTest = [&](BuildingID id) -> bool
|
||||
{
|
||||
if (vstd::contains(t->forbiddenBuildings, id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return t->genBuildingRequirements(id, true).satisfiable(allowedTest, possiblyNotBuiltTest);
|
||||
};
|
||||
|
||||
if (!t->genBuildingRequirements(ID, true).satisfiable(allowedTest, possiblyNotBuiltTest))
|
||||
return EBuildingState::FORBIDDEN;
|
||||
|
||||
if(ID == BuildingID::CAPITOL)
|
||||
{
|
||||
const PlayerState *ps = getPlayer(t->tempOwner, false);
|
||||
|
@ -2139,8 +2139,6 @@ void CGameState::updateRumor()
|
||||
int rumorId = -1, rumorExtra = -1;
|
||||
auto & rand = getRandomGenerator();
|
||||
rumor.type = *RandomGeneratorUtil::nextItem(rumorTypes, rand);
|
||||
if(!map->rumors.size() && rumor.type == RumorState::TYPE_MAP)
|
||||
rumor.type = RumorState::TYPE_RAND;
|
||||
|
||||
do
|
||||
{
|
||||
@ -2181,9 +2179,14 @@ void CGameState::updateRumor()
|
||||
break;
|
||||
}
|
||||
case RumorState::TYPE_MAP:
|
||||
// Makes sure that map rumors only used if there enough rumors too choose from
|
||||
if(map->rumors.size() && (map->rumors.size() > 1 || !rumor.last.count(RumorState::TYPE_MAP)))
|
||||
{
|
||||
rumorId = rand.nextInt(map->rumors.size() - 1);
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
rumor.type = RumorState::TYPE_RAND;
|
||||
|
||||
case RumorState::TYPE_RAND:
|
||||
do
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include "CArtHandler.h"
|
||||
#include "CCreatureHandler.h"
|
||||
#include "spells/CSpellHandler.h"
|
||||
#include "StringConstants.h"
|
||||
#include "CGeneralTextHandler.h"
|
||||
|
||||
const SlotID SlotID::COMMANDER_SLOT_PLACEHOLDER = SlotID(-2);
|
||||
const SlotID SlotID::SUMMONED_SLOT_PLACEHOLDER = SlotID(-3);
|
||||
@ -57,6 +59,32 @@ bool PlayerColor::isValidPlayer() const
|
||||
return num < PLAYER_LIMIT_I;
|
||||
}
|
||||
|
||||
std::string PlayerColor::getStr(bool L10n) const
|
||||
{
|
||||
std::string ret = "unnamed";
|
||||
if(isValidPlayer())
|
||||
{
|
||||
if(L10n)
|
||||
ret = VLC->generaltexth->colors[num];
|
||||
else
|
||||
ret = GameConstants::PLAYER_COLOR_NAMES[num];
|
||||
}
|
||||
else if(L10n)
|
||||
{
|
||||
ret = VLC->generaltexth->allTexts[508];
|
||||
ret[0] = std::tolower(ret[0]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string PlayerColor::getStrCap(bool L10n) const
|
||||
{
|
||||
std::string ret = getStr(L10n);
|
||||
ret[0] = std::toupper(ret[0]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream & os, const Battle::ActionType actionType)
|
||||
{
|
||||
static const std::map<Battle::ActionType, std::string> actionTypeToString =
|
||||
|
@ -262,6 +262,9 @@ class PlayerColor : public BaseForID<PlayerColor, ui8>
|
||||
|
||||
DLL_LINKAGE bool isValidPlayer() const; //valid means < PLAYER_LIMIT (especially non-neutral)
|
||||
|
||||
DLL_LINKAGE std::string getStr(bool L10n = false) const;
|
||||
DLL_LINKAGE std::string getStrCap(bool L10n = false) const;
|
||||
|
||||
friend class CGameInfoCallback;
|
||||
friend class CNonConstInfoCallback;
|
||||
};
|
||||
|
@ -99,6 +99,129 @@ namespace LogicalExpressionDetail
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ContainedClass>
|
||||
class SatisfiabilityVisitor;
|
||||
|
||||
template <typename ContainedClass>
|
||||
class FalsifiabilityVisitor;
|
||||
|
||||
template <typename ContainedClass>
|
||||
class PossibilityVisitor : public boost::static_visitor<bool>
|
||||
{
|
||||
typedef ExpressionBase<ContainedClass> Base;
|
||||
|
||||
protected:
|
||||
std::function<bool(const typename Base::Value &)> satisfiabilityTest;
|
||||
std::function<bool(const typename Base::Value &)> falsifiabilityTest;
|
||||
SatisfiabilityVisitor<ContainedClass> *satisfiabilityVisitor;
|
||||
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(*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(*falsifiabilityVisitor, expr);
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
PossibilityVisitor(std::function<bool (const typename Base::Value &)> satisfiabilityTest,
|
||||
std::function<bool (const typename Base::Value &)> falsifiabilityTest):
|
||||
satisfiabilityTest(satisfiabilityTest),
|
||||
falsifiabilityTest(falsifiabilityTest),
|
||||
satisfiabilityVisitor(nullptr),
|
||||
falsifiabilityVisitor(nullptr)
|
||||
{}
|
||||
|
||||
void setSatisfiabilityVisitor(SatisfiabilityVisitor<ContainedClass> *satisfiabilityVisitor)
|
||||
{
|
||||
this->satisfiabilityVisitor = satisfiabilityVisitor;
|
||||
}
|
||||
|
||||
void setFalsifiabilityVisitor(FalsifiabilityVisitor<ContainedClass> *falsifiabilityVisitor)
|
||||
{
|
||||
this->falsifiabilityVisitor = falsifiabilityVisitor;
|
||||
}
|
||||
};
|
||||
|
||||
/// Visitor to test whether expression's value can be true
|
||||
template <typename ContainedClass>
|
||||
class SatisfiabilityVisitor : public PossibilityVisitor<ContainedClass>
|
||||
{
|
||||
typedef ExpressionBase<ContainedClass> Base;
|
||||
|
||||
public:
|
||||
SatisfiabilityVisitor(std::function<bool (const typename Base::Value &)> satisfiabilityTest,
|
||||
std::function<bool (const typename Base::Value &)> falsifiabilityTest):
|
||||
PossibilityVisitor<ContainedClass>(satisfiabilityTest, falsifiabilityTest)
|
||||
{
|
||||
this->setSatisfiabilityVisitor(this);
|
||||
}
|
||||
|
||||
bool operator()(const typename Base::OperatorAny & element) const
|
||||
{
|
||||
return this->countSatisfiable(element.expressions) != 0;
|
||||
}
|
||||
|
||||
bool operator()(const typename Base::OperatorAll & element) const
|
||||
{
|
||||
return this->countSatisfiable(element.expressions) == element.expressions.size();
|
||||
}
|
||||
|
||||
bool operator()(const typename Base::OperatorNone & element) const
|
||||
{
|
||||
return this->countFalsifiable(element.expressions) == element.expressions.size();
|
||||
}
|
||||
|
||||
bool operator()(const typename Base::Value & element) const
|
||||
{
|
||||
return this->satisfiabilityTest(element);
|
||||
}
|
||||
};
|
||||
|
||||
/// Visitor to test whether expression's value can be false
|
||||
template <typename ContainedClass>
|
||||
class FalsifiabilityVisitor : public PossibilityVisitor<ContainedClass>
|
||||
{
|
||||
typedef ExpressionBase<ContainedClass> Base;
|
||||
|
||||
public:
|
||||
FalsifiabilityVisitor(std::function<bool (const typename Base::Value &)> satisfiabilityTest,
|
||||
std::function<bool (const typename Base::Value &)> falsifiabilityTest):
|
||||
PossibilityVisitor<ContainedClass>(satisfiabilityTest, falsifiabilityTest)
|
||||
{
|
||||
this->setFalsifiabilityVisitor(this);
|
||||
}
|
||||
|
||||
bool operator()(const typename Base::OperatorAny & element) const
|
||||
{
|
||||
return this->countFalsifiable(element.expressions) == element.expressions.size();
|
||||
}
|
||||
|
||||
bool operator()(const typename Base::OperatorAll & element) const
|
||||
{
|
||||
return this->countFalsifiable(element.expressions) != 0;
|
||||
}
|
||||
|
||||
bool operator()(const typename Base::OperatorNone & element) const
|
||||
{
|
||||
return this->countSatisfiable(element.expressions) != 0;
|
||||
}
|
||||
|
||||
bool operator()(const typename Base::Value & element) const
|
||||
{
|
||||
return this->falsifiabilityTest(element);
|
||||
}
|
||||
};
|
||||
|
||||
/// visitor that is trying to generates candidates that must be fulfilled
|
||||
/// to complete this expression
|
||||
template <typename ContainedClass>
|
||||
@ -436,6 +559,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, falsifiabilityTest);
|
||||
LogicalExpressionDetail::FalsifiabilityVisitor<Value> falsifiabilityVisitor(satisfiabilityTest, falsifiabilityTest);
|
||||
|
||||
satisfiabilityVisitor.setFalsifiabilityVisitor(&falsifiabilityVisitor);
|
||||
falsifiabilityVisitor.setSatisfiabilityVisitor(&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
|
||||
{
|
||||
|
@ -1124,7 +1124,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);
|
||||
|
||||
@ -1132,17 +1132,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;
|
||||
|
@ -498,7 +498,9 @@ IQuestObject::IQuestObject():
|
||||
|
||||
IQuestObject::~IQuestObject()
|
||||
{
|
||||
delete quest;
|
||||
///Information about quest should remain accessible even if IQuestObject removed from map
|
||||
///All CQuest objects are freed in CMap destructor
|
||||
//delete quest;
|
||||
}
|
||||
|
||||
bool IQuestObject::checkQuest(const CGHeroInstance* h) const
|
||||
|
@ -1607,14 +1607,14 @@ void CGShrine::onHeroVisit( const CGHeroInstance * h ) const
|
||||
{
|
||||
iw.text.addTxt(MetaString::ADVOB_TXT,131);
|
||||
}
|
||||
else if(ID == Obj::SHRINE_OF_MAGIC_THOUGHT && !h->getSecSkillLevel(SecondarySkill::WISDOM)) //it's third level spell and hero doesn't have wisdom
|
||||
{
|
||||
iw.text.addTxt(MetaString::ADVOB_TXT,130);
|
||||
}
|
||||
else if(vstd::contains(h->spells,spell))//hero already knows the spell
|
||||
{
|
||||
iw.text.addTxt(MetaString::ADVOB_TXT,174);
|
||||
}
|
||||
else if(ID == Obj::SHRINE_OF_MAGIC_THOUGHT && !h->getSecSkillLevel(SecondarySkill::WISDOM)) //it's third level spell and hero doesn't have wisdom
|
||||
{
|
||||
iw.text.addTxt(MetaString::ADVOB_TXT,130);
|
||||
}
|
||||
else //give spell
|
||||
{
|
||||
std::set<SpellID> spells;
|
||||
|
@ -245,6 +245,9 @@ CMap::~CMap()
|
||||
|
||||
for(auto obj : objects)
|
||||
obj.dellNull();
|
||||
|
||||
for(auto quest : quests)
|
||||
quest.dellNull();
|
||||
}
|
||||
|
||||
void CMap::removeBlockVisTiles(CGObjectInstance * obj, bool total)
|
||||
|
@ -945,8 +945,8 @@ void CGameHandler::handleConnection(std::set<PlayerColor> players, CConnection &
|
||||
|
||||
packType = typeList.getTypeID(pack); //get the id of type
|
||||
|
||||
logGlobal->trace("Received client message (request %d by player %d) of type with ID=%d (%s).\n",
|
||||
requestID, player.getNum(), packType, typeid(*pack).name());
|
||||
logGlobal->trace("Received client message (request %d by player %d (%s)) of type with ID=%d (%s).\n",
|
||||
requestID, player, player.getStr(), packType, typeid(*pack).name());
|
||||
}
|
||||
|
||||
//prepare struct informing that action was applied
|
||||
@ -1963,7 +1963,7 @@ bool CGameHandler::moveHero( ObjectInstanceID hid, int3 dst, ui8 teleporting, bo
|
||||
return false;
|
||||
}
|
||||
|
||||
logGlobal->trace("Player %d wants to move hero %d from %s to %s", asker.getNum(), hid.getNum(), h->pos(), dst());
|
||||
logGlobal->trace("Player %d (%s) wants to move hero %d from %s to %s", asker, asker.getStr(), hid.getNum(), h->pos(), dst());
|
||||
const int3 hmpos = CGHeroInstance::convertPosition(dst, false);
|
||||
|
||||
if(!gs->map->isInTheMap(hmpos))
|
||||
|
@ -579,6 +579,7 @@ int main(int argc, char** argv)
|
||||
logConfig.configureDefault();
|
||||
|
||||
handleCommandOptions(argc, argv);
|
||||
if(cmdLineOptions.count("port"))
|
||||
port = cmdLineOptions["port"].as<int>();
|
||||
logNetwork->info("Port %d will be used.", port);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user