1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-14 02:33:51 +02:00

Merge branch 'develop' into SpellsRefactoring8

This commit is contained in:
AlexVinS 2016-09-17 20:29:44 +03:00
commit d993710f8e
19 changed files with 292 additions and 38 deletions

View File

@ -115,15 +115,16 @@ void VCAI::heroMoved(const TryMoveHero & details)
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
validateObject(details.id); //enemy hero may have left visible area validateObject(details.id); //enemy hero may have left visible area
auto hero = cb->getHero(details.id);
cachedSectorMaps.clear(); cachedSectorMaps.clear();
if(details.result == TryMoveHero::TELEPORTATION)
{
const int3 from = CGHeroInstance::convertPosition(details.start, false), const int3 from = CGHeroInstance::convertPosition(details.start, false),
to = CGHeroInstance::convertPosition(details.end, false); to = CGHeroInstance::convertPosition(details.end, false);
const CGObjectInstance *o1 = vstd::frontOrNull(cb->getVisitableObjs(from)), const CGObjectInstance *o1 = vstd::frontOrNull(cb->getVisitableObjs(from)),
*o2 = vstd::frontOrNull(cb->getVisitableObjs(to)); *o2 = vstd::frontOrNull(cb->getVisitableObjs(to));
if(details.result == TryMoveHero::TELEPORTATION)
{
auto t1 = dynamic_cast<const CGTeleport *>(o1); auto t1 = dynamic_cast<const CGTeleport *>(o1);
auto t2 = dynamic_cast<const CGTeleport *>(o2); auto t2 = dynamic_cast<const CGTeleport *>(o2);
if(t1 && t2) 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) 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); LOG_TRACE_PARAMS(logAi, "victoryLossCheckResult '%s'", victoryLossCheckResult.messageToSelf);
NET_EVENT_HANDLER; 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(player == playerID)
{ {
if(victoryLossCheckResult.victory()) if(victoryLossCheckResult.victory())
@ -220,7 +232,7 @@ void VCAI::gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryL
} }
else 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(); finish();
@ -309,7 +321,7 @@ void VCAI::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, Q
auto firstHero = cb->getHero(hero1); auto firstHero = cb->getHero(hero1);
auto secondHero = cb->getHero(hero2); 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([=]() requestActionASAP([=]()
{ {
@ -328,7 +340,11 @@ void VCAI::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, Q
this->pickBestArtifacts(h1, h2); 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); transferFrom2to1 (firstHero, secondHero);
else if(goalpriority1 < goalpriority2) else if(goalpriority1 < goalpriority2)
transferFrom2to1 (secondHero, firstHero); transferFrom2to1 (secondHero, firstHero);
@ -405,6 +421,9 @@ void VCAI::objectRemoved(const CGObjectInstance *obj)
{ {
vstd::erase_if_present(visitableObjs, hero->boat); vstd::erase_if_present(visitableObjs, hero->boat);
vstd::erase_if_present(alreadyVisited, 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; NET_EVENT_HANDLER;
if(sop->what == ObjProperty::OWNER) if(sop->what == ObjProperty::OWNER)
{ {
//we don't want to visit know object twice (do we really?) if(myCb->getPlayerRelations(playerID, (PlayerColor)sop->val) == PlayerRelations::ENEMIES)
if(sop->val == playerID.getNum())
vstd::erase_if_present(visitableObjs, myCb->getObj(sop->id));
else if(myCb->getPlayerRelations(playerID, (PlayerColor)sop->val) == PlayerRelations::ENEMIES)
{ {
//we want to visit objects owned by oppponents //we want to visit objects owned by oppponents
auto obj = myCb->getObj(sop->id, false); auto obj = myCb->getObj(sop->id, false);
if (obj) 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); vstd::erase_if_present(alreadyVisited, obj);
} }
} }
@ -728,7 +744,7 @@ void makePossibleUpgrades(const CArmedInstance *obj)
void VCAI::makeTurn() void VCAI::makeTurn()
{ {
logGlobal->info("Player %d starting turn", playerID.getNum()); logGlobal->info("Player %d (%s) starting turn", playerID, playerID.getStr());
MAKING_TURN; MAKING_TURN;
boost::shared_lock<boost::shared_mutex> gsLock(cb->getGsMutex()); boost::shared_lock<boost::shared_mutex> gsLock(cb->getGsMutex());
@ -1651,7 +1667,7 @@ void VCAI::battleEnd(const BattleResult *br)
assert(status.getBattle() == ONGOING_BATTLE); assert(status.getBattle() == ONGOING_BATTLE);
status.setBattle(ENDING_BATTLE); status.setBattle(ENDING_BATTLE);
bool won = br->winner == myCb->battleGetMySide(); 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(); battlename.clear();
CAdventureAI::battleEnd(br); CAdventureAI::battleEnd(br);
} }
@ -2233,7 +2249,7 @@ HeroPtr VCAI::primaryHero() const
void VCAI::endTurn() void VCAI::endTurn()
{ {
logAi->info("Player %d ends turn", playerID.getNum()); logAi->info("Player %d (%s) ends turn", playerID, playerID.getStr());
if(!status.haveTurn()) if(!status.haveTurn())
{ {
logAi->error("Not having turn at the end of turn???"); logAi->error("Not having turn at the end of turn???");
@ -2245,7 +2261,7 @@ void VCAI::endTurn()
cb->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 } 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) void VCAI::striveToGoal(Goals::TSubgoal ultimateGoal)
@ -2501,6 +2517,9 @@ void VCAI::performTypicalActions()
{ {
for(auto h : getUnblockedHeroes()) 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; logAi->debugStream() << boost::format("Looking into %s, MP=%d") % h->name.c_str() % h->movement;
makePossibleUpgrades(*h); makePossibleUpgrades(*h);
pickBestArtifacts(*h); pickBestArtifacts(*h);

View File

@ -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_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE 1
#define BOOST_BIND_NO_PLACEHOLDERS #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/algorithm/string.hpp>
#include <boost/cstdint.hpp> #include <boost/cstdint.hpp>
#include <boost/current_function.hpp> #include <boost/current_function.hpp>

View File

@ -240,6 +240,7 @@ int main(int argc, char** argv)
("autoSkip", "automatically skip turns in GUI") ("autoSkip", "automatically skip turns in GUI")
("disable-video", "disable video player") ("disable-video", "disable video player")
("nointro,i", "skips intro movies") ("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") ("loadserver","specifies we are the multiplayer server for loaded games")
("loadnumplayers",po::value<int>(),"specifies the number of players connecting to a multiplayer game") ("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.)") ("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; gNoGUI = true;
vm.insert(std::pair<std::string, po::variable_value>("onlyAI", po::variable_value())); 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). // Have effect on X11 system only (Linux).
// For whatever reason in fullscreen mode SDL takes "raw" mouse input from DGA X11 extension // For whatever reason in fullscreen mode SDL takes "raw" mouse input from DGA X11 extension

View File

@ -719,6 +719,10 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
else if(current) else if(current)
{ {
SelectMap sm(*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; *serv << &sm;
UpdateStartOptions uso(sInfo); UpdateStartOptions uso(sInfo);

View File

@ -928,10 +928,15 @@ std::string CClient::aiNameForPlayer(const PlayerSettings &ps, bool battleAI)
return goodAI; return goodAI;
} }
bool CServerHandler::DO_NOT_START_SERVER = false;
void CServerHandler::startServer() void CServerHandler::startServer()
{ {
if(DO_NOT_START_SERVER)
return;
th.update(); th.update();
serverThread = new boost::thread(&CServerHandler::callServer, this); //runs server executable; serverThread = new boost::thread(&CServerHandler::callServer, this); //runs server executable;
if(verbose) if(verbose)
logNetwork->infoStream() << "Setting up thread calling server: " << th.getDiff(); logNetwork->infoStream() << "Setting up thread calling server: " << th.getDiff();
@ -939,6 +944,9 @@ void CServerHandler::startServer()
void CServerHandler::waitForServer() void CServerHandler::waitForServer()
{ {
if(DO_NOT_START_SERVER)
return;
if(!serverThread) if(!serverThread)
startServer(); startServer();

View File

@ -42,6 +42,8 @@ class CServerHandler
private: private:
void callServer(); //calls server via system(), should be called as thread void callServer(); //calls server via system(), should be called as thread
public: public:
static bool DO_NOT_START_SERVER;
CStopWatch th; CStopWatch th;
boost::thread *serverThread; //thread that called system to run server boost::thread *serverThread; //thread that called system to run server
SharedMem *shared; //interprocess memory (for waiting for server) SharedMem *shared; //interprocess memory (for waiting for server)

View File

@ -627,6 +627,8 @@ void CCastleBuildings::buildingClicked(BuildingID building)
case BuildingID::SHIPYARD: case BuildingID::SHIPYARD:
if(town->shipyardStatus() == IBoatGenerator::GOOD) if(town->shipyardStatus() == IBoatGenerator::GOOD)
LOCPLINT->showShipyardDialog(town); LOCPLINT->showShipyardDialog(town);
else if(town->shipyardStatus() == IBoatGenerator::BOAT_ALREADY_BUILT)
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[51]);
break; break;
case BuildingID::FORT: case BuildingID::FORT:

View File

@ -520,6 +520,24 @@ EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTow
if(vstd::contains(t->forbiddenBuildings, ID)) if(vstd::contains(t->forbiddenBuildings, ID))
return EBuildingState::FORBIDDEN; //forbidden 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) if(ID == BuildingID::CAPITOL)
{ {
const PlayerState *ps = getPlayer(t->tempOwner, false); const PlayerState *ps = getPlayer(t->tempOwner, false);

View File

@ -2139,8 +2139,6 @@ void CGameState::updateRumor()
int rumorId = -1, rumorExtra = -1; int rumorId = -1, rumorExtra = -1;
auto & rand = getRandomGenerator(); auto & rand = getRandomGenerator();
rumor.type = *RandomGeneratorUtil::nextItem(rumorTypes, rand); rumor.type = *RandomGeneratorUtil::nextItem(rumorTypes, rand);
if(!map->rumors.size() && rumor.type == RumorState::TYPE_MAP)
rumor.type = RumorState::TYPE_RAND;
do do
{ {
@ -2181,9 +2179,14 @@ void CGameState::updateRumor()
break; break;
} }
case RumorState::TYPE_MAP: 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); rumorId = rand.nextInt(map->rumors.size() - 1);
break; break;
}
else
rumor.type = RumorState::TYPE_RAND;
case RumorState::TYPE_RAND: case RumorState::TYPE_RAND:
do do

View File

@ -17,6 +17,8 @@
#include "CArtHandler.h" #include "CArtHandler.h"
#include "CCreatureHandler.h" #include "CCreatureHandler.h"
#include "spells/CSpellHandler.h" #include "spells/CSpellHandler.h"
#include "StringConstants.h"
#include "CGeneralTextHandler.h"
const SlotID SlotID::COMMANDER_SLOT_PLACEHOLDER = SlotID(-2); const SlotID SlotID::COMMANDER_SLOT_PLACEHOLDER = SlotID(-2);
const SlotID SlotID::SUMMONED_SLOT_PLACEHOLDER = SlotID(-3); const SlotID SlotID::SUMMONED_SLOT_PLACEHOLDER = SlotID(-3);
@ -57,6 +59,32 @@ bool PlayerColor::isValidPlayer() const
return num < PLAYER_LIMIT_I; 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) std::ostream & operator<<(std::ostream & os, const Battle::ActionType actionType)
{ {
static const std::map<Battle::ActionType, std::string> actionTypeToString = static const std::map<Battle::ActionType, std::string> actionTypeToString =

View File

@ -262,6 +262,9 @@ class PlayerColor : public BaseForID<PlayerColor, ui8>
DLL_LINKAGE bool isValidPlayer() const; //valid means < PLAYER_LIMIT (especially non-neutral) 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 CGameInfoCallback;
friend class CNonConstInfoCallback; friend class CNonConstInfoCallback;
}; };

View File

@ -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 /// visitor that is trying to generates candidates that must be fulfilled
/// to complete this expression /// to complete this expression
template <typename ContainedClass> template <typename ContainedClass>
@ -436,6 +559,30 @@ public:
return boost::apply_visitor(testVisitor, data); 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) /// generates list of candidates that can be fulfilled by caller (like AI)
std::vector<Value> getFulfillmentCandidates(std::function<bool(const Value &)> toBool) const std::vector<Value> getFulfillmentCandidates(std::function<bool(const Value &)> toBool) const
{ {

View File

@ -1124,7 +1124,7 @@ bool CGTownInstance::hasBuilt(BuildingID buildingID) const
return vstd::contains(builtBuildings, buildingID); 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); const CBuilding * building = town->buildings.at(buildID);
@ -1132,17 +1132,22 @@ CBuilding::TRequired CGTownInstance::genBuildingRequirements(BuildingID buildID)
[&](const BuildingID & id) -> CBuilding::TRequired::Variant [&](const BuildingID & id) -> CBuilding::TRequired::Variant
{ {
const CBuilding * build = town->buildings.at(id); const CBuilding * build = town->buildings.at(id);
CBuilding::TRequired::OperatorAll requirements;
if (!hasBuilt(id)) if (!hasBuilt(id))
return id; {
requirements.expressions.push_back(id);
CBuilding::TRequired::OperatorAll requirements; if (!deep)
{
return requirements;
}
}
if (build->upgrade != BuildingID::NONE) if (build->upgrade != BuildingID::NONE)
requirements.expressions.push_back(dependTest(build->upgrade)); requirements.expressions.push_back(dependTest(build->upgrade));
requirements.expressions.push_back(build->requirements.morph(dependTest)); requirements.expressions.push_back(build->requirements.morph(dependTest));
return requirements; return requirements;
}; };

View File

@ -238,7 +238,7 @@ public:
bool armedGarrison() const; //true if town has creatures in garrison or garrisoned hero bool armedGarrison() const; //true if town has creatures in garrison or garrisoned hero
int getTownLevel() const; 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 mergeGarrisonOnSiege() const; // merge garrison into army of visiting hero
void removeCapitols (PlayerColor owner) const; void removeCapitols (PlayerColor owner) const;

View File

@ -498,7 +498,9 @@ IQuestObject::IQuestObject():
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 bool IQuestObject::checkQuest(const CGHeroInstance* h) const

View File

@ -1607,14 +1607,14 @@ void CGShrine::onHeroVisit( const CGHeroInstance * h ) const
{ {
iw.text.addTxt(MetaString::ADVOB_TXT,131); 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 else if(vstd::contains(h->spells,spell))//hero already knows the spell
{ {
iw.text.addTxt(MetaString::ADVOB_TXT,174); 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 else //give spell
{ {
std::set<SpellID> spells; std::set<SpellID> spells;

View File

@ -245,6 +245,9 @@ CMap::~CMap()
for(auto obj : objects) for(auto obj : objects)
obj.dellNull(); obj.dellNull();
for(auto quest : quests)
quest.dellNull();
} }
void CMap::removeBlockVisTiles(CGObjectInstance * obj, bool total) void CMap::removeBlockVisTiles(CGObjectInstance * obj, bool total)

View File

@ -945,8 +945,8 @@ void CGameHandler::handleConnection(std::set<PlayerColor> players, CConnection &
packType = typeList.getTypeID(pack); //get the id of type 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", logGlobal->trace("Received client message (request %d by player %d (%s)) of type with ID=%d (%s).\n",
requestID, player.getNum(), packType, typeid(*pack).name()); requestID, player, player.getStr(), packType, typeid(*pack).name());
} }
//prepare struct informing that action was applied //prepare struct informing that action was applied
@ -1963,7 +1963,7 @@ bool CGameHandler::moveHero( ObjectInstanceID hid, int3 dst, ui8 teleporting, bo
return false; 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); const int3 hmpos = CGHeroInstance::convertPosition(dst, false);
if(!gs->map->isInTheMap(hmpos)) if(!gs->map->isInTheMap(hmpos))

View File

@ -579,6 +579,7 @@ int main(int argc, char** argv)
logConfig.configureDefault(); logConfig.configureDefault();
handleCommandOptions(argc, argv); handleCommandOptions(argc, argv);
if(cmdLineOptions.count("port"))
port = cmdLineOptions["port"].as<int>(); port = cmdLineOptions["port"].as<int>();
logNetwork->info("Port %d will be used.", port); logNetwork->info("Port %d will be used.", port);