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

CPlayerInterface: all new code for automatic teleport usage

This commit is contained in:
ArseniyShestakov 2015-03-08 17:17:24 +03:00
parent 530b63f7c4
commit 5233b60243
2 changed files with 67 additions and 27 deletions

View File

@ -97,6 +97,7 @@ static bool objectBlitOrderSorter(const TerrainTileObject & a, const TerrainTil
CPlayerInterface::CPlayerInterface(PlayerColor Player) CPlayerInterface::CPlayerInterface(PlayerColor Player)
{ {
logGlobal->traceStream() << "\tHuman player interface for player " << Player << " being constructed"; logGlobal->traceStream() << "\tHuman player interface for player " << Player << " being constructed";
destinationTeleport = ObjectInstanceID();
observerInDuelMode = false; observerInDuelMode = false;
howManyPeople++; howManyPeople++;
GH.defActionsDef = 0; GH.defActionsDef = 0;
@ -1141,6 +1142,16 @@ void CPlayerInterface::showBlockingDialog( const std::string &text, const std::v
} }
void CPlayerInterface::showTeleportDialog(TeleportChannelID channel, std::vector<ObjectInstanceID> exits, bool impassable, QueryID askID)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
ObjectInstanceID choosenExit;
if(destinationTeleport != ObjectInstanceID() && vstd::contains(exits, destinationTeleport))
choosenExit = destinationTeleport;
cb->selectionMade(choosenExit.getNum(), askID);
}
void CPlayerInterface::tileRevealed(const std::unordered_set<int3, ShashInt3> &pos) void CPlayerInterface::tileRevealed(const std::unordered_set<int3, ShashInt3> &pos)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
@ -1389,8 +1400,17 @@ void CPlayerInterface::showArtifactAssemblyDialog (ui32 artifactID, ui32 assembl
void CPlayerInterface::requestRealized( PackageApplied *pa ) void CPlayerInterface::requestRealized( PackageApplied *pa )
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
if(pa->packType == typeList.getTypeID<MoveHero>() && stillMoveHero.get() == DURING_MOVE) if(pa->packType == typeList.getTypeID<MoveHero>() && stillMoveHero.get() == DURING_MOVE
&& destinationTeleport == ObjectInstanceID())
stillMoveHero.setn(CONTINUE_MOVE); stillMoveHero.setn(CONTINUE_MOVE);
if(destinationTeleport != ObjectInstanceID()
&& pa->packType == typeList.getTypeID<QueryReply>()
&& stillMoveHero.get() == DURING_MOVE)
{ // After teleportation via CGTeleport object is finished
destinationTeleport = ObjectInstanceID();
stillMoveHero.setn(CONTINUE_MOVE);
}
} }
void CPlayerInterface::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID query) void CPlayerInterface::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID query)
@ -2624,30 +2644,47 @@ bool CPlayerInterface::capturedAllEvents()
return false; return false;
} }
void CPlayerInterface::doMoveHero(const CGHeroInstance* h, CGPath path) void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
{ {
int i = 1; int i = 1;
auto getObj = [&](int3 coord, bool ignoreHero = false)
{
return cb->getTile(CGHeroInstance::convertPosition(coord,false))->topVisitableObj(ignoreHero);
};
boost::unique_lock<boost::mutex> un(stillMoveHero.mx);
stillMoveHero.data = CONTINUE_MOVE;
auto doMovement = [&](int3 dst, bool transit = false)
{
stillMoveHero.data = WAITING_MOVE;
cb->moveHero(h, dst, transit);
while(stillMoveHero.data != STOP_MOVE && stillMoveHero.data != CONTINUE_MOVE)
stillMoveHero.cond.wait(un);
};
{ {
path.convert(0); path.convert(0);
boost::unique_lock<boost::mutex> un(stillMoveHero.mx);
stillMoveHero.data = CONTINUE_MOVE;
ETerrainType currentTerrain = ETerrainType::BORDER; // not init yet ETerrainType currentTerrain = ETerrainType::BORDER; // not init yet
ETerrainType newTerrain; ETerrainType newTerrain;
int sh = -1; int sh = -1;
const TerrainTile * curTile = cb->getTile(CGHeroInstance::convertPosition(h->pos, false)); for(i=path.nodes.size()-1; i>0 && (stillMoveHero.data == CONTINUE_MOVE); i--)
for(i=path.nodes.size()-1; i>0 && (stillMoveHero.data == CONTINUE_MOVE || curTile->blocked); i--)
{ {
//changing z coordinate means we're moving through subterranean gate -> it's done automatically upon the visit, so we don't have to request that move here int3 currentCoord = path.nodes[i].coord;
if(path.nodes[i-1].coord.z != path.nodes[i].coord.z) int3 nextCoord = path.nodes[i-1].coord;
continue;
//stop sending move requests if the next node can't be reached at the current turn (hero exhausted his move points) auto nextObject = getObj(nextCoord, nextCoord == h->pos);
if(path.nodes[i-1].turns) if(CGTeleport::isConnected(getObj(currentCoord, currentCoord == h->pos), nextObject))
{ {
CCS->soundh->stopSound(sh);
destinationTeleport = nextObject->id;
doMovement(h->pos);
sh = CCS->soundh->playSound(CCS->soundh->horseSounds[currentTerrain], -1);
continue;
}
if(path.nodes[i-1].turns)
{ //stop sending move requests if the next node can't be reached at the current turn (hero exhausted his move points)
stillMoveHero.data = STOP_MOVE; stillMoveHero.data = STOP_MOVE;
break; break;
} }
@ -2655,13 +2692,12 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance* h, CGPath path)
// Start a new sound for the hero movement or let the existing one carry on. // Start a new sound for the hero movement or let the existing one carry on.
#if 0 #if 0
// TODO // TODO
if (hero is flying && sh == -1) if(hero is flying && sh == -1)
sh = CCS->soundh->playSound(soundBase::horseFlying, -1); sh = CCS->soundh->playSound(soundBase::horseFlying, -1);
#endif #endif
{ {
newTerrain = cb->getTile(CGHeroInstance::convertPosition(path.nodes[i].coord, false))->terType; newTerrain = cb->getTile(CGHeroInstance::convertPosition(currentCoord, false))->terType;
if(newTerrain != currentTerrain)
if (newTerrain != currentTerrain)
{ {
CCS->soundh->stopSound(sh); CCS->soundh->stopSound(sh);
sh = CCS->soundh->playSound(CCS->soundh->horseSounds[newTerrain], -1); sh = CCS->soundh->playSound(CCS->soundh->horseSounds[newTerrain], -1);
@ -2669,19 +2705,22 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance* h, CGPath path)
} }
} }
stillMoveHero.data = WAITING_MOVE; assert(h->pos.z == nextCoord.z); // Z should change only if it's movement via teleporter and in this case this code shouldn't be executed at all
int3 endpos(nextCoord.x, nextCoord.y, h->pos.z);
int3 endpos(path.nodes[i-1].coord.x, path.nodes[i-1].coord.y, h->pos.z);
bool guarded = CGI->mh->map->isInTheMap(cb->getGuardingCreaturePosition(endpos - int3(1, 0, 0)));
logGlobal->traceStream() << "Requesting hero movement to " << endpos; logGlobal->traceStream() << "Requesting hero movement to " << endpos;
cb->moveHero(h,endpos);
while(stillMoveHero.data != STOP_MOVE && stillMoveHero.data != CONTINUE_MOVE) if((i-2 >= 0) // Check there is node after next one; otherwise transit is pointless
stillMoveHero.cond.wait(un); && (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);
logGlobal->traceStream() << "Resuming " << __FUNCTION__; logGlobal->traceStream() << "Resuming " << __FUNCTION__;
if (guarded || showingDialog->get() == true) // Abort movement if a guard was fought or there is a dialog to display (Mantis #1136) bool guarded = cb->isInTheMap(cb->getGuardingCreaturePosition(endpos - int3(1, 0, 0)));
if(guarded || showingDialog->get() == true) // Abort movement if a guard was fought or there is a dialog to display (Mantis #1136)
break; break;
} }
@ -2694,7 +2733,7 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance* h, CGPath path)
//todo: this should be in main thread //todo: this should be in main thread
if (adventureInt) if(adventureInt)
{ {
// (i == 0) means hero went through all the path // (i == 0) means hero went through all the path
adventureInt->updateMoveHero(h, (i != 0)); adventureInt->updateMoveHero(h, (i != 0));

View File

@ -89,6 +89,7 @@ class CPlayerInterface : public CGameInterface, public ILockedUpdatable
const CArmedInstance * currentSelection; const CArmedInstance * currentSelection;
public: public:
bool observerInDuelMode; bool observerInDuelMode;
ObjectInstanceID destinationTeleport; //contain -1 or object id if teleportation
//minor interfaces //minor interfaces
CondSh<bool> *showingDialog; //indicates if dialog box is displayed CondSh<bool> *showingDialog; //indicates if dialog box is displayed