1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +02:00

Teleport: rework code to support exit point selection for whirlpools

This commit is contained in:
ArseniyShestakov 2015-12-02 17:56:26 +03:00
parent f6de3f94ca
commit b5100bee94
7 changed files with 72 additions and 41 deletions

View File

@ -96,6 +96,7 @@ VCAI::VCAI(void)
LOG_TRACE(logAi);
makingTurn = nullptr;
destinationTeleport = ObjectInstanceID();
destinationTeleportPos = int3();
}
VCAI::~VCAI(void)
@ -616,31 +617,32 @@ void VCAI::showBlockingDialog(const std::string &text, const std::vector<Compone
void VCAI::showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID)
{
LOG_TRACE_PARAMS(logAi, "askID '%i', exits '%s'", askID % exits);
// 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;
int choosenExit = -1;
if(impassable)
knownTeleportChannels[channel]->passability = TeleportChannel::IMPASSABLE;
else
{
if(destinationTeleport != ObjectInstanceID() && vstd::contains(exits, destinationTeleport))
choosenExit = destinationTeleport;
auto neededExit = std::make_pair(destinationTeleport, destinationTeleportPos);
if(destinationTeleport != ObjectInstanceID() && vstd::contains(exits, neededExit))
choosenExit = vstd::find_pos(exits, neededExit);
if(!status.channelProbing())
/* if(!status.channelProbing())
{
vstd::copy_if(exits, vstd::set_inserter(teleportChannelProbingList), [&](ObjectInstanceID id) -> bool
{
return !(vstd::contains(visitableObjs, cb->getObj(id)) || id == choosenExit);
});
}
}*/
}
requestActionASAP([=]()
{
answerQuery(askID, choosenExit.getNum());
answerQuery(askID, choosenExit);
});
}
@ -1863,8 +1865,10 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
auto doTeleportMovement = [&](int3 dst, ObjectInstanceID exitId)
{
destinationTeleport = exitId;
cb->moveHero(*h, CGHeroInstance::convertPosition(dst, true));
destinationTeleportPos = CGHeroInstance::convertPosition(dst, true);
cb->moveHero(*h, destinationTeleportPos);
destinationTeleport = ObjectInstanceID();
destinationTeleportPos = int3();
afterMovementCheck();
};

View File

@ -148,6 +148,7 @@ public:
std::map<TeleportChannelID, shared_ptr<TeleportChannel> > knownTeleportChannels;
std::map<const CGObjectInstance *, const CGObjectInstance *> knownSubterraneanGates;
ObjectInstanceID destinationTeleport;
int3 destinationTeleportPos;
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;
@ -360,6 +361,14 @@ public:
template <typename Handler> void serializeInternal(Handler &h, const int version)
{
h & knownTeleportChannels & knownSubterraneanGates & destinationTeleport;
if(version >= 755)
{
h & destinationTeleportPos;
}
else if(!h.saving)
{
destinationTeleportPos = int3();
}
h & townVisitsThisWeek & lockedHeroes & reservedHeroesMap; //FIXME: cannot instantiate abstract class
h & visitableObjs & alreadyVisited & reservedObjs;
h & saving & status & battlename;

View File

@ -97,6 +97,7 @@ CPlayerInterface::CPlayerInterface(PlayerColor Player)
{
logGlobal->traceStream() << "\tHuman player interface for player " << Player << " being constructed";
destinationTeleport = ObjectInstanceID();
destinationTeleportPos = int3();
observerInDuelMode = false;
howManyPeople++;
GH.defActionsDef = 0;
@ -1147,14 +1148,15 @@ void CPlayerInterface::showBlockingDialog( const std::string &text, const std::v
}
void CPlayerInterface::showTeleportDialog(TeleportChannelID channel, std::vector<ObjectInstanceID> exits, bool impassable, QueryID askID)
void CPlayerInterface::showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
ObjectInstanceID choosenExit;
if(destinationTeleport != ObjectInstanceID() && vstd::contains(exits, destinationTeleport))
choosenExit = destinationTeleport;
int choosenExit = -1;
auto neededExit = std::make_pair(destinationTeleport, destinationTeleportPos);
if(destinationTeleport != ObjectInstanceID() && vstd::contains(exits, neededExit))
choosenExit = vstd::find_pos(exits, neededExit);
cb->selectionMade(choosenExit.getNum(), askID);
cb->selectionMade(choosenExit, askID);
}
void CPlayerInterface::tileRevealed(const std::unordered_set<int3, ShashInt3> &pos)
@ -1414,6 +1416,7 @@ void CPlayerInterface::requestRealized( PackageApplied *pa )
&& stillMoveHero.get() == DURING_MOVE)
{ // After teleportation via CGTeleport object is finished
destinationTeleport = ObjectInstanceID();
destinationTeleportPos = int3();
stillMoveHero.setn(CONTINUE_MOVE);
}
}
@ -2663,6 +2666,7 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
{
CCS->soundh->stopSound(sh);
destinationTeleport = nextObject->id;
destinationTeleportPos = nextCoord;
doMovement(h->pos, false);
sh = CCS->soundh->playSound(CCS->soundh->horseSounds[currentTerrain], -1);
continue;

View File

@ -90,6 +90,7 @@ class CPlayerInterface : public CGameInterface, public IUpdateable
public:
bool observerInDuelMode;
ObjectInstanceID destinationTeleport; //contain -1 or object id if teleportation
int3 destinationTeleportPos;
//minor interfaces
CondSh<bool> *showingDialog; //indicates if dialog box is displayed
@ -168,7 +169,7 @@ public:
void showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level) override;
void showShipyardDialog(const IShipyard *obj) override; //obj may be town or shipyard;
void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, int soundID, bool selection, bool cancel) override; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
void showTeleportDialog(TeleportChannelID channel, std::vector<ObjectInstanceID> exits, bool impassable, QueryID askID) override;
void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override;
void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override;
void showPuzzleMap() override;
void viewWorldMap() override;

View File

@ -27,7 +27,7 @@
#include "mapping/CCampaignHandler.h" //for CCampaignState
#include "rmg/CMapGenerator.h" // for CMapGenOptions
const ui32 version = 754;
const ui32 version = 755;
const ui32 minSupportedVersion = 753;
class CISer;

View File

@ -834,7 +834,7 @@ bool CGTeleport::isTeleport(const CGObjectInstance * obj)
bool CGTeleport::isConnected(const CGTeleport * src, const CGTeleport * dst)
{
return src && dst && src != dst && src->isChannelExit(dst->id);
return src && dst && src->isChannelExit(dst->id);
}
bool CGTeleport::isConnected(const CGObjectInstance * src, const CGObjectInstance * dst)
@ -913,7 +913,13 @@ void CGMonolith::onHeroVisit( const CGHeroInstance * h ) const
if(isEntrance())
{
if(cb->isTeleportChannelBidirectional(channel) && 1 < cb->getTeleportChannelExits(channel).size())
td.exits = cb->getTeleportChannelExits(channel);
{
auto exits = cb->getTeleportChannelExits(channel);
for(auto exit : exits)
{
td.exits.push_back(std::make_pair(exit, CGHeroInstance::convertPosition(cb->getObj(exit)->visitablePos(), true)));
}
}
if(cb->isTeleportChannelImpassable(channel))
{
@ -929,9 +935,9 @@ void CGMonolith::onHeroVisit( const CGHeroInstance * h ) const
cb->showTeleportDialog(&td);
}
void CGMonolith::teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer, std::vector<ObjectInstanceID> exits) const
void CGMonolith::teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer, TTeleportExitsList exits) const
{
ObjectInstanceID objId(answer);
int3 dPos;
auto realExits = getAllExits(true);
if(!isEntrance() // Do nothing if hero visited exit only object
|| (!exits.size() && !realExits.size()) // Do nothing if there no exits on this channel
@ -939,14 +945,12 @@ void CGMonolith::teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer,
{
return;
}
else if(objId == ObjectInstanceID())
objId = getRandomExit(hero);
else if(vstd::isValidIndex(exits, answer))
dPos = exits[answer].second;
else
assert(vstd::contains(exits, objId)); // Likely cheating attempt: not random teleporter choosen, but it's not from provided list
dPos = CGHeroInstance::convertPosition(cb->getObj(getRandomExit(hero))->visitablePos(), true);
auto obj = cb->getObj(objId);
if(obj)
cb->moveHero(hero->id,CGHeroInstance::convertPosition(obj->pos,true) - getVisitableOffset(), true);
cb->moveHero(hero->id, dPos, true);
}
void CGMonolith::initObj()
@ -986,7 +990,10 @@ void CGSubterraneanGate::onHeroVisit( const CGHeroInstance * h ) const
td.impassable = true;
}
else
td.exits.push_back(getRandomExit(h));
{
auto exit = getRandomExit(h);
td.exits.push_back(std::make_pair(exit, CGHeroInstance::convertPosition(cb->getObj(exit)->visitablePos(), true)));
}
cb->showTeleportDialog(&td);
}
@ -1085,29 +1092,35 @@ void CGWhirlpool::onHeroVisit( const CGHeroInstance * h ) const
cb->changeStackCount(StackLocation(h, targetstack), -countToTake);
}
else
td.exits = getAllExits(true);
{
auto exits = getAllExits();
for(auto exit : exits)
{
auto blockedPosList = cb->getObj(exit)->getBlockedPos();
for(auto bPos : blockedPosList)
td.exits.push_back(std::make_pair(exit, CGHeroInstance::convertPosition(bPos, true)));
}
}
cb->showTeleportDialog(&td);
}
void CGWhirlpool::teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer, std::vector<ObjectInstanceID> exits) const
void CGWhirlpool::teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer, TTeleportExitsList exits) const
{
ObjectInstanceID objId(answer);
int3 dPos;
auto realExits = getAllExits();
if(!exits.size() && !realExits.size())
return;
else if(objId == ObjectInstanceID())
objId = getRandomExit(hero);
else if(vstd::isValidIndex(exits, answer))
dPos = exits[answer].second;
else
assert(vstd::contains(exits, objId)); // Likely cheating attempt: not random teleporter choosen, but it's not from provided list
auto obj = cb->getObj(objId);
if(obj)
{
auto obj = cb->getObj(getRandomExit(hero));
std::set<int3> tiles = obj->getBlockedPos();
auto & tile = *RandomGeneratorUtil::nextItem(tiles, cb->gameState()->getRandomGenerator());
cb->moveHero(hero->id, CGHeroInstance::convertPosition(tile, true), true);
dPos = CGHeroInstance::convertPosition(*RandomGeneratorUtil::nextItem(tiles, cb->gameState()->getRandomGenerator()), true);
}
cb->moveHero(hero->id, dPos, true);
}
bool CGWhirlpool::isProtected( const CGHeroInstance * h )

View File

@ -247,7 +247,7 @@ public:
ui32 defaultResProduction();
};
typedef std::vector<ObjectInstanceID> TTeleportExitsList;
typedef std::vector<std::pair<ObjectInstanceID, int3>> TTeleportExitsList;
struct DLL_LINKAGE TeleportChannel
{
@ -282,7 +282,7 @@ public:
std::vector<ObjectInstanceID> getAllExits(bool excludeCurrent = false) const;
ObjectInstanceID getRandomExit(const CGHeroInstance * h) const;
virtual void teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer, std::vector<ObjectInstanceID> exits) const = 0;
virtual void teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer, TTeleportExitsList exits) const = 0;
static bool isTeleport(const CGObjectInstance * dst);
static bool isConnected(const CGTeleport * src, const CGTeleport * dst);
@ -303,7 +303,7 @@ class DLL_LINKAGE CGMonolith : public CGTeleport
public:
void onHeroVisit(const CGHeroInstance * h) const override;
void teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer, std::vector<ObjectInstanceID> exits) const override;
void teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer, TTeleportExitsList exits) const override;
void initObj() override;
template <typename Handler> void serialize(Handler &h, const int version)
@ -329,7 +329,7 @@ class DLL_LINKAGE CGWhirlpool : public CGMonolith
{
public:
void onHeroVisit(const CGHeroInstance * h) const override;
void teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer, std::vector<ObjectInstanceID> exits) const override;
void teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer, TTeleportExitsList exits) const override;
static bool isProtected( const CGHeroInstance * h );
template <typename Handler> void serialize(Handler &h, const int version)