1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-29 23:07:48 +02:00

Refactored access to hero paths in CPlayerInterface

This commit is contained in:
Ivan Savenko
2023-02-15 12:08:32 +02:00
parent bb6e1f7ee1
commit 600054e001
7 changed files with 241 additions and 141 deletions

View File

@@ -120,7 +120,164 @@ struct HeroObjectRetriever : boost::static_visitor<const CGHeroInstance *>
}
};
CPlayerInterface::CPlayerInterface(PlayerColor Player)
HeroPathStorage::HeroPathStorage(CPlayerInterface & owner):
owner(owner)
{
}
void HeroPathStorage::setPath(const CGHeroInstance *h, const CGPath & path)
{
paths[h] = path;
}
const CGPath & HeroPathStorage::getPath(const CGHeroInstance *h) const
{
assert(hasPath(h));
return paths.at(h);
}
bool HeroPathStorage::hasPath(const CGHeroInstance *h) const
{
return paths.count(h) > 0;
}
bool HeroPathStorage::setPath(const CGHeroInstance *h, const int3 & destination)
{
CGPath path;
if (!owner.cb->getPathsInfo(h)->getPath(path, destination))
return false;
setPath(h, path);
return true;
}
void HeroPathStorage::removeLastNode(const CGHeroInstance *h)
{
assert(hasPath(h));
if (!hasPath(h))
return;
auto & path = paths[h];
path.nodes.pop_back();
if (path.nodes.size() < 2) //if it was the last one, remove entire path and path with only one tile is not a real path
erasePath(h);
}
void HeroPathStorage::erasePath(const CGHeroInstance *h)
{
paths.erase(h);
adventureInt->updateMoveHero(h, false);
}
void HeroPathStorage::verifyPath(const CGHeroInstance *h)
{
if (!hasPath(h))
return;
setPath(h, getPath(h).endPos());
}
//CGPath * CPlayerInterface::getAndVerifyPath(const CGHeroInstance * h)
//{
// if (vstd::contains(paths,h)) //hero has assigned path
// {
// CGPath &path = paths[h];
// if (!path.nodes.size())
// {
// logGlobal->warn("Warning: empty path found...");
// paths.erasePath(h);
// }
// else
// {
// assert(h->visitablePos() == path.startPos());
// //update the hero path in case of something has changed on map
// if (LOCPLINT->cb->getPathsInfo(h)->getPath(path, path.endPos()))
// return &path;
//
// paths.erase(h);
// return nullptr;
// }
// }
//
// return nullptr;
//}
//
//CGPath * CPlayerInterface::getPath(const CGHeroInstance * h)
//{
// if (vstd::contains(paths,h)) //hero has assigned path
// return &paths[h];
//
// return nullptr;
//}
//removeLastNode
//void HeroPathStorage::setPath(const CGHeroInstance *h, const CGPath & path)
//{
//
//}
//
//const CGPath & HeroPathStorage::getPath(const CGHeroInstance *h)
//{
//
//}
//
//void HeroPathStorage::verifyPath(const CGHeroInstance *h)
//{
//
//}
//void CPlayerInterface::eraseCurrentPathOf(const CGHeroInstance * ho, bool checkForExistanceOfPath)
//{
// if (checkForExistanceOfPath)
// {
// assert(vstd::contains(paths, ho));
// }
// else if (!vstd::contains(paths, ho))
// {
// return;
// }
// assert(ho == adventureInt->selection);
//
// paths.erasePath(ho);
// adventureInt->updateMoveHero(ho, false);
//}
template<typename Handler>
void HeroPathStorage::serialize(Handler & h, int version)
{
std::map<const CGHeroInstance *, int3> pathsMap; //hero -> dest
if (h.saving)
{
for (auto &p : paths)
{
if (p.second.nodes.size())
pathsMap[p.first] = p.second.endPos();
else
logGlobal->debug("%s has assigned an empty path! Ignoring it...", p.first->getNameTranslated());
}
h & pathsMap;
}
else
{
h & pathsMap;
if (owner.cb)
{
for (auto &p : pathsMap)
{
CGPath path;
owner.cb->getPathsInfo(p.first)->getPath(path, p.second);
paths[p.first] = path;
logGlobal->trace("Restored path for hero %s leading to %s with %d nodes", p.first->nodeName(), p.second.toString(), path.nodes.size());
}
}
}
}
CPlayerInterface::CPlayerInterface(PlayerColor Player):
paths(*this)
{
logGlobal->trace("\tHuman player interface for player %s being constructed", Player.getStr());
destinationTeleport = ObjectInstanceID();
@@ -260,8 +417,8 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
bool directlyAttackingCreature =
details.attackedFrom
&& adventureInt->terrain->currentPath //in case if movement has been canceled in the meantime and path was already erased
&& adventureInt->terrain->currentPath->nodes.size() == 3;//FIXME should be 2 but works nevertheless...
&& paths.hasPath(hero) //in case if movement has been canceled in the meantime and path was already erased
&& paths.getPath(hero).nodes.size() == 3;//FIXME should be 2 but works nevertheless...
if(makingTurn && hero->tempOwner == playerID) //we are moving our hero - we may need to update assigned path
{
@@ -271,21 +428,21 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
if(details.result == TryMoveHero::TELEPORTATION)
{
if(adventureInt->terrain->currentPath)
if(paths.hasPath(hero))
{
assert(adventureInt->terrain->currentPath->nodes.size() >= 2);
std::vector<CGPathNode>::const_iterator nodesIt = adventureInt->terrain->currentPath->nodes.end() - 1;
assert(paths.getPath(hero).nodes.size() >= 2);
auto nodesIt = paths.getPath(hero).nodes.end() - 1;
if((nodesIt)->coord == hero->convertToVisitablePos(details.start)
&& (nodesIt - 1)->coord == hero->convertToVisitablePos(details.end))
{
//path was between entrance and exit of teleport -> OK, erase node as usual
removeLastNodeFromPath(hero);
paths.removeLastNode(hero);
}
else
{
//teleport was not along current path, it'll now be invalid (hero is somewhere else)
eraseCurrentPathOf(hero);
paths.erasePath(hero);
}
}
@@ -299,12 +456,12 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
if(hero->pos != details.end //hero didn't change tile but visit succeeded
|| directlyAttackingCreature) // or creature was attacked from endangering tile.
{
eraseCurrentPathOf(hero, false);
paths.erasePath(hero);
}
else if(adventureInt->terrain->currentPath && hero->pos == details.end) //&& hero is moving
else if(paths.hasPath(hero) && hero->pos == details.end) //&& hero is moving
{
if(details.start != details.end) //so we don't touch path when revisiting with spacebar
removeLastNodeFromPath(hero);
paths.removeLastNode(hero);
}
}
@@ -444,8 +601,7 @@ void CPlayerInterface::heroKilled(const CGHeroInstance* hero)
else if (adventureInt->selection == hero)
adventureInt->selection = nullptr;
if (vstd::contains(paths, hero))
paths.erase(hero);
paths.erasePath(hero);
}
void CPlayerInterface::heroVisit(const CGHeroInstance * visitor, const CGObjectInstance * visitedObj, bool start)
@@ -1247,7 +1403,7 @@ void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const Bonus
if ((bonus.type == Bonus::FLYING_MOVEMENT || bonus.type == Bonus::WATER_WALKING) && !gain)
{
//recalculate paths because hero has lost bonus influencing pathfinding
eraseCurrentPathOf(hero, false);
paths.erasePath(hero);
}
}
@@ -1256,33 +1412,7 @@ template <typename Handler> void CPlayerInterface::serializeTempl( Handler &h, c
h & wanderingHeroes;
h & towns;
h & sleepingHeroes;
std::map<const CGHeroInstance *, int3> pathsMap; //hero -> dest
if (h.saving)
{
for (auto &p : paths)
{
if (p.second.nodes.size())
pathsMap[p.first] = p.second.endPos();
else
logGlobal->debug("%s has assigned an empty path! Ignoring it...", p.first->getNameTranslated());
}
h & pathsMap;
}
else
{
h & pathsMap;
if (cb)
for (auto &p : pathsMap)
{
CGPath path;
cb->getPathsInfo(p.first)->getPath(path, p.second);
paths[p.first] = path;
logGlobal->trace("Restored path for hero %s leading to %s with %d nodes", p.first->nodeName(), p.second.toString(), path.nodes.size());
}
}
h & paths;
h & spellbookSettings;
}
@@ -1299,7 +1429,7 @@ void CPlayerInterface::loadGame( BinaryDeserializer & h, const int version )
firstCall = -1;
}
void CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
void CPlayerInterface::moveHero( const CGHeroInstance *h, const CGPath& path )
{
LOG_TRACE(logGlobal);
if (!LOCPLINT->makingTurn)
@@ -1330,7 +1460,7 @@ void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHer
EVENT_HANDLER_CALLED_BY_CLIENT;
auto onEnd = [=](){ cb->selectionMade(0, queryID); };
if (stillMoveHero.get() == DURING_MOVE && adventureInt->terrain->currentPath && adventureInt->terrain->currentPath->nodes.size() > 1) //to ignore calls on passing through garrisons
if (stillMoveHero.get() == DURING_MOVE && paths.hasPath(down) && paths.getPath(down).nodes.size() > 1) //to ignore calls on passing through garrisons
{
onEnd();
return;
@@ -1641,7 +1771,7 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns
bool heroVisibleHere = false;
auto & tile = subArr[tileX][tileY];
for ( auto const & obj : tile.objects)
for(const auto & obj : tile.objects)
{
if (obj.obj == ho)
{
@@ -1856,7 +1986,7 @@ void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellI
GH.popInts(1);
if(spellID == SpellID::FLY || spellID == SpellID::WATER_WALK)
eraseCurrentPathOf(caster, false);
paths.erasePath(caster);
const spells::Spell * spell = CGI->spells()->getByIndex(spellID);
@@ -1872,54 +2002,6 @@ void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellI
CCS->soundh->playSound(castSoundPath);
}
void CPlayerInterface::eraseCurrentPathOf(const CGHeroInstance * ho, bool checkForExistanceOfPath)
{
if (checkForExistanceOfPath)
{
assert(vstd::contains(paths, ho));
}
else if (!vstd::contains(paths, ho))
{
return;
}
assert(ho == adventureInt->selection);
paths.erase(ho);
adventureInt->terrain->currentPath = nullptr;
adventureInt->updateMoveHero(ho, false);
}
void CPlayerInterface::removeLastNodeFromPath(const CGHeroInstance *ho)
{
adventureInt->terrain->currentPath->nodes.erase(adventureInt->terrain->currentPath->nodes.end()-1);
if (adventureInt->terrain->currentPath->nodes.size() < 2) //if it was the last one, remove entire path and path with only one tile is not a real path
eraseCurrentPathOf(ho);
}
CGPath * CPlayerInterface::getAndVerifyPath(const CGHeroInstance * h)
{
if (vstd::contains(paths,h)) //hero has assigned path
{
CGPath &path = paths[h];
if (!path.nodes.size())
{
logGlobal->warn("Warning: empty path found...");
paths.erase(h);
}
else
{
assert(h->visitablePos() == path.startPos());
//update the hero path in case of something has changed on map
if (LOCPLINT->cb->getPathsInfo(h)->getPath(path, path.endPos()))
return &path;
else
paths.erase(h);
}
}
return nullptr;
}
void CPlayerInterface::acceptTurn()
{
if (settings["session"]["autoSkip"].Bool())