1
0
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:
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;
validateObject(details.id); //enemy hero may have left visible area
auto hero = cb->getHero(details.id);
cachedSectorMaps.clear();
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)
{
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));
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);

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_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>

View File

@ -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

View File

@ -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);

View File

@ -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();

View File

@ -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)

View File

@ -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:

View File

@ -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);

View File

@ -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:
rumorId = rand.nextInt(map->rumors.size() - 1);
break;
// 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

View File

@ -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 =

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 std::string getStr(bool L10n = false) const;
DLL_LINKAGE std::string getStrCap(bool L10n = false) const;
friend class CGameInfoCallback;
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
/// 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
{

View File

@ -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;
};

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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))

View File

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