diff --git a/src/otclient/core/map.cpp b/src/otclient/core/map.cpp index ee098529..04e7f12d 100644 --- a/src/otclient/core/map.cpp +++ b/src/otclient/core/map.cpp @@ -24,6 +24,7 @@ #include "game.h" #include "localplayer.h" #include "tile.h" +#include "item.h" #include #include @@ -37,29 +38,27 @@ void Map::draw(const Rect& rect) g_graphics.bindColor(Fw::white); m_framebuffer->bind(); + // draw offsets LocalPlayerPtr localPlayer = g_game.getLocalPlayer(); int walkOffsetX = localPlayer->getWalkOffsetX(); int walkOffsetY = localPlayer->getWalkOffsetY(); - int maxFloor = getMaxVisibleFloor(); - for(int z = MAX_Z-1; z >= maxFloor; --z) { - if(z < maxFloor) - continue; - - int zdif = m_centralPosition.z - z; - for(int y = 0; y < MAP_SIZE_Y; ++y) { - for(int x = 0; x < MAP_SIZE_X; ++x) { - Position tilePos(m_centralPosition.x + (x - PLAYER_OFFSET_X), m_centralPosition.y + (y - PLAYER_OFFSET_Y), m_centralPosition.z); - tilePos.coveredUp(m_centralPosition.z - z); - if(const TilePtr& tile = m_tiles[tilePos]) { - // skip tiles that are behind another tile - if(z > maxFloor && isCompletlyCovered(tilePos, maxFloor)) - continue; - - int x = (7 + (tile->getPosition().x - m_centralPosition.x) - zdif) * NUM_TILE_PIXELS; - int y = (5 + (tile->getPosition().y - m_centralPosition.y) - zdif) * NUM_TILE_PIXELS; - tile->draw(x - walkOffsetX, y - walkOffsetY); - } + // draw from bottom floors to top floors + int firstFloor = getFirstVisibleFloor(); + const int lastFloor = MAX_Z-1; + for(int iz = lastFloor; iz >= firstFloor; --iz) { + // draw tiles in linus pauling's rule order + const int numDiagonals = MAP_SIZE_X + MAP_SIZE_Y - 1; + for(int diagonal = 0; diagonal < numDiagonals; ++diagonal) { + // loop through / diagonal tiles + for(int ix = std::min(diagonal, MAP_SIZE_X - 1), iy = std::max(diagonal - MAP_SIZE_X, 0); ix >= 0 && iy < MAP_SIZE_Y; --ix, ++iy) { + // position on current floor + Position tilePos(m_centralPosition.x + (ix - PLAYER_OFFSET_X), m_centralPosition.y + (iy - PLAYER_OFFSET_Y), m_centralPosition.z); + // adjust tilePos to the wanted floor + tilePos.perspectiveUp(m_centralPosition.z - iz); + // TODO: skip tiles that are behind another tile + if(const TilePtr& tile = m_tiles[tilePos]) + tile->draw(tilePos.to2D(m_centralPosition) - Point(walkOffsetX, walkOffsetY)); } } } @@ -93,7 +92,7 @@ void Map::draw(const Rect& rect) y += creature->getWalkOffsetY() - walkOffsetY; } - creature->drawInformation(rect.x() + x*horizontalStretchFactor, rect.y() + y*verticalStretchFactor, isCovered(tilePos, maxFloor)); + creature->drawInformation(rect.x() + x*horizontalStretchFactor, rect.y() + y*verticalStretchFactor, isCovered(tilePos, firstFloor)); } } } @@ -105,51 +104,62 @@ void Map::clean() m_tiles.clear(); } -int Map::getMaxVisibleFloor() +int Map::getFirstVisibleFloor() { - Position tilePos = m_centralPosition; - tilePos.up(); - TilePtr tile = m_tiles[tilePos]; - if(tile) - return m_centralPosition.z; - - tilePos = Position(m_centralPosition); - while(tilePos.z >= 0) { - tilePos.coveredUp(); - tile = m_tiles[tilePos]; - if(tile) - return tilePos.z + 1; - } - /* - int maxZ = MAP_SIZE_Z - 1; - int currentZ = m_centralPosition.z; - while(maxZ > currentZ) { - TilePtr tile = m_tiles[tilePos]; - if(tilç - maxZ--; - }; - - for(int x = PLAYER_OFFSET_X-1; x <= PLAYER_OFFSET_X+1; ++x) { - for(int y = PLAYER_OFFSET_Y-1; y <= PLAYER_OFFSET_Y+1; ++y) { - if(x == PLAYER_OFFSET_X && y == PLAYER_OFFSET_Y) - continue; - for(int z = currentZ + 1; z < + int firstFloor = 0; + for(int ix = -1; ix <= 1 && firstFloor < m_centralPosition.z; ++ix) { + for(int iy = -1; iy <= 1 && firstFloor < m_centralPosition.z; ++iy) { + Position currentPos(m_centralPosition.x + ix, m_centralPosition.y + iy, m_centralPosition.z); + if((ix == 0 && iy == 0) || isLookPossible(currentPos)) { + Position upperPos = currentPos; + Position perspectivePos = currentPos; + perspectivePos.perspectiveUp(); + upperPos.up(); + while(upperPos.z >= firstFloor) { + if(TilePtr tile = m_tiles[upperPos]) { + if(ThingPtr firstThing = tile->getThing(0)) { + const ThingType type = firstThing->getType(); + if((type.isGround || type.isOnBottom) && !type.isDontHide) { + firstFloor = upperPos.z + 1; + break; + } + } + } + if(TilePtr tile = m_tiles[perspectivePos]) { + if(ThingPtr firstThing = tile->getThing(0)) { + const ThingType type = firstThing->getType(); + if((type.isGround || type.isOnBottom) && !type.isDontHide) { + firstFloor = perspectivePos.z + 1; + break; + } + } + } + perspectivePos.perspectiveUp(); + upperPos.up(); + } + } } } - */ + return firstFloor; +} - return 0; +bool Map::isLookPossible(const Position& pos) +{ + TilePtr tile = m_tiles[pos]; + if(tile) + return tile->isLookPossible(); + return true; } bool Map::isCovered(const Position& pos, int maxFloor) { Position tilePos = pos; - tilePos.coveredUp(); + tilePos.perspectiveUp(); while(tilePos.z >= maxFloor) { TilePtr tile = m_tiles[tilePos]; - if(tile) + if(tile && tile->isFullGround()) return true; - tilePos.coveredUp(); + tilePos.perspectiveUp(); } return false; } @@ -157,7 +167,7 @@ bool Map::isCovered(const Position& pos, int maxFloor) bool Map::isCompletlyCovered(const Position& pos, int maxFloor) { Position tilePos = pos; - tilePos.coveredUp(); + tilePos.perspectiveUp(); while(tilePos.z >= maxFloor) { bool covered = true; for(int x=0;x<2;++x) { @@ -171,7 +181,7 @@ bool Map::isCompletlyCovered(const Position& pos, int maxFloor) } if(covered) return true; - tilePos.coveredUp(); + tilePos.perspectiveUp(); } return false; } diff --git a/src/otclient/core/map.h b/src/otclient/core/map.h index f3cbd680..0117c14f 100644 --- a/src/otclient/core/map.h +++ b/src/otclient/core/map.h @@ -44,7 +44,8 @@ public: void draw(const Rect& rect); void clean(); - int getMaxVisibleFloor(); + int getFirstVisibleFloor(); + bool isLookPossible(const Position& pos); bool isCovered(const Position& pos, int maxFloor); bool isCompletlyCovered(const Position& pos, int maxFloor); diff --git a/src/otclient/core/thingstype.cpp b/src/otclient/core/thingstype.cpp index 6df14882..2670bcd6 100644 --- a/src/otclient/core/thingstype.cpp +++ b/src/otclient/core/thingstype.cpp @@ -129,7 +129,7 @@ void ThingsType::parseThingType(std::stringstream& fin, ThingType& thingType) thingType.isNotMoveable = true; break; case Otc::DatBlockProjectile: // Blocks missiles (walls, magic wall etc) - thingType.isNotProjectable = true; + thingType.isUnsight = true; break; case Otc::DatBlockPathFind: // Blocks pathfind algorithms (monsters) thingType.isNotPathable = true; diff --git a/src/otclient/core/thingtype.h b/src/otclient/core/thingtype.h index 3d429c6a..10b58dc7 100644 --- a/src/otclient/core/thingtype.h +++ b/src/otclient/core/thingtype.h @@ -50,7 +50,7 @@ struct ThingType isSplash = false; isNotWalkable = false; isNotMoveable = false; - isNotProjectable = false; + isUnsight = false; isNotPathable = false; isPickupable = false; isHangable = false; @@ -101,7 +101,7 @@ struct ThingType bool isSplash; bool isNotWalkable; bool isNotMoveable; - bool isNotProjectable; + bool isUnsight; bool isNotPathable; bool isPickupable; bool isHangable; diff --git a/src/otclient/core/tile.cpp b/src/otclient/core/tile.cpp index 32bcf888..2d3d1eda 100644 --- a/src/otclient/core/tile.cpp +++ b/src/otclient/core/tile.cpp @@ -35,7 +35,7 @@ Tile::Tile(const Position& position) m_position = position; } -void Tile::draw(int x, int y) +void Tile::draw(const Point& p) { m_drawElevation = 0; @@ -44,7 +44,7 @@ void Tile::draw(int x, int y) const ThingType& type = thing->getType(); if(!type.isGround && !type.isGroundClip && !type.isOnBottom) break; - thing->draw(x - m_drawElevation, y - m_drawElevation); + thing->draw(p.x - m_drawElevation, p.y - m_drawElevation); m_drawElevation += type.elevation; if(m_drawElevation > MAX_DRAW_ELEVATION) m_drawElevation = MAX_DRAW_ELEVATION; @@ -56,7 +56,7 @@ void Tile::draw(int x, int y) const ThingType& type = thing->getType(); if(thing->asCreature() || type.isOnTop || type.isOnBottom || type.isGroundClip || type.isGround) break; - thing->draw(x - m_drawElevation, y - m_drawElevation); + thing->draw(p.x - m_drawElevation, p.y - m_drawElevation); m_drawElevation += type.elevation; if(m_drawElevation > MAX_DRAW_ELEVATION) m_drawElevation = MAX_DRAW_ELEVATION; @@ -68,25 +68,25 @@ void Tile::draw(int x, int y) for(int yi = -1; yi <= 1; ++yi) { for(CreaturePtr creature : g_map.getTile(m_position + Position(xi, yi, 0))->getCreatures()) { auto& type = creature->getType(); - Rect creatureRect(x + xi*32 + creature->getWalkOffsetX() - type.xDisplacement, y + yi*32 + creature->getWalkOffsetY() - type.yDisplacement, 32, 32); - Rect thisTileRect(x, y, 32, 32); + Rect creatureRect(p.x + xi*32 + creature->getWalkOffsetX() - type.xDisplacement, p.y + yi*32 + creature->getWalkOffsetY() - type.yDisplacement, 32, 32); + Rect thisTileRect(p.x, p.y, 32, 32); // only render creatures where bottom right is inside our rect if(thisTileRect.contains(creatureRect.bottomRight())) - creature->draw(x + xi*32 - m_drawElevation, y + yi*32 - m_drawElevation); + creature->draw(p.x + xi*32 - m_drawElevation, p.y + yi*32 - m_drawElevation); } } } // effects for(const EffectPtr& effect : m_effects) - effect->draw(x - m_drawElevation, y - m_drawElevation); + effect->draw(p.x - m_drawElevation, p.y - m_drawElevation); // top items for(const ThingPtr& thing : m_things) { const ThingType& type = thing->getType(); if(type.isOnTop) - thing->draw(x - m_drawElevation, y - m_drawElevation); + thing->draw(p.x - m_drawElevation, p.y - m_drawElevation); } } @@ -183,6 +183,17 @@ ItemPtr Tile::getGround() return nullptr; } +bool Tile::isFullGround() +{ + ThingPtr ground = getThing(0); + if(!ground) + return false; + const ThingType& type = ground->getType(); + if(type.isGround && type.isFullGround) + return true; + return false; +} + bool Tile::isFullyOpaque() { ThingPtr firstObject = getThing(0); @@ -193,3 +204,13 @@ bool Tile::isFullyOpaque() } return false; } + +bool Tile::isLookPossible() +{ + for(const ThingPtr& thing : m_things) { + const ThingType& type = thing->getType(); + if(type.isUnsight) + return false; + } + return true; +} diff --git a/src/otclient/core/tile.h b/src/otclient/core/tile.h index 84340c38..2cc313d7 100644 --- a/src/otclient/core/tile.h +++ b/src/otclient/core/tile.h @@ -34,7 +34,7 @@ class Tile : public LuaObject public: Tile(const Position& position); - void draw(int x, int y); + void draw(const Point& p); void clean(); void addEffect(const EffectPtr& effect); @@ -48,7 +48,9 @@ public: int getDrawElevation() { return m_drawElevation; } std::vector getCreatures(); ItemPtr getGround(); + bool isFullGround(); bool isFullyOpaque(); + bool isLookPossible(); TilePtr asTile() { return std::static_pointer_cast(shared_from_this()); } diff --git a/src/otclient/util/position.h b/src/otclient/util/position.h index c7441803..7e862e3d 100644 --- a/src/otclient/util/position.h +++ b/src/otclient/util/position.h @@ -25,6 +25,7 @@ #include #include +#include class Position { @@ -70,10 +71,15 @@ public: return std::abs(x-pos.x) <= xdif && std::abs(y-pos.y) <= ydif && std::abs(pos.z-z) <= zdif; } + Point to2D(const Position& centerPos) const { + return Point((7 + (x - centerPos.x) - (centerPos.z - z)) * 32, + (5 + (y - centerPos.y) - (centerPos.z - z)) * 32); + }; + void up(int n = 1) { z-=n; } void down(int n = 1) { z+=n; } - void coveredUp(int n = 1) { x+=n; y+=n; z-=n; } + void perspectiveUp(int n = 1) { x+=n; y+=n; z-=n; } void coveredDown(int n = 1) { x-=n; y-=n; z+=n; } int x;