2022-10-13 01:51:55 +04:00
/*
* maphandler . 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
*
*/
//code is copied from vcmiclient/mapHandler.cpp with minimal changes
2022-09-18 03:23:17 +04:00
# include "StdInc.h"
# include "maphandler.h"
# include "graphics.h"
2023-01-11 15:17:24 +02:00
# include "../lib/RoadHandler.h"
# include "../lib/RiverHandler.h"
2023-01-09 01:17:37 +02:00
# include "../lib/TerrainHandler.h"
2022-09-18 03:23:17 +04:00
# include "../lib/mapping/CMap.h"
# include "../lib/mapObjects/CGHeroInstance.h"
2023-06-02 21:47:37 +03:00
# include "../lib/mapObjects/ObjectTemplate.h"
2024-01-09 16:43:36 +02:00
# include "../lib/mapObjects/MiscObjects.h"
2022-09-18 03:23:17 +04:00
# include "../lib/GameConstants.h"
2025-09-15 13:52:54 +03:00
namespace
{
2022-09-18 03:23:17 +04:00
const int tileSize = 32 ;
2025-09-15 13:52:54 +03:00
bool objectBlitOrderSorter ( const ObjectRect & a , const ObjectRect & b )
2022-09-18 03:23:17 +04:00
{
return MapHandler : : compareObjectBlitOrder ( a . obj , b . obj ) ;
}
2025-09-15 13:52:54 +03:00
QImage flippedImage ( const std : : shared_ptr < QImage > & image , ui8 rotationFlags )
{
const ui8 rotation = rotationFlags % 4 ;
const bool hflip = rotation & 0b01 ;
const bool vflip = rotation & 0b10 ;
# if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
Qt : : Orientations orientations ;
if ( hflip )
orientations | = Qt : : Horizontal ;
if ( vflip )
orientations | = Qt : : Vertical ;
return image - > flipped ( orientations ) ;
# else
return image - > mirrored ( hflip , vflip ) ;
# endif
}
}
2022-09-18 03:23:17 +04:00
int MapHandler : : index ( int x , int y , int z ) const
{
2023-10-20 01:25:06 +02:00
return z * ( map - > width * map - > height ) + y * map - > width + x ;
2022-09-18 03:23:17 +04:00
}
int MapHandler : : index ( const int3 & p ) const
{
return index ( p . x , p . y , p . z ) ;
}
MapHandler : : MapHandler ( )
{
initTerrainGraphics ( ) ;
logGlobal - > info ( " \t Preparing terrain, roads, rivers, borders " ) ;
}
void MapHandler : : reset ( const CMap * Map )
{
map = Map ;
initObjectRects ( ) ;
logGlobal - > info ( " \t Making object rects " ) ;
}
void MapHandler : : initTerrainGraphics ( )
{
auto loadFlipped = [ ] ( TFlippedAnimations & animation , TFlippedCache & cache , const std : : map < std : : string , std : : string > & files )
{
for ( auto & type : files )
{
2022-12-07 23:36:20 +02:00
animation [ type . first ] = std : : make_unique < Animation > ( type . second ) ;
2022-09-18 03:23:17 +04:00
animation [ type . first ] - > preload ( ) ;
const size_t views = animation [ type . first ] - > size ( 0 ) ;
cache [ type . first ] . resize ( views ) ;
2025-09-15 13:52:54 +03:00
2022-09-18 03:23:17 +04:00
for ( int j = 0 ; j < views ; j + + )
cache [ type . first ] [ j ] = animation [ type . first ] - > getImage ( j ) ;
}
} ;
2025-09-15 13:52:54 +03:00
2022-09-18 03:23:17 +04:00
std : : map < std : : string , std : : string > terrainFiles ;
2022-10-08 23:54:45 +04:00
std : : map < std : : string , std : : string > roadFiles ;
std : : map < std : : string , std : : string > riverFiles ;
2025-02-14 16:23:37 +00:00
for ( const auto & terrain : LIBRARY - > terrainTypeHandler - > objects )
2022-10-08 23:54:45 +04:00
{
2023-08-23 15:07:50 +03:00
terrainFiles [ terrain - > getJsonKey ( ) ] = terrain - > tilesFilename . getName ( ) ;
2022-10-08 23:54:45 +04:00
}
2025-02-14 16:23:37 +00:00
for ( const auto & river : LIBRARY - > riverTypeHandler - > objects )
2022-09-18 03:23:17 +04:00
{
2023-08-23 15:07:50 +03:00
riverFiles [ river - > getJsonKey ( ) ] = river - > tilesFilename . getName ( ) ;
2022-10-08 23:54:45 +04:00
}
2025-02-14 16:23:37 +00:00
for ( const auto & road : LIBRARY - > roadTypeHandler - > objects )
2022-10-08 23:54:45 +04:00
{
2023-08-23 15:07:50 +03:00
roadFiles [ road - > getJsonKey ( ) ] = road - > tilesFilename . getName ( ) ;
2022-09-18 03:23:17 +04:00
}
2025-09-15 13:52:54 +03:00
2022-09-18 03:23:17 +04:00
loadFlipped ( terrainAnimations , terrainImages , terrainFiles ) ;
2022-10-08 23:54:45 +04:00
loadFlipped ( riverAnimations , riverImages , riverFiles ) ;
loadFlipped ( roadAnimations , roadImages , roadFiles ) ;
2022-09-18 03:23:17 +04:00
}
2025-10-06 20:33:09 +02:00
void MapHandler : : drawTerrainTile ( QPainter & painter , int x , int y , int z , QPointF offset )
2022-09-18 03:23:17 +04:00
{
2025-09-15 13:52:54 +03:00
const auto & tinfo = map - > getTile ( int3 ( x , y , z ) ) ;
2024-07-13 18:37:13 +00:00
auto terrainName = tinfo . getTerrain ( ) - > getJsonKey ( ) ;
2022-10-08 23:54:45 +04:00
if ( terrainImages . at ( terrainName ) . size ( ) < = tinfo . terView )
2022-09-18 03:23:17 +04:00
return ;
2025-10-06 20:33:09 +02:00
painter . drawImage ( x * tileSize - offset . x ( ) , y * tileSize - offset . y ( ) , flippedImage ( terrainImages . at ( terrainName ) [ tinfo . terView ] , tinfo . extTileFlags ) ) ;
2022-09-18 03:23:17 +04:00
}
2025-10-06 20:33:09 +02:00
void MapHandler : : drawRoad ( QPainter & painter , int x , int y , int z , QPointF offset )
2022-09-18 03:23:17 +04:00
{
2025-09-15 13:52:54 +03:00
const auto & tinfo = map - > getTile ( int3 ( x , y , z ) ) ;
2022-09-18 03:23:17 +04:00
auto * tinfoUpper = map - > isInTheMap ( int3 ( x , y - 1 , z ) ) ? & map - > getTile ( int3 ( x , y - 1 , z ) ) : nullptr ;
2025-09-15 13:52:54 +03:00
2023-03-05 00:20:47 +04:00
if ( tinfoUpper & & tinfoUpper - > roadType )
2022-09-18 03:23:17 +04:00
{
2024-07-13 18:37:13 +00:00
auto roadName = tinfoUpper - > getRoad ( ) - > getJsonKey ( ) ;
2022-10-08 23:54:45 +04:00
if ( roadImages . at ( roadName ) . size ( ) > tinfoUpper - > roadDir )
2022-09-18 03:23:17 +04:00
{
2025-09-15 13:52:54 +03:00
const QRect source { 0 , tileSize / 2 , tileSize , tileSize / 2 } ;
const ui8 rotationFlags = tinfoUpper - > extTileFlags > > 4 ;
2025-10-06 20:33:09 +02:00
painter . drawImage ( QPoint ( x * tileSize - offset . x ( ) , y * tileSize - offset . y ( ) ) , flippedImage ( roadImages . at ( roadName ) [ tinfoUpper - > roadDir ] , rotationFlags ) , source ) ;
2022-09-18 03:23:17 +04:00
}
}
2025-09-15 13:52:54 +03:00
2023-03-05 00:20:47 +04:00
if ( tinfo . roadType ) //print road from this tile
2022-09-18 03:23:17 +04:00
{
2024-07-13 18:37:13 +00:00
auto roadName = tinfo . getRoad ( ) - > getJsonKey ( ) ;
2022-10-08 23:54:45 +04:00
if ( roadImages . at ( roadName ) . size ( ) > tinfo . roadDir )
2022-09-18 03:23:17 +04:00
{
2025-09-15 13:52:54 +03:00
const QRect source { 0 , 0 , tileSize , tileSize / 2 } ;
const ui8 rotationFlags = tinfo . extTileFlags > > 4 ;
2025-10-06 20:33:09 +02:00
painter . drawImage ( QPoint ( x * tileSize - offset . x ( ) , y * tileSize + tileSize / 2 - offset . y ( ) ) , flippedImage ( roadImages . at ( roadName ) [ tinfo . roadDir ] , rotationFlags ) , source ) ;
2022-09-18 03:23:17 +04:00
}
}
}
2025-10-06 20:33:09 +02:00
void MapHandler : : drawRiver ( QPainter & painter , int x , int y , int z , QPointF offset )
2022-09-18 03:23:17 +04:00
{
2025-09-15 13:52:54 +03:00
const auto & tinfo = map - > getTile ( int3 ( x , y , z ) ) ;
2022-09-18 03:23:17 +04:00
2024-07-13 18:37:13 +00:00
if ( ! tinfo . hasRiver ( ) )
2022-09-18 03:23:17 +04:00
return ;
2025-09-15 13:52:54 +03:00
2022-10-08 23:54:45 +04:00
//TODO: use ui8 instead of string key
2024-07-13 18:37:13 +00:00
auto riverName = tinfo . getRiver ( ) - > getJsonKey ( ) ;
2022-09-18 03:23:17 +04:00
2022-10-08 23:54:45 +04:00
if ( riverImages . at ( riverName ) . size ( ) < = tinfo . riverDir )
2022-09-18 03:23:17 +04:00
return ;
2025-09-15 13:52:54 +03:00
const ui8 rotationFlags = tinfo . extTileFlags > > 2 ;
2025-10-06 20:33:09 +02:00
painter . drawImage ( x * tileSize - offset . x ( ) , y * tileSize - offset . y ( ) , flippedImage ( riverImages . at ( riverName ) [ tinfo . riverDir ] , rotationFlags ) ) ;
2022-09-18 03:23:17 +04:00
}
void setPlayerColor ( QImage * sur , PlayerColor player )
{
if ( player = = PlayerColor : : UNFLAGGABLE )
return ;
if ( sur - > format ( ) = = QImage : : Format_Indexed8 )
{
QRgb color = graphics - > neutralColor ;
if ( player ! = PlayerColor : : NEUTRAL & & player < PlayerColor : : PLAYER_LIMIT )
color = graphics - > playerColors . at ( player . getNum ( ) ) ;
sur - > setColor ( 5 , color ) ;
}
else
logGlobal - > warn ( " Warning, setPlayerColor called on not 8bpp surface! " ) ;
}
2023-10-20 01:25:06 +02:00
std : : shared_ptr < QImage > MapHandler : : getObjectImage ( const CGObjectInstance * obj )
2022-09-18 03:23:17 +04:00
{
2023-10-20 01:25:06 +02:00
if ( ! obj
2025-03-14 17:07:30 +00:00
| | ( obj - > ID = = Obj : : HERO & & dynamic_cast < const CGHeroInstance * > ( obj ) - > isGarrisoned ( ) ) //garrisoned hero
| | ( obj - > ID = = Obj : : BOAT & & dynamic_cast < const CGBoat * > ( obj ) - > getBoardedHero ( ) ) ) //boat with hero (hero graphics is used)
2023-10-20 01:25:06 +02:00
{
return nullptr ;
}
2025-09-15 13:52:54 +03:00
2023-10-20 01:25:06 +02:00
std : : shared_ptr < Animation > animation = graphics - > getAnimation ( obj ) ;
2025-09-15 13:52:54 +03:00
2023-10-20 01:25:06 +02:00
//no animation at all
if ( ! animation )
return nullptr ;
2025-09-15 13:52:54 +03:00
2023-10-20 01:25:06 +02:00
//empty animation
if ( animation - > size ( 0 ) = = 0 )
return nullptr ;
2025-09-15 13:52:54 +03:00
2023-10-20 01:25:06 +02:00
auto image = animation - > getImage ( 0 , obj - > ID = = Obj : : HERO ? 2 : 0 ) ;
if ( ! image )
2022-09-18 03:23:17 +04:00
{
2023-10-20 01:25:06 +02:00
//workaround for prisons
image = animation - > getImage ( 0 , 0 ) ;
}
2025-09-15 13:52:54 +03:00
2023-10-20 01:25:06 +02:00
return image ;
}
std : : set < int3 > MapHandler : : removeObject ( const CGObjectInstance * object )
{
std : : set < int3 > result = tilesCache [ object ] ;
for ( auto & t : result )
{
auto & objects = getObjects ( t ) ;
for ( auto iter = objects . begin ( ) ; iter ! = objects . end ( ) ; + + iter )
2022-09-18 03:23:17 +04:00
{
2023-10-20 01:25:06 +02:00
if ( iter - > obj = = object )
{
objects . erase ( iter ) ;
break ;
}
2022-09-18 03:23:17 +04:00
}
2023-10-20 01:25:06 +02:00
}
2025-09-15 13:52:54 +03:00
2023-10-20 01:25:06 +02:00
tilesCache . erase ( object ) ;
return result ;
}
std : : set < int3 > MapHandler : : addObject ( const CGObjectInstance * object )
{
auto image = getObjectImage ( object ) ;
if ( ! image )
return std : : set < int3 > { } ;
2025-09-15 13:52:54 +03:00
2023-10-20 01:25:06 +02:00
for ( int fx = 0 ; fx < object - > getWidth ( ) ; + + fx )
{
for ( int fy = 0 ; fy < object - > getHeight ( ) ; + + fy )
2022-09-18 03:23:17 +04:00
{
2023-10-20 01:25:06 +02:00
int3 currTile ( object - > pos . x - fx , object - > pos . y - fy , object - > pos . z ) ;
QRect cr ( image - > width ( ) - fx * tileSize - tileSize ,
image - > height ( ) - fy * tileSize - tileSize ,
tileSize ,
tileSize ) ;
2025-09-15 13:52:54 +03:00
2023-10-20 01:25:06 +02:00
if ( map - > isInTheMap ( currTile ) & & // within map
cr . x ( ) + cr . width ( ) > 0 & & // image has data on this tile
cr . y ( ) + cr . height ( ) > 0 )
2022-09-18 03:23:17 +04:00
{
2023-10-20 01:25:06 +02:00
getObjects ( currTile ) . emplace_back ( object , cr ) ;
tilesCache [ object ] . insert ( currTile ) ;
2022-09-18 03:23:17 +04:00
}
}
}
2025-09-15 13:52:54 +03:00
2023-10-20 01:25:06 +02:00
return tilesCache [ object ] ;
}
void MapHandler : : initObjectRects ( )
{
tileObjects . clear ( ) ;
tilesCache . clear ( ) ;
if ( ! map )
return ;
2025-09-15 13:52:54 +03:00
2025-08-01 00:37:32 +02:00
tileObjects . resize ( map - > width * map - > height * map - > mapLevels ) ;
2025-09-15 13:52:54 +03:00
2023-10-20 01:25:06 +02:00
//initializing objects / rects
2025-03-13 19:42:57 +00:00
for ( const auto & elem : map - > objects )
2022-09-18 03:23:17 +04:00
{
2025-03-13 19:42:57 +00:00
addObject ( elem . get ( ) ) ;
2022-09-18 03:23:17 +04:00
}
2025-09-15 13:52:54 +03:00
2023-10-20 01:25:06 +02:00
for ( auto & tt : tileObjects )
stable_sort ( tt . begin ( ) , tt . end ( ) , objectBlitOrderSorter ) ;
2022-09-18 03:23:17 +04:00
}
bool MapHandler : : compareObjectBlitOrder ( const CGObjectInstance * a , const CGObjectInstance * b )
{
if ( ! a )
return true ;
if ( ! b )
return false ;
if ( a - > appearance - > printPriority ! = b - > appearance - > printPriority )
return a - > appearance - > printPriority > b - > appearance - > printPriority ;
2025-09-15 13:52:54 +03:00
2022-09-18 03:23:17 +04:00
if ( a - > pos . y ! = b - > pos . y )
return a - > pos . y < b - > pos . y ;
2025-09-15 13:52:54 +03:00
2022-10-08 22:55:15 +04:00
if ( b - > ID = = Obj : : HERO & & a - > ID ! = Obj : : HERO )
2022-09-18 03:23:17 +04:00
return true ;
2022-10-08 22:55:15 +04:00
if ( b - > ID ! = Obj : : HERO & & a - > ID = = Obj : : HERO )
2022-09-18 03:23:17 +04:00
return false ;
2025-09-15 13:52:54 +03:00
2022-09-18 03:23:17 +04:00
if ( ! a - > isVisitable ( ) & & b - > isVisitable ( ) )
return true ;
if ( ! b - > isVisitable ( ) & & a - > isVisitable ( ) )
return false ;
if ( a - > pos . x < b - > pos . x )
return true ;
return false ;
}
2023-10-20 01:25:06 +02:00
ObjectRect : : ObjectRect ( const CGObjectInstance * obj_ , QRect rect_ )
2025-09-15 13:52:54 +03:00
: obj ( obj_ )
, rect ( rect_ )
2022-09-18 03:23:17 +04:00
{
}
2023-10-20 01:25:06 +02:00
ObjectRect : : ~ ObjectRect ( )
2022-09-18 03:23:17 +04:00
{
}
std : : shared_ptr < QImage > MapHandler : : findFlagBitmap ( const CGHeroInstance * hero , int anim , const PlayerColor color , int group ) const
{
2025-03-26 15:37:26 +00:00
if ( ! hero | | hero - > inBoat ( ) )
2022-09-18 03:23:17 +04:00
return std : : shared_ptr < QImage > ( ) ;
2025-09-15 13:52:54 +03:00
2023-02-19 22:05:19 +02:00
return findFlagBitmapInternal ( graphics - > heroFlagAnimations . at ( color . getNum ( ) ) , anim , group , hero - > moveDir , true ) ;
2022-09-18 03:23:17 +04:00
}
std : : shared_ptr < QImage > MapHandler : : findFlagBitmapInternal ( std : : shared_ptr < Animation > animation , int anim , int group , ui8 dir , bool moving ) const
{
size_t groupSize = animation - > size ( group ) ;
if ( groupSize = = 0 )
return nullptr ;
2025-09-15 13:52:54 +03:00
2022-09-18 03:23:17 +04:00
if ( moving )
return animation - > getImage ( anim % groupSize , group ) ;
else
return animation - > getImage ( ( anim / 4 ) % groupSize , group ) ;
}
2023-10-20 01:25:06 +02:00
MapHandler : : BitmapHolder MapHandler : : findObjectBitmap ( const CGObjectInstance * obj , int anim , int group ) const
2022-09-18 03:23:17 +04:00
{
if ( ! obj )
2023-10-20 01:25:06 +02:00
return MapHandler : : BitmapHolder ( ) ;
2022-09-18 03:23:17 +04:00
// normal object
std : : shared_ptr < Animation > animation = graphics - > getAnimation ( obj ) ;
size_t groupSize = animation - > size ( group ) ;
if ( groupSize = = 0 )
2023-10-20 01:25:06 +02:00
return MapHandler : : BitmapHolder ( ) ;
2025-09-15 13:52:54 +03:00
2022-09-18 03:23:17 +04:00
animation - > playerColored ( obj - > tempOwner ) ;
auto bitmap = animation - > getImage ( anim % groupSize , group ) ;
2025-09-15 13:52:54 +03:00
2022-09-18 03:23:17 +04:00
if ( ! bitmap )
2023-10-20 01:25:06 +02:00
return MapHandler : : BitmapHolder ( ) ;
2022-09-18 03:23:17 +04:00
setPlayerColor ( bitmap . get ( ) , obj - > tempOwner ) ;
2025-09-15 13:52:54 +03:00
2023-10-20 01:25:06 +02:00
return MapHandler : : BitmapHolder ( bitmap ) ;
2022-09-18 03:23:17 +04:00
}
2023-10-20 01:25:06 +02:00
std : : vector < ObjectRect > & MapHandler : : getObjects ( const int3 & tile )
2022-09-18 03:23:17 +04:00
{
2023-10-20 01:25:06 +02:00
return tileObjects [ index ( tile ) ] ;
}
std : : vector < ObjectRect > & MapHandler : : getObjects ( int x , int y , int z )
{
return tileObjects [ index ( x , y , z ) ] ;
2022-09-18 03:23:17 +04:00
}
2025-10-15 23:55:08 +02:00
void MapHandler : : drawObjects ( QPainter & painter , const QRectF & section , int z , std : : set < const CGObjectInstance * > & locked )
2022-09-18 03:23:17 +04:00
{
2023-10-13 05:21:09 +02:00
painter . setRenderHint ( QPainter : : Antialiasing , false ) ;
painter . setRenderHint ( QPainter : : SmoothPixmapTransform , false ) ;
2025-10-15 23:55:08 +02:00
std : : map < int3 , std : : set < const CGObjectInstance * > > objectMap ; //following the natural order of int3 we draw from north-west to south-east, in accordance with H3's perspective
2023-10-13 05:21:09 +02:00
2022-09-18 03:23:17 +04:00
2025-10-15 23:55:08 +02:00
int left = static_cast < int > ( std : : round ( section . left ( ) ) ) / tileSize ;
int right = static_cast < int > ( std : : round ( section . right ( ) ) ) / tileSize ;
int top = static_cast < int > ( std : : round ( section . top ( ) ) ) / tileSize ;
int bottom = static_cast < int > ( std : : round ( section . bottom ( ) ) ) / tileSize ;
2022-09-18 03:23:17 +04:00
2025-10-15 23:55:08 +02:00
for ( int x = left ; x < right ; + + x )
{
for ( int y = top ; y < bottom ; + + y )
2022-09-18 03:23:17 +04:00
{
2025-10-15 23:55:08 +02:00
for ( auto & object : getObjects ( x , y , z ) )
objectMap [ object . obj - > pos ] . insert ( object . obj ) ;
2022-09-18 03:23:17 +04:00
}
}
2025-10-15 23:55:08 +02:00
for ( auto const & objectsOnTile : objectMap )
{
auto tile = objectsOnTile . first ;
auto objects = objectsOnTile . second ;
for ( const CGObjectInstance * object : objects )
drawObjectAt ( painter , object , tile . x , tile . y , section . topLeft ( ) , locked . count ( object ) ) ;
}
2022-09-18 03:23:17 +04:00
}
2025-10-15 23:55:08 +02:00
void MapHandler : : drawObjectAt ( QPainter & painter , const CGObjectInstance * obj , int x , int y , QPointF offset , bool locked )
2022-09-18 03:23:17 +04:00
{
if ( ! obj )
{
logGlobal - > error ( " Stray map object that isn't fading " ) ;
return ;
}
uint8_t animationFrame = 0 ;
auto objData = findObjectBitmap ( obj , animationFrame , obj - > ID = = Obj : : HERO ? 2 : 0 ) ;
if ( obj - > ID = = Obj : : HERO & & obj - > tempOwner . isValidPlayer ( ) )
objData . flagBitmap = findFlagBitmap ( dynamic_cast < const CGHeroInstance * > ( obj ) , 0 , obj - > tempOwner , 4 ) ;
2025-09-15 13:52:54 +03:00
2022-09-18 03:23:17 +04:00
if ( objData . objBitmap )
{
2025-10-15 23:55:08 +02:00
QPoint point ( ( x + 1 ) * tileSize - ( objData . objBitmap - > width ( ) + offset . x ( ) ) , ( y + 1 ) * tileSize - ( objData . objBitmap - > height ( ) + offset . y ( ) ) ) ;
QRect rect ( point , QSize ( objData . objBitmap - > width ( ) , objData . objBitmap - > height ( ) ) ) ;
painter . drawImage ( rect , * objData . objBitmap ) ;
if ( locked )
{
painter . setCompositionMode ( QPainter : : CompositionMode_DestinationIn ) ;
painter . fillRect ( rect , Qt : : Dense4Pattern ) ;
painter . setCompositionMode ( QPainter : : CompositionMode_SourceOver ) ;
}
2025-09-15 13:52:54 +03:00
2022-09-18 03:23:17 +04:00
if ( objData . flagBitmap )
2025-10-15 23:55:08 +02:00
painter . drawImage ( point , * objData . flagBitmap ) ;
2022-09-18 03:23:17 +04:00
}
}
QRgb MapHandler : : getTileColor ( int x , int y , int z )
{
// if object at tile is owned - it will be colored as its owner
for ( auto & object : getObjects ( x , y , z ) )
{
if ( ! object . obj - > getBlockedPos ( ) . count ( int3 ( x , y , z ) ) )
continue ;
2025-09-15 13:52:54 +03:00
2022-09-18 03:23:17 +04:00
PlayerColor player = object . obj - > getOwner ( ) ;
if ( player = = PlayerColor : : NEUTRAL )
return graphics - > neutralColor ;
else
2023-08-27 01:35:38 +03:00
if ( player . isValidPlayer ( ) )
2022-09-18 03:23:17 +04:00
return graphics - > playerColors [ player . getNum ( ) ] ;
}
2025-09-15 13:52:54 +03:00
2022-09-18 03:23:17 +04:00
// else - use terrain color (blocked version or normal)
2025-09-15 13:52:54 +03:00
2022-09-18 03:23:17 +04:00
auto & tile = map - > getTile ( int3 ( x , y , z ) ) ;
2025-09-15 13:52:54 +03:00
2024-07-13 18:37:13 +00:00
auto color = tile . getTerrain ( ) - > minimapUnblocked ;
if ( tile . blocked ( ) & & ( ! tile . visitable ( ) ) )
color = tile . getTerrain ( ) - > minimapBlocked ;
2025-09-15 13:52:54 +03:00
2023-01-30 00:12:43 +02:00
return qRgb ( color . r , color . g , color . b ) ;
2022-09-18 03:23:17 +04:00
}
void MapHandler : : drawMinimapTile ( QPainter & painter , int x , int y , int z )
{
painter . setPen ( getTileColor ( x , y , z ) ) ;
painter . drawPoint ( x , y ) ;
}
2023-10-20 01:25:06 +02:00
std : : set < int3 > MapHandler : : invalidate ( const CGObjectInstance * obj )
2022-09-18 03:23:17 +04:00
{
2023-10-20 01:25:06 +02:00
auto t1 = removeObject ( obj ) ;
auto t2 = addObject ( obj ) ;
t1 . insert ( t2 . begin ( ) , t2 . end ( ) ) ;
2025-09-15 13:52:54 +03:00
2023-10-20 01:25:06 +02:00
for ( auto & tt : t2 )
stable_sort ( tileObjects [ index ( tt ) ] . begin ( ) , tileObjects [ index ( tt ) ] . end ( ) , objectBlitOrderSorter ) ;
2025-09-15 13:52:54 +03:00
2023-10-20 01:25:06 +02:00
return t1 ;
2022-09-18 03:23:17 +04:00
}
void MapHandler : : invalidateObjects ( )
{
2023-10-20 01:25:06 +02:00
initObjectRects ( ) ;
2022-09-18 03:23:17 +04:00
}