From 0bbbc6e13dc8180cf1d98f9866bc72a510162eb3 Mon Sep 17 00:00:00 2001 From: paramat Date: Wed, 30 Dec 2015 04:22:58 +0000 Subject: [PATCH] Liquids: Flow into and destroy 'floodable' nodes Add new node property 'floodable', default false Define "air" as floodable = true in C++ and lua --- builtin/game/item.lua | 1 + builtin/game/register.lua | 1 + doc/lua_api.txt | 1 + src/map.cpp | 70 ++++++++++++++++++--------------- src/nodedef.cpp | 4 ++ src/nodedef.h | 2 + src/script/common/c_content.cpp | 2 + 7 files changed, 49 insertions(+), 32 deletions(-) diff --git a/builtin/game/item.lua b/builtin/game/item.lua index d16601d3..c168bf09 100644 --- a/builtin/game/item.lua +++ b/builtin/game/item.lua @@ -574,6 +574,7 @@ core.nodedef_default = { diggable = true, climbable = false, buildable_to = false, + floodable = false, liquidtype = "none", liquid_alternative_flowing = "", liquid_alternative_source = "", diff --git a/builtin/game/register.lua b/builtin/game/register.lua index 992fdf74..ba5f69d6 100644 --- a/builtin/game/register.lua +++ b/builtin/game/register.lua @@ -289,6 +289,7 @@ core.register_node(":air", { pointable = false, diggable = false, buildable_to = true, + floodable = true, air_equivalent = true, drop = "", groups = {not_in_creative_inventory=1}, diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 37d0aaab..ea5029e6 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -3396,6 +3396,7 @@ Definition tables diggable = true, -- If false, can never be dug climbable = false, -- If true, can be climbed on (ladder) buildable_to = false, -- If true, placed nodes can replace this node + floodable = false, -- If true, liquids flow into and replace this node liquidtype = "none", -- "none"/"source"/"flowing" liquid_alternative_flowing = "", -- Flowing version of source liquid liquid_alternative_source = "", -- Source version of flowing liquid diff --git a/src/map.cpp b/src/map.cpp index ceebd40a..ac29cfee 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1654,10 +1654,10 @@ void Map::transformLiquids(std::map & modified_blocks) loop_max *= m_transforming_liquid_loop_count_multiplier; #endif - while(m_transforming_liquid.size() != 0) + while (m_transforming_liquid.size() != 0) { // This should be done here so that it is done when continue is used - if(loopcount >= initial_size || loopcount >= loop_max) + if (loopcount >= initial_size || loopcount >= loop_max) break; loopcount++; @@ -1674,21 +1674,24 @@ void Map::transformLiquids(std::map & modified_blocks) */ s8 liquid_level = -1; content_t liquid_kind = CONTENT_IGNORE; - LiquidType liquid_type = nodemgr->get(n0).liquid_type; + content_t floodable_node = CONTENT_AIR; + ContentFeatures cf = nodemgr->get(n0); + LiquidType liquid_type = cf.liquid_type; switch (liquid_type) { case LIQUID_SOURCE: liquid_level = LIQUID_LEVEL_SOURCE; - liquid_kind = nodemgr->getId(nodemgr->get(n0).liquid_alternative_flowing); + liquid_kind = nodemgr->getId(cf.liquid_alternative_flowing); break; case LIQUID_FLOWING: liquid_level = (n0.param2 & LIQUID_LEVEL_MASK); liquid_kind = n0.getContent(); break; case LIQUID_NONE: - // if this is an air node, it *could* be transformed into a liquid. otherwise, - // continue with the next node. - if (n0.getContent() != CONTENT_AIR) + // if this node is 'floodable', it *could* be transformed + // into a liquid, otherwise, continue with the next node. + if (!cf.floodable) continue; + floodable_node = n0.getContent(); liquid_kind = CONTENT_AIR; break; } @@ -1718,9 +1721,10 @@ void Map::transformLiquids(std::map & modified_blocks) } v3s16 npos = p0 + dirs[i]; NodeNeighbor nb(getNodeNoEx(npos), nt, npos); + ContentFeatures cfnb = nodemgr->get(nb.n); switch (nodemgr->get(nb.n.getContent()).liquid_type) { case LIQUID_NONE: - if (nb.n.getContent() == CONTENT_AIR) { + if (cfnb.floodable) { airs[num_airs++] = nb; // if the current node is a water source the neighbor // should be enqueded for transformation regardless of whether the @@ -1738,8 +1742,8 @@ void Map::transformLiquids(std::map & modified_blocks) case LIQUID_SOURCE: // if this node is not (yet) of a liquid type, choose the first liquid type we encounter if (liquid_kind == CONTENT_AIR) - liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing); - if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) { + liquid_kind = nodemgr->getId(cfnb.liquid_alternative_flowing); + if (nodemgr->getId(cfnb.liquid_alternative_flowing) != liquid_kind) { neutrals[num_neutrals++] = nb; } else { // Do not count bottom source, it will screw things up @@ -1750,8 +1754,8 @@ void Map::transformLiquids(std::map & modified_blocks) case LIQUID_FLOWING: // if this node is not (yet) of a liquid type, choose the first liquid type we encounter if (liquid_kind == CONTENT_AIR) - liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing); - if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) { + liquid_kind = nodemgr->getId(cfnb.liquid_alternative_flowing); + if (nodemgr->getId(cfnb.liquid_alternative_flowing) != liquid_kind) { neutrals[num_neutrals++] = nb; } else { flows[num_flows++] = nb; @@ -1770,8 +1774,8 @@ void Map::transformLiquids(std::map & modified_blocks) s8 max_node_level = -1; u8 range = nodemgr->get(liquid_kind).liquid_range; - if (range > LIQUID_LEVEL_MAX+1) - range = LIQUID_LEVEL_MAX+1; + if (range > LIQUID_LEVEL_MAX + 1) + range = LIQUID_LEVEL_MAX + 1; if ((num_sources >= 2 && nodemgr->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) { // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid) @@ -1780,10 +1784,11 @@ void Map::transformLiquids(std::map & modified_blocks) new_node_content = nodemgr->getId(nodemgr->get(liquid_kind).liquid_alternative_source); } else if (num_sources >= 1 && sources[0].t != NEIGHBOR_LOWER) { // liquid_kind is set properly, see above - new_node_content = liquid_kind; max_node_level = new_node_level = LIQUID_LEVEL_MAX; - if (new_node_level < (LIQUID_LEVEL_MAX+1-range)) - new_node_content = CONTENT_AIR; + if (new_node_level >= (LIQUID_LEVEL_MAX + 1 - range)) + new_node_content = liquid_kind; + else + new_node_content = floodable_node; } else { // no surrounding sources, so get the maximum level that can flow into this node for (u16 i = 0; i < num_flows; i++) { @@ -1794,16 +1799,16 @@ void Map::transformLiquids(std::map & modified_blocks) max_node_level = LIQUID_LEVEL_MAX; if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX) max_node_level = nb_liquid_level + WATER_DROP_BOOST; - } else if (nb_liquid_level > max_node_level) + } else if (nb_liquid_level > max_node_level) { max_node_level = nb_liquid_level; + } break; case NEIGHBOR_LOWER: break; case NEIGHBOR_SAME_LEVEL: if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK && - nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) { + nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) max_node_level = nb_liquid_level - 1; - } break; } } @@ -1821,23 +1826,25 @@ void Map::transformLiquids(std::map & modified_blocks) new_node_level = liquid_level + 1; if (new_node_level != max_node_level) must_reflow.push_back(p0); - } else + } else { new_node_level = max_node_level; + } - if (max_node_level >= (LIQUID_LEVEL_MAX+1-range)) + if (max_node_level >= (LIQUID_LEVEL_MAX + 1 - range)) new_node_content = liquid_kind; else - new_node_content = CONTENT_AIR; + new_node_content = floodable_node; } /* check if anything has changed. if not, just continue with the next node. */ - if (new_node_content == n0.getContent() && (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING || - ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level && - ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK) - == flowing_down))) + if (new_node_content == n0.getContent() && + (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING || + ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level && + ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK) + == flowing_down))) continue; @@ -1857,11 +1864,10 @@ void Map::transformLiquids(std::map & modified_blocks) // Find out whether there is a suspect for this action std::string suspect; - if(m_gamedef->rollback()) { + if (m_gamedef->rollback()) suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1); - } - if(m_gamedef->rollback() && !suspect.empty()){ + if (m_gamedef->rollback() && !suspect.empty()) { // Blame suspect RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true); // Get old node for rollback @@ -1880,10 +1886,10 @@ void Map::transformLiquids(std::map & modified_blocks) v3s16 blockpos = getNodeBlockPos(p0); MapBlock *block = getBlockNoCreateNoEx(blockpos); - if(block != NULL) { + if (block != NULL) { modified_blocks[blockpos] = block; // If new or old node emits light, MapBlock requires lighting update - if(nodemgr->get(n0).light_source != 0 || + if (nodemgr->get(n0).light_source != 0 || nodemgr->get(n00).light_source != 0) lighting_modified_blocks[block->getPos()] = block; } diff --git a/src/nodedef.cpp b/src/nodedef.cpp index b5ccc3b9..2ebe1c13 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -233,6 +233,7 @@ void ContentFeatures::reset() diggable = true; climbable = false; buildable_to = false; + floodable = false; rightclickable = true; leveled = 0; liquid_type = LIQUID_NONE; @@ -318,6 +319,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const // the protocol version os<