diff --git a/src/client/luafunctions.cpp b/src/client/luafunctions.cpp index 4ba1c823a3..6263899e9e 100644 --- a/src/client/luafunctions.cpp +++ b/src/client/luafunctions.cpp @@ -130,8 +130,6 @@ void Client::registerLuaFunctions() g_lua.registerSingletonClass("g_map"); g_lua.bindSingletonFunction("g_map", "isLookPossible", &Map::isLookPossible, &g_map); - g_lua.bindSingletonFunction("g_map", "isCovered", &Map::isCovered, &g_map); - g_lua.bindSingletonFunction("g_map", "isCompletelyCovered", &Map::isCompletelyCovered, &g_map); g_lua.bindSingletonFunction("g_map", "addThing", &Map::addThing, &g_map); g_lua.bindSingletonFunction("g_map", "addStaticText", &Map::addStaticText, &g_map); g_lua.bindSingletonFunction("g_map", "addAnimatedText", &Map::addAnimatedText, &g_map); @@ -904,14 +902,17 @@ void Client::registerLuaFunctions() g_lua.bindClassMemberFunction("isWalkable", &Tile::isWalkable); g_lua.bindClassMemberFunction("hasElevation", &Tile::hasElevation); + g_lua.bindClassMemberFunction("isCovered", &Tile::isCovered); + g_lua.bindClassMemberFunction("isCompletelyCovered", &Tile::isCompletelyCovered); g_lua.bindClassMemberFunction("isFullGround", &Tile::isFullGround); g_lua.bindClassMemberFunction("isFullyOpaque", &Tile::isFullyOpaque); g_lua.bindClassMemberFunction("isLookPossible", &Tile::isLookPossible); - g_lua.bindClassMemberFunction("hasCreatures", &Tile::hasCreatures); g_lua.bindClassMemberFunction("isEmpty", &Tile::isEmpty); g_lua.bindClassMemberFunction("isClickable", &Tile::isClickable); g_lua.bindClassMemberFunction("isPathable", &Tile::isPathable); + g_lua.bindClassMemberFunction("hasCreatures", &Tile::hasCreatures); + g_lua.bindClassMemberFunction("select", &Tile::select); g_lua.bindClassMemberFunction("unselect", &Tile::unselect); g_lua.bindClassMemberFunction("isSelected", &Tile::isSelected); diff --git a/src/client/map.cpp b/src/client/map.cpp index 4be5bfa792..4db0a7a040 100644 --- a/src/client/map.cpp +++ b/src/client/map.cpp @@ -660,13 +660,18 @@ bool Map::isLookPossible(const Position& pos) return tile && tile->isLookPossible(); } -bool Map::isCovered(const Position& pos, const uint8_t firstFloor) +bool Map::isCovered(const Position& pos, bool& isLoading, const uint8_t firstFloor) { // check for tiles on top of the postion Position tilePos = pos; while (tilePos.coveredUp() && tilePos.z >= firstFloor) { // the below tile is covered when the above tile has a full opaque if (const auto& tile = getTile(tilePos)) { + if (tile->isLoading()) { + isLoading = true; + return false; + } + if (tile->isFullyOpaque()) return true; } @@ -680,7 +685,7 @@ bool Map::isCovered(const Position& pos, const uint8_t firstFloor) return false; } -bool Map::isCompletelyCovered(const Position& pos, const uint8_t firstFloor) +bool Map::isCompletelyCovered(const Position& pos, bool& isLoading, const uint8_t firstFloor) { const auto& checkTile = getTile(pos); Position tilePos = pos; @@ -711,6 +716,11 @@ bool Map::isCompletelyCovered(const Position& pos, const uint8_t firstFloor) for (auto x = -1; ++x < 2 && !done;) { for (auto y = -1; ++y < 2 && !done;) { const auto& tile = getTile(tilePos.translated(-x, -y)); + if (tile && tile->isLoading()) { + isLoading = true; + return false; + } + if (!tile || !tile->isFullyOpaque()) { covered = false; done = true; diff --git a/src/client/map.h b/src/client/map.h index 8fe31098ac..5ceeef396e 100644 --- a/src/client/map.h +++ b/src/client/map.h @@ -267,8 +267,18 @@ class Map void setCentralPosition(const Position& centralPosition); bool isLookPossible(const Position& pos); - bool isCovered(const Position& pos, uint8_t firstFloor = 0); - bool isCompletelyCovered(const Position& pos, uint8_t firstFloor = 0); + bool isCovered(const Position& pos, uint8_t firstFloor = 0) { + bool isLoading = false; + return isCovered(pos, isLoading, firstFloor); + } + + bool isCompletelyCovered(const Position& pos, uint8_t firstFloor = 0) { + bool isLoading = false; + return isCompletelyCovered(pos, isLoading, firstFloor); + } + + bool isCovered(const Position& pos, bool& isLoading, uint8_t firstFloor = 0); + bool isCompletelyCovered(const Position& pos, bool& isLoading, uint8_t firstFloor = 0); bool isAwareOfPosition(const Position& pos) const { return isAwareOfPosition(pos, m_awareRange); } bool isAwareOfPosition(const Position& pos, const AwareRange& awareRange) const; diff --git a/src/client/spriteappearances.cpp b/src/client/spriteappearances.cpp index 1008548b35..48b2018bb2 100644 --- a/src/client/spriteappearances.cpp +++ b/src/client/spriteappearances.cpp @@ -233,8 +233,9 @@ ImagePtr SpriteAppearances::getSpriteImage(const int id, bool& isLoading) if (!image->hasTransparentPixel()) { // The image must be more than 4 pixels transparent to be considered transparent. uint8_t cntTrans = 0; - for (const uint8_t pixel : image->getPixels()) { - if (pixel == 0x00 && ++cntTrans > 4) { + const auto& buf = image->getPixels(); + for (size_t i = 3, n = buf.size(); i < n; i += 4) { + if (buf[i] == 0x00 && ++cntTrans > 4) { image->setTransparentPixel(true); break; } diff --git a/src/client/spritemanager.cpp b/src/client/spritemanager.cpp index 8ff8a0d6a4..61b6e9ec44 100644 --- a/src/client/spritemanager.cpp +++ b/src/client/spritemanager.cpp @@ -290,6 +290,8 @@ ImagePtr SpriteManager::getSpriteImage(const int id, const FileStreamPtr& file) const uint16_t transparentPixels = readU16FromBuffer(spriteBuffer.data(), offset); const uint16_t coloredPixels = readU16FromBuffer(spriteBuffer.data(), offset); + transparentCount += transparentPixels; + const int transparentBytes = transparentPixels * 4; if (writePos + transparentBytes > maxWriteSize) break; @@ -330,8 +332,10 @@ ImagePtr SpriteManager::getSpriteImage(const int id, const FileStreamPtr& file) } } - if (writePos < maxWriteSize) + if (writePos < maxWriteSize) { std::memset(pixels + writePos, 0, maxWriteSize - writePos); + transparentCount += maxWriteSize - writePos; + } if (hasAlpha || transparentCount > 4) image->setTransparentPixel(true); diff --git a/src/client/thing.h b/src/client/thing.h index 93146a110f..613c40abd2 100644 --- a/src/client/thing.h +++ b/src/client/thing.h @@ -145,6 +145,7 @@ class Thing : public AttachableObject bool isTopEffect() { return getThingType()->isTopEffect(); } bool isPodium() const { return getThingType()->isPodium(); } bool isOpaque() const { return getThingType()->isOpaque(); } + bool isLoading() const { return getThingType()->isLoading(); } bool isSingleDimension() const { return getThingType()->isSingleDimension(); } bool isTall(const bool useRealSize = false) const { return getThingType()->isTall(useRealSize); } diff --git a/src/client/thingtype.h b/src/client/thingtype.h index 31ed291a0a..429feee1d0 100644 --- a/src/client/thingtype.h +++ b/src/client/thingtype.h @@ -439,8 +439,9 @@ class ThingType final : public LuaObject bool isPodium() { return (m_flags & ThingFlagAttrPodium); } bool isTopEffect() { return (m_flags & ThingFlagAttrTopEffect); } bool hasAction() { return (m_flags & ThingFlagAttrDefaultAction); } - bool isOpaque() { if (m_opaque == -1) getTexture(0); return m_opaque == 1; } + bool isOpaque() { return m_opaque == 1; } bool isDecoKit() { return (m_flags & ThingFlagAttrDecoKit); } + bool isLoading() const { return m_loading.load(std::memory_order_acquire); } bool isItem() const { return m_category == ThingCategoryItem; } bool isEffect() const { return m_category == ThingCategoryEffect; } diff --git a/src/client/tile.cpp b/src/client/tile.cpp index 99a5662b14..d15e525078 100644 --- a/src/client/tile.cpp +++ b/src/client/tile.cpp @@ -623,11 +623,19 @@ bool Tile::isCompletelyCovered(const uint8_t firstFloor, const bool resetCache) const uint32_t idState = 1 << (firstFloor + g_gameConfig.getMapMaxZ()); if ((m_isCompletelyCovered & idChecked) == 0) { m_isCompletelyCovered |= idChecked; - if (g_map.isCompletelyCovered(m_position, firstFloor)) { + bool isLoading = false; + if (g_map.isCompletelyCovered(m_position, isLoading, firstFloor)) { m_isCompletelyCovered |= idState; m_isCovered |= idChecked; // Set covered is Checked m_isCovered |= idState; } + + if (isLoading) { + m_isCompletelyCovered &= ~idState; + m_isCovered &= ~idChecked; + m_isCovered &= ~idState; + return false; + } } return (m_isCompletelyCovered & idState) == idState; @@ -642,8 +650,15 @@ bool Tile::isCovered(const int8_t firstFloor) if ((m_isCovered & idChecked) == 0) { m_isCovered |= idChecked; - if (g_map.isCovered(m_position, firstFloor)) + bool isLoading = false; + if (g_map.isCovered(m_position, isLoading, firstFloor)) m_isCovered |= idState; + + if (isLoading) { + m_isCovered &= ~idChecked; + m_isCovered &= ~idState; + return false; + } } return (m_isCovered & idState) == idState; @@ -878,9 +893,6 @@ void Tile::setThingFlag(const ThingPtr& thing) if (thing->isFullGround()) m_thingTypeFlag |= FULL_GROUND; - if (thing->isOpaque()) - m_thingTypeFlag |= IS_OPAQUE; - if (thing->hasElevation()) ++m_elevation; } @@ -1004,4 +1016,25 @@ bool Tile::canShoot(int distance) if (distance > 0 && std::max(std::abs(m_position.x - playerPos.x), std::abs(m_position.y - playerPos.y)) > distance) return false; return g_map.isSightClear(playerPos, m_position); +} + +bool Tile::isFullyOpaque() { + if (isFullGround()) + return true; + + for (const auto& thing : m_things) { + if (thing->isOpaque()) + return true; + } + + return false; +} + +bool Tile::isLoading() const { + for (const auto& thing : m_things) { + if (thing->isLoading()) + return true; + } + + return false; } \ No newline at end of file diff --git a/src/client/tile.h b/src/client/tile.h index 235103b9be..14b61c0aea 100644 --- a/src/client/tile.h +++ b/src/client/tile.h @@ -70,7 +70,7 @@ enum TileThingType : uint32_t HAS_DISPLACEMENT = 1 << 5, IS_NOT_PATHAB = 1 << 6, ELEVATION = 1 << 7, - IS_OPAQUE = 1 << 8, + // IS_OPAQUE = 1 << 8, HAS_LIGHT = 1 << 9, HAS_TALL_THINGS = 1 << 10, HAS_WIDE_THINGS = 1 << 11, @@ -137,13 +137,14 @@ class Tile final : public AttachableObject bool isClickable(); bool isPathable() { return (m_thingTypeFlag & NOT_PATHABLE) == 0; } bool isFullGround() { return m_thingTypeFlag & FULL_GROUND; } - bool isFullyOpaque() { return m_thingTypeFlag & IS_OPAQUE; } + bool isFullyOpaque(); bool isSingleDimension() { return (m_thingTypeFlag & NOT_SINGLE_DIMENSION) == 0 && m_walkingCreatures.empty(); } bool isLookPossible() { return (m_thingTypeFlag & BLOCK_PROJECTTILE) == 0; } bool isEmpty() { return m_things.empty(); } bool isDrawable() { return !isEmpty() || !m_walkingCreatures.empty() || hasEffect() || hasAttachedEffects(); } bool isCovered(int8_t firstFloor); bool isCompletelyCovered(uint8_t firstFloor, bool resetCache); + bool isLoading() const; bool hasBlockingCreature() const;