New lightweight minimap format, finish #15
This commit is contained in:
		
							parent
							
								
									cf0ecf418d
								
							
						
					
					
						commit
						e81dd31ae3
					
				| 
						 | 
				
			
			@ -530,7 +530,10 @@ function processChannelTabMenu(tab, mousePos, mouseButton)
 | 
			
		|||
    --menu:addOption(tr('Show Server Messages'), function() --[[TODO]] end)
 | 
			
		||||
    menu:addSeparator()
 | 
			
		||||
  end
 | 
			
		||||
  menu:addOption(tr('Clear Messages'), function() clearChannel(consoleTabBar) end)
 | 
			
		||||
 | 
			
		||||
  if consoleTabBar:getCurrentTab() == tab then
 | 
			
		||||
    menu:addOption(tr('Clear Messages'), function() clearChannel(consoleTabBar) end)
 | 
			
		||||
  end
 | 
			
		||||
  --menu:addOption(tr('Save Messages'), function() --[[TODO]] end)
 | 
			
		||||
 | 
			
		||||
  menu:display(mousePos)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -551,9 +551,8 @@ function processMouseAction(menuPosition, mouseButton, autoWalkPos, lookThing, u
 | 
			
		|||
  player:stopAutoWalk()
 | 
			
		||||
 | 
			
		||||
  if autoWalkPos and keyboardModifiers == KeyboardNoModifier and mouseButton == MouseLeftButton then
 | 
			
		||||
    if not player:autoWalk(autoWalkPos) then
 | 
			
		||||
      modules.game_textmessage.displayStatusMessage(tr('There is no way.'))
 | 
			
		||||
    end
 | 
			
		||||
    player.onAutoWalkFail = function() modules.game_textmessage.displayStatusMessage(tr('There is no way.')) end
 | 
			
		||||
    player:autoWalk(autoWalkPos)
 | 
			
		||||
    return true
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,7 @@ navigating = false
 | 
			
		|||
minimapWidget = nil
 | 
			
		||||
minimapButton = nil
 | 
			
		||||
minimapWindow = nil
 | 
			
		||||
 | 
			
		||||
otmm = false
 | 
			
		||||
flagsPanel    = nil
 | 
			
		||||
flagWindow    = nil
 | 
			
		||||
nextFlagId    = 0
 | 
			
		||||
| 
						 | 
				
			
			@ -49,6 +49,7 @@ function init()
 | 
			
		|||
  reset()
 | 
			
		||||
  minimapWindow:setup()
 | 
			
		||||
  loadMapFlags()
 | 
			
		||||
  useOTMM()
 | 
			
		||||
  
 | 
			
		||||
  if g_game.isOnline() then
 | 
			
		||||
    addEvent(function() updateMapFlags() end)
 | 
			
		||||
| 
						 | 
				
			
			@ -263,17 +264,32 @@ end
 | 
			
		|||
 | 
			
		||||
function loadMap()
 | 
			
		||||
  local protocolVersion = g_game.getProtocolVersion()
 | 
			
		||||
  local minimapFile = '/minimap_' .. protocolVersion .. '.otcm'
 | 
			
		||||
  if g_resources.fileExists(minimapFile) then
 | 
			
		||||
    g_map.clean()
 | 
			
		||||
    g_map.loadOtcm(minimapFile)
 | 
			
		||||
  g_map.clean()
 | 
			
		||||
  g_minimap.clean()
 | 
			
		||||
 | 
			
		||||
  if otmm then
 | 
			
		||||
    local minimapFile = '/minimap.otmm'
 | 
			
		||||
    if g_resources.fileExists(minimapFile) then
 | 
			
		||||
      g_minimap.loadOtmm(minimapFile)
 | 
			
		||||
    end
 | 
			
		||||
  else
 | 
			
		||||
    local minimapFile = '/minimap_' .. protocolVersion .. '.otcm'
 | 
			
		||||
    if g_resources.fileExists(minimapFile) then
 | 
			
		||||
      g_map.loadOtcm(minimapFile)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function saveMap()
 | 
			
		||||
  local protocolVersion = g_game.getProtocolVersion()
 | 
			
		||||
  local minimapFile = '/minimap_' .. protocolVersion .. '.otcm'
 | 
			
		||||
  g_map.saveOtcm(minimapFile)
 | 
			
		||||
 | 
			
		||||
  if otmm then
 | 
			
		||||
    local minimapFile = '/minimap.otmm'
 | 
			
		||||
    g_minimap.saveOtmm(minimapFile)
 | 
			
		||||
  else
 | 
			
		||||
    local minimapFile = '/minimap_' .. protocolVersion .. '.otcm'
 | 
			
		||||
    g_map.saveOtcm(minimapFile)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function toggle()
 | 
			
		||||
| 
						 | 
				
			
			@ -286,6 +302,10 @@ function toggle()
 | 
			
		|||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function useOTMM()
 | 
			
		||||
  otmm = true
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function isClickInRange(position, fromPosition, toPosition)
 | 
			
		||||
  return (position.x >= fromPosition.x and position.y >= fromPosition.y and position.x <= toPosition.x and position.y <= toPosition.y)
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -363,11 +363,10 @@ namespace Otc
 | 
			
		|||
    };
 | 
			
		||||
 | 
			
		||||
    enum PathFindFlags {
 | 
			
		||||
        PathFindAllowNullTiles = 1,
 | 
			
		||||
        PathFindAllowNotSeenTiles = 1,
 | 
			
		||||
        PathFindAllowCreatures = 2,
 | 
			
		||||
        PathFindAllowNonPathable = 4,
 | 
			
		||||
        PathFindAllowNonWalkable = 8,
 | 
			
		||||
        PathFindAllowChangeFloor = 16
 | 
			
		||||
        PathFindAllowNonWalkable = 8
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    enum AutomapFlags
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -193,9 +193,11 @@ bool LocalPlayer::autoWalk(const Position& destination)
 | 
			
		|||
            limitedPath.resize(127);
 | 
			
		||||
    } else {
 | 
			
		||||
        // no known path found, try to discover one
 | 
			
		||||
        result = g_map.findPath(m_position, destination, 1000, Otc::PathFindAllowNullTiles);
 | 
			
		||||
        if(std::get<1>(result) != Otc::PathFindResultOk)
 | 
			
		||||
        result = g_map.findPath(m_position, destination, 1000, Otc::PathFindAllowNotSeenTiles);
 | 
			
		||||
        if(std::get<1>(result) != Otc::PathFindResultOk) {
 | 
			
		||||
            callLuaField("onAutoWalkFail");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Position currentPos = m_position;
 | 
			
		||||
        for(auto dir : std::get<0>(result)) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,7 @@
 | 
			
		|||
#include "player.h"
 | 
			
		||||
#include "localplayer.h"
 | 
			
		||||
#include "map.h"
 | 
			
		||||
#include "minimap.h"
 | 
			
		||||
#include "thingtypemanager.h"
 | 
			
		||||
#include "spritemanager.h"
 | 
			
		||||
#include "shadermanager.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -116,7 +117,12 @@ void Client::registerLuaFunctions()
 | 
			
		|||
    g_lua.bindSingletonFunction("g_map", "getSpawnFile", &Map::getSpawnFile, &g_map);
 | 
			
		||||
    g_lua.bindSingletonFunction("g_map", "setSpawnFile", &Map::setSpawnFile, &g_map);
 | 
			
		||||
    g_lua.bindSingletonFunction("g_map", "createTile", &Map::createTile, &g_map);
 | 
			
		||||
    g_lua.bindSingletonFunction("g_map", "getSize", &Map::getSize, &g_map);;
 | 
			
		||||
    g_lua.bindSingletonFunction("g_map", "getSize", &Map::getSize, &g_map);
 | 
			
		||||
 | 
			
		||||
    g_lua.registerSingletonClass("g_minimap");
 | 
			
		||||
    g_lua.bindSingletonFunction("g_minimap", "clean", &Minimap::clean, &g_minimap);
 | 
			
		||||
    g_lua.bindSingletonFunction("g_minimap", "loadOtmm", &Minimap::loadOtmm, &g_minimap);
 | 
			
		||||
    g_lua.bindSingletonFunction("g_minimap", "saveOtmm", &Minimap::saveOtmm, &g_minimap);
 | 
			
		||||
 | 
			
		||||
    g_lua.registerSingletonClass("g_creatures");
 | 
			
		||||
    g_lua.bindSingletonFunction("g_creatures", "getCreatures", &CreatureManager::getCreatures, &g_creatures);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -600,27 +600,39 @@ std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> Map::findPath(const
 | 
			
		|||
                if(i == 0 && j == 0)
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                bool wasSeen = false;
 | 
			
		||||
                bool hasCreature = false;
 | 
			
		||||
                bool isNotWalkable = true;
 | 
			
		||||
                bool isNotPathable = true;
 | 
			
		||||
                int speed = 100;
 | 
			
		||||
 | 
			
		||||
                Position neighborPos = currentNode->pos.translated(i, j);
 | 
			
		||||
                const TilePtr& tile = getTile(neighborPos);
 | 
			
		||||
                if(g_map.isAwareOfPosition(neighborPos)) {
 | 
			
		||||
                    wasSeen = true;
 | 
			
		||||
                    if(const TilePtr& tile = getTile(neighborPos)) {
 | 
			
		||||
                        hasCreature = tile->hasCreature();
 | 
			
		||||
                        isNotWalkable = !tile->isWalkable();
 | 
			
		||||
                        isNotPathable = !tile->isPathable();
 | 
			
		||||
                        speed = tile->getGroundSpeed();
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    const MinimapTile& mtile = g_minimap.getTile(neighborPos);
 | 
			
		||||
                    wasSeen = mtile.hasFlag(MinimapTileWasSeen);
 | 
			
		||||
                    isNotWalkable = mtile.hasFlag(MinimapTileNotWalkable);
 | 
			
		||||
                    isNotPathable = mtile.hasFlag(MinimapTileNotPathable);
 | 
			
		||||
                    speed = mtile.getSpeed();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                float walkFactor = 0;
 | 
			
		||||
                if(neighborPos != goalPos) {
 | 
			
		||||
                    /*
 | 
			
		||||
                      Known Issue with Otc::PathFindAllowNullTiles flag:
 | 
			
		||||
                      If you are above ground floor this will attempt to path over null
 | 
			
		||||
                      tiles, need to rework this for "fly servers" and blank map click,
 | 
			
		||||
                      but it is breaking normal path finding.
 | 
			
		||||
                    */
 | 
			
		||||
                    if(!(flags & Otc::PathFindAllowNullTiles) && (!tile || tile->isEmpty()))
 | 
			
		||||
                    if(!(flags & Otc::PathFindAllowNotSeenTiles) && !wasSeen)
 | 
			
		||||
                        continue;
 | 
			
		||||
                    if(tile) {
 | 
			
		||||
                        if(!(flags & Otc::PathFindAllowCreatures) && tile->hasCreature())
 | 
			
		||||
                    if(wasSeen) {
 | 
			
		||||
                        if(!(flags & Otc::PathFindAllowCreatures) && hasCreature)
 | 
			
		||||
                            continue;
 | 
			
		||||
                        if(!(flags & Otc::PathFindAllowNonPathable) && !tile->isPathable())
 | 
			
		||||
                        if(!(flags & Otc::PathFindAllowNonPathable) && isNotPathable)
 | 
			
		||||
                            continue;
 | 
			
		||||
                        if(!(flags & Otc::PathFindAllowNonWalkable) && !tile->isWalkable())
 | 
			
		||||
                            continue;
 | 
			
		||||
                        if(!(flags & Otc::PathFindAllowChangeFloor) && tile->changesFloor())
 | 
			
		||||
                        if(!(flags & Otc::PathFindAllowNonWalkable) && isNotWalkable)
 | 
			
		||||
                            continue;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -631,8 +643,7 @@ std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> Map::findPath(const
 | 
			
		|||
                else
 | 
			
		||||
                    walkFactor += 1.0f;
 | 
			
		||||
 | 
			
		||||
                int groundSpeed = tile ? tile->getGroundSpeed() : 100;
 | 
			
		||||
                float cost = currentNode->cost + (groundSpeed * walkFactor) / 100.0f;
 | 
			
		||||
                float cost = currentNode->cost + (speed * walkFactor) / 100.0f;
 | 
			
		||||
 | 
			
		||||
                Node *neighborNode;
 | 
			
		||||
                if(nodes.find(neighborPos) == nodes.end()) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -382,7 +382,6 @@ bool Map::loadOtcm(const std::string& fileName)
 | 
			
		|||
        if(!fin)
 | 
			
		||||
            stdext::throw_exception("unable to open file");
 | 
			
		||||
 | 
			
		||||
        stdext::timer loadTimer;
 | 
			
		||||
        fin->cache();
 | 
			
		||||
 | 
			
		||||
        uint32 signature = fin->getU32();
 | 
			
		||||
| 
						 | 
				
			
			@ -446,8 +445,6 @@ bool Map::loadOtcm(const std::string& fileName)
 | 
			
		|||
 | 
			
		||||
        fin->close();
 | 
			
		||||
 | 
			
		||||
        // well, this is really slow
 | 
			
		||||
        g_logger.debug(stdext::format("Otcm load time: %.2f seconds", loadTimer.elapsed_seconds()));
 | 
			
		||||
        return true;
 | 
			
		||||
    } catch(stdext::exception& e) {
 | 
			
		||||
        g_logger.error(stdext::format("failed to load OTCM map: %s", e.what()));
 | 
			
		||||
| 
						 | 
				
			
			@ -519,7 +516,6 @@ void Map::saveOtcm(const std::string& fileName)
 | 
			
		|||
        fin->flush();
 | 
			
		||||
 | 
			
		||||
        fin->close();
 | 
			
		||||
        //g_logger.debug(stdext::format("Otcm save time: %.2f seconds", saveTimer.elapsed_seconds()));
 | 
			
		||||
    } catch(stdext::exception& e) {
 | 
			
		||||
        g_logger.error(stdext::format("failed to save OTCM map: %s", e.what()));
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,40 +27,17 @@
 | 
			
		|||
#include <framework/graphics/texture.h>
 | 
			
		||||
#include <framework/graphics/painter.h>
 | 
			
		||||
#include <framework/graphics/framebuffermanager.h>
 | 
			
		||||
#include <framework/core/resourcemanager.h>
 | 
			
		||||
#include <framework/core/filestream.h>
 | 
			
		||||
#include <boost/concept_check.hpp>
 | 
			
		||||
#include <zlib.h>
 | 
			
		||||
 | 
			
		||||
Minimap g_minimap;
 | 
			
		||||
 | 
			
		||||
void MinimapBlock::updateImage()
 | 
			
		||||
{
 | 
			
		||||
    if(!m_image)
 | 
			
		||||
        m_image = ImagePtr(new Image(Size(MMBLOCK_SIZE, MMBLOCK_SIZE)));
 | 
			
		||||
    else
 | 
			
		||||
        m_image->resize(Size(MMBLOCK_SIZE, MMBLOCK_SIZE));
 | 
			
		||||
 | 
			
		||||
    for(int x=0;x<MMBLOCK_SIZE;++x)
 | 
			
		||||
        for(int y=0;y<MMBLOCK_SIZE;++y)
 | 
			
		||||
            m_image->setPixel(x, y, Color::from8bit(getTile(x, y).color).rgba());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MinimapBlock::updateTexture()
 | 
			
		||||
{
 | 
			
		||||
    if(!m_image)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if(!m_texture) {
 | 
			
		||||
        m_texture = TexturePtr(new Texture(m_image, true));
 | 
			
		||||
    } else {
 | 
			
		||||
        m_texture->uploadPixels(m_image, true);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MinimapBlock::clean()
 | 
			
		||||
{
 | 
			
		||||
    m_tiles.fill(MinimapTile());
 | 
			
		||||
    m_image.reset();
 | 
			
		||||
    m_texture.reset();
 | 
			
		||||
    m_shouldDraw = false;
 | 
			
		||||
    m_mustUpdate = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -69,19 +46,32 @@ void MinimapBlock::update()
 | 
			
		|||
    if(!m_mustUpdate)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if(m_shouldDraw) {
 | 
			
		||||
        updateImage();
 | 
			
		||||
        updateTexture();
 | 
			
		||||
    ImagePtr image(new Image(Size(MMBLOCK_SIZE, MMBLOCK_SIZE)));
 | 
			
		||||
 | 
			
		||||
    bool shouldDraw = false;
 | 
			
		||||
    for(int x=0;x<MMBLOCK_SIZE;++x) {
 | 
			
		||||
        for(int y=0;y<MMBLOCK_SIZE;++y) {
 | 
			
		||||
            uint32 col = Color::from8bit(getTile(x, y).color).rgba();
 | 
			
		||||
            image->setPixel(x, y, col);
 | 
			
		||||
            if(col != 0)
 | 
			
		||||
                shouldDraw = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(shouldDraw) {
 | 
			
		||||
        if(!m_texture) {
 | 
			
		||||
            m_texture = TexturePtr(new Texture(image, true));
 | 
			
		||||
        } else {
 | 
			
		||||
            m_texture->uploadPixels(image, true);
 | 
			
		||||
        }
 | 
			
		||||
    } else
 | 
			
		||||
        m_texture.reset();
 | 
			
		||||
 | 
			
		||||
    m_mustUpdate = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MinimapBlock::updateTile(int x, int y, const MinimapTile& tile)
 | 
			
		||||
{
 | 
			
		||||
    if(tile.color != 0)
 | 
			
		||||
        m_shouldDraw = true;
 | 
			
		||||
 | 
			
		||||
    if(m_tiles[getTileIndex(x,y)].color != tile.color)
 | 
			
		||||
        m_mustUpdate = true;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -90,7 +80,6 @@ void MinimapBlock::updateTile(int x, int y, const MinimapTile& tile)
 | 
			
		|||
 | 
			
		||||
void Minimap::init()
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Minimap::terminate()
 | 
			
		||||
| 
						 | 
				
			
			@ -141,13 +130,17 @@ void Minimap::draw(const Rect& screenRect, const Position& mapCenter, float scal
 | 
			
		|||
            if(x < 0 || x >= 65536 - MMBLOCK_SIZE)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            Position blockPos(x, y, mapCenter.z);
 | 
			
		||||
            if(!hasBlock(blockPos))
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            MinimapBlock& block = getBlock(Position(x, y, mapCenter.z));
 | 
			
		||||
            block.update();
 | 
			
		||||
 | 
			
		||||
            if(block.shouldDraw()) {
 | 
			
		||||
            const TexturePtr& tex = block.getTexture();
 | 
			
		||||
            if(tex) {
 | 
			
		||||
                Rect src(0, 0, MMBLOCK_SIZE, MMBLOCK_SIZE);
 | 
			
		||||
                Rect dest(Point(xs,ys), src.size() * scale);
 | 
			
		||||
                const TexturePtr& tex = block.getTexture();
 | 
			
		||||
 | 
			
		||||
                tex->setSmooth(scale < 1.0f);
 | 
			
		||||
                g_painter->drawTexturedRect(dest, tex, src);
 | 
			
		||||
| 
						 | 
				
			
			@ -186,36 +179,151 @@ Position Minimap::getPosition(const Point& point, const Rect& screenRect, const
 | 
			
		|||
 | 
			
		||||
void Minimap::updateTile(const Position& pos, const TilePtr& tile)
 | 
			
		||||
{
 | 
			
		||||
    MinimapBlock& block = getBlock(pos);
 | 
			
		||||
    Point offsetPos = getBlockOffset(Point(pos.x, pos.y));
 | 
			
		||||
 | 
			
		||||
    MinimapTile minimapTile;
 | 
			
		||||
    if(tile) {
 | 
			
		||||
        minimapTile.color = tile->getMinimapColorByte();
 | 
			
		||||
        if(tile->isWalkable())
 | 
			
		||||
            minimapTile.flags |= MinimapTileWalkable;
 | 
			
		||||
        if(tile->isPathable())
 | 
			
		||||
            minimapTile.flags |= MinimapTilePathable;
 | 
			
		||||
        if(tile->changesFloor())
 | 
			
		||||
            minimapTile.flags |= MinimapTileChangesFloor;
 | 
			
		||||
        minimapTile.flags |= MinimapTileWasSeen;
 | 
			
		||||
        if(!tile->isWalkable(true))
 | 
			
		||||
            minimapTile.flags |= MinimapTileNotWalkable;
 | 
			
		||||
        if(!tile->isPathable())
 | 
			
		||||
            minimapTile.flags |= MinimapTileNotPathable;
 | 
			
		||||
        minimapTile.speed = std::min((int)std::ceil(tile->getGroundSpeed() / 10.0f), 255);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    block.updateTile(pos.x - offsetPos.x, pos.y - offsetPos.y, minimapTile);
 | 
			
		||||
    if(minimapTile != MinimapTile()) {
 | 
			
		||||
        MinimapBlock& block = getBlock(pos);
 | 
			
		||||
        Point offsetPos = getBlockOffset(Point(pos.x, pos.y));
 | 
			
		||||
        block.updateTile(pos.x - offsetPos.x, pos.y - offsetPos.y, minimapTile);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Minimap::checkTileProperty(const Position& pos, int flags)
 | 
			
		||||
const MinimapTile& Minimap::getTile(const Position& pos)
 | 
			
		||||
{
 | 
			
		||||
    MinimapBlock& block = getBlock(pos);
 | 
			
		||||
    Point offsetPos = getBlockOffset(Point(pos.x, pos.y));
 | 
			
		||||
    return block.getTile(pos.x - offsetPos.x, pos.y - offsetPos.y).flags & flags;
 | 
			
		||||
    static MinimapTile nulltile;
 | 
			
		||||
    if(pos.z <= Otc::MAX_Z && hasBlock(pos)) {
 | 
			
		||||
        MinimapBlock& block = getBlock(pos);
 | 
			
		||||
        Point offsetPos = getBlockOffset(Point(pos.x, pos.y));
 | 
			
		||||
        return block.getTile(pos.x - offsetPos.x, pos.y - offsetPos.y);
 | 
			
		||||
    }
 | 
			
		||||
    return nulltile;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Minimap::loadOtmm(const std::string& fileName)
 | 
			
		||||
bool Minimap::loadOtmm(const std::string& fileName)
 | 
			
		||||
{
 | 
			
		||||
    try {
 | 
			
		||||
        FileStreamPtr fin = g_resources.openFile(fileName);
 | 
			
		||||
        if(!fin)
 | 
			
		||||
            stdext::throw_exception("unable to open file");
 | 
			
		||||
 | 
			
		||||
        fin->cache();
 | 
			
		||||
 | 
			
		||||
        uint32 signature = fin->getU32();
 | 
			
		||||
        if(signature != OTMM_SIGNATURE)
 | 
			
		||||
            stdext::throw_exception("invalid OTMM file");
 | 
			
		||||
 | 
			
		||||
        uint16 start = fin->getU16();
 | 
			
		||||
        uint16 version = fin->getU16();
 | 
			
		||||
        fin->getU32(); // flags
 | 
			
		||||
 | 
			
		||||
        switch(version) {
 | 
			
		||||
            case 1: {
 | 
			
		||||
                fin->getString(); // description
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            default:
 | 
			
		||||
                stdext::throw_exception("OTMM version not supported");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fin->seek(start);
 | 
			
		||||
 | 
			
		||||
        uint blockSize = MMBLOCK_SIZE * MMBLOCK_SIZE * sizeof(MinimapTile);
 | 
			
		||||
        std::vector<uchar> compressBuffer(compressBound(blockSize));
 | 
			
		||||
 | 
			
		||||
        while(true) {
 | 
			
		||||
            Position pos;
 | 
			
		||||
            pos.x = fin->getU16();
 | 
			
		||||
            pos.y = fin->getU16();
 | 
			
		||||
            pos.z = fin->getU8();
 | 
			
		||||
 | 
			
		||||
            // end of file
 | 
			
		||||
            if(!pos.isValid())
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            MinimapBlock& block = getBlock(pos);
 | 
			
		||||
            ulong len = fin->getU16();
 | 
			
		||||
            ulong destLen = blockSize;
 | 
			
		||||
            fin->read(compressBuffer.data(), len);
 | 
			
		||||
            int ret = uncompress((uchar*)&block.getTiles(), &destLen, compressBuffer.data(), len);
 | 
			
		||||
            assert(ret == Z_OK);
 | 
			
		||||
            assert(destLen == blockSize);
 | 
			
		||||
            block.mustUpdate();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fin->close();
 | 
			
		||||
        return true;
 | 
			
		||||
    } catch(stdext::exception& e) {
 | 
			
		||||
        g_logger.error(stdext::format("failed to load OTMM minimap: %s", e.what()));
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Minimap::saveOtmm(const std::string& fileName)
 | 
			
		||||
{
 | 
			
		||||
    try {
 | 
			
		||||
        stdext::timer saveTimer;
 | 
			
		||||
 | 
			
		||||
        FileStreamPtr fin = g_resources.createFile(fileName);
 | 
			
		||||
        fin->cache();
 | 
			
		||||
 | 
			
		||||
        //TODO: compression flag with zlib
 | 
			
		||||
        uint32 flags = 0;
 | 
			
		||||
 | 
			
		||||
        // header
 | 
			
		||||
        fin->addU32(OTMM_SIGNATURE);
 | 
			
		||||
        fin->addU16(0); // data start, will be overwritten later
 | 
			
		||||
        fin->addU16(OTMM_VERSION);
 | 
			
		||||
        fin->addU32(flags);
 | 
			
		||||
 | 
			
		||||
        // version 1 header
 | 
			
		||||
        fin->addString("OTMM 1.0"); // description
 | 
			
		||||
 | 
			
		||||
        // go back and rewrite where the map data starts
 | 
			
		||||
        uint32 start = fin->tell();
 | 
			
		||||
        fin->seek(4);
 | 
			
		||||
        fin->addU16(start);
 | 
			
		||||
        fin->seek(start);
 | 
			
		||||
 | 
			
		||||
        uint blockSize = MMBLOCK_SIZE * MMBLOCK_SIZE * sizeof(MinimapTile);
 | 
			
		||||
        std::vector<uchar> compressBuffer(compressBound(blockSize));
 | 
			
		||||
        const int COMPRESS_LEVEL = 3;
 | 
			
		||||
 | 
			
		||||
        for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) {
 | 
			
		||||
            for(auto& it : m_tileBlocks[z]) {
 | 
			
		||||
                int index = it.first;
 | 
			
		||||
                MinimapBlock& block = it.second;
 | 
			
		||||
                Position pos = getIndexPosition(index, z);
 | 
			
		||||
                fin->addU16(pos.x);
 | 
			
		||||
                fin->addU16(pos.y);
 | 
			
		||||
                fin->addU8(pos.z);
 | 
			
		||||
 | 
			
		||||
                ulong len = blockSize;
 | 
			
		||||
                int ret = compress2(compressBuffer.data(), &len, (uchar*)&block.getTiles(), blockSize, COMPRESS_LEVEL);
 | 
			
		||||
                assert(ret == Z_OK);
 | 
			
		||||
                fin->addU16(len);
 | 
			
		||||
                fin->write(compressBuffer.data(), len);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // end of file
 | 
			
		||||
        Position invalidPos;
 | 
			
		||||
        fin->addU16(invalidPos.x);
 | 
			
		||||
        fin->addU16(invalidPos.y);
 | 
			
		||||
        fin->addU8(invalidPos.z);
 | 
			
		||||
 | 
			
		||||
        fin->flush();
 | 
			
		||||
 | 
			
		||||
        fin->close();
 | 
			
		||||
    } catch(stdext::exception& e) {
 | 
			
		||||
        g_logger.error(stdext::format("failed to save OTMM minimap: %s", e.what()));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,31 +28,33 @@
 | 
			
		|||
#include <framework/graphics/declarations.h>
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    MMBLOCK_SIZE = 64
 | 
			
		||||
    MMBLOCK_SIZE = 64,
 | 
			
		||||
    OTMM_SIGNATURE = 0x4D4d544F,
 | 
			
		||||
    OTMM_VERSION = 1
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum MinimapTileFlags {
 | 
			
		||||
    MinimapTilePathable = 1,
 | 
			
		||||
    MinimapTileWalkable = 2,
 | 
			
		||||
    MinimapTileChangesFloor = 4
 | 
			
		||||
    MinimapTileWasSeen = 1,
 | 
			
		||||
    MinimapTileNotPathable = 2,
 | 
			
		||||
    MinimapTileNotWalkable = 4
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#pragma pack(push,1) // disable memory alignment
 | 
			
		||||
struct MinimapTile
 | 
			
		||||
{
 | 
			
		||||
    MinimapTile() : flags(0), color(0) { }
 | 
			
		||||
    MinimapTile() : flags(0), color(0), speed(100) { }
 | 
			
		||||
    uint8 flags;
 | 
			
		||||
    uint8 color;
 | 
			
		||||
 | 
			
		||||
    bool operator==(const MinimapTile& other) { return color == other.color && flags == other.flags; }
 | 
			
		||||
    uint8 speed;
 | 
			
		||||
    bool hasFlag(MinimapTileFlags flag) const { return flags & flag; }
 | 
			
		||||
    int getSpeed() const { return speed * 10; }
 | 
			
		||||
    bool operator==(const MinimapTile& other) const { return color == other.color && flags == other.flags && speed == other.speed; }
 | 
			
		||||
    bool operator!=(const MinimapTile& other) const { return !(*this == other); }
 | 
			
		||||
};
 | 
			
		||||
#pragma pack(pop)
 | 
			
		||||
 | 
			
		||||
class MinimapBlock
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    void updateImage();
 | 
			
		||||
    void updateTexture();
 | 
			
		||||
    void clean();
 | 
			
		||||
    void update();
 | 
			
		||||
    void updateTile(int x, int y, const MinimapTile& tile);
 | 
			
		||||
| 
						 | 
				
			
			@ -60,17 +62,16 @@ public:
 | 
			
		|||
    void resetTile(int x, int y) { m_tiles[getTileIndex(x,y)] = MinimapTile(); }
 | 
			
		||||
    uint getTileIndex(int x, int y) { return ((y % MMBLOCK_SIZE) * MMBLOCK_SIZE) + (x % MMBLOCK_SIZE); }
 | 
			
		||||
    const TexturePtr& getTexture() { return m_texture; }
 | 
			
		||||
    std::array<MinimapTile, MMBLOCK_SIZE *MMBLOCK_SIZE> getTiles() { return m_tiles; }
 | 
			
		||||
    bool shouldDraw() { return m_shouldDraw; }
 | 
			
		||||
 | 
			
		||||
    std::array<MinimapTile, MMBLOCK_SIZE *MMBLOCK_SIZE>& getTiles() { return m_tiles; }
 | 
			
		||||
    void mustUpdate() { m_mustUpdate = true; }
 | 
			
		||||
private:
 | 
			
		||||
    ImagePtr m_image;
 | 
			
		||||
    TexturePtr m_texture;
 | 
			
		||||
    stdext::boolean<false> m_shouldDraw;
 | 
			
		||||
    std::array<MinimapTile, MMBLOCK_SIZE *MMBLOCK_SIZE> m_tiles;
 | 
			
		||||
    stdext::boolean<true> m_mustUpdate;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#pragma pack(pop)
 | 
			
		||||
 | 
			
		||||
class Minimap
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -84,15 +85,18 @@ public:
 | 
			
		|||
    Position getPosition(const Point& point, const Rect& screenRect, const Position& mapCenter, float scale);
 | 
			
		||||
 | 
			
		||||
    void updateTile(const Position& pos, const TilePtr& tile);
 | 
			
		||||
    bool checkTileProperty(const Position& pos, int flags);
 | 
			
		||||
    const MinimapTile& getTile(const Position& pos);
 | 
			
		||||
 | 
			
		||||
    void loadOtmm(const std::string& fileName);
 | 
			
		||||
    bool loadOtmm(const std::string& fileName);
 | 
			
		||||
    void saveOtmm(const std::string& fileName);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool hasBlock(const Position& pos) { return m_tileBlocks[pos.z].find(getBlockIndex(pos)) != m_tileBlocks[pos.z].end(); }
 | 
			
		||||
    MinimapBlock& getBlock(const Position& pos) { return m_tileBlocks[pos.z][getBlockIndex(pos)]; }
 | 
			
		||||
    Point getBlockOffset(const Point& pos) { return Point(pos.x - pos.x % MMBLOCK_SIZE,
 | 
			
		||||
                                                          pos.y - pos.y % MMBLOCK_SIZE); }
 | 
			
		||||
    Position getIndexPosition(int index, int z) { return Position((index % (65536 / MMBLOCK_SIZE))*MMBLOCK_SIZE,
 | 
			
		||||
                                                                  (index / (65536 / MMBLOCK_SIZE))*MMBLOCK_SIZE, z); }
 | 
			
		||||
    uint getBlockIndex(const Position& pos) { return ((pos.y / MMBLOCK_SIZE) * (65536 / MMBLOCK_SIZE)) + (pos.x / MMBLOCK_SIZE); }
 | 
			
		||||
    std::unordered_map<uint, MinimapBlock> m_tileBlocks[Otc::MAX_Z+1];
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -563,7 +563,6 @@ void ProtocolGame::sendCloseRuleViolation(const std::string& reporter)
 | 
			
		|||
    OutputMessagePtr msg(new OutputMessage);
 | 
			
		||||
    msg->addU8(Proto::ClientCloseRuleViolation);
 | 
			
		||||
    msg->addString(reporter);
 | 
			
		||||
    dump << "ProtocolGame::sendCloseRuleViolation" << reporter;
 | 
			
		||||
    send(msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -571,7 +570,6 @@ void ProtocolGame::sendCancelRuleViolation()
 | 
			
		|||
{
 | 
			
		||||
    OutputMessagePtr msg(new OutputMessage);
 | 
			
		||||
    msg->addU8(Proto::ClientCancelRuleViolation);
 | 
			
		||||
    dump << "ProtocolGame::sendCancelRuleViolation";
 | 
			
		||||
    send(msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,7 +72,6 @@ bool ThingTypeManager::loadDat(std::string file)
 | 
			
		|||
 | 
			
		||||
        m_datSignature = fin->getU32();
 | 
			
		||||
 | 
			
		||||
        int numThings[ThingLastCategory];
 | 
			
		||||
        for(int category = 0; category < ThingLastCategory; ++category) {
 | 
			
		||||
            int count = fin->getU16() + 1;
 | 
			
		||||
            m_thingTypes[category].clear();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -476,7 +476,7 @@ ThingPtr Tile::getTopMultiUseThing()
 | 
			
		|||
    return m_things[0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Tile::isWalkable()
 | 
			
		||||
bool Tile::isWalkable(bool ignoreCreatures)
 | 
			
		||||
{
 | 
			
		||||
    if(!getGround())
 | 
			
		||||
        return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -485,24 +485,17 @@ bool Tile::isWalkable()
 | 
			
		|||
        if(thing->isNotWalkable())
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if(thing->isCreature()) {
 | 
			
		||||
            CreaturePtr creature = thing->static_self_cast<Creature>();
 | 
			
		||||
            if(!creature->isPassable() && creature->canBeSeen())
 | 
			
		||||
                return false;
 | 
			
		||||
        if(!ignoreCreatures) {
 | 
			
		||||
            if(thing->isCreature()) {
 | 
			
		||||
                CreaturePtr creature = thing->static_self_cast<Creature>();
 | 
			
		||||
                if(!creature->isPassable() && creature->canBeSeen())
 | 
			
		||||
                    return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Tile::changesFloor()
 | 
			
		||||
{
 | 
			
		||||
    for(const ThingPtr& thing : m_things) {
 | 
			
		||||
        if(thing->isTranslucent() || (thing->isOnBottom() && thing->hasElevation()))
 | 
			
		||||
            return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Tile::isPathable()
 | 
			
		||||
{
 | 
			
		||||
    for(const ThingPtr& thing : m_things) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,8 +94,7 @@ public:
 | 
			
		|||
    uint8 getMinimapColorByte();
 | 
			
		||||
    int getThingCount() { return m_things.size() + m_effects.size(); }
 | 
			
		||||
    bool isPathable();
 | 
			
		||||
    bool isWalkable();
 | 
			
		||||
    bool changesFloor();
 | 
			
		||||
    bool isWalkable(bool ignoreCreatures = false);
 | 
			
		||||
    bool isFullGround();
 | 
			
		||||
    bool isFullyOpaque();
 | 
			
		||||
    bool isSingleDimension();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue