mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-26 22:57:00 +02:00
VCAI: add all new movement code include teleports and transit support
This commit is contained in:
parent
665712c196
commit
12cf883740
132
AI/VCAI/VCAI.cpp
132
AI/VCAI/VCAI.cpp
@ -95,6 +95,7 @@ VCAI::VCAI(void)
|
||||
{
|
||||
LOG_TRACE(logAi);
|
||||
makingTurn = nullptr;
|
||||
destinationTeleport = ObjectInstanceID();
|
||||
}
|
||||
|
||||
VCAI::~VCAI(void)
|
||||
@ -122,11 +123,19 @@ void VCAI::heroMoved(const TryMoveHero & details)
|
||||
const CGObjectInstance *o1 = frontOrNull(cb->getVisitableObjs(from)),
|
||||
*o2 = frontOrNull(cb->getVisitableObjs(to));
|
||||
|
||||
if(o1 && o2 && o1->ID == Obj::SUBTERRANEAN_GATE && o2->ID == Obj::SUBTERRANEAN_GATE)
|
||||
auto t1 = dynamic_cast<const CGTeleport *>(o1);
|
||||
auto t2 = dynamic_cast<const CGTeleport *>(o2);
|
||||
if(t1 && t2)
|
||||
{
|
||||
knownSubterraneanGates[o1] = o2;
|
||||
knownSubterraneanGates[o2] = o1;
|
||||
logAi->debugStream() << boost::format("Found a pair of subterranean gates between %s and %s!") % from % to;
|
||||
if(ETeleportChannelType::BIDIRECTIONAL == cb->getTeleportChannelType(t1->channel))
|
||||
{
|
||||
if(o1->ID == Obj::SUBTERRANEAN_GATE)
|
||||
{
|
||||
knownSubterraneanGates[o1] = o2;
|
||||
knownSubterraneanGates[o2] = o1;
|
||||
logAi->debugStream() << boost::format("Found a pair of subterranean gates between %s and %s!") % from % to;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -590,6 +599,37 @@ void VCAI::showBlockingDialog(const std::string &text, const std::vector<Compone
|
||||
});
|
||||
}
|
||||
|
||||
void VCAI::showTeleportDialog(TeleportChannelID channel, std::vector<ObjectInstanceID> exits, bool impassable, QueryID askID)
|
||||
{
|
||||
LOG_TRACE_PARAMS(logAi, "askID '%i', exits '%s'", askID % exits);
|
||||
NET_EVENT_HANDLER;
|
||||
status.addQuery(askID, boost::str(boost::format("Teleport dialog query with %d exits")
|
||||
% exits.size()));
|
||||
|
||||
ObjectInstanceID choosenExit;
|
||||
if(impassable)
|
||||
knownTeleportChannels[channel]->passability = TeleportChannel::IMPASSABLE;
|
||||
else
|
||||
{
|
||||
if(destinationTeleport != ObjectInstanceID() && vstd::contains(exits, destinationTeleport))
|
||||
choosenExit = destinationTeleport;
|
||||
|
||||
if(!status.channelProbing())
|
||||
{
|
||||
vstd::erase_if(exits, [&](ObjectInstanceID id) -> bool
|
||||
{
|
||||
return vstd::contains(visitableObjs, cb->getObj(id)) || id == choosenExit;
|
||||
});
|
||||
teleportChannelProbingList = exits;
|
||||
}
|
||||
}
|
||||
|
||||
requestActionASAP([=]()
|
||||
{
|
||||
answerQuery(askID, choosenExit.getNum());
|
||||
});
|
||||
}
|
||||
|
||||
void VCAI::showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID)
|
||||
{
|
||||
LOG_TRACE_PARAMS(logAi, "removableUnits '%i', queryID '%i'", removableUnits % queryID);
|
||||
@ -1649,6 +1689,18 @@ bool VCAI::isAccessibleForHero(const int3 & pos, HeroPtr h, bool includeAllies /
|
||||
|
||||
bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
{
|
||||
auto afterMovementCheck = [&]() -> void
|
||||
{
|
||||
waitTillFree(); //movement may cause battle or blocking dialog
|
||||
if(!h)
|
||||
{
|
||||
lostHero(h);
|
||||
if (status.channelProbing()) // if hero lost during channel probing we need to switch this mode off
|
||||
status.setChannelProbing(false);
|
||||
throw std::runtime_error("Hero was lost!");
|
||||
}
|
||||
};
|
||||
|
||||
logAi->debugStream() << boost::format("Moving hero %s to tile %s") % h->name % dst;
|
||||
int3 startHpos = h->visitablePos();
|
||||
bool ret = false;
|
||||
@ -1657,12 +1709,8 @@ 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, CGHeroInstance::convertPosition(dst, true));
|
||||
waitTillFree(); //movement may cause battle or blocking dialog
|
||||
if(!h) // TODO is it feasible to hero get killed there if game work properly?
|
||||
{ // not sure if AI can currently reconsider to attack bank while staying on it. Check issue 2084 on mantis for more information.
|
||||
lostHero(h);
|
||||
throw std::runtime_error("Hero was lost!");
|
||||
}
|
||||
afterMovementCheck();// TODO: is it feasible to hero get killed there if game work properly?
|
||||
// not sure if AI can currently reconsider to attack bank while staying on it. Check issue 2084 on mantis for more information.
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
@ -1675,9 +1723,54 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
throw goalFulfilledException (sptr(Goals::VisitTile(dst).sethero(h)));
|
||||
}
|
||||
|
||||
auto getObj = [&](int3 coord, bool ignoreHero = false)
|
||||
{
|
||||
return cb->getTile(coord,false)->topVisitableObj(ignoreHero);
|
||||
};
|
||||
|
||||
auto doMovement = [&](int3 dst, bool transit = false)
|
||||
{
|
||||
cb->moveHero(*h, CGHeroInstance::convertPosition(dst, true), transit);
|
||||
};
|
||||
|
||||
auto doTeleportMovement = [&](int3 dst, ObjectInstanceID exitId)
|
||||
{
|
||||
destinationTeleport = exitId;
|
||||
cb->moveHero(*h, CGHeroInstance::convertPosition(dst, true));
|
||||
destinationTeleport = ObjectInstanceID();
|
||||
afterMovementCheck();
|
||||
};
|
||||
|
||||
auto doChannelProbing = [&]() -> void
|
||||
{
|
||||
auto currentExit = getObj(CGHeroInstance::convertPosition(h->pos,false));
|
||||
assert(currentExit);
|
||||
|
||||
status.setChannelProbing(true);
|
||||
for(auto exit : teleportChannelProbingList)
|
||||
doTeleportMovement(CGHeroInstance::convertPosition(h->pos,false), exit);
|
||||
teleportChannelProbingList.clear();
|
||||
doTeleportMovement(CGHeroInstance::convertPosition(h->pos,false), currentExit->id);
|
||||
status.setChannelProbing(false);
|
||||
};
|
||||
|
||||
int i=path.nodes.size()-1;
|
||||
for(; i>0; i--)
|
||||
{
|
||||
int3 currentCoord = path.nodes[i].coord;
|
||||
int3 nextCoord = path.nodes[i-1].coord;
|
||||
|
||||
auto currentObject = getObj(currentCoord, currentCoord == CGHeroInstance::convertPosition(h->pos,false));
|
||||
auto nextObject = getObj(nextCoord);
|
||||
if(CGTeleport::isConnected(currentObject, nextObject))
|
||||
{ //we use special login if hero standing on teleporter it's mean we need
|
||||
doTeleportMovement(currentCoord, nextObject->id);
|
||||
if(teleportChannelProbingList.size())
|
||||
doChannelProbing();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
//stop sending move requests if the next node can't be reached at the current turn (hero exhausted his move points)
|
||||
if(path.nodes[i-1].turns)
|
||||
{
|
||||
@ -1689,16 +1782,19 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
if(endpos == h->visitablePos())
|
||||
continue;
|
||||
|
||||
cb->moveHero(*h, CGHeroInstance::convertPosition(endpos, true));
|
||||
waitTillFree(); //movement may cause battle or blocking dialog
|
||||
boost::this_thread::interruption_point();
|
||||
if(!h) //we lost hero - remove all tasks assigned to him/her
|
||||
{
|
||||
lostHero(h);
|
||||
//we need to throw, otherwise hero will be assigned to sth again
|
||||
throw std::runtime_error("Hero was lost!");
|
||||
if((i-2 >= 0) // Check there is node after next one; otherwise transit is pointless
|
||||
&& (CGTeleport::isConnected(nextObject, getObj(path.nodes[i-2].coord))
|
||||
|| CGTeleport::isTeleport(nextObject)))
|
||||
{ // Hero should be able to go through object if it's allow transit
|
||||
doMovement(endpos, true);
|
||||
}
|
||||
else
|
||||
doMovement(endpos);
|
||||
|
||||
afterMovementCheck();
|
||||
|
||||
if(teleportChannelProbingList.size())
|
||||
doChannelProbing();
|
||||
}
|
||||
ret = !i;
|
||||
}
|
||||
|
@ -143,6 +143,8 @@ public:
|
||||
|
||||
std::map<TeleportChannelID, shared_ptr<TeleportChannel> > knownTeleportChannels;
|
||||
std::map<const CGObjectInstance *, const CGObjectInstance *> knownSubterraneanGates;
|
||||
ObjectInstanceID destinationTeleport;
|
||||
std::vector<ObjectInstanceID> teleportChannelProbingList; //list of teleport channel exits that not visible and need to be (re-)explored
|
||||
//std::vector<const CGObjectInstance *> visitedThisWeek; //only OPWs
|
||||
std::map<HeroPtr, std::set<const CGTownInstance *> > townVisitsThisWeek;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user