1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

* Creatures now guard surrounding tiles.

This commit is contained in:
OnionKnight
2010-05-06 12:13:31 +00:00
parent a0d72590d3
commit cc616616c1
9 changed files with 130 additions and 25 deletions

View File

@@ -188,6 +188,11 @@ bool CCallback::getTownInfo( const CGObjectInstance *town, InfoAboutTown &dest )
return true;
}
int3 CCallback::guardingCreaturePosition (int3 pos) const
{
return gs->guardingCreaturePosition(pos);
}
int CCallback::howManyHeroes(bool includeGarrisoned) const
{
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);

View File

@@ -278,6 +278,7 @@ public:
void recalculatePaths(); //updates pathfinder info (should be called when moving hero is over)
bool getHeroInfo(const CGObjectInstance *hero, InfoAboutHero &dest) const;
bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const;
int3 guardingCreaturePosition (int3 pos) const;
//battle
int battleGetBattlefieldType(); // 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines 8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields 15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog 21. "favourable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship

View File

@@ -1854,6 +1854,8 @@ void CAdvMapInt::tileHovered(const int3 &tile)
}
}
const bool guardingCreature = CGI->mh->map->isInTheMap(LOCPLINT->cb->guardingCreaturePosition(tile));
if(selection->ID == TOWNI_TYPE)
{
if(objAtTile && objAtTile->tempOwner == LOCPLINT->playerID)
@@ -1917,13 +1919,6 @@ void CAdvMapInt::tileHovered(const int3 &tile)
CGI->curh->changeGraphic(0, 3);
}
}
else if(objAtTile->ID == 54) //monster
{
if(accessible)
CGI->curh->changeGraphic(0, 5 + turns*6);
else
CGI->curh->changeGraphic(0, 0);
}
else if(objAtTile->ID == 8) //boat
{
if(accessible)
@@ -1946,6 +1941,10 @@ void CAdvMapInt::tileHovered(const int3 &tile)
else
CGI->curh->changeGraphic(0, 0);
}
else if (guardingCreature && accessible) //(objAtTile->ID == 54) //monster
{
CGI->curh->changeGraphic(0, 5 + turns*6);
}
else
{
if(accessible)
@@ -1963,6 +1962,9 @@ void CAdvMapInt::tileHovered(const int3 &tile)
{
if(accessible)
{
if (guardingCreature) {
CGI->curh->changeGraphic(0, 5 + turns*6);
} else {
if(pnode->land)
{
if(LOCPLINT->cb->getTileInfo(h->getPosition(false))->tertype != TerrainTile::water)
@@ -1973,6 +1975,7 @@ void CAdvMapInt::tileHovered(const int3 &tile)
else
CGI->curh->changeGraphic(0, 6 + turns*6);
}
}
else
CGI->curh->changeGraphic(0, 0);
}

View File

@@ -237,6 +237,9 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
adventureInt->minimap.draw(screen2);
adventureInt->heroList.draw(screen2);
bool directlyAttackingCreature =
CGI->mh->map->isInTheMap(details.attackedFrom)
&& adventureInt->terrain.currentPath->nodes.size() == 3;
if(makingTurn && ho->tempOwner == playerID) //we are moving our hero - we may need to update assigned path
{
@@ -248,7 +251,8 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
//TODO: smooth disappear / appear effect
}
if (details.result != TryMoveHero::SUCCESS && details.result != TryMoveHero::FAILED) //hero didn't change tile but visit succeeded
if (details.result != TryMoveHero::SUCCESS && details.result != TryMoveHero::FAILED //hero didn't change tile but visit succeeded
|| directlyAttackingCreature) // or creature was attacked from endangering tile.
{
eraseCurrentPathOf(ho);
}
@@ -317,6 +321,18 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
if(stillMoveHero.get() == WAITING_MOVE)
stillMoveHero.setn(DURING_MOVE);
// Hero attacked creature directly, set direction to face it.
if (directlyAttackingCreature) {
// Get direction to attacker.
int3 posOffset = details.attackedFrom - details.end + int3(2, 1, 0);
const ui8 dirLookup[3][3] = {
1, 2, 3,
8, 0, 4,
7, 6, 5
};
// FIXME: Avoid const_cast, make moveDir mutable in some other way?
const_cast<CGHeroInstance *>(ho)->moveDir = dirLookup[posOffset.y][posOffset.x];
}
}
void CPlayerInterface::heroKilled(const CGHeroInstance* hero)
{
@@ -976,6 +992,7 @@ bool CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
stillMoveHero.data = STOP_MOVE;
break;
}
// Start a new sound for the hero movement or let the existing one carry on.
#if 0
// TODO
@@ -995,12 +1012,17 @@ bool CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
stillMoveHero.data = WAITING_MOVE;
int3 endpos(path.nodes[i-1].coord.x, path.nodes[i-1].coord.y, h->pos.z);
bool guarded = CGI->mh->map->isInTheMap(cb->guardingCreaturePosition(endpos - int3(1, 0, 0)));
cb->moveHero(h,endpos);
eventsM.unlock();
while(stillMoveHero.data != STOP_MOVE && stillMoveHero.data != CONTINUE_MOVE)
stillMoveHero.cond.wait(un);
eventsM.lock();
if (guarded) // Abort movement if a guard was fought.
break;
}
CGI->soundh->stopSound(sh);

View File

@@ -2124,6 +2124,12 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int
}
}
}
else if (map->isInTheMap(guardingCreaturePosition(int3(i, j, k)))
&& tinfo->blockingObjects.size() == 0)
{
// Monster close by; blocked visit for battle.
node.accessible = CGPathNode::BLOCKVIS;
}
if(onLand && !node.land) //hero can walk only on land and tile lays on the water
{
@@ -2197,15 +2203,25 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int
remains = moveAtNextTile - cost;
}
if(dp.turns==0xff //we haven't been here before
const bool guardedPosition = guardingCreaturePosition(cp->coord) != int3(-1, -1, -1);
const bool neighborIsGuard = guardingCreaturePosition(cp->coord) == dp.coord;
if((dp.turns==0xff //we haven't been here before
|| dp.turns > turnAtNextTile
|| (dp.turns >= turnAtNextTile && dp.moveRemains < remains)) //this route is faster
&& (!guardedPosition || neighborIsGuard)) // Can step into tile of guard
{
assert(&dp != cp->theNodeBefore); //two tiles can't point to each other
dp.moveRemains = remains;
dp.turns = turnAtNextTile;
dp.theNodeBefore = cp;
if(dp.accessible == CGPathNode::ACCESSIBLE)
const bool guardedNeighbor = guardingCreaturePosition(dp.coord) != int3(-1, -1, -1);
const bool positionIsGuard = guardingCreaturePosition(cp->coord) == cp->coord;
if (dp.accessible == CGPathNode::ACCESSIBLE
|| (guardedNeighbor && !positionIsGuard)) // Can step into a hostile tile once.
{
mq.push(&dp);
}
@@ -2214,6 +2230,51 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int
} //queue loop
}
/**
* Tells if the tile is guarded by a monster as well as the position
* of the monster that will attack on it.
*
* @return int3(-1, -1, -1) if the tile is unguarded, or the position of
* the monster guarding the tile.
*/
int3 CGameState::guardingCreaturePosition (int3 pos) const
{
// Give monster at position priority.
if (!map->isInTheMap(pos))
return int3(-1, -1, -1);
const TerrainTile &posTile = map->terrain[pos.x][pos.y][pos.z];
if (posTile.visitable) {
BOOST_FOREACH (CGObjectInstance* obj, posTile.visitableObjects) {
if (obj->ID == 54) { // Monster
return pos;
}
}
}
// See if there are any monsters adjacent.
pos -= int3(1, 1, 0); // Start with top left.
for (int dx = 0; dx < 3; dx++) {
for (int dy = 0; dy < 3; dy++) {
if (map->isInTheMap(pos)) {
TerrainTile &tile = map->terrain[pos.x][pos.y][pos.z];
if (tile.visitable) {
BOOST_FOREACH (CGObjectInstance* obj, tile.visitableObjects) {
if (obj->ID == 54) { // Monster
return pos;
}
}
}
}
pos.y++;
}
pos.y -= 3;
pos.x++;
}
return int3(-1, -1, -1);
}
bool CGameState::isVisible(int3 pos, int player)
{
if(player == 255) //neutral player

View File

@@ -400,6 +400,7 @@ public:
bool checkForVisitableDir(const int3 & src, const TerrainTile *pom, const int3 & dst) const; //check if src tile is visitable from dst tile
bool getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath &ret); //calculates path between src and dest; returns pointer to newly allocated CPath or NULL if path does not exists
void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int3 src = int3(-1,-1,-1), int movement = -1); //calculates possible paths for hero, by default uses current hero position and movement left; returns pointer to newly allocated CPath or NULL if path does not exists
int3 guardingCreaturePosition (int3 pos) const;
int victoryCheck(ui8 player) const; //checks if given player is winner; -1 if std victory, 1 if special victory, 0 else
int lossCheck(ui8 player) const; //checks if given player is loser; -1 if std loss, 1 if special, 0 else
ui8 checkForStandardWin() const; //returns color of player that accomplished standard victory conditions or 255 if no winner

View File

@@ -466,7 +466,7 @@ struct RemoveObject : public CPackForClient //500
};
struct TryMoveHero : public CPackForClient //501
{
TryMoveHero(){type = 501;humanKnows=false;};
TryMoveHero(){type = 501;humanKnows=false; attackedFrom = int3(-1, -1, -1);};
void applyFirstCl(CClient *cl);
void applyCl(CClient *cl);
void applyGs(CGameState *gs);
@@ -480,12 +480,13 @@ struct TryMoveHero : public CPackForClient //501
ui8 result; //uses EResult
int3 start, end; //h3m format
std::set<int3> fowRevealed; //revealed tiles
int3 attackedFrom; // Set when stepping into endangered tile.
bool humanKnows; //used locally during applying to client
template <typename Handler> void serialize(Handler &h, const int version)
{
h & id & result & start & end & movePoints & fowRevealed;
h & id & result & start & end & movePoints & fowRevealed & attackedFrom;
}
};
struct SetGarrisons : public CPackForClient //502

View File

@@ -342,8 +342,9 @@ void TryMoveHero::applyGs( CGameState *gs )
CGHeroInstance *h = gs->getHero(id);
h->movement = movePoints;
if((result == SUCCESS || result == BLOCKING_VISIT || result == EMBARK || result == DISEMBARK) && start != end)
if((result == SUCCESS || result == BLOCKING_VISIT || result == EMBARK || result == DISEMBARK) && start != end) {
h->moveDir = getDir(start,end);
}
if(result == EMBARK) //hero enters boat at dest tile
{

View File

@@ -1562,7 +1562,7 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
if(!gs->map->isInTheMap(hmpos))
{
tlog1 << "Destination tile os out of the map!\n";
tlog1 << "Destination tile is outside the map!\n";
return false;
}
@@ -1663,13 +1663,16 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
}
else //normal move
{
tmh.result = TryMoveHero::SUCCESS;
BOOST_FOREACH(CGObjectInstance *obj, gs->map->terrain[h->pos.x-1][h->pos.y][h->pos.z].visitableObjects)
{
obj->onHeroLeave(h);
}
getTilesInRange(tmh.fowRevealed,h->getSightCenter()+(tmh.end-tmh.start),h->getSightRadious(),h->tempOwner,1);
int3 guardPos = gs->guardingCreaturePosition(int3(hmpos.x, hmpos.y, hmpos.z));
tmh.result = TryMoveHero::SUCCESS;
tmh.attackedFrom = guardPos;
sendAndApply(&tmh);
tlog5 << "Moved to " <<tmh.end<<std::endl;
@@ -1687,10 +1690,17 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
// {
// objectVisited(obj, h);
// }
// If a creature guards the tile, block visit.
if (gs->map->isInTheMap(guardPos)) {
const TerrainTile &guardTile = gs->map->terrain[guardPos.x][guardPos.y][guardPos.z];
objectVisited(guardTile.visitableObjects.back(), h);
}
tlog5 << "Movement end!\n";
return true;
}
}
else //instant move - teleportation
{
BOOST_FOREACH(CGObjectInstance* obj, t.blockingObjects)