1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-15 00:05:02 +02:00

Rotation rebase2 (#912)

* Instead of [x][y][z] coordinates, map will be stored as [z][x][y].
* Nullkiller AI can get it too.
* Use boost::multi_array instead of nested vectors
* In MapHandler too
* Rotate foreach algorithms, too
* VCAI gets rotated, too
This commit is contained in:
DjWarmonger
2022-09-18 16:39:10 +02:00
committed by GitHub
parent e85f8a56bb
commit 7ba271edf1
44 changed files with 502 additions and 1015 deletions

View File

@ -205,12 +205,14 @@ void foreach_tile_pos(const Func & foo)
// some micro-optimizations since this function gets called a LOT // some micro-optimizations since this function gets called a LOT
// callback pointer is thread-specific and slow to retrieve -> read map size only once // callback pointer is thread-specific and slow to retrieve -> read map size only once
int3 mapSize = cb->getMapSize(); int3 mapSize = cb->getMapSize();
for(int i = 0; i < mapSize.x; i++) for(int z = 0; z < mapSize.z; z++)
{ {
for(int j = 0; j < mapSize.y; j++) for(int x = 0; x < mapSize.x; x++)
{ {
for(int k = 0; k < mapSize.z; k++) for(int y = 0; y < mapSize.y; y++)
foo(int3(i, j, k)); {
foo(int3(x, y, z));
}
} }
} }
} }
@ -219,12 +221,14 @@ template<class Func>
void foreach_tile_pos(CCallback * cbp, const Func & foo) // avoid costly retrieval of thread-specific pointer void foreach_tile_pos(CCallback * cbp, const Func & foo) // avoid costly retrieval of thread-specific pointer
{ {
int3 mapSize = cbp->getMapSize(); int3 mapSize = cbp->getMapSize();
for(int i = 0; i < mapSize.x; i++) for(int z = 0; z < mapSize.z; z++)
{ {
for(int j = 0; j < mapSize.y; j++) for(int x = 0; x < mapSize.x; x++)
{ {
for(int k = 0; k < mapSize.z; k++) for(int y = 0; y < mapSize.y; y++)
foo(cbp, int3(i, j, k)); {
foo(cbp, int3(x, y, z));
}
} }
} }
} }
@ -275,23 +279,23 @@ bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObject
template<typename TFunc> template<typename TFunc>
void pforeachTilePos(crint3 mapSize, TFunc fn) void pforeachTilePos(crint3 mapSize, TFunc fn)
{
for(int z = 0; z < mapSize.z; ++z)
{ {
parallel_for(blocked_range<size_t>(0, mapSize.x), [&](const blocked_range<size_t>& r) parallel_for(blocked_range<size_t>(0, mapSize.x), [&](const blocked_range<size_t>& r)
{ {
int3 pos; int3 pos(0, 0, z);
for(pos.x = r.begin(); pos.x != r.end(); ++pos.x) for(pos.x = r.begin(); pos.x != r.end(); ++pos.x)
{ {
for(pos.y = 0; pos.y < mapSize.y; ++pos.y) for(pos.y = 0; pos.y < mapSize.y; ++pos.y)
{
for(pos.z = 0; pos.z < mapSize.z; ++pos.z)
{ {
fn(pos); fn(pos);
} }
} }
}
}); });
} }
}
class CDistanceSorter class CDistanceSorter
{ {

View File

@ -39,7 +39,7 @@ AISharedStorage::AISharedStorage(int3 sizes)
{ {
if(!shared){ if(!shared){
shared.reset(new boost::multi_array<AIPathNode, 5>( shared.reset(new boost::multi_array<AIPathNode, 5>(
boost::extents[sizes.x][sizes.y][sizes.z][EPathfindingLayer::NUM_LAYERS][NUM_CHAINS])); boost::extents[EPathfindingLayer::NUM_LAYERS][sizes.z][sizes.x][sizes.y][NUM_CHAINS]));
} }
nodes = shared; nodes = shared;
@ -69,23 +69,24 @@ void AINodeStorage::initialize(const PathfinderOptions & options, const CGameSta
//TODO: fix this code duplication with NodeStorage::initialize, problem is to keep `resetTile` inline //TODO: fix this code duplication with NodeStorage::initialize, problem is to keep `resetTile` inline
const PlayerColor fowPlayer = ai->playerID; const PlayerColor fowPlayer = ai->playerID;
const auto & fow = static_cast<const CGameInfoCallback *>(gs)->getPlayerTeam(fowPlayer)->fogOfWarMap; const auto fow = static_cast<const CGameInfoCallback *>(gs)->getPlayerTeam(fowPlayer)->fogOfWarMap;
const int3 sizes = gs->getMapSize(); const int3 sizes = gs->getMapSize();
//Each thread gets different x, but an array of y located next to each other in memory
parallel_for(blocked_range<size_t>(0, sizes.x), [&](const blocked_range<size_t>& r) parallel_for(blocked_range<size_t>(0, sizes.x), [&](const blocked_range<size_t>& r)
{ {
//make 200% sure that these are loop invariants (also a bit shorter code), let compiler do the rest(loop unswitching) int3 pos;
for(pos.z = 0; pos.z < sizes.z; ++pos.z)
{
const bool useFlying = options.useFlying; const bool useFlying = options.useFlying;
const bool useWaterWalking = options.useWaterWalking; const bool useWaterWalking = options.useWaterWalking;
const PlayerColor player = playerID; const PlayerColor player = playerID;
int3 pos;
for(pos.x = r.begin(); pos.x != r.end(); ++pos.x) for(pos.x = r.begin(); pos.x != r.end(); ++pos.x)
{ {
for(pos.y = 0; pos.y < sizes.y; ++pos.y) for(pos.y = 0; pos.y < sizes.y; ++pos.y)
{
for(pos.z = 0; pos.z < sizes.z; ++pos.z)
{ {
const TerrainTile* tile = &gs->map->getTile(pos); const TerrainTile* tile = &gs->map->getTile(pos);
if (!tile->terType.isPassable()) if (!tile->terType.isPassable())
@ -140,7 +141,7 @@ boost::optional<AIPathNode *> AINodeStorage::getOrCreateNode(
{ {
int bucketIndex = ((uintptr_t)actor) % BUCKET_COUNT; int bucketIndex = ((uintptr_t)actor) % BUCKET_COUNT;
int bucketOffset = bucketIndex * BUCKET_SIZE; int bucketOffset = bucketIndex * BUCKET_SIZE;
auto chains = nodes.get(pos, layer); auto chains = nodes.get(pos, layer); //FIXME: chain was the innermost layer
if(chains[0].blocked()) if(chains[0].blocked())
{ {

View File

@ -120,23 +120,19 @@ enum EHeroChainPass
class AISharedStorage class AISharedStorage
{ {
/// 1-3 - position on map, 4 - layer (air, water, land), 5 - chain (normal, battle, spellcast and combinations) // 1 - layer (air, water, land)
// 2-4 - position on map[z][x][y]
// 5 - chain (normal, battle, spellcast and combinations)
static std::shared_ptr<boost::multi_array<AIPathNode, 5>> shared; static std::shared_ptr<boost::multi_array<AIPathNode, 5>> shared;
std::shared_ptr<boost::multi_array<AIPathNode, 5>> nodes; std::shared_ptr<boost::multi_array<AIPathNode, 5>> nodes;
public: public:
AISharedStorage(int3 mapSize); AISharedStorage(int3 mapSize);
~AISharedStorage(); ~AISharedStorage();
/*STRONG_INLINE
boost::detail::multi_array::sub_array<AIPathNode, 1> get(int3 tile, EPathfindingLayer layer)
{
return (*nodes)[tile.x][tile.y][tile.z][layer];
}*/
STRONG_INLINE STRONG_INLINE
boost::detail::multi_array::sub_array<AIPathNode, 1> get(int3 tile, EPathfindingLayer layer) const boost::detail::multi_array::sub_array<AIPathNode, 1> get(int3 tile, EPathfindingLayer layer) const
{ {
return (*nodes)[tile.x][tile.y][tile.z][layer]; return (*nodes)[layer][tile.z][tile.x][tile.y];
} }
}; };

View File

@ -137,55 +137,6 @@ bool HeroPtr::operator==(const HeroPtr & rhs) const
return h == rhs.get(true); return h == rhs.get(true);
} }
void foreach_tile_pos(std::function<void(const int3 & pos)> foo)
{
// some micro-optimizations since this function gets called a LOT
// callback pointer is thread-specific and slow to retrieve -> read map size only once
int3 mapSize = cb->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(int3(i, j, k));
}
}
}
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)
{
CCallback * cbp = cb.get(); // avoid costly retrieval of thread-specific pointer
for(const int3 & dir : int3::getDirs())
{
const int3 n = pos + dir;
if(cbp->isInTheMap(n))
foo(pos + dir);
}
}
void foreach_neighbour(CCallback * cbp, const int3 & pos, std::function<void(CCallback * cbp, const int3 & pos)> foo)
{
for(const int3 & dir : int3::getDirs())
{
const int3 n = pos + dir;
if(cbp->isInTheMap(n))
foo(cbp, pos + dir);
}
}
bool CDistanceSorter::operator()(const CGObjectInstance * lhs, const CGObjectInstance * rhs) const bool CDistanceSorter::operator()(const CGObjectInstance * lhs, const CGObjectInstance * rhs) const
{ {
const CGPathNode * ln = ai->myCb->getPathsInfo(hero)->getPathInfo(lhs->visitablePos()); const CGPathNode * ln = ai->myCb->getPathsInfo(hero)->getPathInfo(lhs->visitablePos());

View File

@ -18,6 +18,7 @@
#include "../../lib/mapObjects/CObjectHandler.h" #include "../../lib/mapObjects/CObjectHandler.h"
#include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/mapObjects/CGHeroInstance.h"
#include "../../lib/CPathfinder.h" #include "../../lib/CPathfinder.h"
#include "../../CCallback.h"
class CCallback; class CCallback;
struct creInfo; struct creInfo;
@ -34,6 +35,8 @@ const int ALLOWED_ROAMING_HEROES = 8;
extern const double SAFE_ATTACK_CONSTANT; extern const double SAFE_ATTACK_CONSTANT;
extern const int GOLD_RESERVE; extern const int GOLD_RESERVE;
extern boost::thread_specific_ptr<CCallback> cb;
//provisional class for AI to store a reference to an owned hero object //provisional class for AI to store a reference to an owned hero object
//checks if it's valid on access, should be used in place of const CGHeroInstance* //checks if it's valid on access, should be used in place of const CGHeroInstance*
@ -154,10 +157,62 @@ struct creInfo
}; };
creInfo infoFromDC(const dwellingContent & dc); creInfo infoFromDC(const dwellingContent & dc);
void foreach_tile_pos(std::function<void(const int3 & pos)> foo); template<class Func>
void foreach_tile_pos(CCallback * cbp, std::function<void(CCallback * cbp, const int3 & pos)> foo); // avoid costly retrieval of thread-specific pointer void foreach_tile_pos(const Func & 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 // some micro-optimizations since this function gets called a LOT
// callback pointer is thread-specific and slow to retrieve -> read map size only once
int3 mapSize = cb->getMapSize();
for(int z = 0; z < mapSize.z; z++)
{
for(int x = 0; x < mapSize.x; x++)
{
for(int y = 0; y < mapSize.y; y++)
{
foo(int3(x, y, z));
}
}
}
}
template<class Func>
void foreach_tile_pos(CCallback * cbp, const Func & foo) // avoid costly retrieval of thread-specific pointer
{
int3 mapSize = cbp->getMapSize();
for(int z = 0; z < mapSize.z; z++)
{
for(int x = 0; x < mapSize.x; x++)
{
for(int y = 0; y < mapSize.y; y++)
{
foo(cbp, int3(x, y, z));
}
}
}
}
template<class Func>
void foreach_neighbour(const int3 & pos, const Func & foo)
{
CCallback * cbp = cb.get(); // avoid costly retrieval of thread-specific pointer
for(const int3 & dir : int3::getDirs())
{
const int3 n = pos + dir;
if(cbp->isInTheMap(n))
foo(pos + dir);
}
}
template<class Func>
void foreach_neighbour(CCallback * cbp, const int3 & pos, const Func & foo) // avoid costly retrieval of thread-specific pointer
{
for(const int3 & dir : int3::getDirs())
{
const int3 n = pos + dir;
if(cbp->isInTheMap(n))
foo(cbp, pos + dir);
}
}
bool canBeEmbarkmentPoint(const TerrainTile * t, bool fromWater); bool canBeEmbarkmentPoint(const TerrainTile * t, bool fromWater);
bool isBlockedBorderGate(int3 tileToHit); bool isBlockedBorderGate(int3 tileToHit);

View File

@ -17,8 +17,6 @@ set(VCAI_SRCS
ArmyManager.cpp ArmyManager.cpp
ResourceManager.cpp ResourceManager.cpp
BuildingManager.cpp BuildingManager.cpp
SectorMap.cpp
BuildingManager.cpp
MapObjectsEvaluator.cpp MapObjectsEvaluator.cpp
FuzzyEngines.cpp FuzzyEngines.cpp
FuzzyHelper.cpp FuzzyHelper.cpp
@ -68,8 +66,6 @@ set(VCAI_HEADERS
ArmyManager.h ArmyManager.h
ResourceManager.h ResourceManager.h
BuildingManager.h BuildingManager.h
SectorMap.h
BuildingManager.h
MapObjectsEvaluator.h MapObjectsEvaluator.h
FuzzyEngines.h FuzzyEngines.h
FuzzyHelper.h FuzzyHelper.h

View File

@ -18,6 +18,7 @@
struct HeroPtr; struct HeroPtr;
class VCAI; class VCAI;
class FuzzyHelper; class FuzzyHelper;
class CCallback;
namespace Goals namespace Goals
{ {

View File

@ -57,13 +57,16 @@ namespace Goals
void scanSector(int scanRadius) void scanSector(int scanRadius)
{ {
for(int x = ourPos.x - scanRadius; x <= ourPos.x + scanRadius; x++) int3 tile = int3(0, 0, ourPos.z);
{
for(int y = ourPos.y - scanRadius; y <= ourPos.y + scanRadius; y++)
{
int3 tile = int3(x, y, ourPos.z);
if(cbp->isInTheMap(tile) && ts->fogOfWarMap[tile.x][tile.y][tile.z]) const auto & slice = (*(ts->fogOfWarMap))[ourPos.z];
for(tile.x = ourPos.x - scanRadius; tile.x <= ourPos.x + scanRadius; tile.x++)
{
for(tile.y = ourPos.y - scanRadius; tile.y <= ourPos.y + scanRadius; tile.y++)
{
if(cbp->isInTheMap(tile) && slice[tile.x][tile.y])
{ {
scanTile(tile); scanTile(tile);
} }
@ -84,13 +87,13 @@ namespace Goals
foreach_tile_pos([&](const int3 & pos) foreach_tile_pos([&](const int3 & pos)
{ {
if(ts->fogOfWarMap[pos.x][pos.y][pos.z]) if((*(ts->fogOfWarMap))[pos.z][pos.x][pos.y])
{ {
bool hasInvisibleNeighbor = false; bool hasInvisibleNeighbor = false;
foreach_neighbour(cbp, pos, [&](CCallback * cbp, int3 neighbour) foreach_neighbour(cbp, pos, [&](CCallback * cbp, int3 neighbour)
{ {
if(!ts->fogOfWarMap[neighbour.x][neighbour.y][neighbour.z]) if(!(*(ts->fogOfWarMap))[neighbour.z][neighbour.x][neighbour.y])
{ {
hasInvisibleNeighbor = true; hasInvisibleNeighbor = true;
} }
@ -174,7 +177,7 @@ namespace Goals
{ {
foreach_neighbour(cbp, tile, [&](CCallback * cbp, int3 neighbour) foreach_neighbour(cbp, tile, [&](CCallback * cbp, int3 neighbour)
{ {
if(ts->fogOfWarMap[neighbour.x][neighbour.y][neighbour.z]) if((*(ts->fogOfWarMap))[neighbour.z][neighbour.x][neighbour.y])
{ {
out.push_back(neighbour); out.push_back(neighbour);
} }
@ -182,18 +185,20 @@ namespace Goals
} }
} }
int howManyTilesWillBeDiscovered( int howManyTilesWillBeDiscovered(const int3 & pos) const
const int3 & pos) const
{ {
int ret = 0; int ret = 0;
for(int x = pos.x - sightRadius; x <= pos.x + sightRadius; x++) int3 npos = int3(0, 0, pos.z);
const auto & slice = (*(ts->fogOfWarMap))[pos.z];
for(npos.x = pos.x - sightRadius; npos.x <= pos.x + sightRadius; npos.x++)
{ {
for(int y = pos.y - sightRadius; y <= pos.y + sightRadius; y++) for(npos.y = pos.y - sightRadius; npos.y <= pos.y + sightRadius; npos.y++)
{ {
int3 npos = int3(x, y, pos.z);
if(cbp->isInTheMap(npos) if(cbp->isInTheMap(npos)
&& pos.dist2d(npos) - 0.5 < sightRadius && pos.dist2d(npos) - 0.5 < sightRadius
&& !ts->fogOfWarMap[npos.x][npos.y][npos.z]) && !slice[npos.x][npos.y])
{ {
if(allowDeadEndCancellation if(allowDeadEndCancellation
&& !hasReachableNeighbor(npos)) && !hasReachableNeighbor(npos))

View File

@ -20,7 +20,7 @@
AINodeStorage::AINodeStorage(const int3 & Sizes) AINodeStorage::AINodeStorage(const int3 & Sizes)
: sizes(Sizes) : sizes(Sizes)
{ {
nodes.resize(boost::extents[sizes.x][sizes.y][sizes.z][EPathfindingLayer::NUM_LAYERS][NUM_CHAINS]); nodes.resize(boost::extents[EPathfindingLayer::NUM_LAYERS][sizes.z][sizes.x][sizes.y][NUM_CHAINS]);
dangerEvaluator.reset(new FuzzyHelper()); dangerEvaluator.reset(new FuzzyHelper());
} }
@ -28,8 +28,6 @@ AINodeStorage::~AINodeStorage() = default;
void AINodeStorage::initialize(const PathfinderOptions & options, const CGameState * gs) void AINodeStorage::initialize(const PathfinderOptions & options, const CGameState * gs)
{ {
//TODO: fix this code duplication with NodeStorage::initialize, problem is to keep `resetTile` inline
int3 pos; int3 pos;
const int3 sizes = gs->getMapSize(); const int3 sizes = gs->getMapSize();
const auto & fow = static_cast<const CGameInfoCallback *>(gs)->getPlayerTeam(hero->tempOwner)->fogOfWarMap; const auto & fow = static_cast<const CGameInfoCallback *>(gs)->getPlayerTeam(hero->tempOwner)->fogOfWarMap;
@ -39,11 +37,11 @@ void AINodeStorage::initialize(const PathfinderOptions & options, const CGameSta
const bool useFlying = options.useFlying; const bool useFlying = options.useFlying;
const bool useWaterWalking = options.useWaterWalking; const bool useWaterWalking = options.useWaterWalking;
for(pos.z=0; pos.z < sizes.z; ++pos.z)
{
for(pos.x=0; pos.x < sizes.x; ++pos.x) for(pos.x=0; pos.x < sizes.x; ++pos.x)
{ {
for(pos.y=0; pos.y < sizes.y; ++pos.y) for(pos.y=0; pos.y < sizes.y; ++pos.y)
{
for(pos.z=0; pos.z < sizes.z; ++pos.z)
{ {
const TerrainTile * tile = &gs->map->getTile(pos); const TerrainTile * tile = &gs->map->getTile(pos);
if(!tile->terType.isPassable()) if(!tile->terType.isPassable())
@ -87,7 +85,7 @@ bool AINodeStorage::isBattleNode(const CGPathNode * node) const
boost::optional<AIPathNode *> AINodeStorage::getOrCreateNode(const int3 & pos, const EPathfindingLayer layer, int chainNumber) boost::optional<AIPathNode *> AINodeStorage::getOrCreateNode(const int3 & pos, const EPathfindingLayer layer, int chainNumber)
{ {
auto chains = nodes[pos.x][pos.y][pos.z][layer]; auto chains = nodes[layer][pos.z][pos.x][pos.y];
for(AIPathNode & node : chains) for(AIPathNode & node : chains)
{ {
@ -126,7 +124,7 @@ void AINodeStorage::resetTile(const int3 & coord, EPathfindingLayer layer, CGPat
{ {
for(int i = 0; i < NUM_CHAINS; i++) for(int i = 0; i < NUM_CHAINS; i++)
{ {
AIPathNode & heroNode = nodes[coord.x][coord.y][coord.z][layer][i]; AIPathNode & heroNode = nodes[layer][coord.z][coord.x][coord.y][i];
heroNode.chainMask = 0; heroNode.chainMask = 0;
heroNode.danger = 0; heroNode.danger = 0;
@ -290,7 +288,7 @@ void AINodeStorage::calculateTownPortalTeleportations(
bool AINodeStorage::hasBetterChain(const PathNodeInfo & source, CDestinationNodeInfo & destination) const bool AINodeStorage::hasBetterChain(const PathNodeInfo & source, CDestinationNodeInfo & destination) const
{ {
auto pos = destination.coord; auto pos = destination.coord;
auto chains = nodes[pos.x][pos.y][pos.z][EPathfindingLayer::LAND]; auto chains = nodes[EPathfindingLayer::LAND][pos.z][pos.x][pos.y];
auto destinationNode = getAINode(destination.node); auto destinationNode = getAINode(destination.node);
for(const AIPathNode & node : chains) for(const AIPathNode & node : chains)
@ -323,7 +321,7 @@ bool AINodeStorage::hasBetterChain(const PathNodeInfo & source, CDestinationNode
bool AINodeStorage::isTileAccessible(const int3 & pos, const EPathfindingLayer layer) const bool AINodeStorage::isTileAccessible(const int3 & pos, const EPathfindingLayer layer) const
{ {
const AIPathNode & node = nodes[pos.x][pos.y][pos.z][layer][0]; const AIPathNode & node = nodes[layer][pos.z][pos.x][pos.y][0];
return node.action != CGPathNode::ENodeAction::UNKNOWN; return node.action != CGPathNode::ENodeAction::UNKNOWN;
} }
@ -331,7 +329,7 @@ bool AINodeStorage::isTileAccessible(const int3 & pos, const EPathfindingLayer l
std::vector<AIPath> AINodeStorage::getChainInfo(const int3 & pos, bool isOnLand) const std::vector<AIPath> AINodeStorage::getChainInfo(const int3 & pos, bool isOnLand) const
{ {
std::vector<AIPath> paths; std::vector<AIPath> paths;
auto chains = nodes[pos.x][pos.y][pos.z][isOnLand ? EPathfindingLayer::LAND : EPathfindingLayer::SAIL]; auto chains = nodes[isOnLand ? EPathfindingLayer::LAND : EPathfindingLayer::SAIL][pos.z][pos.x][pos.y];
auto initialPos = hero->visitablePos(); auto initialPos = hero->visitablePos();
for(const AIPathNode & node : chains) for(const AIPathNode & node : chains)

View File

@ -17,6 +17,10 @@
#include "../Goals/AbstractGoal.h" #include "../Goals/AbstractGoal.h"
#include "Actions/ISpecialAction.h" #include "Actions/ISpecialAction.h"
class CCallback;
extern boost::thread_specific_ptr<CCallback> cb; //for templates
struct AIPathNode : public CGPathNode struct AIPathNode : public CGPathNode
{ {
uint32_t chainMask; uint32_t chainMask;
@ -57,7 +61,9 @@ class AINodeStorage : public INodeStorage
private: private:
int3 sizes; int3 sizes;
/// 1-3 - position on map, 4 - layer (air, water, land), 5 - chain (normal, battle, spellcast and combinations) // 1 - layer (air, water, land)
// 2-4 - position on map[z][x][y]
// 5 - chain (normal, battle, spellcast and combinations)
boost::multi_array<AIPathNode, 5> nodes; boost::multi_array<AIPathNode, 5> nodes;
const CPlayerSpecificInfoCallback * cb; const CPlayerSpecificInfoCallback * cb;
const VCAI * ai; const VCAI * ai;

View File

@ -1,431 +0,0 @@
/*
* SectorMap.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "SectorMap.h"
#include "VCAI.h"
#include "../../CCallback.h"
#include "../../lib/mapping/CMap.h"
#include "../../lib/mapObjects/MapObjects.h"
#include "../../lib/CPathfinder.h"
#include "../../lib/CGameState.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
SectorMap::SectorMap()
{
update();
}
SectorMap::SectorMap(HeroPtr h)
{
update();
makeParentBFS(h->visitablePos());
}
bool SectorMap::markIfBlocked(TSectorID & sec, crint3 pos, const TerrainTile * t)
{
if (t->blocked && !t->visitable)
{
sec = NOT_AVAILABLE;
return true;
}
return false;
}
bool SectorMap::markIfBlocked(TSectorID & sec, crint3 pos)
{
return markIfBlocked(sec, pos, getTile(pos));
}
void SectorMap::update()
{
visibleTiles = cb->getAllVisibleTiles();
auto shape = visibleTiles->shape();
sector.resize(boost::extents[shape[0]][shape[1]][shape[2]]);
clear();
int curSector = 3; //0 is invisible, 1 is not explored
CCallback * cbp = cb.get(); //optimization
foreach_tile_pos([&](crint3 pos)
{
if (retrieveTile(pos) == NOT_CHECKED)
{
if (!markIfBlocked(retrieveTile(pos), pos))
exploreNewSector(pos, curSector++, cbp);
}
});
valid = true;
}
SectorMap::TSectorID & SectorMap::retrieveTileN(SectorMap::TSectorArray & a, const int3 & pos)
{
return a[pos.x][pos.y][pos.z];
}
const SectorMap::TSectorID & SectorMap::retrieveTileN(const SectorMap::TSectorArray & a, const int3 & pos)
{
return a[pos.x][pos.y][pos.z];
}
void SectorMap::clear()
{
//TODO: rotate to [z][x][y]
auto fow = cb->getVisibilityMap();
//TODO: any magic to automate this? will need array->array conversion
//std::transform(fow.begin(), fow.end(), sector.begin(), [](const ui8 &f) -> unsigned short
//{
// return f; //type conversion
//});
auto width = fow.size();
auto height = fow.front().size();
auto depth = fow.front().front().size();
for (size_t x = 0; x < width; x++)
{
for (size_t y = 0; y < height; y++)
{
for (size_t z = 0; z < depth; z++)
sector[x][y][z] = fow[x][y][z];
}
}
valid = false;
}
void SectorMap::exploreNewSector(crint3 pos, int num, CCallback * cbp)
{
Sector & s = infoOnSectors[num];
s.id = num;
s.water = getTile(pos)->isWater();
std::queue<int3> toVisit;
toVisit.push(pos);
while (!toVisit.empty())
{
int3 curPos = toVisit.front();
toVisit.pop();
TSectorID & sec = retrieveTile(curPos);
if (sec == NOT_CHECKED)
{
const TerrainTile * t = getTile(curPos);
if (!markIfBlocked(sec, curPos, t))
{
if (t->isWater() == s.water) //sector is only-water or only-land
{
sec = num;
s.tiles.push_back(curPos);
foreach_neighbour(cbp, curPos, [&](CCallback * cbp, crint3 neighPos)
{
if (retrieveTile(neighPos) == NOT_CHECKED)
{
toVisit.push(neighPos);
//parent[neighPos] = curPos;
}
const TerrainTile * nt = getTile(neighPos);
if (nt && nt->isWater() != s.water && canBeEmbarkmentPoint(nt, s.water))
{
s.embarkmentPoints.push_back(neighPos);
}
});
if (t->visitable)
{
auto obj = t->visitableObjects.front();
if (cb->getObj(obj->id, false)) // FIXME: we have to filter invisible objcts like events, but probably TerrainTile shouldn't be used in SectorMap at all
s.visitableObjs.push_back(obj);
}
}
}
}
}
vstd::removeDuplicates(s.embarkmentPoints);
}
void SectorMap::write(crstring fname)
{
std::ofstream out(fname);
for (int k = 0; k < cb->getMapSize().z; k++)
{
for (int j = 0; j < cb->getMapSize().y; j++)
{
for (int i = 0; i < cb->getMapSize().x; i++)
{
out << (int)sector[i][j][k] << '\t';
}
out << std::endl;
}
out << std::endl;
}
}
/*
this functions returns one target tile or invalid tile. We will use it to poll possible destinations
For ship construction etc, another function (goal?) is needed
*/
int3 SectorMap::firstTileToGet(HeroPtr h, crint3 dst)
{
int3 ret(-1, -1, -1);
int sourceSector = retrieveTile(h->visitablePos());
int destinationSector = retrieveTile(dst);
const Sector * src = &infoOnSectors[sourceSector];
const Sector * dest = &infoOnSectors[destinationSector];
if (sourceSector != destinationSector) //use ships, shipyards etc..
{
if (ai->isAccessibleForHero(dst, h)) //pathfinder can find a way using ships and gates if tile is not blocked by objects
return dst;
std::map<const Sector *, const Sector *> preds;
std::queue<const Sector *> sectorQueue;
sectorQueue.push(src);
while (!sectorQueue.empty())
{
const Sector * s = sectorQueue.front();
sectorQueue.pop();
for (int3 ep : s->embarkmentPoints)
{
Sector * neigh = &infoOnSectors[retrieveTile(ep)];
//preds[s].push_back(neigh);
if (!preds[neigh])
{
preds[neigh] = s;
sectorQueue.push(neigh);
}
}
}
if (!preds[dest])
{
//write("test.txt");
return ret;
//throw cannotFulfillGoalException(boost::str(boost::format("Cannot find connection between sectors %d and %d") % src->id % dst->id));
}
std::vector<const Sector *> toTraverse;
toTraverse.push_back(dest);
while (toTraverse.back() != src)
{
toTraverse.push_back(preds[toTraverse.back()]);
}
if (preds[dest])
{
//TODO: would be nice to find sectors in loop
const Sector * sectorToReach = toTraverse.at(toTraverse.size() - 2);
if (!src->water && sectorToReach->water) //embark
{
//embark on ship -> look for an EP with a boat
auto firstEP = boost::find_if(src->embarkmentPoints, [=](crint3 pos) -> bool
{
const TerrainTile * t = getTile(pos);
if (t && t->visitableObjects.size() == 1 && t->topVisitableId() == Obj::BOAT)
{
if (retrieveTile(pos) == sectorToReach->id)
return true;
}
return false;
});
if (firstEP != src->embarkmentPoints.end())
{
return *firstEP;
}
else
{
//we need to find a shipyard with an access to the desired sector's EP
//TODO what about Summon Boat spell?
std::vector<const IShipyard *> shipyards;
for (const CGTownInstance * t : cb->getTownsInfo())
{
if (t->hasBuilt(BuildingID::SHIPYARD))
shipyards.push_back(t);
}
for (const CGObjectInstance * obj : ai->getFlaggedObjects())
{
if (obj->ID != Obj::TOWN) //towns were handled in the previous loop
{
if (const IShipyard * shipyard = IShipyard::castFrom(obj))
shipyards.push_back(shipyard);
}
}
shipyards.erase(boost::remove_if(shipyards, [=](const IShipyard * shipyard) -> bool
{
return shipyard->shipyardStatus() != 0 || retrieveTile(shipyard->bestLocation()) != sectorToReach->id;
}), shipyards.end());
if (!shipyards.size())
{
//TODO consider possibility of building shipyard in a town
return ret;
//throw cannotFulfillGoalException("There is no known shipyard!");
}
//we have only shipyards that possibly can build ships onto the appropriate EP
auto ownedGoodShipyard = boost::find_if(shipyards, [](const IShipyard * s) -> bool
{
return s->o->tempOwner == ai->playerID;
});
if (ownedGoodShipyard != shipyards.end())
{
const IShipyard * s = *ownedGoodShipyard;
TResources shipCost;
s->getBoatCost(shipCost);
if (cb->getResourceAmount().canAfford(shipCost))
{
int3 ret = s->bestLocation();
cb->buildBoat(s); //TODO: move actions elsewhere
return ret;
}
else
{
//TODO gather res
return ret;
//throw cannotFulfillGoalException("Not enough resources to build a boat");
}
}
else
{
//TODO pick best shipyard to take over
return shipyards.front()->o->visitablePos();
}
}
}
else if (src->water && !sectorToReach->water)
{
//TODO
//disembark
return ret;
}
else //use subterranean gates - not needed since gates are now handled via Pathfinder
{
return ret;
//throw cannotFulfillGoalException("Land-land and water-water inter-sector transitions are not implemented!");
}
}
else
{
return ret;
//throw cannotFulfillGoalException("Inter-sector route detection failed: not connected sectors?");
}
}
else //tiles are in same sector
{
return findFirstVisitableTile(h, dst);
}
}
int3 SectorMap::findFirstVisitableTile(HeroPtr h, crint3 dst)
{
int3 ret(-1, -1, -1);
int3 curtile = dst;
while (curtile != h->visitablePos())
{
auto topObj = cb->getTopObj(curtile);
if (topObj && topObj->ID == Obj::HERO && topObj != h.h)
{
if (cb->getPlayerRelations(h->tempOwner, topObj->tempOwner) != PlayerRelations::ENEMIES)
{
logAi->warn("Another allied hero stands in our way");
return ret;
}
}
if (ai->myCb->getPathsInfo(h.get())->getPathInfo(curtile)->reachable())
{
return curtile;
}
else
{
auto i = parent.find(curtile);
if (i != parent.end())
{
assert(curtile != i->second);
curtile = i->second;
}
else
{
return ret;
//throw cannotFulfillGoalException("Unreachable tile in sector? Should not happen!");
}
}
}
return ret;
}
void SectorMap::makeParentBFS(crint3 source)
{
parent.clear();
int mySector = retrieveTile(source);
std::queue<int3> toVisit;
toVisit.push(source);
while (!toVisit.empty())
{
int3 curPos = toVisit.front();
toVisit.pop();
TSectorID & sec = retrieveTile(curPos);
assert(sec == mySector); //consider only tiles from the same sector
UNUSED(sec);
foreach_neighbour(curPos, [&](crint3 neighPos)
{
if (retrieveTile(neighPos) == mySector && !vstd::contains(parent, neighPos))
{
if (cb->canMoveBetween(curPos, neighPos))
{
toVisit.push(neighPos);
parent[neighPos] = curPos;
}
}
});
}
}
SectorMap::TSectorID & SectorMap::retrieveTile(crint3 pos)
{
return retrieveTileN(sector, pos);
}
TerrainTile * SectorMap::getTile(crint3 pos) const
{
//out of bounds access should be handled by boost::multi_array
//still we cached this array to avoid any checks
return visibleTiles->operator[](pos.x)[pos.y][pos.z];
}
std::vector<const CGObjectInstance *> SectorMap::getNearbyObjs(HeroPtr h, bool sectorsAround)
{
const Sector * heroSector = &infoOnSectors[retrieveTile(h->visitablePos())];
if (sectorsAround)
{
std::vector<const CGObjectInstance *> ret;
for (auto embarkPoint : heroSector->embarkmentPoints)
{
const Sector * embarkSector = &infoOnSectors[retrieveTile(embarkPoint)];
range::copy(embarkSector->visitableObjs, std::back_inserter(ret));
}
return ret;
}
return heroSector->visitableObjs;
}

View File

@ -1,70 +0,0 @@
/*
* SectorMap.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "AIUtility.h"
enum
{
NOT_VISIBLE = 0,
NOT_CHECKED = 1,
NOT_AVAILABLE
};
struct SectorMap
{
//a sector is set of tiles that would be mutually reachable if all visitable objs would be passable (incl monsters)
struct Sector
{
int id;
std::vector<int3> tiles;
std::vector<int3> embarkmentPoints; //tiles of other sectors onto which we can (dis)embark
std::vector<const CGObjectInstance *> visitableObjs;
bool water; //all tiles of sector are land or water
Sector()
{
id = -1;
water = false;
}
};
typedef unsigned short TSectorID; //smaller than int to allow -1 value. Max number of sectors 65K should be enough for any proper map.
typedef boost::multi_array<TSectorID, 3> TSectorArray;
bool valid; //some kind of lazy eval
std::map<int3, int3> parent;
TSectorArray sector;
//std::vector<std::vector<std::vector<unsigned char>>> pathfinderSector;
std::map<int, Sector> infoOnSectors;
std::shared_ptr<boost::multi_array<TerrainTile *, 3>> visibleTiles;
SectorMap();
SectorMap(HeroPtr h);
void update();
void clear();
void exploreNewSector(crint3 pos, int num, CCallback * cbp);
void write(crstring fname);
bool markIfBlocked(TSectorID & sec, crint3 pos, const TerrainTile * t);
bool markIfBlocked(TSectorID & sec, crint3 pos);
TSectorID & retrieveTile(crint3 pos);
TSectorID & retrieveTileN(TSectorArray & vectors, const int3 & pos);
const TSectorID & retrieveTileN(const TSectorArray & vectors, const int3 & pos);
TerrainTile * getTile(crint3 pos) const;
std::vector<const CGObjectInstance *> getNearbyObjs(HeroPtr h, bool sectorsAround);
void makeParentBFS(crint3 source);
int3 firstTileToGet(HeroPtr h, crint3 dst); //if h wants to reach tile dst, which tile he should visit to clear the way?
int3 findFirstVisitableTile(HeroPtr h, crint3 dst);
};

View File

@ -324,7 +324,7 @@ int3 CCallback::getGuardingCreaturePosition(int3 tile)
if (!gs->map->isInTheMap(tile)) if (!gs->map->isInTheMap(tile))
return int3(-1,-1,-1); return int3(-1,-1,-1);
return gs->map->guardingCreaturePositions[tile.x][tile.y][tile.z]; return gs->map->guardingCreaturePositions[tile.z][tile.x][tile.y];
} }
void CCallback::calculatePaths( const CGHeroInstance *hero, CPathsInfo &out) void CCallback::calculatePaths( const CGHeroInstance *hero, CPathsInfo &out)

View File

@ -218,7 +218,7 @@ void CPlayerInterface::yourTurn()
STRONG_INLINE void subRect(const int & x, const int & y, const int & z, const SDL_Rect & r, const ObjectInstanceID & hid) STRONG_INLINE void subRect(const int & x, const int & y, const int & z, const SDL_Rect & r, const ObjectInstanceID & hid)
{ {
TerrainTile2 & hlp = CGI->mh->ttiles[x][y][z]; TerrainTile2 & hlp = CGI->mh->ttiles[z][x][y];
for (auto & elem : hlp.objects) for (auto & elem : hlp.objects)
if (elem.obj && elem.obj->id == hid) if (elem.obj && elem.obj->id == hid)
{ {
@ -229,7 +229,7 @@ STRONG_INLINE void subRect(const int & x, const int & y, const int & z, const SD
STRONG_INLINE void delObjRect(const int & x, const int & y, const int & z, const ObjectInstanceID & hid) STRONG_INLINE void delObjRect(const int & x, const int & y, const int & z, const ObjectInstanceID & hid)
{ {
TerrainTile2 & hlp = CGI->mh->ttiles[x][y][z]; TerrainTile2 & hlp = CGI->mh->ttiles[z][x][y];
for (int h=0; h<hlp.objects.size(); ++h) for (int h=0; h<hlp.objects.size(); ++h)
if (hlp.objects[h].obj && hlp.objects[h].obj->id == hid) if (hlp.objects[h].obj && hlp.objects[h].obj->id == hid)
{ {
@ -244,6 +244,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
if(LOCPLINT != this) if(LOCPLINT != this)
return; return;
//FIXME: read once and store
if(settings["session"]["spectate"].Bool() && settings["session"]["spectate-ignore-hero"].Bool()) if(settings["session"]["spectate"].Bool() && settings["session"]["spectate-ignore-hero"].Bool())
return; return;
@ -255,7 +256,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
//AI hero left the visible area (we can't obtain info) //AI hero left the visible area (we can't obtain info)
//TODO very evil workaround -> retrieve pointer to hero so we could animate it //TODO very evil workaround -> retrieve pointer to hero so we could animate it
// TODO -> we should not need full CGHeroInstance structure to display animation or it should not be handled by playerint (but by the client itself) // TODO -> we should not need full CGHeroInstance structure to display animation or it should not be handled by playerint (but by the client itself)
const TerrainTile2 & tile = CGI->mh->ttiles[hp.x - 1][hp.y][hp.z]; const TerrainTile2 & tile = CGI->mh->ttiles[hp.z][hp.x - 1][hp.y];
for(auto & elem : tile.objects) for(auto & elem : tile.objects)
if(elem.obj && elem.obj->id == details.id) if(elem.obj && elem.obj->id == details.id)
hero = dynamic_cast<const CGHeroInstance *>(elem.obj); hero = dynamic_cast<const CGHeroInstance *>(elem.obj);
@ -1738,41 +1739,43 @@ int CPlayerInterface::getLastIndex( std::string namePrefix)
void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroInstance * ho, const int3 &hp ) void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroInstance * ho, const int3 &hp )
{ {
auto subArr = (CGI->mh->ttiles)[hp.z];
if (details.end.x+1 == details.start.x && details.end.y+1 == details.start.y) //tl if (details.end.x+1 == details.start.x && details.end.y+1 == details.start.y) //tl
{ {
//ho->moveDir = 1; //ho->moveDir = 1;
ho->isStanding = false; ho->isStanding = false;
CGI->mh->ttiles[hp.x-3][hp.y-2][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, -31))); subArr[hp.x-3][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, -31)));
CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 1, -31))); subArr[hp.x-2][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 1, -31)));
CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 33, -31))); subArr[hp.x-1][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 33, -31)));
CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 65, -31))); subArr[hp.x][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 65, -31)));
CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 1))); subArr[hp.x-3][hp.y-1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 1)));
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1, 1), ho->id); subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1, 1), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33, 1), ho->id); subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33, 1), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65, 1), ho->id); subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65, 1), ho->id);
CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 33))); subArr[hp.x-3][hp.y].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 33)));
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1, 33), ho->id); subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1, 33), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33, 33), ho->id); subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33, 33), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65, 33), ho->id); subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65, 33), ho->id);
std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-3][hp.y-2].objects.begin(), subArr[hp.x-3][hp.y-2].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-2][hp.y-2].objects.begin(), subArr[hp.x-2][hp.y-2].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-1][hp.y-2].objects.begin(), subArr[hp.x-1][hp.y-2].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x][hp.y-2].objects.begin(), subArr[hp.x][hp.y-2].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-3][hp.y-1].objects.begin(), subArr[hp.x-3][hp.y-1].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-3][hp.y].objects.begin(), subArr[hp.x-3][hp.y].objects.end(), objectBlitOrderSorter);
} }
else if (details.end.x == details.start.x && details.end.y+1 == details.start.y) //t else if (details.end.x == details.start.x && details.end.y+1 == details.start.y) //t
{ {
//ho->moveDir = 2; //ho->moveDir = 2;
ho->isStanding = false; ho->isStanding = false;
CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 0, -31))); subArr[hp.x-2][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 0, -31)));
CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 32, -31))); subArr[hp.x-1][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 32, -31)));
CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 64, -31))); subArr[hp.x][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 64, -31)));
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 0, 1), ho->id); subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 0, 1), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 32, 1), ho->id); subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 32, 1), ho->id);
@ -1782,37 +1785,37 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 32, 33), ho->id); subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 32, 33), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 64, 33), ho->id); subRect(hp.x, hp.y, hp.z, genRect(32, 32, 64, 33), ho->id);
std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-2][hp.y-2].objects.begin(), subArr[hp.x-2][hp.y-2].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-1][hp.y-2].objects.begin(), subArr[hp.x-1][hp.y-2].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x][hp.y-2].objects.begin(), subArr[hp.x][hp.y-2].objects.end(), objectBlitOrderSorter);
} }
else if (details.end.x-1 == details.start.x && details.end.y+1 == details.start.y) //tr else if (details.end.x-1 == details.start.x && details.end.y+1 == details.start.y) //tr
{ {
//ho->moveDir = 3; //ho->moveDir = 3;
ho->isStanding = false; ho->isStanding = false;
CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -1, -31))); subArr[hp.x-2][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -1, -31)));
CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 31, -31))); subArr[hp.x-1][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 31, -31)));
CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 63, -31))); subArr[hp.x][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 63, -31)));
CGI->mh->ttiles[hp.x+1][hp.y-2][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, -31))); subArr[hp.x+1][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, -31)));
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1, 1), ho->id); subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1, 1), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31, 1), ho->id); subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31, 1), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63, 1), ho->id); subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63, 1), ho->id);
CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 1))); subArr[hp.x+1][hp.y-1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 1)));
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1, 33), ho->id); subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1, 33), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31, 33), ho->id); subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31, 33), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63, 33), ho->id); subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63, 33), ho->id);
CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 33))); subArr[hp.x+1][hp.y].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 33)));
std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-2][hp.y-2].objects.begin(), subArr[hp.x-2][hp.y-2].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-1][hp.y-2].objects.begin(), subArr[hp.x-1][hp.y-2].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x][hp.y-2].objects.begin(), subArr[hp.x][hp.y-2].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x+1][hp.y-2].objects.begin(), subArr[hp.x+1][hp.y-2].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x+1][hp.y-1].objects.begin(), subArr[hp.x+1][hp.y-1].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x+1][hp.y].objects.begin(), subArr[hp.x+1][hp.y].objects.end(), objectBlitOrderSorter);
} }
else if (details.end.x-1 == details.start.x && details.end.y == details.start.y) //r else if (details.end.x-1 == details.start.x && details.end.y == details.start.y) //r
{ {
@ -1821,16 +1824,16 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1, 0), ho->id); subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1, 0), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31, 0), ho->id); subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31, 0), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63, 0), ho->id); subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63, 0), ho->id);
CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 0))); subArr[hp.x+1][hp.y-1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 0)));
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1, 32), ho->id); subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1, 32), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31, 32), ho->id); subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31, 32), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63, 32), ho->id); subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63, 32), ho->id);
CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 32))); subArr[hp.x+1][hp.y].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 32)));
std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x+1][hp.y-1].objects.begin(), subArr[hp.x+1][hp.y-1].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x+1][hp.y].objects.begin(), subArr[hp.x+1][hp.y].objects.end(), objectBlitOrderSorter);
} }
else if (details.end.x-1 == details.start.x && details.end.y-1 == details.start.y) //br else if (details.end.x-1 == details.start.x && details.end.y-1 == details.start.y) //br
{ {
@ -1839,26 +1842,26 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1, -1), ho->id); subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1, -1), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31, -1), ho->id); subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31, -1), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63, -1), ho->id); subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63, -1), ho->id);
CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, -1))); subArr[hp.x+1][hp.y-1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, -1)));
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1, 31), ho->id); subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1, 31), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31, 31), ho->id); subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31, 31), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63, 31), ho->id); subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63, 31), ho->id);
CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 31))); subArr[hp.x+1][hp.y].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 31)));
CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -1, 63))); subArr[hp.x-2][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -1, 63)));
CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 31, 63))); subArr[hp.x-1][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 31, 63)));
CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 63, 63))); subArr[hp.x][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 63, 63)));
CGI->mh->ttiles[hp.x+1][hp.y+1][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 63))); subArr[hp.x+1][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 63)));
std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x+1][hp.y-1].objects.begin(), subArr[hp.x+1][hp.y-1].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x+1][hp.y].objects.begin(), subArr[hp.x+1][hp.y].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-2][hp.y+1].objects.begin(), subArr[hp.x-2][hp.y+1].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-1][hp.y+1].objects.begin(), subArr[hp.x-1][hp.y+1].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x][hp.y+1].objects.begin(), subArr[hp.x][hp.y+1].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x+1][hp.y+1].objects.begin(), subArr[hp.x+1][hp.y+1].objects.end(), objectBlitOrderSorter);
} }
else if (details.end.x == details.start.x && details.end.y-1 == details.start.y) //b else if (details.end.x == details.start.x && details.end.y-1 == details.start.y) //b
{ {
@ -1872,59 +1875,59 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 32, 31), ho->id); subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 32, 31), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 64, 31), ho->id); subRect(hp.x, hp.y, hp.z, genRect(32, 32, 64, 31), ho->id);
CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 0, 63))); subArr[hp.x-2][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 0, 63)));
CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 32, 63))); subArr[hp.x-1][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 32, 63)));
CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 64, 63))); subArr[hp.x][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 64, 63)));
std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-2][hp.y+1].objects.begin(), subArr[hp.x-2][hp.y+1].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-1][hp.y+1].objects.begin(), subArr[hp.x-1][hp.y+1].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x][hp.y+1].objects.begin(), subArr[hp.x][hp.y+1].objects.end(), objectBlitOrderSorter);
} }
else if (details.end.x+1 == details.start.x && details.end.y-1 == details.start.y) //bl else if (details.end.x+1 == details.start.x && details.end.y-1 == details.start.y) //bl
{ {
//ho->moveDir = 7; //ho->moveDir = 7;
ho->isStanding = false; ho->isStanding = false;
CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, -1))); subArr[hp.x-3][hp.y-1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, -1)));
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1, -1), ho->id); subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1, -1), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33, -1), ho->id); subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33, -1), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65, -1), ho->id); subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65, -1), ho->id);
CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 31))); subArr[hp.x-3][hp.y].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 31)));
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1, 31), ho->id); subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1, 31), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33, 31), ho->id); subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33, 31), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65, 31), ho->id); subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65, 31), ho->id);
CGI->mh->ttiles[hp.x-3][hp.y+1][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 63))); subArr[hp.x-3][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 63)));
CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 1, 63))); subArr[hp.x-2][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 1, 63)));
CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 33, 63))); subArr[hp.x-1][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 33, 63)));
CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 65, 63))); subArr[hp.x][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 65, 63)));
std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-3][hp.y-1].objects.begin(), subArr[hp.x-3][hp.y-1].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-3][hp.y].objects.begin(), subArr[hp.x-3][hp.y].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-3][hp.y+1].objects.begin(), subArr[hp.x-3][hp.y+1].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-2][hp.y+1].objects.begin(), subArr[hp.x-2][hp.y+1].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-1][hp.y+1].objects.begin(), subArr[hp.x-1][hp.y+1].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x][hp.y+1].objects.begin(), subArr[hp.x][hp.y+1].objects.end(), objectBlitOrderSorter);
} }
else if (details.end.x+1 == details.start.x && details.end.y == details.start.y) //l else if (details.end.x+1 == details.start.x && details.end.y == details.start.y) //l
{ {
//ho->moveDir = 8; //ho->moveDir = 8;
ho->isStanding = false; ho->isStanding = false;
CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 0))); subArr[hp.x-3][hp.y-1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 0)));
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1, 0), ho->id); subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1, 0), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33, 0), ho->id); subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33, 0), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65, 0), ho->id); subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65, 0), ho->id);
CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 32))); subArr[hp.x-3][hp.y].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 32)));
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1, 32), ho->id); subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1, 32), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33, 32), ho->id); subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33, 32), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65, 32), ho->id); subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65, 32), ho->id);
std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-3][hp.y-1].objects.begin(), subArr[hp.x-3][hp.y-1].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[hp.x-3][hp.y].objects.begin(), subArr[hp.x-3][hp.y].objects.end(), objectBlitOrderSorter);
} }
} }
@ -2154,13 +2157,16 @@ void CPlayerInterface::finishMovement( const TryMoveHero &details, const int3 &h
subRect(details.end.x, details.end.y, details.end.z, genRect(32, 32, 64, 32), ho->id); subRect(details.end.x, details.end.y, details.end.z, genRect(32, 32, 64, 32), ho->id);
//restoring good order of objects //restoring good order of objects
std::stable_sort(CGI->mh->ttiles[details.end.x-2][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-2][details.end.y-1][details.end.z].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[details.end.x-1][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-1][details.end.y-1][details.end.z].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[details.end.x][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x][details.end.y-1][details.end.z].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[details.end.x-2][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-2][details.end.y][details.end.z].objects.end(), objectBlitOrderSorter); boost::detail::multi_array::sub_array<TerrainTile2, 2> subArr = (CGI->mh->ttiles)[details.end.z];
std::stable_sort(CGI->mh->ttiles[details.end.x-1][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-1][details.end.y][details.end.z].objects.end(), objectBlitOrderSorter);
std::stable_sort(CGI->mh->ttiles[details.end.x][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x][details.end.y][details.end.z].objects.end(), objectBlitOrderSorter); std::stable_sort(subArr[details.end.x-2][details.end.y-1].objects.begin(), subArr[details.end.x-2][details.end.y-1].objects.end(), objectBlitOrderSorter);
std::stable_sort(subArr[details.end.x-1][details.end.y-1].objects.begin(), subArr[details.end.x-1][details.end.y-1].objects.end(), objectBlitOrderSorter);
std::stable_sort(subArr[details.end.x][details.end.y-1].objects.begin(), subArr[details.end.x][details.end.y-1].objects.end(), objectBlitOrderSorter);
std::stable_sort(subArr[details.end.x-2][details.end.y].objects.begin(), subArr[details.end.x-2][details.end.y].objects.end(), objectBlitOrderSorter);
std::stable_sort(subArr[details.end.x-1][details.end.y].objects.begin(), subArr[details.end.x-1][details.end.y].objects.end(), objectBlitOrderSorter);
std::stable_sort(subArr[details.end.x][details.end.y].objects.begin(), subArr[details.end.x][details.end.y].objects.end(), objectBlitOrderSorter);
} }
void CPlayerInterface::gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult ) void CPlayerInterface::gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult )
@ -2882,7 +2888,7 @@ void CPlayerInterface::updateAmbientSounds(bool resetAll)
{ {
int dist = pos.dist(tile, int3::DIST_CHEBYSHEV); int dist = pos.dist(tile, int3::DIST_CHEBYSHEV);
// We want sound for every special terrain on tile and not just one on top // We want sound for every special terrain on tile and not just one on top
for(auto & ttObj : CGI->mh->ttiles[tile.x][tile.y][tile.z].objects) for(auto & ttObj : CGI->mh->ttiles[tile.z][tile.x][tile.y].objects)
{ {
if(ttObj.ambientSound) if(ttObj.ambientSound)
updateSounds(ttObj.ambientSound.get(), dist); updateSounds(ttObj.ambientSound.get(), dist);

View File

@ -52,20 +52,22 @@ struct NeighborTilesInfo
d1, d1,
d2, d2,
d3; d3;
NeighborTilesInfo(const int3 & pos, const int3 & sizes, const std::vector< std::vector< std::vector<ui8> > > & visibilityMap) NeighborTilesInfo(const int3 & pos, const int3 & sizes, std::shared_ptr<const boost::multi_array<ui8, 3>> visibilityMap)
{ {
auto getTile = [&](int dx, int dy)->bool auto getTile = [&](int dx, int dy)->bool
{ {
if ( dx + pos.x < 0 || dx + pos.x >= sizes.x if ( dx + pos.x < 0 || dx + pos.x >= sizes.x
|| dy + pos.y < 0 || dy + pos.y >= sizes.y) || dy + pos.y < 0 || dy + pos.y >= sizes.y)
return false; return false;
return settings["session"]["spectate"].Bool() ? true : visibilityMap[dx+pos.x][dy+pos.y][pos.z];
//FIXME: please do not read settings for every tile...
return settings["session"]["spectate"].Bool() ? true : (*visibilityMap)[pos.z][dx+pos.x][dy+pos.y];
}; };
d7 = getTile(-1, -1); //789 d7 = getTile(-1, -1); //789
d8 = getTile( 0, -1); //456 d8 = getTile( 0, -1); //456
d9 = getTile(+1, -1); //123 d9 = getTile(+1, -1); //123
d4 = getTile(-1, 0); d4 = getTile(-1, 0);
d5 = visibilityMap[pos.x][pos.y][pos.z]; d5 = (*visibilityMap)[pos.z][pos.x][pos.y];
d6 = getTile(+1, 0); d6 = getTile(+1, 0);
d1 = getTile(-1, +1); d1 = getTile(-1, +1);
d2 = getTile( 0, +1); d2 = getTile( 0, +1);
@ -113,22 +115,9 @@ void CMapHandler::prepareFOWDefs()
FoWfullHide[frame] = graphics->fogOfWarFullHide->getImage(frame); FoWfullHide[frame] = graphics->fogOfWarFullHide->getImage(frame);
//initialization of type of full-hide image //initialization of type of full-hide image
hideBitmap.resize(sizes.x); hideBitmap.resize(boost::extents[sizes.z][sizes.x][sizes.y]);
for (auto & elem : hideBitmap) for (int i = 0; i < hideBitmap.num_elements(); i++)
{ hideBitmap.data()[i] = CRandomGenerator::getDefault().nextInt(size - 1);
elem.resize(sizes.y);
}
for (auto & elem : hideBitmap)
{
for (int j = 0; j < sizes.y; ++j)
{
elem[j].resize(sizes.z);
for(int k = 0; k < sizes.z; ++k)
{
elem[j][k] = CRandomGenerator::getDefault().nextInt((int)size - 1);
}
}
}
size = graphics->fogOfWarPartialHide->size(0); size = graphics->fogOfWarPartialHide->size(0);
FoWpartialHide.resize(size); FoWpartialHide.resize(size);
@ -211,16 +200,12 @@ void CMapHandler::initTerrainGraphics()
// Create enough room for the whole map and its frame // Create enough room for the whole map and its frame
ttiles.resize(sizes.x, frameW, frameW); //ttiles.resize(sizes.x, frameW, frameW);
for (int i=0-frameW;i<ttiles.size()-frameW;i++)
{ //FIXME: why do we even handle array with z (surface and undeground) at the same time?
ttiles[i].resize(sizes.y, frameH, frameH);
} ttiles.resize(boost::extents[sizes.z][sizes.x + 2 * frameW][sizes.y + 2 * frameH]);
for (int i=0-frameW;i<ttiles.size()-frameW;i++) ttiles.reindex(std::list<int>{ 0, -frameW, -frameH }); //need to move starting coordinates so that used index is always positive
{
for (int j=0-frameH;j<(int)sizes.y+frameH;j++)
ttiles[i][j].resize(sizes.z, 0, 0);
}
} }
void CMapHandler::initBorderGraphics() void CMapHandler::initBorderGraphics()
@ -321,19 +306,21 @@ void CMapHandler::initObjectRects()
obj->coveringAt(currTile.x, currTile.y) // object is visible here obj->coveringAt(currTile.x, currTile.y) // object is visible here
) )
{ {
ttiles[currTile.x][currTile.y][currTile.z].objects.push_back(toAdd); ttiles[currTile.z][currTile.x][currTile.y].objects.push_back(toAdd);
} }
} }
} }
} }
for(int ix=0; ix<ttiles.size()-frameW; ++ix) auto shape = ttiles.shape();
for(size_t z = 0; z < shape[0]; z++)
{ {
for(int iy=0; iy<ttiles[0].size()-frameH; ++iy) for(size_t x = 0; x < shape[1] - frameW; x++)
{ {
for(int iz=0; iz<ttiles[0][0].size(); ++iz) for(size_t y = 0; y < shape[2] - frameH; y++)
{ {
stable_sort(ttiles[ix][iy][iz].objects.begin(), ttiles[ix][iy][iz].objects.end(), objectBlitOrderSorter); auto & objects = ttiles[z][x][y].objects;
stable_sort(objects.begin(), objects.end(), objectBlitOrderSorter);
} }
} }
} }
@ -351,7 +338,7 @@ void CMapHandler::init()
//sizes of terrain //sizes of terrain
sizes.x = map->width; sizes.x = map->width;
sizes.y = map->height; sizes.y = map->height;
sizes.z = map->twoLevel ? 2 : 1; sizes.z = map->levels();
// Total number of visible tiles. Subtract the center tile, then // Total number of visible tiles. Subtract the center tile, then
// compute the number of tiles on each side, and reassemble. // compute the number of tiles on each side, and reassemble.
@ -557,7 +544,9 @@ void CMapHandler::CMapWorldViewBlitter::drawTileOverlay(SDL_Surface * targetSurf
const CGObjectInstance * obj = object.obj; const CGObjectInstance * obj = object.obj;
const bool sameLevel = obj->pos.z == pos.z; const bool sameLevel = obj->pos.z == pos.z;
const bool isVisible = settings["session"]["spectate"].Bool() ? true : (*info->visibilityMap)[pos.x][pos.y][pos.z];
//FIXME: Don't read options in a loop :v
const bool isVisible = settings["session"]["spectate"].Bool() ? true : (*info->visibilityMap)[pos.z][pos.x][pos.y];
const bool isVisitable = obj->visitableAt(pos.x, pos.y); const bool isVisitable = obj->visitableAt(pos.x, pos.y);
if(sameLevel && isVisible && isVisitable) if(sameLevel && isVisible && isVisitable)
@ -826,11 +815,11 @@ void CMapHandler::CMapBlitter::drawRiver(SDL_Surface * targetSurf, const Terrain
void CMapHandler::CMapBlitter::drawFow(SDL_Surface * targetSurf) const void CMapHandler::CMapBlitter::drawFow(SDL_Surface * targetSurf) const
{ {
const NeighborTilesInfo neighborInfo(pos, parent->sizes, *info->visibilityMap); const NeighborTilesInfo neighborInfo(pos, parent->sizes, info->visibilityMap);
int retBitmapID = neighborInfo.getBitmapID();// >=0 -> partial hide, <0 - full hide int retBitmapID = neighborInfo.getBitmapID();// >=0 -> partial hide, <0 - full hide
if (retBitmapID < 0) if (retBitmapID < 0)
retBitmapID = - parent->hideBitmap[pos.x][pos.y][pos.z] - 1; //fully hidden retBitmapID = - parent->hideBitmap[pos.z][pos.x][pos.y] - 1; //fully hidden
std::shared_ptr<IImage> image; std::shared_ptr<IImage> image;
@ -865,7 +854,7 @@ void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingIn
realTileRect.x = realPos.x; realTileRect.x = realPos.x;
realTileRect.y = realPos.y; realTileRect.y = realPos.y;
const TerrainTile2 & tile = parent->ttiles[pos.x][pos.y][pos.z]; const TerrainTile2 & tile = parent->ttiles[pos.z][pos.x][pos.y];
const TerrainTile & tinfo = parent->map->getTile(pos); const TerrainTile & tinfo = parent->map->getTile(pos);
const TerrainTile * tinfoUpper = pos.y > 0 ? &parent->map->getTile(int3(pos.x, pos.y - 1, pos.z)) : nullptr; const TerrainTile * tinfoUpper = pos.y > 0 ? &parent->map->getTile(int3(pos.x, pos.y - 1, pos.z)) : nullptr;
@ -896,9 +885,9 @@ void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingIn
} }
else else
{ {
const TerrainTile2 & tile = parent->ttiles[pos.x][pos.y][pos.z]; const TerrainTile2 & tile = parent->ttiles[pos.z][pos.x][pos.y];
if(!settings["session"]["spectate"].Bool() && !(*info->visibilityMap)[pos.x][pos.y][topTile.z] && !info->showAllTerrain) if(!settings["session"]["spectate"].Bool() && !(*info->visibilityMap)[topTile.z][pos.x][pos.y] && !info->showAllTerrain)
drawFow(targetSurf); drawFow(targetSurf);
// overlay needs to be drawn over fow, because of artifacts-aura-like spells // overlay needs to be drawn over fow, because of artifacts-aura-like spells
@ -1105,7 +1094,7 @@ bool CMapHandler::CMapBlitter::canDrawCurrentTile() const
if(settings["session"]["spectate"].Bool()) if(settings["session"]["spectate"].Bool())
return true; return true;
const NeighborTilesInfo neighbors(pos, parent->sizes, *info->visibilityMap); const NeighborTilesInfo neighbors(pos, parent->sizes, info->visibilityMap);
return !neighbors.areAllHidden(); return !neighbors.areAllHidden();
} }
@ -1136,7 +1125,7 @@ bool CMapHandler::updateObjectsFade()
++iter; ++iter;
else // fade finished else // fade finished
{ {
auto &objs = ttiles[pos.x][pos.y][pos.z].objects; auto &objs = ttiles[pos.z][pos.x][pos.y].objects;
for (auto objIter = objs.begin(); objIter != objs.end(); ++objIter) for (auto objIter = objs.begin(); objIter != objs.end(); ++objIter)
{ {
if ((*objIter).fadeAnimKey == (*iter).first) if ((*objIter).fadeAnimKey == (*iter).first)
@ -1210,6 +1199,9 @@ bool CMapHandler::printObject(const CGObjectInstance * obj, bool fadein)
const int tilesW = bitmap->width()/32; const int tilesW = bitmap->width()/32;
const int tilesH = bitmap->height()/32; const int tilesH = bitmap->height()/32;
auto ttilesWidth = ttiles.shape()[1];
auto ttilesHeight = ttiles.shape()[2];
for(int fx=0; fx<tilesW; ++fx) for(int fx=0; fx<tilesW; ++fx)
{ {
for(int fy=0; fy<tilesH; ++fy) for(int fy=0; fy<tilesH; ++fy)
@ -1220,10 +1212,13 @@ bool CMapHandler::printObject(const CGObjectInstance * obj, bool fadein)
cr.x = fx*32; cr.x = fx*32;
cr.y = fy*32; cr.y = fy*32;
if((obj->pos.x + fx - tilesW+1)>=0 && (obj->pos.x + fx - tilesW+1)<ttiles.size()-frameW && (obj->pos.y + fy - tilesH+1)>=0 && (obj->pos.y + fy - tilesH+1)<ttiles[0].size()-frameH) if((obj->pos.x + fx - tilesW + 1) >= 0 &&
(obj->pos.x + fx - tilesW + 1) < ttilesWidth - frameW &&
(obj->pos.y + fy - tilesH + 1) >= 0 &&
(obj->pos.y + fy - tilesH + 1) < ttilesHeight - frameH)
{ {
int3 pos(obj->pos.x + fx - tilesW + 1, obj->pos.y + fy - tilesH + 1, obj->pos.z); int3 pos(obj->pos.x + fx - tilesW + 1, obj->pos.y + fy - tilesH + 1, obj->pos.z);
TerrainTile2 & curt = ttiles[pos.x][pos.y][pos.z]; TerrainTile2 & curt = ttiles[pos.z][pos.x][pos.y];
TerrainTileObject toAdd(obj, cr, obj->visitableAt(pos.x, pos.y)); TerrainTileObject toAdd(obj, cr, obj->visitableAt(pos.x, pos.y));
if (fadein && ADVOPT.objectFading) if (fadein && ADVOPT.objectFading)
@ -1252,59 +1247,26 @@ bool CMapHandler::printObject(const CGObjectInstance * obj, bool fadein)
bool CMapHandler::hideObject(const CGObjectInstance * obj, bool fadeout) bool CMapHandler::hideObject(const CGObjectInstance * obj, bool fadeout)
{ {
//optimized version which reveals weird bugs with missing def name for(size_t z = 0; z < map->levels(); z++)
//auto pos = obj->pos;
//for (size_t i = pos.x; i > pos.x - obj->getWidth(); i--)
//{
// for (size_t j = pos.y; j > pos.y - obj->getHeight(); j--)
// {
// int3 t(i, j, pos.z);
// if (!map->isInTheMap(t))
// continue;
// auto &objs = ttiles[i][j][pos.z].objects;
// for (size_t x = 0; x < objs.size(); x++)
// {
// auto ourObj = objs[x].obj;
// if (ourObj && ourObj->id == obj->id)
// {
// if (fadeout && ADVOPT.objectFading) // object should be faded == erase is delayed until the end of fadeout
// {
// if (startObjectFade(objs[x], false, t))
// objs[x].obj = nullptr; //set original pointer to null
// else
// objs.erase(objs.begin() + x);
// }
// else
// objs.erase(objs.begin() + x);
// break;
// }
// }
// }
//}
for (size_t i = 0; i<map->width; i++)
{ {
for (size_t j = 0; j<map->height; j++) for(size_t x = 0; x < map->width; x++)
{ {
for (size_t k = 0; k<(map->twoLevel ? 2 : 1); k++) for(size_t y = 0; y < map->height; y++)
{ {
auto &objs = ttiles[(int)i][(int)j][(int)k].objects; auto &objs = ttiles[(int)z][(int)x][(int)y].objects;
for (size_t x = 0; x < objs.size(); x++) for(size_t i = 0; i < objs.size(); i++)
{ {
if (objs[x].obj && objs[x].obj->id == obj->id) if (objs[i].obj && objs[i].obj->id == obj->id)
{ {
if (fadeout && ADVOPT.objectFading) // object should be faded == erase is delayed until the end of fadeout if (fadeout && ADVOPT.objectFading) // object should be faded == erase is delayed until the end of fadeout
{ {
if (startObjectFade(objs[x], false, int3((si32)i, (si32)j, (si32)k))) if (startObjectFade(objs[i], false, int3((si32)x, (si32)y, (si32)z)))
objs[x].obj = nullptr; objs[i].obj = nullptr;
else else
objs.erase(objs.begin() + x); objs.erase(objs.begin() + i);
} }
else else
objs.erase(objs.begin() + x); objs.erase(objs.begin() + i);
break; break;
} }
} }
@ -1392,7 +1354,7 @@ CMapHandler::CMapHandler()
bool CMapHandler::hasObjectHole(const int3 & pos) const bool CMapHandler::hasObjectHole(const int3 & pos) const
{ {
const TerrainTile2 & tt = ttiles[pos.x][pos.y][pos.z]; const TerrainTile2 & tt = ttiles[pos.z][pos.x][pos.y];
for(auto & elem : tt.objects) for(auto & elem : tt.objects)
{ {
@ -1411,7 +1373,7 @@ void CMapHandler::getTerrainDescr(const int3 & pos, std::string & out, bool isRM
out = CGI->objtypeh->getObjectName(Obj::FAVORABLE_WINDS); out = CGI->objtypeh->getObjectName(Obj::FAVORABLE_WINDS);
return; return;
} }
const TerrainTile2 & tt = ttiles[pos.x][pos.y][pos.z]; const TerrainTile2 & tt = ttiles[pos.z][pos.x][pos.y];
bool isTile2Terrain = false; bool isTile2Terrain = false;
out.clear(); out.clear();

View File

@ -92,7 +92,7 @@ struct MapDrawingInfo
{ {
bool scaled; bool scaled;
int3 &topTile; // top-left tile in viewport [in tiles] int3 &topTile; // top-left tile in viewport [in tiles]
const std::vector< std::vector< std::vector<ui8> > > * visibilityMap; std::shared_ptr<const boost::multi_array<ui8, 3>> visibilityMap;
SDL_Rect * drawBounds; // map rect drawing bounds on screen SDL_Rect * drawBounds; // map rect drawing bounds on screen
std::shared_ptr<CAnimation> icons; // holds overlay icons for world view mode std::shared_ptr<CAnimation> icons; // holds overlay icons for world view mode
float scale; // map scale for world view mode (only if scaled == true) float scale; // map scale for world view mode (only if scaled == true)
@ -110,9 +110,10 @@ struct MapDrawingInfo
bool showAllTerrain; //for expert viewEarth bool showAllTerrain; //for expert viewEarth
MapDrawingInfo(int3 &topTile_, const std::vector< std::vector< std::vector<ui8> > > * visibilityMap_, SDL_Rect * drawBounds_, std::shared_ptr<CAnimation> icons_ = nullptr) MapDrawingInfo(int3 &topTile_, std::shared_ptr<const boost::multi_array<ui8, 3>> visibilityMap_, SDL_Rect * drawBounds_, std::shared_ptr<CAnimation> icons_ = nullptr)
: scaled(false), : scaled(false),
topTile(topTile_), topTile(topTile_),
visibilityMap(visibilityMap_), visibilityMap(visibilityMap_),
drawBounds(drawBounds_), drawBounds(drawBounds_),
icons(icons_), icons(icons_),
@ -332,7 +333,7 @@ class CMapHandler
void initTerrainGraphics(); void initTerrainGraphics();
void prepareFOWDefs(); void prepareFOWDefs();
public: public:
PseudoV< PseudoV< PseudoV<TerrainTile2> > > ttiles; //informations about map tiles boost::multi_array<TerrainTile2, 3> ttiles; //informations about map tiles [z][x][y]
int3 sizes; //map size (x = width, y = height, z = number of levels) int3 sizes; //map size (x = width, y = height, z = number of levels)
const CMap * map; const CMap * map;
@ -368,7 +369,7 @@ public:
//Fog of War cache (not owned) //Fog of War cache (not owned)
std::vector<std::shared_ptr<IImage>> FoWfullHide; std::vector<std::shared_ptr<IImage>> FoWfullHide;
std::vector<std::vector<std::vector<ui8> > > hideBitmap; //frame indexes (in FoWfullHide) of graphic that should be used to fully hide a tile boost::multi_array<ui8, 3> hideBitmap; //frame indexes (in FoWfullHide) of graphic that should be used to fully hide a tile
std::vector<std::shared_ptr<IImage>> FoWpartialHide; std::vector<std::shared_ptr<IImage>> FoWpartialHide;

View File

@ -380,7 +380,7 @@ void CTerrainRect::show(SDL_Surface * to)
{ {
if (adventureInt->mode == EAdvMapMode::NORMAL) if (adventureInt->mode == EAdvMapMode::NORMAL)
{ {
MapDrawingInfo info(adventureInt->position, &LOCPLINT->cb->getVisibilityMap(), &pos); MapDrawingInfo info(adventureInt->position, LOCPLINT->cb->getVisibilityMap(), &pos);
info.otherheroAnim = true; info.otherheroAnim = true;
info.anim = adventureInt->anim; info.anim = adventureInt->anim;
info.heroAnim = adventureInt->heroAnim; info.heroAnim = adventureInt->heroAnim;
@ -407,7 +407,7 @@ void CTerrainRect::showAll(SDL_Surface * to)
// world view map is static and doesn't need redraw every frame // world view map is static and doesn't need redraw every frame
if (adventureInt->mode == EAdvMapMode::WORLD_VIEW) if (adventureInt->mode == EAdvMapMode::WORLD_VIEW)
{ {
MapDrawingInfo info(adventureInt->position, &LOCPLINT->cb->getVisibilityMap(), &pos, adventureInt->worldViewIcons); MapDrawingInfo info(adventureInt->position, LOCPLINT->cb->getVisibilityMap(), &pos, adventureInt->worldViewIcons);
info.scaled = true; info.scaled = true;
info.scale = adventureInt->worldViewScale; info.scale = adventureInt->worldViewScale;
adventureInt->worldViewOptions.adjustDrawingInfo(info); adventureInt->worldViewOptions.adjustDrawingInfo(info);
@ -757,7 +757,7 @@ void CAdvMapInt::fworldViewScale4x()
void CAdvMapInt::fswitchLevel() void CAdvMapInt::fswitchLevel()
{ {
// with support for future multi-level maps :) // with support for future multi-level maps :)
int maxLevels = CGI->mh->map->twoLevel ? 2 : 1; int maxLevels = CGI->mh->map->levels();
if (maxLevels < 2) if (maxLevels < 2)
return; return;

View File

@ -1514,7 +1514,7 @@ void CPuzzleWindow::showAll(SDL_Surface * to)
Rect mapRect = genRect(544, 591, pos.x + 8, pos.y + 7); Rect mapRect = genRect(544, 591, pos.x + 8, pos.y + 7);
int3 topTile = grailPos - moveInt; int3 topTile = grailPos - moveInt;
MapDrawingInfo info(topTile, &LOCPLINT->cb->getVisibilityMap(), &mapRect); MapDrawingInfo info(topTile, LOCPLINT->cb->getVisibilityMap(), &mapRect);
info.puzzleMode = true; info.puzzleMode = true;
info.grailPos = grailPos; info.grailPos = grailPos;
CGI->mh->drawTerrainRectNew(to, &info); CGI->mh->drawTerrainRectNew(to, &info);

View File

@ -502,28 +502,29 @@ const TerrainTile * CGameInfoCallback::getTile( int3 tile, bool verbose) const
} }
//TODO: typedef? //TODO: typedef?
std::shared_ptr<boost::multi_array<TerrainTile*, 3>> CGameInfoCallback::getAllVisibleTiles() const std::shared_ptr<const boost::multi_array<TerrainTile*, 3>> CGameInfoCallback::getAllVisibleTiles() const
{ {
assert(player.is_initialized()); assert(player.is_initialized());
auto team = getPlayerTeam(player.get()); auto team = getPlayerTeam(player.get());
size_t width = gs->map->width; size_t width = gs->map->width;
size_t height = gs->map->height; size_t height = gs->map->height;
size_t levels = (gs->map->twoLevel ? 2 : 1); size_t levels = gs->map->levels();
auto ptr = new boost::multi_array<TerrainTile*, 3>(boost::extents[levels][width][height]);
boost::multi_array<TerrainTile*, 3> tileArray(boost::extents[width][height][levels]); int3 tile;
for(tile.z = 0; tile.z < levels; tile.z++)
for (size_t x = 0; x < width; x++) for(tile.x = 0; tile.x < width; tile.x++)
for (size_t y = 0; y < height; y++) for(tile.y = 0; tile.y < height; tile.y++)
for (size_t z = 0; z < levels; z++)
{ {
if (team->fogOfWarMap[x][y][z]) if ((*team->fogOfWarMap)[tile.z][tile.x][tile.y])
tileArray[x][y][z] = &gs->map->getTile(int3((si32)x, (si32)y, (si32)z)); (*ptr)[tile.z][tile.x][tile.y] = &gs->map->getTile(tile);
else else
tileArray[x][y][z] = nullptr; (*ptr)[tile.z][tile.x][tile.y] = nullptr;
} }
return std::make_shared<boost::multi_array<TerrainTile*, 3>>(tileArray);
return std::shared_ptr<const boost::multi_array<TerrainTile*, 3>>(ptr);
} }
EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTownInstance *t, BuildingID ID ) EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTownInstance *t, BuildingID ID )
@ -694,7 +695,7 @@ CGameInfoCallback::CGameInfoCallback(CGameState *GS, boost::optional<PlayerColor
player = Player; player = Player;
} }
const std::vector< std::vector< std::vector<ui8> > > & CPlayerSpecificInfoCallback::getVisibilityMap() const std::shared_ptr<const boost::multi_array<ui8, 3>> CPlayerSpecificInfoCallback::getVisibilityMap() const
{ {
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx); //boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
return gs->getPlayerTeam(*player)->fogOfWarMap; return gs->getPlayerTeam(*player)->fogOfWarMap;

View File

@ -185,7 +185,7 @@ public:
virtual const CMapHeader * getMapHeader()const; virtual const CMapHeader * getMapHeader()const;
virtual int3 getMapSize() const; //returns size of map - z is 1 for one - level map and 2 for two level map virtual int3 getMapSize() const; //returns size of map - z is 1 for one - level map and 2 for two level map
virtual const TerrainTile * getTile(int3 tile, bool verbose = true) const; virtual const TerrainTile * getTile(int3 tile, bool verbose = true) const;
virtual std::shared_ptr<boost::multi_array<TerrainTile*, 3>> getAllVisibleTiles() const; virtual std::shared_ptr<const boost::multi_array<TerrainTile*, 3>> getAllVisibleTiles() const;
virtual bool isInTheMap(const int3 &pos) const; virtual bool isInTheMap(const int3 &pos) const;
virtual void getVisibleTilesInRange(std::unordered_set<int3, ShashInt3> &tiles, int3 pos, int radious, int3::EDistanceFormula distanceFormula = int3::DIST_2D) const; virtual void getVisibleTilesInRange(std::unordered_set<int3, ShashInt3> &tiles, int3 pos, int radious, int3::EDistanceFormula distanceFormula = int3::DIST_2D) const;
virtual void calculatePaths(std::shared_ptr<PathfinderConfig> config); virtual void calculatePaths(std::shared_ptr<PathfinderConfig> config);
@ -235,7 +235,7 @@ public:
virtual int getResourceAmount(Res::ERes type) const; virtual int getResourceAmount(Res::ERes type) const;
virtual TResources getResourceAmount() const; virtual TResources getResourceAmount() const;
virtual const std::vector< std::vector< std::vector<ui8> > > & getVisibilityMap()const; //returns visibility map virtual std::shared_ptr<const boost::multi_array<ui8, 3>> getVisibilityMap() const; //returns visibility map
//virtual const PlayerSettings * getPlayerSettings(PlayerColor color) const; //virtual const PlayerSettings * getPlayerSettings(PlayerColor color) const;
}; };

View File

@ -954,19 +954,20 @@ void CGameState::initGrailPosition()
static const int BORDER_WIDTH = 9; // grail must be at least 9 tiles away from border static const int BORDER_WIDTH = 9; // grail must be at least 9 tiles away from border
// add all not blocked tiles in range // add all not blocked tiles in range
for (int i = BORDER_WIDTH; i < map->width - BORDER_WIDTH ; i++)
for (int z = 0; z < map->levels(); z++)
{ {
for (int j = BORDER_WIDTH; j < map->height - BORDER_WIDTH; j++) for(int x = BORDER_WIDTH; x < map->width - BORDER_WIDTH ; x++)
{ {
for (int k = 0; k < (map->twoLevel ? 2 : 1); k++) for(int y = BORDER_WIDTH; y < map->height - BORDER_WIDTH; y++)
{ {
const TerrainTile &t = map->getTile(int3(i, j, k)); const TerrainTile &t = map->getTile(int3(x, y, z));
if(!t.blocked if(!t.blocked
&& !t.visitable && !t.visitable
&& t.terType.isLand() && t.terType.isLand()
&& t.terType.isPassable() && t.terType.isPassable()
&& (int)map->grailPos.dist2dSQ(int3(i, j, k)) <= (map->grailRadius * map->grailRadius)) && (int)map->grailPos.dist2dSQ(int3(x, y, z)) <= (map->grailRadius * map->grailRadius))
allowedPos.push_back(int3(i,j,k)); allowedPos.push_back(int3(x,y,z));
} }
} }
} }
@ -1593,20 +1594,13 @@ void CGameState::giveCampaignBonusToHero(CGHeroInstance * hero)
void CGameState::initFogOfWar() void CGameState::initFogOfWar()
{ {
logGlobal->debug("\tFog of war"); //FIXME: should be initialized after all bonuses are set logGlobal->debug("\tFog of war"); //FIXME: should be initialized after all bonuses are set
int layers = map->levels();
for(auto & elem : teams) for(auto & elem : teams)
{ {
elem.second.fogOfWarMap.resize(map->width); auto fow = elem.second.fogOfWarMap;
for(int g=0; g<map->width; ++g) fow->resize(boost::extents[layers][map->width][map->height]);
elem.second.fogOfWarMap[g].resize(map->height); std::fill(fow->data(), fow->data() + fow->num_elements(), 0);
for(int g=-0; g<map->width; ++g)
for(int h=0; h<map->height; ++h)
elem.second.fogOfWarMap[g][h].resize(map->twoLevel ? 2 : 1, 0);
for(int g=0; g<map->width; ++g)
for(int h=0; h<map->height; ++h)
for(int v = 0; v < (map->twoLevel ? 2 : 1); ++v)
elem.second.fogOfWarMap[g][h][v] = 0;
for(CGObjectInstance *obj : map->objects) for(CGObjectInstance *obj : map->objects)
{ {
@ -1616,7 +1610,7 @@ void CGameState::initFogOfWar()
getTilesInRange(tiles, obj->getSightCenter(), obj->getSightRadius(), obj->tempOwner, 1); getTilesInRange(tiles, obj->getSightCenter(), obj->getSightRadius(), obj->tempOwner, 1);
for(int3 tile : tiles) for(int3 tile : tiles)
{ {
elem.second.fogOfWarMap[tile.x][tile.y][tile.z] = 1; (*elem.second.fogOfWarMap)[tile.z][tile.x][tile.y] = 1;
} }
} }
} }
@ -2019,6 +2013,7 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out)
void CGameState::calculatePaths(std::shared_ptr<PathfinderConfig> config) void CGameState::calculatePaths(std::shared_ptr<PathfinderConfig> config)
{ {
//FIXME: creating pathfinder is costly, maybe reset / clear is enough?
CPathfinder pathfinder(this, config); CPathfinder pathfinder(this, config);
pathfinder.calculatePaths(); pathfinder.calculatePaths();
} }
@ -2080,7 +2075,7 @@ std::vector<CGObjectInstance*> CGameState::guardingCreatures (int3 pos) const
int3 CGameState::guardingCreaturePosition (int3 pos) const int3 CGameState::guardingCreaturePosition (int3 pos) const
{ {
return gs->map->guardingCreaturePositions[pos.x][pos.y][pos.z]; return gs->map->guardingCreaturePositions[pos.z][pos.x][pos.y];
} }
void CGameState::updateRumor() void CGameState::updateRumor()
@ -2164,7 +2159,7 @@ bool CGameState::isVisible(int3 pos, PlayerColor player)
if(player.isSpectator()) if(player.isSpectator())
return true; return true;
return getPlayerTeam(player)->fogOfWarMap[pos.x][pos.y][pos.z]; return (*getPlayerTeam(player)->fogOfWarMap)[pos.z][pos.x][pos.y];
} }
bool CGameState::isVisible( const CGObjectInstance *obj, boost::optional<PlayerColor> player ) bool CGameState::isVisible( const CGObjectInstance *obj, boost::optional<PlayerColor> player )
@ -3096,6 +3091,7 @@ int ArmyDescriptor::getStrength() const
TeamState::TeamState() TeamState::TeamState()
{ {
setNodeType(TEAM); setNodeType(TEAM);
fogOfWarMap = std::make_shared<boost::multi_array<ui8, 3>>();
} }
TeamState::TeamState(TeamState && other): TeamState::TeamState(TeamState && other):

View File

@ -33,17 +33,17 @@ void NodeStorage::initialize(const PathfinderOptions & options, const CGameState
int3 pos; int3 pos;
const PlayerColor player = out.hero->tempOwner; const PlayerColor player = out.hero->tempOwner;
const int3 sizes = gs->getMapSize(); const int3 sizes = gs->getMapSize();
const auto & fow = static_cast<const CGameInfoCallback *>(gs)->getPlayerTeam(player)->fogOfWarMap; const auto fow = static_cast<const CGameInfoCallback *>(gs)->getPlayerTeam(player)->fogOfWarMap;
//make 200% sure that these are loop invariants (also a bit shorter code), let compiler do the rest(loop unswitching) //make 200% sure that these are loop invariants (also a bit shorter code), let compiler do the rest(loop unswitching)
const bool useFlying = options.useFlying; const bool useFlying = options.useFlying;
const bool useWaterWalking = options.useWaterWalking; const bool useWaterWalking = options.useWaterWalking;
for(pos.z=0; pos.z < sizes.z; ++pos.z)
{
for(pos.x=0; pos.x < sizes.x; ++pos.x) for(pos.x=0; pos.x < sizes.x; ++pos.x)
{ {
for(pos.y=0; pos.y < sizes.y; ++pos.y) for(pos.y=0; pos.y < sizes.y; ++pos.y)
{
for(pos.z=0; pos.z < sizes.z; ++pos.z)
{ {
const TerrainTile * tile = &gs->map->getTile(pos); const TerrainTile * tile = &gs->map->getTile(pos);
if(tile->terType.isWater()) if(tile->terType.isWater())
@ -1304,7 +1304,7 @@ void CGPath::convert(ui8 mode)
CPathsInfo::CPathsInfo(const int3 & Sizes, const CGHeroInstance * hero_) CPathsInfo::CPathsInfo(const int3 & Sizes, const CGHeroInstance * hero_)
: sizes(Sizes), hero(hero_) : sizes(Sizes), hero(hero_)
{ {
nodes.resize(boost::extents[sizes.x][sizes.y][sizes.z][ELayer::NUM_LAYERS]); nodes.resize(boost::extents[ELayer::NUM_LAYERS][sizes.z][sizes.x][sizes.y]);
} }
CPathsInfo::~CPathsInfo() = default; CPathsInfo::~CPathsInfo() = default;
@ -1336,11 +1336,11 @@ bool CPathsInfo::getPath(CGPath & out, const int3 & dst) const
const CGPathNode * CPathsInfo::getNode(const int3 & coord) const const CGPathNode * CPathsInfo::getNode(const int3 & coord) const
{ {
auto landNode = &nodes[coord.x][coord.y][coord.z][ELayer::LAND]; auto landNode = &nodes[ELayer::LAND][coord.z][coord.x][coord.y];
if(landNode->reachable()) if(landNode->reachable())
return landNode; return landNode;
else else
return &nodes[coord.x][coord.y][coord.z][ELayer::SAIL]; return &nodes[ELayer::SAIL][coord.z][coord.x][coord.y];
} }
PathNodeInfo::PathNodeInfo() PathNodeInfo::PathNodeInfo()

View File

@ -178,7 +178,7 @@ struct DLL_LINKAGE CPathsInfo
const CGHeroInstance * hero; const CGHeroInstance * hero;
int3 hpos; int3 hpos;
int3 sizes; int3 sizes;
boost::multi_array<CGPathNode, 4> nodes; //[w][h][level][layer] boost::multi_array<CGPathNode, 4> nodes; //[layer][level][w][h]
CPathsInfo(const int3 & Sizes, const CGHeroInstance * hero_); CPathsInfo(const int3 & Sizes, const CGHeroInstance * hero_);
~CPathsInfo(); ~CPathsInfo();
@ -189,7 +189,7 @@ struct DLL_LINKAGE CPathsInfo
STRONG_INLINE STRONG_INLINE
CGPathNode * getNode(const int3 & coord, const ELayer layer) CGPathNode * getNode(const int3 & coord, const ELayer layer)
{ {
return &nodes[coord.x][coord.y][coord.z][layer]; return &nodes[layer][coord.z][coord.x][coord.y];
} }
}; };

View File

@ -81,7 +81,7 @@ public:
TeamID id; //position in gameState::teams TeamID id; //position in gameState::teams
std::set<PlayerColor> players; // members of this team std::set<PlayerColor> players; // members of this team
//TODO: boost::array, bool if possible //TODO: boost::array, bool if possible
std::vector<std::vector<std::vector<ui8> > > fogOfWarMap; //true - visible, false - hidden std::shared_ptr<boost::multi_array<ui8, 3>> fogOfWarMap; //[z][x][y] true - visible, false - hidden
TeamState(); TeamState();
TeamState(TeamState && other); TeamState(TeamState && other);

View File

@ -38,14 +38,13 @@
void CPrivilegedInfoCallback::getFreeTiles(std::vector<int3> & tiles) const void CPrivilegedInfoCallback::getFreeTiles(std::vector<int3> & tiles) const
{ {
std::vector<int> floors; std::vector<int> floors;
for (int b = 0; b < (gs->map->twoLevel ? 2 : 1); ++b) for(int b = 0; b < gs->map->levels(); ++b)
{ {
floors.push_back(b); floors.push_back(b);
} }
const TerrainTile *tinfo; const TerrainTile *tinfo;
for (auto zd : floors) for (auto zd : floors)
{ {
for (int xd = 0; xd < gs->map->width; xd++) for (int xd = 0; xd < gs->map->width; xd++)
{ {
for (int yd = 0; yd < gs->map->height; yd++) for (int yd = 0; yd < gs->map->height; yd++)
@ -80,8 +79,8 @@ void CPrivilegedInfoCallback::getTilesInRange(std::unordered_set<int3, ShashInt3
if(distance <= radious) if(distance <= radious)
{ {
if(!player if(!player
|| (mode == 1 && team->fogOfWarMap[xd][yd][pos.z]==0) || (mode == 1 && (*team->fogOfWarMap)[pos.z][xd][yd] == 0)
|| (mode == -1 && team->fogOfWarMap[xd][yd][pos.z]==1) || (mode == -1 && (*team->fogOfWarMap)[pos.z][xd][yd] == 1)
) )
tiles.insert(int3(xd,yd,pos.z)); tiles.insert(int3(xd,yd,pos.z));
} }
@ -103,7 +102,7 @@ void CPrivilegedInfoCallback::getAllTiles(std::unordered_set<int3, ShashInt3> &
std::vector<int> floors; std::vector<int> floors;
if(level == -1) if(level == -1)
{ {
for(int b = 0; b < (gs->map->twoLevel ? 2 : 1); ++b) for(int b = 0; b < gs->map->levels(); ++b)
{ {
floors.push_back(b); floors.push_back(b);
} }

View File

@ -177,8 +177,9 @@ DLL_LINKAGE void SetMovePoints::applyGs(CGameState *gs)
DLL_LINKAGE void FoWChange::applyGs(CGameState *gs) DLL_LINKAGE void FoWChange::applyGs(CGameState *gs)
{ {
TeamState * team = gs->getPlayerTeam(player); TeamState * team = gs->getPlayerTeam(player);
auto fogOfWarMap = team->fogOfWarMap;
for(int3 t : tiles) for(int3 t : tiles)
team->fogOfWarMap[t.x][t.y][t.z] = mode; (*fogOfWarMap)[t.z][t.x][t.y] = mode;
if (mode == 0) //do not hide too much if (mode == 0) //do not hide too much
{ {
std::unordered_set<int3, ShashInt3> tilesRevealed; std::unordered_set<int3, ShashInt3> tilesRevealed;
@ -200,7 +201,7 @@ DLL_LINKAGE void FoWChange::applyGs(CGameState *gs)
} }
} }
for(int3 t : tilesRevealed) //probably not the most optimal solution ever for(int3 t : tilesRevealed) //probably not the most optimal solution ever
team->fogOfWarMap[t.x][t.y][t.z] = 1; (*fogOfWarMap)[t.z][t.x][t.y] = 1;
} }
} }
@ -561,8 +562,9 @@ void TryMoveHero::applyGs(CGameState *gs)
gs->map->addBlockVisTiles(h); gs->map->addBlockVisTiles(h);
} }
auto fogOfWarMap = gs->getPlayerTeam(h->getOwner())->fogOfWarMap;
for(int3 t : fowRevealed) for(int3 t : fowRevealed)
gs->getPlayerTeam(h->getOwner())->fogOfWarMap[t.x][t.y][t.z] = 1; (*fogOfWarMap)[t.z][t.x][t.y] = 1;
} }
DLL_LINKAGE void NewStructures::applyGs(CGameState *gs) DLL_LINKAGE void NewStructures::applyGs(CGameState *gs)

View File

@ -14,13 +14,13 @@
namespace PathfinderUtil namespace PathfinderUtil
{ {
using FoW = std::vector<std::vector<std::vector<ui8> > >; using FoW = std::shared_ptr<const boost::multi_array<ui8, 3>>;
using ELayer = EPathfindingLayer; using ELayer = EPathfindingLayer;
template<EPathfindingLayer::EEPathfindingLayer layer> template<EPathfindingLayer::EEPathfindingLayer layer>
CGPathNode::EAccessibility evaluateAccessibility(const int3 & pos, const TerrainTile * tinfo, const FoW & fow, const PlayerColor player, const CGameState * gs) CGPathNode::EAccessibility evaluateAccessibility(const int3 & pos, const TerrainTile * tinfo, FoW fow, const PlayerColor player, const CGameState * gs)
{ {
if(!fow[pos.x][pos.y][pos.z]) if(!(*fow)[pos.z][pos.x][pos.y])
return CGPathNode::BLOCKED; return CGPathNode::BLOCKED;
switch(layer) switch(layer)

View File

@ -522,10 +522,15 @@ CStack * BattleInfo::getStack(int stackID, bool onlyAlive)
return const_cast<CStack *>(battleGetStackByID(stackID, onlyAlive)); return const_cast<CStack *>(battleGetStackByID(stackID, onlyAlive));
} }
BattleInfo::BattleInfo() BattleInfo::BattleInfo():
: round(-1), activeStack(-1), town(nullptr), tile(-1,-1,-1), round(-1),
battlefieldType(BattleField::NONE), terrainType(), activeStack(-1),
tacticsSide(0), tacticDistance(0) town(nullptr),
tile(-1,-1,-1),
battlefieldType(BattleField::NONE),
terrainType(),
tacticsSide(0),
tacticDistance(0)
{ {
setBattle(this); setBattle(this);
setNodeType(BATTLE); setNodeType(BATTLE);

View File

@ -149,19 +149,23 @@ static bool ruleIsAny(const std::string & rule)
///CDrawLinesOperation ///CDrawLinesOperation
CDrawLinesOperation::CDrawLinesOperation(CMap * map, const CTerrainSelection & terrainSel, CRandomGenerator * gen): CDrawLinesOperation::CDrawLinesOperation(CMap * map, const CTerrainSelection & terrainSel, CRandomGenerator * gen):
CMapOperation(map), terrainSel(terrainSel), gen(gen) CMapOperation(map),
terrainSel(terrainSel),
gen(gen)
{ {
} }
///CDrawRoadsOperation ///CDrawRoadsOperation
CDrawRoadsOperation::CDrawRoadsOperation(CMap * map, const CTerrainSelection & terrainSel, const std::string & roadType, CRandomGenerator * gen): CDrawRoadsOperation::CDrawRoadsOperation(CMap * map, const CTerrainSelection & terrainSel, const std::string & roadType, CRandomGenerator * gen):
CDrawLinesOperation(map, terrainSel, gen), roadType(roadType) CDrawLinesOperation(map, terrainSel,gen),
roadType(roadType)
{ {
} }
///CDrawRiversOperation ///CDrawRiversOperation
CDrawRiversOperation::CDrawRiversOperation(CMap * map, const CTerrainSelection & terrainSel, const std::string & riverType, CRandomGenerator * gen): CDrawRiversOperation::CDrawRiversOperation(CMap * map, const CTerrainSelection & terrainSel, const std::string & riverType, CRandomGenerator * gen):
CDrawLinesOperation(map, terrainSel, gen), riverType(riverType) CDrawLinesOperation(map, terrainSel, gen),
riverType(riverType)
{ {
} }

View File

@ -228,7 +228,11 @@ CMapHeader::CMapHeader() : version(EMapFormat::SOD), height(72), width(72),
CMapHeader::~CMapHeader() CMapHeader::~CMapHeader()
{ {
}
ui8 CMapHeader::levels() const
{
return (twoLevel ? 2 : 1);
} }
CMap::CMap() CMap::CMap()
@ -246,15 +250,15 @@ CMap::~CMap()
{ {
if(terrain) if(terrain)
{ {
for (int i=0; i<width; i++) for(int z = 0; z < levels(); z++)
{ {
for(int j=0; j<height; j++) for(int x = 0; x < width; x++)
{ {
delete [] terrain[i][j]; delete[] terrain[z][x];
delete [] guardingCreaturePositions[i][j]; delete[] guardingCreaturePositions[z][x];
} }
delete [] terrain[i]; delete[] terrain[z];
delete [] guardingCreaturePositions[i]; delete[] guardingCreaturePositions[z];
} }
delete [] terrain; delete [] terrain;
delete [] guardingCreaturePositions; delete [] guardingCreaturePositions;
@ -271,16 +275,16 @@ CMap::~CMap()
void CMap::removeBlockVisTiles(CGObjectInstance * obj, bool total) void CMap::removeBlockVisTiles(CGObjectInstance * obj, bool total)
{ {
const int zVal = obj->pos.z;
for(int fx = 0; fx < obj->getWidth(); ++fx) for(int fx = 0; fx < obj->getWidth(); ++fx)
{ {
int xVal = obj->pos.x - fx;
for(int fy = 0; fy < obj->getHeight(); ++fy) for(int fy = 0; fy < obj->getHeight(); ++fy)
{ {
int xVal = obj->pos.x - fx;
int yVal = obj->pos.y - fy; int yVal = obj->pos.y - fy;
int zVal = obj->pos.z;
if(xVal>=0 && xVal < width && yVal>=0 && yVal < height) if(xVal>=0 && xVal < width && yVal>=0 && yVal < height)
{ {
TerrainTile & curt = terrain[xVal][yVal][zVal]; TerrainTile & curt = terrain[zVal][xVal][yVal];
if(total || obj->visitableAt(xVal, yVal)) if(total || obj->visitableAt(xVal, yVal))
{ {
curt.visitableObjects -= obj; curt.visitableObjects -= obj;
@ -298,16 +302,16 @@ void CMap::removeBlockVisTiles(CGObjectInstance * obj, bool total)
void CMap::addBlockVisTiles(CGObjectInstance * obj) void CMap::addBlockVisTiles(CGObjectInstance * obj)
{ {
const int zVal = obj->pos.z;
for(int fx = 0; fx < obj->getWidth(); ++fx) for(int fx = 0; fx < obj->getWidth(); ++fx)
{ {
int xVal = obj->pos.x - fx;
for(int fy = 0; fy < obj->getHeight(); ++fy) for(int fy = 0; fy < obj->getHeight(); ++fy)
{ {
int xVal = obj->pos.x - fx;
int yVal = obj->pos.y - fy; int yVal = obj->pos.y - fy;
int zVal = obj->pos.z;
if(xVal>=0 && xVal < width && yVal >= 0 && yVal < height) if(xVal>=0 && xVal < width && yVal >= 0 && yVal < height)
{ {
TerrainTile & curt = terrain[xVal][yVal][zVal]; TerrainTile & curt = terrain[zVal][xVal][yVal];
if(obj->visitableAt(xVal, yVal)) if(obj->visitableAt(xVal, yVal))
{ {
curt.visitableObjects.push_back(obj); curt.visitableObjects.push_back(obj);
@ -326,12 +330,14 @@ void CMap::addBlockVisTiles(CGObjectInstance * obj)
void CMap::calculateGuardingGreaturePositions() void CMap::calculateGuardingGreaturePositions()
{ {
int levels = twoLevel ? 2 : 1; int levels = twoLevel ? 2 : 1;
for (int i=0; i<width; i++) for(int z = 0; z < levels; z++)
{ {
for(int j=0; j<height; j++) for(int x = 0; x < width; x++)
{ {
for (int k = 0; k < levels; k++) for(int y = 0; y < height; y++)
guardingCreaturePositions[i][j][k] = guardingCreaturePosition(int3(i,j,k)); {
guardingCreaturePositions[z][x][y] = guardingCreaturePosition(int3(x, y, z));
}
} }
} }
} }
@ -389,13 +395,13 @@ bool CMap::isInTheMap(const int3 & pos) const
TerrainTile & CMap::getTile(const int3 & tile) TerrainTile & CMap::getTile(const int3 & tile)
{ {
assert(isInTheMap(tile)); assert(isInTheMap(tile));
return terrain[tile.x][tile.y][tile.z]; return terrain[tile.z][tile.x][tile.y];
} }
const TerrainTile & CMap::getTile(const int3 & tile) const const TerrainTile & CMap::getTile(const int3 & tile) const
{ {
assert(isInTheMap(tile)); assert(isInTheMap(tile));
return terrain[tile.x][tile.y][tile.z]; return terrain[tile.z][tile.x][tile.y];
} }
bool CMap::isWaterTile(const int3 &pos) const bool CMap::isWaterTile(const int3 &pos) const
@ -679,17 +685,17 @@ void CMap::removeObject(CGObjectInstance * obj)
void CMap::initTerrain() void CMap::initTerrain()
{ {
int level = twoLevel ? 2 : 1; int level = levels();
terrain = new TerrainTile**[width]; terrain = new TerrainTile**[level];
guardingCreaturePositions = new int3**[width]; guardingCreaturePositions = new int3**[level];
for (int i = 0; i < width; ++i) for(int z = 0; z < level; ++z)
{ {
terrain[i] = new TerrainTile*[height]; terrain[z] = new TerrainTile*[width];
guardingCreaturePositions[i] = new int3*[height]; guardingCreaturePositions[z] = new int3*[width];
for (int j = 0; j < height; ++j) for(int x = 0; x < width; ++x)
{ {
terrain[i][j] = new TerrainTile[level]; terrain[z][x] = new TerrainTile[height];
guardingCreaturePositions[i][j] = new int3[level]; guardingCreaturePositions[z][x] = new int3[height];
} }
} }
} }

View File

@ -286,6 +286,8 @@ public:
CMapHeader(); CMapHeader();
virtual ~CMapHeader(); virtual ~CMapHeader();
ui8 levels() const;
EMapFormat::EMapFormat version; /// The default value is EMapFormat::SOD. EMapFormat::EMapFormat version; /// The default value is EMapFormat::SOD.
si32 height; /// The default value is 72. si32 height; /// The default value is 72.
si32 width; /// The default value is 72. si32 width; /// The default value is 72.
@ -432,18 +434,18 @@ public:
h & questIdentifierToId; h & questIdentifierToId;
//TODO: viccondetails //TODO: viccondetails
int level = twoLevel ? 2 : 1; const int level = levels();
if(h.saving) if(h.saving)
{ {
// Save terrain // Save terrain
for(int i = 0; i < width ; ++i) for(int z = 0; z < level; ++z)
{ {
for(int j = 0; j < height ; ++j) for(int x = 0; x < width; ++x)
{ {
for(int k = 0; k < level; ++k) for(int y = 0; y < height; ++y)
{ {
h & terrain[i][j][k]; h & terrain[z][x][y];
h & guardingCreaturePositions[i][j][k]; h & guardingCreaturePositions[z][x][y];
} }
} }
} }
@ -451,26 +453,27 @@ public:
else else
{ {
// Load terrain // Load terrain
terrain = new TerrainTile**[width]; terrain = new TerrainTile**[level];
guardingCreaturePositions = new int3**[width]; guardingCreaturePositions = new int3**[level];
for(int i = 0; i < width; ++i) for(int z = 0; z < level; ++z)
{ {
terrain[i] = new TerrainTile*[height]; terrain[z] = new TerrainTile*[width];
guardingCreaturePositions[i] = new int3*[height]; guardingCreaturePositions[z] = new int3*[width];
for(int j = 0; j < height; ++j) for(int x = 0; x < width; ++x)
{ {
terrain[i][j] = new TerrainTile[level]; terrain[z][x] = new TerrainTile[height];
guardingCreaturePositions[i][j] = new int3[level]; guardingCreaturePositions[z][x] = new int3[height];
} }
} }
for(int i = 0; i < width ; ++i) for(int z = 0; z < level; ++z)
{ {
for(int j = 0; j < height ; ++j) for(int x = 0; x < width; ++x)
{ {
for(int k = 0; k < level; ++k) for(int y = 0; y < height; ++y)
{ {
h & terrain[i][j][k];
h & guardingCreaturePositions[i][j][k]; h & terrain[z][x][y];
h & guardingCreaturePositions[z][x][y];
} }
} }
} }

View File

@ -84,7 +84,7 @@ struct DLL_LINKAGE TerrainTile
ui8 terView; ui8 terView;
std::string riverType; std::string riverType;
ui8 riverDir; ui8 riverDir;
std::string roadType; std::string roadType; //TODO: switch to ui8
ui8 roadDir; ui8 roadDir;
/// first two bits - how to rotate terrain graphic (next two - river graphic, next two - road); /// first two bits - how to rotate terrain graphic (next two - river graphic, next two - road);
/// 7th bit - whether tile is coastal (allows disembarking if land or block movement if water); 8th bit - Favorable Winds effect /// 7th bit - whether tile is coastal (allows disembarking if land or block movement if water); 8th bit - Favorable Winds effect

View File

@ -923,18 +923,20 @@ void CMapLoaderH3M::readTerrain()
map->initTerrain(); map->initTerrain();
// Read terrain // Read terrain
for(int a = 0; a < 2; ++a) int3 pos;
for(pos.z = 0; pos.z < 2; ++pos.z)
{ {
if(a == 1 && !map->twoLevel) if(pos.z == 1 && !map->twoLevel)
{ {
break; break;
} }
for(int c = 0; c < map->width; c++) //OH3 format is [z][y][x]
for(pos.y = 0; pos.y < map->height; pos.y++)
{ {
for(int z = 0; z < map->height; z++) for(pos.x = 0; pos.x < map->width; pos.x++)
{ {
auto & tile = map->getTile(int3(z, c, a)); auto & tile = map->getTile(pos);
tile.terType = Terrain::createTerrainTypeH3M(reader.readUInt8()); tile.terType = Terrain::createTerrainTypeH3M(reader.readUInt8());
tile.terView = reader.readUInt8(); tile.terView = reader.readUInt8();
tile.riverType = RIVER_NAMES[reader.readUInt8()]; tile.riverType = RIVER_NAMES[reader.readUInt8()];

View File

@ -162,8 +162,8 @@ std::string CMapGenerator::getMapDescription() const
std::stringstream ss; std::stringstream ss;
ss << boost::str(boost::format(std::string("Map created by the Random Map Generator.\nTemplate was %s, Random seed was %d, size %dx%d") + ss << boost::str(boost::format(std::string("Map created by the Random Map Generator.\nTemplate was %s, Random seed was %d, size %dx%d") +
", levels %s, players %d, computers %d, water %s, monster %s, VCMI map") % mapTemplate->getName() % ", levels %d, players %d, computers %d, water %s, monster %s, VCMI map") % mapTemplate->getName() %
randomSeed % map->map().width % map->map().height % (map->map().twoLevel ? "2" : "1") % static_cast<int>(mapGenOptions.getPlayerCount()) % randomSeed % map->map().width % map->map().height % map->map().levels() % static_cast<int>(mapGenOptions.getPlayerCount()) %
static_cast<int>(mapGenOptions.getCompOnlyPlayerCount()) % waterContentStr[mapGenOptions.getWaterContent()] % static_cast<int>(mapGenOptions.getCompOnlyPlayerCount()) % waterContentStr[mapGenOptions.getWaterContent()] %
monsterStrengthStr[monsterStrengthIndex]); monsterStrengthStr[monsterStrengthIndex]);

View File

@ -498,24 +498,24 @@ void CZonePlacer::assignZones(CRandomGenerator * rand)
zone->setPos(int3(total.x / size, total.y / size, total.z / size)); zone->setPos(int3(total.x / size, total.y / size, total.z / size));
}; };
int levels = map.map().twoLevel ? 2 : 1; int levels = map.map().levels();
/* /*
1. Create Voronoi diagram 1. Create Voronoi diagram
2. find current center of mass for each zone. Move zone to that center to balance zones sizes 2. find current center of mass for each zone. Move zone to that center to balance zones sizes
*/ */
for (int i = 0; i<width; i++) int3 pos;
for(pos.z = 0; pos.z < levels; pos.z++)
{ {
for (int j = 0; j<height; j++) for(pos.x = 0; pos.x < width; pos.x++)
{ {
for (int k = 0; k < levels; k++) for(pos.y = 0; pos.y < height; pos.y++)
{ {
distances.clear(); distances.clear();
int3 pos(i, j, k);
for(auto zone : zones) for(auto zone : zones)
{ {
if (zone.second->getPos().z == k) if (zone.second->getPos().z == pos.z)
distances.push_back(std::make_pair(zone.second, (float)pos.dist2dSQ(zone.second->getPos()))); distances.push_back(std::make_pair(zone.second, (float)pos.dist2dSQ(zone.second->getPos())));
else else
distances.push_back(std::make_pair(zone.second, std::numeric_limits<float>::max())); distances.push_back(std::make_pair(zone.second, std::numeric_limits<float>::max()));
@ -533,17 +533,16 @@ void CZonePlacer::assignZones(CRandomGenerator * rand)
for (auto zone : zones) for (auto zone : zones)
zone.second->clearTiles(); //now populate them again zone.second->clearTiles(); //now populate them again
for (int i=0; i<width; i++) for (pos.z = 0; pos.z < levels; pos.z++)
{ {
for(int j=0; j<height; j++) for (pos.x = 0; pos.x < width; pos.x++)
{ {
for (int k = 0; k < levels; k++) for (pos.y = 0; pos.y < height; pos.y++)
{ {
distances.clear(); distances.clear();
int3 pos(i, j, k);
for (auto zone : zones) for (auto zone : zones)
{ {
if (zone.second->getPos().z == k) if (zone.second->getPos().z == pos.z)
distances.push_back (std::make_pair(zone.second, metric(pos, zone.second->getPos()))); distances.push_back (std::make_pair(zone.second, metric(pos, zone.second->getPos())));
else else
distances.push_back (std::make_pair(zone.second, std::numeric_limits<float>::max())); distances.push_back (std::make_pair(zone.second, std::numeric_limits<float>::max()));

View File

@ -175,46 +175,4 @@ void createObstaclesCommon2(RmgMap & map, CRandomGenerator & generator)
} }
} }
} }
//tighten obstacles to improve visuals
/*for (int i = 0; i < 3; ++i)
{
int blockedTiles = 0;
int freeTiles = 0;
for (int z = 0; z < (map.map().twoLevel ? 2 : 1); z++)
{
for (int x = 0; x < map.map().width; x++)
{
for (int y = 0; y < map.map().height; y++)
{
int3 tile(x, y, z);
if (!map.isPossible(tile)) //only possible tiles can change
continue;
int blockedNeighbours = 0;
int freeNeighbours = 0;
map.foreach_neighbour(tile, [&map, &blockedNeighbours, &freeNeighbours](int3 &pos)
{
if (map.isBlocked(pos))
blockedNeighbours++;
if (map.isFree(pos))
freeNeighbours++;
});
if (blockedNeighbours > 4)
{
map.setOccupied(tile, ETileType::BLOCKED);
blockedTiles++;
}
else if (freeNeighbours > 4)
{
map.setOccupied(tile, ETileType::FREE);
freeTiles++;
}
}
}
}
logGlobal->trace("Set %d tiles to BLOCKED and %d tiles to FREE", blockedTiles, freeTiles);
}*/
} }

View File

@ -40,6 +40,7 @@ public:
public: public:
MODIFICATOR(ObjectManager); MODIFICATOR(ObjectManager);
void process() override; void process() override;
void init() override; void init() override;

View File

@ -73,8 +73,8 @@ void RmgMap::initTiles(CMapGenerator & generator)
{ {
mapInstance->initTerrain(); mapInstance->initTerrain();
tiles.resize(boost::extents[mapInstance->width][mapInstance->height][mapInstance->twoLevel ? 2 : 1]); tiles.resize(boost::extents[mapInstance->width][mapInstance->height][mapInstance->levels()]);
zoneColouring.resize(boost::extents[mapInstance->width][mapInstance->height][mapInstance->twoLevel ? 2 : 1]); zoneColouring.resize(boost::extents[mapInstance->width][mapInstance->height][mapInstance->levels()]);
//init native town count with 0 //init native town count with 0
for (auto faction : VLC->townh->getAllowedFactions()) for (auto faction : VLC->townh->getAllowedFactions())
@ -302,7 +302,7 @@ void RmgMap::dump(bool zoneId) const
{ {
static int id = 0; static int id = 0;
std::ofstream out(boost::to_string(boost::format("zone_%d.txt") % id++)); std::ofstream out(boost::to_string(boost::format("zone_%d.txt") % id++));
int levels = mapInstance->twoLevel ? 2 : 1; int levels = mapInstance->levels();
int width = mapInstance->width; int width = mapInstance->width;
int height = mapInstance->height; int height = mapInstance->height;
for (int k = 0; k < levels; k++) for (int k = 0; k < levels; k++)

View File

@ -369,16 +369,16 @@ void Modificator::dump()
{ {
std::ofstream out(boost::to_string(boost::format("seed_%d_modzone_%d_%s.txt") % generator.getRandomSeed() % zone.getId() % getName())); std::ofstream out(boost::to_string(boost::format("seed_%d_modzone_%d_%s.txt") % generator.getRandomSeed() % zone.getId() % getName()));
auto & mapInstance = map.map(); auto & mapInstance = map.map();
int levels = mapInstance.twoLevel ? 2 : 1; int levels = mapInstance.levels();
int width = mapInstance.width; int width = mapInstance.width;
int height = mapInstance.height; int height = mapInstance.height;
for (int k = 0; k < levels; k++) for(int z = 0; z < levels; z++)
{ {
for(int j=0; j<height; j++) for(int j=0; j<height; j++)
{ {
for(int i=0; i<width; i++) for(int i=0; i<width; i++)
{ {
out << dump(int3(i, j, k)); out << dump(int3(i, j, z));
} }
out << std::endl; out << std::endl;
} }

View File

@ -560,6 +560,20 @@ public:
data = boost::optional<T>(); data = boost::optional<T>();
} }
} }
template <typename T>
void load(boost::multi_array<T, 3> & data)
{
ui32 length = readAndCheckLength();
ui32 x, y, z;
load(x);
load(y);
load(z);
data.resize(boost::extents[x][y][z]);
assert(length == data.num_elements()); //x*y*z should be equal to number of elements
for(ui32 i = 0; i < length; i++)
load(data.data()[i]);
}
}; };
class DLL_LINKAGE CLoadFile : public IBinaryReader class DLL_LINKAGE CLoadFile : public IBinaryReader

View File

@ -350,6 +350,18 @@ public:
save((ui8)0); save((ui8)0);
} }
} }
template <typename T>
void save(const boost::multi_array<T, 3> &data)
{
ui32 length = data.num_elements();
*this & length;
auto shape = data.shape();
ui32 x = shape[0], y = shape[1], z = shape[2];
*this & x & y & z;
for(ui32 i = 0; i < length; i++)
save(data.data()[i]);
}
}; };
class DLL_LINKAGE CSaveFile : public IBinaryWriter class DLL_LINKAGE CSaveFile : public IBinaryWriter

View File

@ -571,7 +571,7 @@ ESpellCastResult ViewMechanics::applyAdventureEffects(SpellCastEnvironment * env
const auto spellLevel = parameters.caster->getSpellSchoolLevel(owner); const auto spellLevel = parameters.caster->getSpellSchoolLevel(owner);
const auto & fowMap = env->getCb()->getPlayerTeam(parameters.caster->getOwner())->fogOfWarMap; const auto fowMap = env->getCb()->getPlayerTeam(parameters.caster->getOwner())->fogOfWarMap;
for(const CGObjectInstance * obj : env->getMap()->objects) for(const CGObjectInstance * obj : env->getMap()->objects)
{ {
@ -580,7 +580,7 @@ ESpellCastResult ViewMechanics::applyAdventureEffects(SpellCastEnvironment * env
{ {
ObjectPosInfo posInfo(obj); ObjectPosInfo posInfo(obj);
if(fowMap[posInfo.pos.x][posInfo.pos.y][posInfo.pos.z] == 0) if((*fowMap)[posInfo.pos.x][posInfo.pos.y][posInfo.pos.z] == 0)
pack.objectPositions.push_back(posInfo); pack.objectPositions.push_back(posInfo);
} }
} }

View File

@ -1993,12 +1993,14 @@ void CGameHandler::newTurn()
fw.mode = 1; fw.mode = 1;
fw.player = player; fw.player = player;
// find all hidden tiles // find all hidden tiles
const auto & fow = getPlayerTeam(player)->fogOfWarMap; const auto fow = getPlayerTeam(player)->fogOfWarMap;
for (size_t i=0; i<fow.size(); i++)
for (size_t j=0; j<fow.at(i).size(); j++) auto shape = fow->shape();
for (size_t k=0; k<fow.at(i).at(j).size(); k++) for(size_t z = 0; z < shape[0]; z++)
if (!fow.at(i).at(j).at(k)) for(size_t x = 0; x < shape[1]; x++)
fw.tiles.insert(int3((si32)i,(si32)j,(si32)k)); for(size_t y = 0; y < shape[2]; y++)
if (!(*fow)[z][x][y])
fw.tiles.insert(int3(x, y, z));
sendAndApply (&fw); sendAndApply (&fw);
} }
@ -7012,13 +7014,15 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
fc.mode = (cheat == "vcmieagles" ? 1 : 0); fc.mode = (cheat == "vcmieagles" ? 1 : 0);
fc.player = player; fc.player = player;
const auto & fowMap = gs->getPlayerTeam(player)->fogOfWarMap; const auto & fowMap = gs->getPlayerTeam(player)->fogOfWarMap;
auto hlp_tab = new int3[gs->map->width * gs->map->height * (gs->map->twoLevel ? 2 : 1)]; auto hlp_tab = new int3[gs->map->width * gs->map->height * (gs->map->levels())];
int lastUnc = 0; int lastUnc = 0;
for (int i = 0; i < gs->map->width; i++)
for (int j = 0; j < gs->map->height; j++) for(int z = 0; z < gs->map->levels(); z++)
for (int k = 0; k < (gs->map->twoLevel ? 2 : 1); k++) for(int x = 0; x < gs->map->width; x++)
if (!fowMap.at(i).at(j).at(k) || !fc.mode) for(int y = 0; y < gs->map->height; y++)
hlp_tab[lastUnc++] = int3(i, j, k); if(!(*fowMap)[z][x][y] || !fc.mode)
hlp_tab[lastUnc++] = int3(x, y, z);
fc.tiles.insert(hlp_tab, hlp_tab + lastUnc); fc.tiles.insert(hlp_tab, hlp_tab + lastUnc);
delete [] hlp_tab; delete [] hlp_tab;
sendAndApply(&fc); sendAndApply(&fc);