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:
commit
d993710f8e
@ -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,9 +340,13 @@ 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);
|
||||||
else //regular criteria
|
else //regular criteria
|
||||||
{
|
{
|
||||||
@ -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);
|
||||||
|
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_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>
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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:
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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 =
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
@ -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))
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user