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

- Moved gameState::guardingCreaturePosition() to CMap so it doesn't need to be recalculated many times for every player.

- Some optimizations with local cb pinter in VCAI.
This commit is contained in:
DjWarmonger 2014-04-01 11:53:28 +00:00
parent ec54381b12
commit 30b79588db
15 changed files with 192 additions and 108 deletions

View File

@ -135,6 +135,16 @@ void foreach_tile_pos(std::function<void(const int3& pos)> foo)
} }
void foreach_tile_pos(CCallback * cbp, std::function<void(CCallback * cbp, const int3& pos)> foo)
{
int3 mapSize = cbp->getMapSize();
for(int i = 0; i < mapSize.x; i++)
for(int j = 0; j < mapSize.y; j++)
for(int k = 0; k < mapSize.z; k++)
foo(cbp, int3(i,j,k));
}
void foreach_neighbour(const int3 &pos, std::function<void(const int3& pos)> foo) void foreach_neighbour(const int3 &pos, std::function<void(const int3& pos)> foo)
{ {
CCallback * cbp = cb.get(); // avoid costly retrieval of thread-specific pointer CCallback * cbp = cb.get(); // avoid costly retrieval of thread-specific pointer
@ -147,6 +157,16 @@ void foreach_neighbour(const int3 &pos, std::function<void(const int3& pos)> foo
} }
} }
void foreach_neighbour(CCallback * cbp, const int3 &pos, std::function<void(CCallback * cbp, const int3& pos)> foo)
{
for(const int3 &dir : dirs)
{
const int3 n = pos + dir;
if(cbp->isInTheMap(n))
foo(cbp, pos+dir);
}
}
std::string strFromInt3(int3 pos) std::string strFromInt3(int3 pos)
{ {
std::ostringstream oss; std::ostringstream oss;
@ -180,7 +200,7 @@ ui64 evaluateDanger(crint3 tile)
if(visObjs.size()) if(visObjs.size())
objectDanger = evaluateDanger(visObjs.back()); objectDanger = evaluateDanger(visObjs.back());
int3 guardPos = cb->guardingCreaturePosition(tile); int3 guardPos = cb->getGuardingCreaturePosition(tile);
if(guardPos.x >= 0 && guardPos != tile) if(guardPos.x >= 0 && guardPos != tile)
guardDanger = evaluateDanger(guardPos); guardDanger = evaluateDanger(guardPos);
@ -378,7 +398,7 @@ bool isBlockedBorderGate(int3 tileToHit)
&& cb->getPathInfo(tileToHit)->accessible != CGPathNode::ACCESSIBLE; && cb->getPathInfo(tileToHit)->accessible != CGPathNode::ACCESSIBLE;
} }
int howManyTilesWillBeDiscovered(const int3 &pos, int radious) int howManyTilesWillBeDiscovered(const int3 &pos, int radious, CCallback * cbp)
{ //TODO: do not explore dead-end boundaries { //TODO: do not explore dead-end boundaries
int ret = 0; int ret = 0;
for(int x = pos.x - radious; x <= pos.x + radious; x++) for(int x = pos.x - radious; x <= pos.x + radious; x++)
@ -386,9 +406,9 @@ int howManyTilesWillBeDiscovered(const int3 &pos, int radious)
for(int y = pos.y - radious; y <= pos.y + radious; y++) for(int y = pos.y - radious; y <= pos.y + radious; y++)
{ {
int3 npos = int3(x,y,pos.z); int3 npos = int3(x,y,pos.z);
if(cb->isInTheMap(npos) && pos.dist2d(npos) - 0.5 < radious && !cb->isVisible(npos)) if(cbp->isInTheMap(npos) && pos.dist2d(npos) - 0.5 < radious && !cbp->isVisible(npos))
{ {
if (!boundaryBetweenTwoPoints (pos, npos)) if (!boundaryBetweenTwoPoints (pos, npos, cbp))
ret++; ret++;
} }
} }
@ -397,7 +417,7 @@ int howManyTilesWillBeDiscovered(const int3 &pos, int radious)
return ret; return ret;
} }
bool boundaryBetweenTwoPoints (int3 pos1, int3 pos2) //determines if two points are separated by known barrier bool boundaryBetweenTwoPoints (int3 pos1, int3 pos2, CCallback * cbp) //determines if two points are separated by known barrier
{ {
int xMin = std::min (pos1.x, pos2.x); int xMin = std::min (pos1.x, pos2.x);
int xMax = std::max (pos1.x, pos2.x); int xMax = std::max (pos1.x, pos2.x);
@ -411,7 +431,7 @@ bool boundaryBetweenTwoPoints (int3 pos1, int3 pos2) //determines if two points
int3 tile = int3(x, y, pos1.z); //use only on same level, ofc int3 tile = int3(x, y, pos1.z); //use only on same level, ofc
if (abs(pos1.dist2d(tile) - pos2.dist2d(tile)) < 1.5) if (abs(pos1.dist2d(tile) - pos2.dist2d(tile)) < 1.5)
{ {
if (!(cb->isVisible(tile) && cb->getTile(tile)->blocked)) //if there's invisible or unblocked tile between, it's good if (!(cbp->isVisible(tile) && cbp->getTile(tile)->blocked)) //if there's invisible or unblocked tile between, it's good
return false; return false;
} }
} }
@ -421,7 +441,7 @@ bool boundaryBetweenTwoPoints (int3 pos1, int3 pos2) //determines if two points
int howManyTilesWillBeDiscovered(int radious, int3 pos, crint3 dir) int howManyTilesWillBeDiscovered(int radious, int3 pos, crint3 dir)
{ {
return howManyTilesWillBeDiscovered(pos + dir, radious); return howManyTilesWillBeDiscovered(pos + dir, radious, cb.get());
} }
void getVisibleNeighbours(const std::vector<int3> &tiles, std::vector<int3> &out) void getVisibleNeighbours(const std::vector<int3> &tiles, std::vector<int3> &out)

View File

@ -175,9 +175,11 @@ void removeDuplicates(std::vector<T> &vec)
std::string strFromInt3(int3 pos); std::string strFromInt3(int3 pos);
void foreach_tile_pos(std::function<void(const int3& pos)> foo); void foreach_tile_pos(std::function<void(const int3& pos)> foo);
void foreach_tile_pos(CCallback * cbp, std::function<void(CCallback * cbp, const int3& pos)> foo); // avoid costly retrieval of thread-specific pointer
void foreach_neighbour(const int3 &pos, std::function<void(const int3& pos)> foo); void foreach_neighbour(const int3 &pos, std::function<void(const int3& pos)> foo);
void foreach_neighbour(CCallback * cbp, const int3 &pos, std::function<void(CCallback * cbp, const int3& pos)> foo); // avoid costly retrieval of thread-specific pointer
int howManyTilesWillBeDiscovered(const int3 &pos, int radious); int howManyTilesWillBeDiscovered(const int3 &pos, int radious, CCallback * cbp);
int howManyTilesWillBeDiscovered(int radious, int3 pos, crint3 dir); int howManyTilesWillBeDiscovered(int radious, int3 pos, crint3 dir);
void getVisibleNeighbours(const std::vector<int3> &tiles, std::vector<int3> &out); void getVisibleNeighbours(const std::vector<int3> &tiles, std::vector<int3> &out);
@ -192,7 +194,7 @@ bool shouldVisit (HeroPtr h, const CGObjectInstance * obj);
ui64 evaluateDanger(const CGObjectInstance *obj); ui64 evaluateDanger(const CGObjectInstance *obj);
ui64 evaluateDanger(crint3 tile, const CGHeroInstance *visitor); ui64 evaluateDanger(crint3 tile, const CGHeroInstance *visitor);
bool isSafeToVisit(HeroPtr h, crint3 tile); bool isSafeToVisit(HeroPtr h, crint3 tile);
bool boundaryBetweenTwoPoints (int3 pos1, int3 pos2); bool boundaryBetweenTwoPoints (int3 pos1, int3 pos2, CCallback * cbp);
bool compareMovement(HeroPtr lhs, HeroPtr rhs); bool compareMovement(HeroPtr lhs, HeroPtr rhs);
bool compareHeroStrength(HeroPtr h1, HeroPtr h2); bool compareHeroStrength(HeroPtr h1, HeroPtr h2);

View File

@ -2245,9 +2245,11 @@ int3 VCAI::explorationNewPoint(HeroPtr h)
std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow] std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow]
tiles.resize(radius); tiles.resize(radius);
CCallback * cbp = cb.get();
foreach_tile_pos([&](const int3 &pos) foreach_tile_pos([&](const int3 &pos)
{ {
if(!cb->isVisible(pos)) if(!cbp->isVisible(pos))
tiles[0].push_back(pos); tiles[0].push_back(pos);
}); });
@ -2261,14 +2263,14 @@ int3 VCAI::explorationNewPoint(HeroPtr h)
for(const int3 &tile : tiles[i]) for(const int3 &tile : tiles[i])
{ {
if (cb->getTile(tile)->blocked) //does it shorten the time? if (cbp->getTile(tile)->blocked) //does it shorten the time?
continue; continue;
if (!cb->getPathInfo(tile)->reachable()) //this will remove tiles that are guarded by monsters (or removable objects) if (!cbp->getPathInfo(tile)->reachable()) //this will remove tiles that are guarded by monsters (or removable objects)
continue; continue;
CGPath path; CGPath path;
cb->getPath2(tile, path); cbp->getPath2(tile, path);
float ourValue = (float)howManyTilesWillBeDiscovered(tile, radius) / (path.nodes.size() + 1); //+1 prevents erratic jumps float ourValue = (float)howManyTilesWillBeDiscovered(tile, radius, cbp) / (path.nodes.size() + 1); //+1 prevents erratic jumps
if (ourValue > bestValue) //avoid costly checks of tiles that don't reveal much if (ourValue > bestValue) //avoid costly checks of tiles that don't reveal much
{ {
@ -2292,9 +2294,11 @@ int3 VCAI::explorationDesperate(HeroPtr h)
std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow] std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow]
tiles.resize(radius); tiles.resize(radius);
CCallback * cbp = cb.get();
foreach_tile_pos([&](const int3 &pos) foreach_tile_pos([&](const int3 &pos)
{ {
if(!cb->isVisible(pos)) if(!cbp->isVisible(pos))
tiles[0].push_back(pos); tiles[0].push_back(pos);
}); });
@ -2308,9 +2312,9 @@ int3 VCAI::explorationDesperate(HeroPtr h)
for(const int3 &tile : tiles[i]) for(const int3 &tile : tiles[i])
{ {
if (cb->getTile(tile)->blocked) //does it shorten the time? if (cbp->getTile(tile)->blocked) //does it shorten the time?
continue; continue;
if (!howManyTilesWillBeDiscovered(tile, radius)) //avoid costly checks of tiles that don't reveal much if (!howManyTilesWillBeDiscovered(tile, radius, cbp)) //avoid costly checks of tiles that don't reveal much
continue; continue;
auto t = sm.firstTileToGet(h, tile); auto t = sm.firstTileToGet(h, tile);
@ -2682,12 +2686,14 @@ void SectorMap::update()
{ {
clear(); clear();
int curSector = 3; //0 is invisible, 1 is not explored int curSector = 3; //0 is invisible, 1 is not explored
CCallback * cbp = cb.get(); //optimization
foreach_tile_pos([&](crint3 pos) foreach_tile_pos([&](crint3 pos)
{ {
if(retreiveTile(pos) == NOT_CHECKED) if(retreiveTile(pos) == NOT_CHECKED)
{ {
if(!markIfBlocked(retreiveTile(pos), pos)) if(!markIfBlocked(retreiveTile(pos), pos))
exploreNewSector(pos, curSector++); exploreNewSector(pos, curSector++, cbp);
} }
}); });
valid = true; valid = true;
@ -2699,11 +2705,11 @@ void SectorMap::clear()
valid = false; valid = false;
} }
void SectorMap::exploreNewSector(crint3 pos, int num) void SectorMap::exploreNewSector(crint3 pos, int num, CCallback * cbp)
{ {
Sector &s = infoOnSectors[num]; Sector &s = infoOnSectors[num];
s.id = num; s.id = num;
s.water = cb->getTile(pos)->isWater(); s.water = cbp->getTile(pos)->isWater();
std::queue<int3> toVisit; std::queue<int3> toVisit;
toVisit.push(pos); toVisit.push(pos);
@ -2714,21 +2720,21 @@ void SectorMap::exploreNewSector(crint3 pos, int num)
ui8 &sec = retreiveTile(curPos); ui8 &sec = retreiveTile(curPos);
if(sec == NOT_CHECKED) if(sec == NOT_CHECKED)
{ {
const TerrainTile *t = cb->getTile(curPos); const TerrainTile *t = cbp->getTile(curPos);
if(!markIfBlocked(sec, curPos, t)) if(!markIfBlocked(sec, curPos, t))
{ {
if(t->isWater() == s.water) //sector is only-water or only-land if(t->isWater() == s.water) //sector is only-water or only-land
{ {
sec = num; sec = num;
s.tiles.push_back(curPos); s.tiles.push_back(curPos);
foreach_neighbour(curPos, [&](crint3 neighPos) foreach_neighbour(cbp, curPos, [&](CCallback * cbp, crint3 neighPos)
{ {
if(retreiveTile(neighPos) == NOT_CHECKED) if(retreiveTile(neighPos) == NOT_CHECKED)
{ {
toVisit.push(neighPos); toVisit.push(neighPos);
//parent[neighPos] = curPos; //parent[neighPos] = curPos;
} }
const TerrainTile *nt = cb->getTile(neighPos, false); const TerrainTile *nt = cbp->getTile(neighPos, false);
if(nt && nt->isWater() != s.water && canBeEmbarkmentPoint(nt)) if(nt && nt->isWater() != s.water && canBeEmbarkmentPoint(nt))
{ {
s.embarkmentPoints.push_back(neighPos); s.embarkmentPoints.push_back(neighPos);

View File

@ -102,7 +102,7 @@ struct SectorMap
SectorMap(HeroPtr h); SectorMap(HeroPtr h);
void update(); void update();
void clear(); void clear();
void exploreNewSector(crint3 pos, int num); void exploreNewSector(crint3 pos, int num, CCallback * cbp);
void write(crstring fname); void write(crstring fname);
unsigned char &retreiveTile(crint3 pos); unsigned char &retreiveTile(crint3 pos);

View File

@ -356,6 +356,17 @@ int CCallback::getMovementCost(const CGHeroInstance * hero, int3 dest)
return gs->getMovementCost(hero, hero->visitablePos(), dest, hero->hasBonusOfType (Bonus::FLYING_MOVEMENT), hero->movement); return gs->getMovementCost(hero, hero->visitablePos(), dest, hero->hasBonusOfType (Bonus::FLYING_MOVEMENT), hero->movement);
} }
int3 CCallback::getGuardingCreaturePosition(int3 tile)
{
if (!gs->map->isInTheMap(tile))
return int3(-1,-1,-1);
validatePaths();
boost::unique_lock<boost::mutex> pathLock(cl->pathMx);
return gs->map->guardingCreaturePositions[tile.x][tile.y][tile.z];
}
void CCallback::recalculatePaths() void CCallback::recalculatePaths()
{ {
cl->calculatePaths(cl->IGameCallback::getSelectedHero(*player)); cl->calculatePaths(cl->IGameCallback::getSelectedHero(*player));

View File

@ -112,6 +112,7 @@ public:
virtual bool getPath2(int3 dest, CGPath &ret); //uses main, client pathfinder info virtual bool getPath2(int3 dest, CGPath &ret); //uses main, client pathfinder info
virtual bool canMoveBetween(const int3 &a, const int3 &b); virtual bool canMoveBetween(const int3 &a, const int3 &b);
virtual int getMovementCost(const CGHeroInstance * hero, int3 dest); virtual int getMovementCost(const CGHeroInstance * hero, int3 dest);
virtual int3 getGuardingCreaturePosition(int3 tile); //uses main, client pathfinder info
virtual void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int3 src = int3(-1,-1,-1), int movement = -1); virtual void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int3 src = int3(-1,-1,-1), int movement = -1);
virtual void recalculatePaths(); //updates main, client pathfinder info (should be called when moving hero is over) virtual void recalculatePaths(); //updates main, client pathfinder info (should be called when moving hero is over)

View File

@ -1279,7 +1279,7 @@ void CAdvMapInt::tileHovered(const int3 &mapPos)
} }
} }
const bool guardingCreature = CGI->mh->map->isInTheMap(LOCPLINT->cb->guardingCreaturePosition(mapPos)); const bool guardingCreature = CGI->mh->map->isInTheMap(LOCPLINT->cb->getGuardingCreaturePosition(mapPos));
if(selection->ID == Obj::TOWN) if(selection->ID == Obj::TOWN)
{ {

View File

@ -1344,7 +1344,7 @@ bool CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
stillMoveHero.data = WAITING_MOVE; stillMoveHero.data = WAITING_MOVE;
int3 endpos(path.nodes[i-1].coord.x, path.nodes[i-1].coord.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->guardingCreaturePosition(endpos - int3(1, 0, 0))); 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); cb->moveHero(h,endpos);

View File

@ -2237,7 +2237,7 @@ std::vector<CGObjectInstance*> CGameState::guardingCreatures (int3 pos) const
{ {
for (CGObjectInstance* obj : tile.visitableObjects) for (CGObjectInstance* obj : tile.visitableObjects)
{ {
if (obj->ID == Obj::MONSTER && checkForVisitableDir(pos, &map->getTile(originalPos), originalPos)) // Monster being able to attack investigated tile if (obj->ID == Obj::MONSTER && map->checkForVisitableDir(pos, &map->getTile(originalPos), originalPos)) // Monster being able to attack investigated tile
{ {
guards.push_back(obj); guards.push_back(obj);
} }
@ -2256,53 +2256,7 @@ std::vector<CGObjectInstance*> CGameState::guardingCreatures (int3 pos) const
int3 CGameState::guardingCreaturePosition (int3 pos) const int3 CGameState::guardingCreaturePosition (int3 pos) const
{ {
const int3 originalPos = pos; return gs->map->guardingCreaturePositions[pos.x][pos.y][pos.z];
// Give monster at position priority.
if (!map->isInTheMap(pos))
return int3(-1, -1, -1);
const TerrainTile &posTile = map->getTile(pos);
if (posTile.visitable)
{
for (CGObjectInstance* obj : posTile.visitableObjects)
{
if(obj->blockVisit)
{
if (obj->ID == Obj::MONSTER) // Monster
return pos;
else
return int3(-1, -1, -1); //blockvis objects are not guarded by neighbouring creatures
}
}
}
// 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))
{
const auto & tile = map->getTile(pos);
if (tile.visitable && (tile.isWater() == posTile.isWater()))
{
for (CGObjectInstance* obj : tile.visitableObjects)
{
if (obj->ID == Obj::MONSTER && checkForVisitableDir(pos, &posTile, originalPos)) // Monster being able to attack investigated tile
{
return pos;
}
}
}
}
pos.y++;
}
pos.y -= 3;
pos.x++;
}
return int3(-1, -1, -1);
} }
bool CGameState::isVisible(int3 pos, PlayerColor player) bool CGameState::isVisible(int3 pos, PlayerColor player)
@ -2338,22 +2292,7 @@ bool CGameState::isVisible( const CGObjectInstance *obj, boost::optional<PlayerC
bool CGameState::checkForVisitableDir(const int3 & src, const int3 & dst) const bool CGameState::checkForVisitableDir(const int3 & src, const int3 & dst) const
{ {
const TerrainTile * pom = &map->getTile(dst); const TerrainTile * pom = &map->getTile(dst);
return checkForVisitableDir(src, pom, dst); return map->checkForVisitableDir(src, pom, dst);
}
bool CGameState::checkForVisitableDir( const int3 & src, const TerrainTile *pom, const int3 & dst ) const
{
for(ui32 b=0; b<pom->visitableObjects.size(); ++b) //checking destination tile
{
if(!vstd::contains(pom->blockingObjects, pom->visitableObjects[b])) //this visitable object is not blocking, ignore
continue;
const CGObjectInstance * obj = pom->visitableObjects[b];
if (!obj->appearance.isVisitableFrom(src.x - dst.x, src.y - dst.y))
return false;
}
return true;
} }
EVictoryLossCheckResult CGameState::checkForVictoryAndLoss(PlayerColor player) const EVictoryLossCheckResult CGameState::checkForVictoryAndLoss(PlayerColor player) const
@ -3350,6 +3289,7 @@ void CPathfinder::initializeGraph()
curPos = int3(i,j,k); curPos = int3(i,j,k);
const TerrainTile *tinfo = &gs->map->getTile(int3(i, j, k)); const TerrainTile *tinfo = &gs->map->getTile(int3(i, j, k));
CGPathNode &node = graph[i][j][k]; CGPathNode &node = graph[i][j][k];
node.accessible = evaluateAccessibility(tinfo); node.accessible = evaluateAccessibility(tinfo);
node.turns = 0xff; node.turns = 0xff;
node.moveRemains = 0; node.moveRemains = 0;
@ -3405,7 +3345,7 @@ void CPathfinder::calculatePaths(int3 src /*= int3(-1,-1,-1)*/, int movement /*=
cp = mq.front(); cp = mq.front();
mq.pop_front(); mq.pop_front();
const int3 sourceGuardPosition = guardingCreaturePosition(cp->coord); const int3 sourceGuardPosition = gs->map->guardingCreaturePositions[cp->coord.x][cp->coord.y][cp->coord.z];
bool guardedSource = (sourceGuardPosition != int3(-1, -1, -1) && cp->coord != src); bool guardedSource = (sourceGuardPosition != int3(-1, -1, -1) && cp->coord != src);
ct = &gs->map->getTile(cp->coord); ct = &gs->map->getTile(cp->coord);
@ -3498,7 +3438,7 @@ void CPathfinder::calculatePaths(int3 src /*= int3(-1,-1,-1)*/, int movement /*=
dp->turns = turnAtNextTile; dp->turns = turnAtNextTile;
dp->theNodeBefore = cp; dp->theNodeBefore = cp;
const bool guardedDst = guardingCreaturePosition(dp->coord) != int3(-1, -1, -1) const bool guardedDst = gs->map->guardingCreaturePositions[dp->coord.x][dp->coord.y][dp->coord.z].valid()
&& dp->accessible == CGPathNode::BLOCKVIS; && dp->accessible == CGPathNode::BLOCKVIS;
if (dp->accessible == CGPathNode::ACCESSIBLE if (dp->accessible == CGPathNode::ACCESSIBLE
@ -3558,7 +3498,7 @@ CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const TerrainTile
} }
} }
} }
else if (gs->map->isInTheMap(guardingCreaturePosition(curPos)) else if (gs->map->guardingCreaturePositions[curPos.x][curPos.y][curPos.z].valid()
&& !tinfo->blocked) && !tinfo->blocked)
{ {
// Monster close by; blocked visit for battle. // Monster close by; blocked visit for battle.

View File

@ -431,7 +431,6 @@ public:
UpgradeInfo getUpgradeInfo(const CStackInstance &stack); UpgradeInfo getUpgradeInfo(const CStackInstance &stack);
PlayerRelations::PlayerRelations getPlayerRelations(PlayerColor color1, PlayerColor color2); PlayerRelations::PlayerRelations getPlayerRelations(PlayerColor color1, PlayerColor color2);
bool checkForVisitableDir(const int3 & src, const int3 & dst) const; //check if src tile is visitable from dst tile bool checkForVisitableDir(const int3 & src, const int3 & dst) const; //check if src tile is visitable from dst tile
bool checkForVisitableDir(const int3 & src, const TerrainTile *pom, const int3 & dst) const; //check if src tile is visitable from dst tile
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 nullptr 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 nullptr if path does not exists
int3 guardingCreaturePosition (int3 pos) const; int3 guardingCreaturePosition (int3 pos) const;
std::vector<CGObjectInstance*> guardingCreatures (int3 pos) const; std::vector<CGObjectInstance*> guardingCreatures (int3 pos) const;

View File

@ -406,7 +406,7 @@ bool CGameInfoCallback::getTownInfo( const CGObjectInstance *town, InfoAboutTown
return true; return true;
} }
int3 CGameInfoCallback::guardingCreaturePosition (int3 pos) const int3 CGameInfoCallback::guardingCreaturePosition (int3 pos) const //FIXME: redundant?
{ {
ERROR_RET_VAL_IF(!isVisible(pos), "Tile is not visible!", int3(-1,-1,-1)); ERROR_RET_VAL_IF(!isVisible(pos), "Tile is not visible!", int3(-1,-1,-1));
return gs->guardingCreaturePosition(pos); return gs->guardingCreaturePosition(pos);

View File

@ -380,6 +380,7 @@ DLL_LINKAGE void RemoveObject::applyGs( CGameState *gs )
} }
gs->map->objects[id.getNum()].dellNull(); gs->map->objects[id.getNum()].dellNull();
gs->map->calculateGuardingGreaturePositions();
} }
static int getDir(int3 src, int3 dst) static int getDir(int3 src, int3 dst)
@ -613,6 +614,7 @@ DLL_LINKAGE void NewObject::applyGs( CGameState *gs )
gs->map->objects.push_back(o); gs->map->objects.push_back(o);
gs->map->addBlockVisTiles(o); gs->map->addBlockVisTiles(o);
o->initObj(); o->initObj();
gs->map->calculateGuardingGreaturePositions();
logGlobal->debugStream() << "added object id=" << id << "; address=" << (intptr_t)o << "; name=" << o->getHoverText(); logGlobal->debugStream() << "added object id=" << id << "; address=" << (intptr_t)o << "; name=" << o->getHoverText();
} }

View File

@ -216,13 +216,18 @@ CMap::~CMap()
{ {
if(terrain) if(terrain)
{ {
for(int ii=0;ii<width;ii++) for (int i=0; i<width; i++)
{ {
for(int jj=0;jj<height;jj++) for(int j=0; j<height; j++)
delete [] terrain[ii][jj]; {
delete [] terrain[ii]; delete [] terrain[i][j];
delete [] guardingCreaturePositions[i][j];
}
delete [] terrain[i];
delete [] guardingCreaturePositions[i];
} }
delete [] terrain; delete [] terrain;
delete [] guardingCreaturePositions;
} }
} }
@ -280,6 +285,19 @@ void CMap::addBlockVisTiles(CGObjectInstance * obj)
} }
} }
void CMap::calculateGuardingGreaturePositions()
{
int levels = twoLevel ? 2 : 1;
for (int i=0; i<width; i++)
{
for(int j=0; j<height; j++)
{
for (int k = 0; k < levels; k++)
guardingCreaturePositions[i][j][k] = guardingCreaturePosition(int3(i,j,k));
}
}
}
CGHeroInstance * CMap::getHero(int heroID) CGHeroInstance * CMap::getHero(int heroID)
{ {
for(auto & elem : heroesOnMap) for(auto & elem : heroesOnMap)
@ -318,6 +336,75 @@ bool CMap::isWaterTile(const int3 &pos) const
return isInTheMap(pos) && getTile(pos).terType == ETerrainType::WATER; return isInTheMap(pos) && getTile(pos).terType == ETerrainType::WATER;
} }
bool CMap::checkForVisitableDir(const int3 & src, const TerrainTile *pom, const int3 & dst ) const
{
for(ui32 b=0; b<pom->visitableObjects.size(); ++b) //checking destination tile
{
if(!vstd::contains(pom->blockingObjects, pom->visitableObjects[b])) //this visitable object is not blocking, ignore
continue;
const CGObjectInstance * obj = pom->visitableObjects[b];
if (!obj->appearance.isVisitableFrom(src.x - dst.x, src.y - dst.y))
return false;
}
return true;
}
int3 CMap::guardingCreaturePosition (int3 pos) const
{
const int3 originalPos = pos;
// Give monster at position priority.
if (!isInTheMap(pos))
return int3(-1, -1, -1);
const TerrainTile &posTile = getTile(pos);
if (posTile.visitable)
{
for (CGObjectInstance* obj : posTile.visitableObjects)
{
if(obj->blockVisit)
{
if (obj->ID == Obj::MONSTER) // Monster
return pos;
else
return int3(-1, -1, -1); //blockvis objects are not guarded by neighbouring creatures
}
}
}
// See if there are any monsters adjacent.
bool water = posTile.isWater();
pos -= int3(1, 1, 0); // Start with top left.
for (int dx = 0; dx < 3; dx++)
{
for (int dy = 0; dy < 3; dy++)
{
if (isInTheMap(pos))
{
const auto & tile = getTile(pos);
if (tile.visitable && (tile.isWater() == water))
{
for (CGObjectInstance* obj : tile.visitableObjects)
{
if (obj->ID == Obj::MONSTER && checkForVisitableDir(pos, &posTile, originalPos)) // Monster being able to attack investigated tile
{
return pos;
}
}
}
}
pos.y++;
}
pos.y -= 3;
pos.x++;
}
return int3(-1, -1, -1);
}
const CGObjectInstance * CMap::getObjectiveObjectFrom(int3 pos, Obj::EObj type) const CGObjectInstance * CMap::getObjectiveObjectFrom(int3 pos, Obj::EObj type)
{ {
for (CGObjectInstance * object : getTile(pos).visitableObjects) for (CGObjectInstance * object : getTile(pos).visitableObjects)
@ -432,13 +519,17 @@ void CMap::addQuest(CGObjectInstance * quest)
void CMap::initTerrain() void CMap::initTerrain()
{ {
int level = twoLevel ? 2 : 1;
terrain = new TerrainTile**[width]; terrain = new TerrainTile**[width];
for(int i = 0; i < width; ++i) guardingCreaturePositions = new int3**[width];
for (int i = 0; i < width; ++i)
{ {
terrain[i] = new TerrainTile*[height]; terrain[i] = new TerrainTile*[height];
for(int j = 0; j < height; ++j) guardingCreaturePositions[i] = new int3*[height];
for (int j = 0; j < height; ++j)
{ {
terrain[i][j] = new TerrainTile[twoLevel ? 2 : 1]; terrain[i][j] = new TerrainTile[level];
guardingCreaturePositions[i][j] = new int3[level];
} }
} }
} }

View File

@ -391,9 +391,12 @@ public:
const TerrainTile & getTile(const int3 & tile) const; const TerrainTile & getTile(const int3 & tile) const;
bool isInTheMap(const int3 & pos) const; bool isInTheMap(const int3 & pos) const;
bool isWaterTile(const int3 & pos) const; bool isWaterTile(const int3 & pos) const;
bool checkForVisitableDir( const int3 & src, const TerrainTile *pom, const int3 & dst ) const;
int3 guardingCreaturePosition (int3 pos) const;
void addBlockVisTiles(CGObjectInstance * obj); void addBlockVisTiles(CGObjectInstance * obj);
void removeBlockVisTiles(CGObjectInstance * obj, bool total = false); void removeBlockVisTiles(CGObjectInstance * obj, bool total = false);
void calculateGuardingGreaturePositions();
void addNewArtifactInstance(CArtifactInstance * art); void addNewArtifactInstance(CArtifactInstance * art);
void eraseArtifactInstance(CArtifactInstance * art); void eraseArtifactInstance(CArtifactInstance * art);
@ -433,6 +436,8 @@ public:
unique_ptr<CMapEditManager> editManager; unique_ptr<CMapEditManager> editManager;
int3 ***guardingCreaturePositions;
private: private:
/// a 3-dimensional array of terrain tiles, access is as follows: x, y, level. where level=1 is underground /// a 3-dimensional array of terrain tiles, access is as follows: x, y, level. where level=1 is underground
TerrainTile*** terrain; TerrainTile*** terrain;
@ -447,6 +452,7 @@ public:
h & questIdentifierToId; h & questIdentifierToId;
//TODO: viccondetails //TODO: viccondetails
int level = twoLevel ? 2 : 1;
if(h.saving) if(h.saving)
{ {
// Save terrain // Save terrain
@ -454,9 +460,10 @@ public:
{ {
for(int j = 0; j < height ; ++j) for(int j = 0; j < height ; ++j)
{ {
for(int k = 0; k < (twoLevel ? 2 : 1); ++k) for(int k = 0; k < level; ++k)
{ {
h & terrain[i][j][k]; h & terrain[i][j][k];
h & guardingCreaturePositions[i][j][k];
} }
} }
} }
@ -465,21 +472,25 @@ public:
{ {
// Load terrain // Load terrain
terrain = new TerrainTile**[width]; terrain = new TerrainTile**[width];
for(int ii = 0; ii < width; ++ii) guardingCreaturePositions = new int3**[width];
for(int i = 0; i < width; ++i)
{ {
terrain[ii] = new TerrainTile*[height]; terrain[i] = new TerrainTile*[height];
for(int jj = 0; jj < height; ++jj) guardingCreaturePositions[i] = new int3*[height];
for(int j = 0; j < height; ++j)
{ {
terrain[ii][jj] = new TerrainTile[twoLevel ? 2 : 1]; terrain[i][j] = new TerrainTile[level];
guardingCreaturePositions[i][j] = new int3[level];
} }
} }
for(int i = 0; i < width ; ++i) for(int i = 0; i < width ; ++i)
{ {
for(int j = 0; j < height ; ++j) for(int j = 0; j < height ; ++j)
{ {
for(int k = 0; k < (twoLevel ? 2 : 1); ++k) for(int k = 0; k < level; ++k)
{ {
h & terrain[i][j][k]; h & terrain[i][j][k];
h & guardingCreaturePositions[i][j][k];
} }
} }
} }

View File

@ -134,6 +134,7 @@ void CMapLoaderH3M::init()
logGlobal->debugStream() << "\tReading " << mlt.name << " took " << mlt.time << " ms."; logGlobal->debugStream() << "\tReading " << mlt.name << " took " << mlt.time << " ms.";
} }
} }
map->calculateGuardingGreaturePositions();
} }
void CMapLoaderH3M::readHeader() void CMapLoaderH3M::readHeader()