/******************************************************************** 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 "LiquidTile.hpp" #include "world/level/Level.hpp" LiquidTile::LiquidTile(int id, Material* pMtl) : Tile(id, pMtl == Material::lava ? TEXTURE_LAVA : TEXTURE_WATER, pMtl) { field_6C = 0; field_70[0] = 0; field_74[0] = 0; setTicking(true); } void LiquidTile::animateTick(Level* level, int x, int y, int z, Random* random) { if (m_pMaterial == Material::water) { if (!random->nextInt(64)) // @BUG: Return value unused. level->getData(x, y, z); } // @BUG: Redundant check for isSolidTile? if (m_pMaterial == Material::lava && level->getMaterial(x, y + 1, z) == Material::air && !level->isSolidTile(x, y + 1, z) && !random->nextInt(3)) { level->addParticle("lava", x + random->nextFloat(), y + m_aabb.max.y, z + random->nextFloat(), 0.0f, 0.0f, 0.0f); } } void LiquidTile::fizz(Level* level, int x, int y, int z) { for (int i = 0; i < 8; i++) { level->addParticle("largesmoke", x + Mth::random(), y + 1.2f, z + Mth::random(), 0.0f, 0.0f, 0.0f); } } AABB* LiquidTile::getAABB(Level*, int x, int y, int z) { return nullptr; } float LiquidTile::getBrightness(LevelSource* level, int x, int y, int z) { float b1 = level->getBrightness(x, y, z); float b2 = level->getBrightness(x, y + 1, z); if (b1 <= b2) b1 = b2; return b1; } int LiquidTile::getColor(LevelSource* level, int x, int y, int z) { return 0x999999FF; } int LiquidTile::getDepth(Level* level, int x, int y, int z) { if (level->getMaterial(x, y, z) != m_pMaterial) return -1; return level->getData(x, y, z); } int LiquidTile::getRenderedDepth(LevelSource* level, int x, int y, int z) { if (level->getMaterial(x, y, z) != m_pMaterial) return -1; int res = level->getData(x, y, z); if (res > 7) res = 0; return res; } Vec3 LiquidTile::getFlow(LevelSource* level, int x, int y, int z) { Vec3 result; int depthLocal = getRenderedDepth(level, x, y, z); for (int i = 0; i < 4; i++) { int checkX = x, checkY = y, checkZ = z; switch (i) { case 0: checkX--; break; case 1: checkZ--; break; case 2: checkX++; break; case 3: checkZ++; break; } int depthCheck = getRenderedDepth(level, checkX, checkY, checkZ); if (depthCheck < 0) { if (level->getMaterial(checkX, checkY, checkZ)->blocksMotion()) continue; depthCheck = getRenderedDepth(level, checkX, checkY - 1, checkZ); if (depthCheck >= 0) { int mult = depthCheck - (depthLocal - 8); result += Vec3(float((checkX - x) * mult), float((checkY - y) * mult), float((checkZ - z) * mult)); } continue; } else { int mult = depthCheck - depthLocal; result += Vec3(float((checkX - x) * mult), float((checkY - y) * mult), float((checkZ - z) * mult)); } } if (level->getData(x, y, z) >= 8) { if (shouldRenderFace(level, x, y, z - 1, DIR_ZNEG) || shouldRenderFace(level, x, y, z + 1, DIR_ZPOS) || shouldRenderFace(level, x - 1, y, z, DIR_XNEG) || shouldRenderFace(level, x + 1, y, z, DIR_XPOS) || shouldRenderFace(level, x, y + 1, z - 1, DIR_ZNEG) || shouldRenderFace(level, x, y + 1, z + 1, DIR_ZPOS) || shouldRenderFace(level, x - 1, y + 1, z, DIR_XNEG) || shouldRenderFace(level, x + 1, y + 1, z, DIR_XPOS)) { result = result.normalize() + Vec3(0, -6, 0); } } return result.normalize(); } int LiquidTile::getRenderLayer() { return m_pMaterial == Material::water ? LAYER_ALPHA : LAYER_OPAQUE; } int LiquidTile::getRenderShape() { return SHAPE_WATER; } int LiquidTile::getResource(int x, Random* random) { return 0; } int LiquidTile::getResourceCount(Random* random) { return 0; } float LiquidTile::getSlopeAngle(LevelSource* level, int x, int y, int z, Material* pMtl) { Vec3 vec; if (pMtl == Material::water) vec = ((LiquidTile*)Tile::water)->getFlow(level, x, y, z); if (pMtl == Material::lava) vec = ((LiquidTile*)Tile::lava)->getFlow(level, x, y, z); if (vec.x == 0 && vec.z == 0) return -1000.0f; return atan2f(vec.z, vec.x) + float(-0.5f * 3.1416f); } int LiquidTile::getTexture(int dir) { if (dir > 1) return m_TextureFrame + 1; return m_TextureFrame; } int LiquidTile::getTexture(int dir, int data) { // @TODO: revert to using Tile::getTexture return Tile::getTexture(dir, data); } int LiquidTile::getTickDelay() { if (m_pMaterial == Material::water) return 5; if (m_pMaterial == Material::lava) return 30; return 0; } void LiquidTile::handleEntityInside(Level* level, int x, int y, int z, Entity* pEnt, Vec3& vec) { vec += getFlow(level, x, y, z); } bool LiquidTile::isCubeShaped() { return false; } bool LiquidTile::isSolidRender() { return false; } bool LiquidTile::mayPick(int data, bool b) { if (!b) return false; return data == 0; } void LiquidTile::neighborChanged(Level* level, int x, int y, int z, int dir) { updateLiquid(level, x, y, z); } void LiquidTile::onPlace(Level* level, int x, int y, int z) { updateLiquid(level, x, y, z); } bool LiquidTile::shouldRenderFace(LevelSource* level, int x, int y, int z, int dir) { Material* pMtl = level->getMaterial(x, y, z); if (pMtl == m_pMaterial || pMtl == Material::ice) return false; if (dir == DIR_YPOS) return true; return Tile::shouldRenderFace(level, x, y, z, dir); } void LiquidTile::tick(Level*, int x, int y, int z, Random* random) { } void LiquidTile::updateLiquid(Level* level, int x, int y, int z) { if (level->getTile(x, y, z) != m_ID) return; if (m_pMaterial != Material::lava) // such interactions do not apply to water return; if (level->getMaterial(x, y, z - 1) == Material::water || level->getMaterial(x, y, z + 1) == Material::water || level->getMaterial(x - 1, y, z) == Material::water || level->getMaterial(x + 1, y, z) == Material::water || level->getMaterial(x, y + 1, z) == Material::water) { Tile* newTile; int data = level->getData(x, y, z); if (data == 0) { newTile = Tile::obsidian; } else if (data > 4) { // @NOTE: huh? fizz(level, x, y, z); return; } else { newTile = Tile::stoneBrick; } level->setTile(x, y, z, newTile->m_ID); fizz(level, x, y, z); } }