Liquids: Flow into and destroy 'floodable' nodes
authorparamat <mat.gregory@virginmedia.com>
Wed, 30 Dec 2015 04:22:58 +0000 (04:22 +0000)
committerparamat <mat.gregory@virginmedia.com>
Thu, 7 Jan 2016 05:57:19 +0000 (05:57 +0000)
Add new node property 'floodable', default false
Define "air" as floodable = true in C++ and lua

builtin/game/item.lua
builtin/game/register.lua
doc/lua_api.txt
src/map.cpp
src/nodedef.cpp
src/nodedef.h
src/script/common/c_content.cpp

index d16601d30947c7b776e8fa13577f9f1e382045ec..c168bf09610bc40a5ed7b9adb1b9fd58a9aebfc9 100644 (file)
@@ -574,6 +574,7 @@ core.nodedef_default = {
        diggable = true,
        climbable = false,
        buildable_to = false,
+       floodable = false,
        liquidtype = "none",
        liquid_alternative_flowing = "",
        liquid_alternative_source = "",
index 992fdf74481ae0a0f8f7e1347297c635e7e0f43a..ba5f69d67defaab0f7ad940002e3d99255267b77 100644 (file)
@@ -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},
index 37d0aaabc8905e788e6216d36f2a04662c44b7c3..ea5029e61eeb62a357bbc616f9b023d69ccf68ed 100644 (file)
@@ -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
index ceebd40a35d636659d888237e928619e463c55c1..ac29cfeeeac786a87e388666e4fcbff0df008e50 100644 (file)
@@ -1654,10 +1654,10 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & 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;
                }
index b5ccc3b94e94521a0a2912bab773c68c684644b5..2ebe1c1316250d31075e57875e9c98413555724d 100644 (file)
@@ -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<<serializeString(mesh);
        collision_box.serialize(os, protocol_version);
+       writeU8(os, floodable);
 }
 
 void ContentFeatures::deSerialize(std::istream &is)
@@ -388,6 +390,7 @@ void ContentFeatures::deSerialize(std::istream &is)
                // otherwise changes the protocol version
        mesh = deSerializeString(is);
        collision_box.deSerialize(is);
+       floodable = readU8(is);
        }catch(SerializationError &e) {};
 }
 
@@ -520,6 +523,7 @@ void CNodeDefManager::clear()
                f.pointable           = false;
                f.diggable            = false;
                f.buildable_to        = true;
+               f.floodable           = true;
                f.is_ground_content   = true;
                // Insert directly into containers
                content_t c = CONTENT_AIR;
index 7a84b0316c1df4dbaab48fe7a50043935aefc091..8f4942c044afe7be31424648ed305a9b6dfa9e5a 100644 (file)
@@ -229,6 +229,8 @@ struct ContentFeatures
        bool climbable;
        // Player can build on these
        bool buildable_to;
+       // Liquids flow into and replace node
+       bool floodable;
        // Player cannot build to these (placement prediction disabled)
        bool rightclickable;
        // Flowing liquid or snow, value = default level
index 36a5c2ddd700e96d21304d1317a342e091015eaa..62de2c968147e10f9169a78ca71a5121c4d9700b 100644 (file)
@@ -481,6 +481,8 @@ ContentFeatures read_content_features(lua_State *L, int index)
        getboolfield(L, index, "climbable", f.climbable);
        // Player can build on these
        getboolfield(L, index, "buildable_to", f.buildable_to);
+       // Liquids flow into and replace node
+       getboolfield(L, index, "floodable", f.floodable);
        // Whether the node is non-liquid, source liquid or flowing liquid
        f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
                        ScriptApiNode::es_LiquidType, LIQUID_NONE);