/******************************************************************** Minecraft: Pocket Edition - Decompilation Project Copyright (C) 2023 iProgramInCpp The following code is licensed under the BSD 1 clause license. SPDX-License-Identifier: BSD-1-Clause ********************************************************************/ #include "DoorTile.hpp" #include "world/level/Level.hpp" #include "world/item/Item.hpp" DoorTile::DoorTile(int ID, Material* pMtl) : Tile(ID, pMtl) { m_TextureFrame = TEXTURE_DOOR_BOTTOM; if (pMtl == Material::metal) m_TextureFrame = TEXTURE_DOOR_IRON_BOTTOM; Tile::setShape(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f); } int DoorTile::use(Level* level, int x, int y, int z, Player* player) { // well, you know, iron doors can't be opened by right clicking if (m_pMaterial == Material::metal) return 1; int data = level->getData(x, y, z); // if we're the top tile if (data & 8) { if (level->getTile(x, y - 1, z) == m_ID) use(level, x, y - 1, z, player); } else { data ^= 4; if (level->getTile(x, y + 1, z) == m_ID) level->setData(x, y + 1, z, data + 8); level->setData(x, y, z, data); // @BUG: marking the wrong tiles as dirty? No problem because setData sends an update immediately anyways level->setTilesDirty(x, y - 1, z, x, y, z); std::string snd; if (Mth::random() < 0.5f) snd = "random.door_open"; else snd = "random.door_close"; level->playSound(float(x) + 0.5f, float(y) + 0.5f, float(z) + 0.5f, snd, 1.0f, 0.9f + 0.1f * level->m_random.nextFloat()); } return 1; } void DoorTile::attack(Level* level, int x, int y, int z, Player* player) { use(level, x, y, z, player); } // @HUH: This function has NO references to itself. Not even in the vtable of the tile. // This could have been an attempt by Mojang to override a function, but it clearly failed // From this, I suspect that they never actually used the `override` keyword for their classes. bool DoorTile::blocksLight() { return false; } HitResult DoorTile::clip(Level* level, int x, int y, int z, Vec3 v1, Vec3 v2) { // @NOTE: Tile::clip calls updateShape too. So this is redundant updateShape(level, x, y, z); return Tile::clip(level, x, y, z, v1, v2); } AABB* DoorTile::getAABB(Level* level, int x, int y, int z) { updateShape(level, x, y, z); return Tile::getAABB(level, x, y, z); } int DoorTile::getDir(int data) { if (!isOpen(data)) return (data - 1) & 3; return data & 3; } int DoorTile::getRenderShape() { return SHAPE_DOOR; } int DoorTile::getResource(int data, Random* random) { // breaking the top of the tile doesn't drop anything. // In JE, it probably fixed a certain dupe glitch with doors if (isTop(data)) return 0; if (m_pMaterial == Material::metal) return Item::door_iron->m_itemID; return Item::door_wood->m_itemID; } int DoorTile::getTexture(int dir, int data) { if (dir == 0 || dir == 1) return m_TextureFrame; int doorDir = getDir(data); if ((doorDir == 0 || doorDir == 2) != (dir <= 3)) return m_TextureFrame; int l = doorDir / 2 + ((dir & 1) ^ doorDir); l += (data & 4) / 4; int idx = m_TextureFrame - (data & 8) * 2; if ((l & 1) != 0) idx = -idx; return idx; } AABB DoorTile::getTileAABB(Level* level, int x, int y, int z) { updateShape(level, x, y, z); return Tile::getTileAABB(level, x, y, z); } bool DoorTile::isCubeShaped() { return false; } bool DoorTile::isSolidRender() { return false; } bool DoorTile::mayPlace(Level* level, int x, int y, int z) { return y <= 126 && level->isSolidTile(x, y - 1, z) && Tile::mayPlace(level, x, y, z) && Tile::mayPlace(level, x, y + 1, z); } void DoorTile::setShape(int dir) { // @NOTE: What? Why 2 tiles tall?? Tile::setShape(0.0f, 0.0f, 0.0f, 1.0f, 2.0f, 1.0f); switch (dir) { case 0: Tile::setShape(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.1875f); break; case 1: Tile::setShape(0.8125f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f); break; case 2: Tile::setShape(0.0f, 0.0f, 0.8125f, 1.0f, 1.0f, 1.0f); break; case 3: Tile::setShape(0.0f, 0.0f, 0.0f, 0.1875f, 1.0f, 1.0f); break; } } void DoorTile::updateShape(LevelSource* level, int x, int y, int z) { setShape(getDir(level->getData(x, y, z))); } void DoorTile::setOpen(Level* level, int x, int y, int z, bool bOpen) { int data = level->getData(x, y, z); if (isTop(data)) { if (level->getTile(x, y - 1, z) == m_ID) setOpen(level, x, y - 1, z, bOpen); return; } if (isOpen(level->getData(x, y, z)) != bOpen) { if (level->getTile(x, y + 1, z) == m_ID) level->setData(x, y + 1, z, (data ^ 4) + 8); level->setData(x, y, z, data ^ 4); level->setTilesDirty(x, y - 1, z, x, y, z); std::string snd; if (Mth::random() < 0.5f) snd = "random.door_open"; else snd = "random.door_close"; level->playSound(float(x) + 0.5f, float(y) + 0.5f, float(z) + 0.5f, snd, 1.0f, 0.9f + 0.1f * level->m_random.nextFloat()); } } void DoorTile::neighborChanged(Level* level, int x, int y, int z, int newTile) { int isTop = level->getData(x, y, z) & 8; if (isTop) { if (level->getTile(x, y - 1, z) != m_ID) level->setTile(x, y, z, TILE_AIR); if (newTile > 0) { if (Tile::tiles[newTile]->isSignalSource()) neighborChanged(level, x, y - 1, z, newTile); } return; } if (level->getTile(x, y + 1, z) != m_ID) { level->setTile(x, y, z, TILE_AIR); isTop = 1; } if (!level->isSolidTile(x, y - 1, z)) { level->setTile(x, y, z, TILE_AIR); if (level->getTile(x, y + 1, z) == m_ID) level->setTile(x, y + 1, z, TILE_AIR); } if (!isTop && newTile > 0 && Tile::tiles[newTile]->isSignalSource()) { bool bOpen = false; if (level->hasNeighborSignal(x, y, z) || level->hasNeighborSignal(x, y + 1, z)) bOpen = true; setOpen(level, x, y, z, bOpen); } }