1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-22 22:13:35 +02:00

Allow sending requests to move across multiple tiles at once

This commit is contained in:
Ivan Savenko 2024-04-18 15:13:16 +03:00
parent 7d93206786
commit d5a2ad1be8
8 changed files with 55 additions and 21 deletions

View File

@ -1216,7 +1216,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
{
//FIXME: this assertion fails also if AI moves onto defeated guarded object
//assert(cb->getVisitableObjs(dst).size() > 1); //there's no point in revisiting tile where there is no visitable object
cb->moveHero(*h, h->convertFromVisitablePos(dst));
cb->moveHero(*h, h->convertFromVisitablePos(dst), false);
afterMovementCheck(); // TODO: is it feasible to hero get killed there if game work properly?
// If revisiting, teleport probing is never done, and so the entries into the list would remain unused and uncleared
teleportChannelProbingList.clear();
@ -1278,7 +1278,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
destinationTeleport = exitId;
if(exitPos.valid())
destinationTeleportPos = h->convertFromVisitablePos(exitPos);
cb->moveHero(*h, h->pos);
cb->moveHero(*h, h->pos, false);
destinationTeleport = ObjectInstanceID();
destinationTeleportPos = int3(-1);
afterMovementCheck();

View File

@ -1837,7 +1837,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
{
//FIXME: this assertion fails also if AI moves onto defeated guarded object
assert(cb->getVisitableObjs(dst).size() > 1); //there's no point in revisiting tile where there is no visitable object
cb->moveHero(*h, h->convertFromVisitablePos(dst));
cb->moveHero(*h, h->convertFromVisitablePos(dst), false);
afterMovementCheck(); // TODO: is it feasible to hero get killed there if game work properly?
// If revisiting, teleport probing is never done, and so the entries into the list would remain unused and uncleared
teleportChannelProbingList.clear();
@ -1899,7 +1899,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
destinationTeleport = exitId;
if(exitPos.valid())
destinationTeleportPos = h->convertFromVisitablePos(exitPos);
cb->moveHero(*h, h->pos);
cb->moveHero(*h, h->pos, false);
destinationTeleport = ObjectInstanceID();
destinationTeleportPos = int3(-1);
afterMovementCheck();

View File

@ -34,11 +34,16 @@ bool CCallback::teleportHero(const CGHeroInstance *who, const CGTownInstance *wh
return true;
}
bool CCallback::moveHero(const CGHeroInstance *h, int3 dst, bool transit)
void CCallback::moveHero(const CGHeroInstance *h, const int3 & destination, bool transit)
{
MoveHero pack(dst,h->id,transit);
MoveHero pack({destination}, h->id, transit);
sendRequest(&pack);
}
void CCallback::moveHero(const CGHeroInstance *h, const std::vector<int3> & path, bool transit)
{
MoveHero pack(path, h->id, transit);
sendRequest(&pack);
return true;
}
int CCallback::selectionMade(int selection, QueryID queryID)

View File

@ -67,7 +67,8 @@ class IGameActionCallback
{
public:
//hero
virtual bool moveHero(const CGHeroInstance *h, int3 dst, bool transit) =0; //dst must be free, neighbouring tile (this function can move hero only by one tile)
virtual void moveHero(const CGHeroInstance *h, const std::vector<int3> & path, bool transit) =0; //moves hero alongside provided path
virtual void moveHero(const CGHeroInstance *h, const int3 & destination, bool transit) =0; //moves hero alongside provided path
virtual bool dismissHero(const CGHeroInstance * hero)=0; //dismisses given hero; true - successfuly, false - not successfuly
virtual void dig(const CGObjectInstance *hero)=0;
virtual void castSpell(const CGHeroInstance *hero, SpellID spellID, const int3 &pos = int3(-1, -1, -1))=0; //cast adventure map spell
@ -159,7 +160,8 @@ public:
void unregisterBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents);
//commands
bool moveHero(const CGHeroInstance *h, int3 dst, bool transit = false) override; //dst must be free, neighbouring tile (this function can move hero only by one tile)
void moveHero(const CGHeroInstance *h, const std::vector<int3> & path, bool transit) override;
void moveHero(const CGHeroInstance *h, const int3 & destination, bool transit) override;
bool teleportHero(const CGHeroInstance *who, const CGTownInstance *where);
int selectionMade(int selection, QueryID queryID) override;
int sendQueryReply(std::optional<int32_t> reply, QueryID queryID) override;

View File

@ -355,22 +355,38 @@ void HeroMovementController::requestMovementStart(const CGHeroInstance * h, cons
void HeroMovementController::moveInstant(const CGHeroInstance * h, const CGPath & path)
{
stopMovementSound();
bool useTransit = path.nextNode().layer == EPathfindingLayer::AIR || path.nextNode().layer == EPathfindingLayer::WATER;
std::vector<int3> pathToMove;
for (auto const & node : boost::adaptors::reverse(path.nodes))
{
if (node.coord == h->visitablePos())
continue; // first node, ignore - this is hero current position
if(node.isTeleportAction())
return; // pause after monolith / subterra gates
break; // pause after monolith / subterra gates
if (node.turns != 0)
return; // ran out of MP
break; // ran out of move points
bool useTransitHere = node.layer == EPathfindingLayer::AIR || node.layer == EPathfindingLayer::WATER;
if (useTransitHere != useTransit)
break;
int3 coord = h->convertFromVisitablePos(node.coord);
pathToMove.push_back(coord);
bool useTransit = node.layer == EPathfindingLayer::AIR || node.layer == EPathfindingLayer::WATER;
LOCPLINT->cb->moveHero(h, coord, useTransit);
if (LOCPLINT->cb->guardingCreaturePosition(node.coord) != int3(-1, -1, -1))
break; // we reached zone-of-control of wandering monster
if (!LOCPLINT->cb->getVisitableObjs(node.coord).empty())
break; // we reached event, garrison or some other visitable object - end this movement batch
}
if (!pathToMove.empty())
{
//updateMovementSound(h, path.currNode().coord, path.nextNode().coord, path.nextNode().action);
LOCPLINT->cb->moveHero(h, pathToMove, useTransit);
}
}

View File

@ -314,7 +314,7 @@ void AdventureMapShortcuts::visitObject()
const CGHeroInstance *h = LOCPLINT->localState->getCurrentHero();
if(h)
LOCPLINT->cb->moveHero(h, h->pos);
LOCPLINT->cb->moveHero(h, h->pos, false);
}
void AdventureMapShortcuts::openObject()

View File

@ -59,22 +59,23 @@ struct DLL_LINKAGE DismissHero : public CPackForServer
struct DLL_LINKAGE MoveHero : public CPackForServer
{
MoveHero() = default;
MoveHero(const int3 & Dest, const ObjectInstanceID & HID, bool Transit)
: dest(Dest)
MoveHero(const std::vector<int3> & path, const ObjectInstanceID & HID, bool Transit)
: path(path)
, hid(HID)
, transit(Transit)
{
}
int3 dest;
std::vector<int3> path;
ObjectInstanceID hid;
bool transit = false;
void visitTyped(ICPackVisitor & visitor) override;
template <typename Handler> void serialize(Handler & h)
template<typename Handler>
void serialize(Handler & h)
{
h & static_cast<CPackForServer &>(*this);
h & dest;
h & path;
h & hid;
h & transit;
}

View File

@ -59,7 +59,17 @@ void ApplyGhNetPackVisitor::visitDismissHero(DismissHero & pack)
void ApplyGhNetPackVisitor::visitMoveHero(MoveHero & pack)
{
gh.throwIfWrongOwner(&pack, pack.hid);
result = gh.moveHero(pack.hid, pack.dest, 0, pack.transit, pack.player);
for (auto const & dest : pack.path)
{
if (!gh.moveHero(pack.hid, dest, 0, pack.transit, pack.player))
{
result = false;
return;
}
}
result = true;
}
void ApplyGhNetPackVisitor::visitCastleTeleportHero(CastleTeleportHero & pack)