mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-24 08:32:34 +02:00
Merge pull request #3498 from IvanSavenko/simturns_pathfinder
[1.4.3] Fixes for simultaneous turns
This commit is contained in:
commit
b4a1a755a4
@ -41,6 +41,7 @@ namespace AIPathfinding
|
||||
std::shared_ptr<AINodeStorage> nodeStorage)
|
||||
:PathfinderConfig(nodeStorage, makeRuleset(cb, ai, nodeStorage)), hero(nodeStorage->getHero())
|
||||
{
|
||||
options.ignoreGuards = false;
|
||||
options.useEmbarkAndDisembark = true;
|
||||
options.useTeleportTwoWay = true;
|
||||
options.useTeleportOneWay = true;
|
||||
|
@ -467,6 +467,18 @@ void AdventureMapInterface::hotkeyEndingTurn()
|
||||
LOCPLINT->cb->endTurn();
|
||||
|
||||
mapAudio->onPlayerTurnEnded();
|
||||
|
||||
// Normally, game will receive PlayerStartsTurn call almost instantly with new player ID that will switch UI to waiting mode
|
||||
// However, when simturns are active it is possible for such call not to come because another player is still acting
|
||||
// So find first player other than ours that is acting at the moment and update UI as if he had started turn
|
||||
for (auto player = PlayerColor(0); player < PlayerColor::PLAYER_LIMIT; ++player)
|
||||
{
|
||||
if (player != LOCPLINT->playerID && LOCPLINT->cb->isPlayerMakingTurn(player))
|
||||
{
|
||||
onEnemyTurnStarted(player, LOCPLINT->cb->getStartInfo()->playerInfos.at(player).isControlledByHuman());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const CGObjectInstance* AdventureMapInterface::getActiveObject(const int3 &mapPos)
|
||||
|
@ -22,6 +22,14 @@
|
||||
#include "../../lib/MetaString.h"
|
||||
#include "../../lib/CGeneralTextHandler.h"
|
||||
|
||||
static std::string timeToString(int time)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << time / 1000 / 60 << ":" << std::setw(2) << std::setfill('0') << time / 1000 % 60;
|
||||
return ss.str();
|
||||
};
|
||||
|
||||
|
||||
std::vector<TurnTimerInfo> OptionsTabBase::getTimerPresets() const
|
||||
{
|
||||
std::vector<TurnTimerInfo> result;
|
||||
@ -141,43 +149,51 @@ OptionsTabBase::OptionsTabBase(const JsonPath & configPath)
|
||||
else if(l.empty())
|
||||
return sec;
|
||||
|
||||
return std::stoi(l) * 60 + std::stoi(r);
|
||||
return std::min(24*60, std::stoi(l)) * 60 + std::stoi(r);
|
||||
};
|
||||
|
||||
addCallback("parseAndSetTimer_base", [parseTimerString](const std::string & str){
|
||||
addCallback("parseAndSetTimer_base", [this, parseTimerString](const std::string & str){
|
||||
int time = parseTimerString(str) * 1000;
|
||||
if(time >= 0)
|
||||
{
|
||||
TurnTimerInfo tinfo = SEL->getStartInfo()->turnTimerInfo;
|
||||
tinfo.baseTimer = time;
|
||||
CSH->setTurnTimerInfo(tinfo);
|
||||
if(auto ww = widget<CTextInput>("chessFieldBase"))
|
||||
ww->setText(timeToString(time), false);
|
||||
}
|
||||
});
|
||||
addCallback("parseAndSetTimer_turn", [parseTimerString](const std::string & str){
|
||||
addCallback("parseAndSetTimer_turn", [this, parseTimerString](const std::string & str){
|
||||
int time = parseTimerString(str) * 1000;
|
||||
if(time >= 0)
|
||||
{
|
||||
TurnTimerInfo tinfo = SEL->getStartInfo()->turnTimerInfo;
|
||||
tinfo.turnTimer = time;
|
||||
CSH->setTurnTimerInfo(tinfo);
|
||||
if(auto ww = widget<CTextInput>("chessFieldTurn"))
|
||||
ww->setText(timeToString(time), false);
|
||||
}
|
||||
});
|
||||
addCallback("parseAndSetTimer_battle", [parseTimerString](const std::string & str){
|
||||
addCallback("parseAndSetTimer_battle", [this, parseTimerString](const std::string & str){
|
||||
int time = parseTimerString(str) * 1000;
|
||||
if(time >= 0)
|
||||
{
|
||||
TurnTimerInfo tinfo = SEL->getStartInfo()->turnTimerInfo;
|
||||
tinfo.battleTimer = time;
|
||||
CSH->setTurnTimerInfo(tinfo);
|
||||
if(auto ww = widget<CTextInput>("chessFieldBattle"))
|
||||
ww->setText(timeToString(time), false);
|
||||
}
|
||||
});
|
||||
addCallback("parseAndSetTimer_unit", [parseTimerString](const std::string & str){
|
||||
addCallback("parseAndSetTimer_unit", [this, parseTimerString](const std::string & str){
|
||||
int time = parseTimerString(str) * 1000;
|
||||
if(time >= 0)
|
||||
{
|
||||
TurnTimerInfo tinfo = SEL->getStartInfo()->turnTimerInfo;
|
||||
tinfo.unitTimer = time;
|
||||
CSH->setTurnTimerInfo(tinfo);
|
||||
if(auto ww = widget<CTextInput>("chessFieldUnit"))
|
||||
ww->setText(timeToString(time), false);
|
||||
}
|
||||
});
|
||||
|
||||
@ -359,14 +375,6 @@ void OptionsTabBase::recreate()
|
||||
}
|
||||
}
|
||||
|
||||
//chess timer
|
||||
auto timeToString = [](int time) -> std::string
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << time / 1000 / 60 << ":" << std::setw(2) << std::setfill('0') << time / 1000 % 60;
|
||||
return ss.str();
|
||||
};
|
||||
|
||||
if(auto ww = widget<CTextInput>("chessFieldBase"))
|
||||
ww->setText(timeToString(turnTimerRemote.baseTimer), false);
|
||||
if(auto ww = widget<CTextInput>("chessFieldTurn"))
|
||||
|
@ -371,6 +371,8 @@
|
||||
|
||||
"pathfinder" :
|
||||
{
|
||||
// if enabled, pathfinder will build path through locations guarded by wandering monsters
|
||||
"ignoreGuards" : false,
|
||||
// if enabled, pathfinder will take use of any available boats
|
||||
"useBoat" : true,
|
||||
// if enabled, pathfinder will take use of any bidirectional monoliths
|
||||
|
@ -95,6 +95,7 @@ void GameSettings::load(const JsonNode & input)
|
||||
{EGameSettings::TEXTS_ROAD, "textData", "road" },
|
||||
{EGameSettings::TEXTS_SPELL, "textData", "spell" },
|
||||
{EGameSettings::TEXTS_TERRAIN, "textData", "terrain" },
|
||||
{EGameSettings::PATHFINDER_IGNORE_GUARDS, "pathfinder", "ignoreGuards" },
|
||||
{EGameSettings::PATHFINDER_USE_BOAT, "pathfinder", "useBoat" },
|
||||
{EGameSettings::PATHFINDER_USE_MONOLITH_TWO_WAY, "pathfinder", "useMonolithTwoWay" },
|
||||
{EGameSettings::PATHFINDER_USE_MONOLITH_ONE_WAY_UNIQUE, "pathfinder", "useMonolithOneWayUnique" },
|
||||
|
@ -60,6 +60,7 @@ enum class EGameSettings
|
||||
MAP_FORMAT_JSON_VCMI,
|
||||
MAP_FORMAT_IN_THE_WAKE_OF_GODS,
|
||||
PATHFINDER_USE_BOAT,
|
||||
PATHFINDER_IGNORE_GUARDS,
|
||||
PATHFINDER_USE_MONOLITH_TWO_WAY,
|
||||
PATHFINDER_USE_MONOLITH_ONE_WAY_UNIQUE,
|
||||
PATHFINDER_USE_MONOLITH_ONE_WAY_RANDOM,
|
||||
|
@ -21,6 +21,7 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
PathfinderOptions::PathfinderOptions()
|
||||
: useFlying(true)
|
||||
, useWaterWalking(true)
|
||||
, ignoreGuards(VLC->settings()->getBoolean(EGameSettings::PATHFINDER_IGNORE_GUARDS))
|
||||
, useEmbarkAndDisembark(VLC->settings()->getBoolean(EGameSettings::PATHFINDER_USE_BOAT))
|
||||
, useTeleportTwoWay(VLC->settings()->getBoolean(EGameSettings::PATHFINDER_USE_MONOLITH_TWO_WAY))
|
||||
, useTeleportOneWay(VLC->settings()->getBoolean(EGameSettings::PATHFINDER_USE_MONOLITH_ONE_WAY_UNIQUE))
|
||||
|
@ -25,6 +25,7 @@ struct DLL_LINKAGE PathfinderOptions
|
||||
bool useFlying;
|
||||
bool useWaterWalking;
|
||||
bool useEmbarkAndDisembark;
|
||||
bool ignoreGuards;
|
||||
bool useTeleportTwoWay; // Two-way monoliths and Subterranean Gate
|
||||
bool useTeleportOneWay; // One-way monoliths with one known exit only
|
||||
bool useTeleportOneWayRandom; // One-way monoliths with more than one known exit
|
||||
|
@ -271,7 +271,12 @@ PathfinderBlockingRule::BlockingReason MovementAfterDestinationRule::getBlocking
|
||||
case EPathNodeAction::BATTLE:
|
||||
/// Movement after BATTLE action only possible from guarded tile to guardian tile
|
||||
if(destination.guarded)
|
||||
return BlockingReason::DESTINATION_GUARDED;
|
||||
{
|
||||
if (pathfinderHelper->options.ignoreGuards)
|
||||
return BlockingReason::DESTINATION_GUARDED;
|
||||
else
|
||||
return BlockingReason::NONE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@ -299,6 +304,7 @@ PathfinderBlockingRule::BlockingReason MovementToDestinationRule::getBlockingRea
|
||||
if(source.guarded)
|
||||
{
|
||||
if(!(pathfinderConfig->options.originalMovementRules && source.node->layer == EPathfindingLayer::AIR)
|
||||
&& !pathfinderConfig->options.ignoreGuards
|
||||
&& (!destination.isGuardianTile || pathfinderHelper->getGuardiansCount(source.coord) > 1)) // Can step into tile of guard
|
||||
{
|
||||
return BlockingReason::SOURCE_GUARDED;
|
||||
|
@ -106,6 +106,8 @@ bool TurnOrderProcessor::playersInContact(PlayerColor left, PlayerColor right) c
|
||||
{
|
||||
CPathsInfo out(mapSize, hero);
|
||||
auto config = std::make_shared<SingleHeroPathfinderConfig>(out, gameHandler->gameState(), hero);
|
||||
config->options.ignoreGuards = true;
|
||||
config->options.turnLimit = 1;
|
||||
CPathfinder pathfinder(gameHandler->gameState(), config);
|
||||
pathfinder.calculatePaths();
|
||||
|
||||
@ -120,6 +122,8 @@ bool TurnOrderProcessor::playersInContact(PlayerColor left, PlayerColor right) c
|
||||
{
|
||||
CPathsInfo out(mapSize, hero);
|
||||
auto config = std::make_shared<SingleHeroPathfinderConfig>(out, gameHandler->gameState(), hero);
|
||||
config->options.ignoreGuards = true;
|
||||
config->options.turnLimit = 1;
|
||||
CPathfinder pathfinder(gameHandler->gameState(), config);
|
||||
pathfinder.calculatePaths();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user