Viscous fluids
authorGiuseppe Bilotta <giuseppe.bilotta@gmail.com>
Tue, 16 Aug 2011 17:56:57 +0000 (19:56 +0200)
committerGiuseppe Bilotta <giuseppe.bilotta@gmail.com>
Tue, 16 Aug 2011 18:37:46 +0000 (20:37 +0200)
src/content_mapnode.cpp
src/map.cpp
src/mapnode.h

index 7174a8a4b7cdea7fe749fb0531c35c1b781b6010..f45853c4a3e0815e008e368ad26f0d31017bb291 100644 (file)
@@ -26,6 +26,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #define WATER_ALPHA 160
 
+#define WATER_VISC 1
+#define LAVA_VISC 7
+
 // TODO: Get rid of these and set up some attributes like toughness,
 //       fluffyness, and a funciton to calculate time and durability loss
 //       (and sound? and whatever else) from them
@@ -374,6 +377,7 @@ void content_mapnode_init()
        f->liquid_type = LIQUID_FLOWING;
        f->liquid_alternative_flowing = CONTENT_WATER;
        f->liquid_alternative_source = CONTENT_WATERSOURCE;
+       f->liquid_viscosity = WATER_VISC;
        f->vertex_alpha = WATER_ALPHA;
        if(f->special_material == NULL && g_texturesource)
        {
@@ -421,6 +425,7 @@ void content_mapnode_init()
        f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
        f->liquid_alternative_flowing = CONTENT_WATER;
        f->liquid_alternative_source = CONTENT_WATERSOURCE;
+       f->liquid_viscosity = WATER_VISC;
        f->vertex_alpha = WATER_ALPHA;
        if(f->special_material == NULL && g_texturesource)
        {
@@ -451,6 +456,7 @@ void content_mapnode_init()
        f->liquid_type = LIQUID_FLOWING;
        f->liquid_alternative_flowing = CONTENT_LAVA;
        f->liquid_alternative_source = CONTENT_LAVASOURCE;
+       f->liquid_viscosity = LAVA_VISC;
        f->damage_per_second = 4*2;
        if(f->special_material == NULL && g_texturesource)
        {
@@ -499,6 +505,7 @@ void content_mapnode_init()
        f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
        f->liquid_alternative_flowing = CONTENT_LAVA;
        f->liquid_alternative_source = CONTENT_LAVASOURCE;
+       f->liquid_viscosity = LAVA_VISC;
        f->damage_per_second = 4*2;
        if(f->special_material == NULL && g_texturesource)
        {
index 3aff00c949f7a921cc7f3f0841f5330b0f6f50d0..6331055aa229217666735c3dcb4366b93c8dd08e 100644 (file)
@@ -1562,6 +1562,9 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
        /*if(initial_size != 0)
                dstream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
 
+       // list of nodes that due to viscosity have not reached their max level height
+       UniqueQueue<v3s16> must_reflow;
+
        while(m_transforming_liquid.size() != 0)
        {
                // This should be done here so that it is done when continue is used
@@ -1672,6 +1675,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                 */
                content_t new_node_content;
                s8 new_node_level = -1;
+               s8 max_node_level = -1;
                if (num_sources >= 2 || liquid_type == LIQUID_SOURCE) {
                        // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
                        // or the flowing alternative of the first of the surrounding sources (if it's air), so
@@ -1680,34 +1684,51 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                } else if (num_sources == 1 && sources[0].t != NEIGHBOR_LOWER) {
                        // liquid_kind is set properly, see above
                        new_node_content = liquid_kind;
-                       new_node_level = LIQUID_LEVEL_MAX;
+                       max_node_level = new_node_level = LIQUID_LEVEL_MAX;
                } else {
                        // no surrounding sources, so get the maximum level that can flow into this node
                        for (u16 i = 0; i < num_flows; i++) {
                                u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
                                switch (flows[i].t) {
                                        case NEIGHBOR_UPPER:
-                                               if (nb_liquid_level + WATER_DROP_BOOST > new_node_level) {
-                                                       new_node_level = LIQUID_LEVEL_MAX;
+                                               if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) {
+                                                       max_node_level = LIQUID_LEVEL_MAX;
                                                        if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
-                                                               new_node_level = nb_liquid_level + WATER_DROP_BOOST;
+                                                               max_node_level = nb_liquid_level + WATER_DROP_BOOST;
                                                }
                                                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 > new_node_level) {
-                                                       new_node_level = nb_liquid_level - 1;
+                                                       nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) {
+                                                       max_node_level = nb_liquid_level - 1;
                                                }
                                                break;
                                }
                        }
 
+                       if (max_node_level != liquid_level) {
+                               // amount to gain, limited by viscosity
+                               // must be at least 1 in absolute value
+                               s8 level_inc = max_node_level - liquid_level;
+                               u8 viscosity = content_features(liquid_kind).liquid_viscosity;
+                               if (level_inc < -viscosity || level_inc > viscosity)
+                                       new_node_level = liquid_level + level_inc/viscosity;
+                               else if (level_inc < 0)
+                                       new_node_level = liquid_level - 1;
+                               else if (level_inc > 0)
+                                       new_node_level = liquid_level + 1;
+                               if (new_node_level != max_node_level)
+                                       must_reflow.push_back(p0);
+                       } else
+                               new_node_level = max_node_level;
+
                        if (new_node_level >= 0)
                                new_node_content = liquid_kind;
                        else
                                new_node_content = CONTENT_AIR;
+
                }
 
                /*
@@ -1760,6 +1781,8 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                }
        }
        //dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
+       while (must_reflow.size() > 0)
+               m_transforming_liquid.push_back(must_reflow.pop_front());
 }
 
 NodeMetadata* Map::getNodeMetadata(v3s16 p)
index 77f6b321f631b599db4c847fa924fd1f630d0a29..4c2b9285336d5d40cd887afaab35ebf1d68dc6f4 100644 (file)
@@ -153,6 +153,10 @@ struct ContentFeatures
        content_t liquid_alternative_flowing;
        // If the content is liquid, this is the source version of the liquid.
        content_t liquid_alternative_source;
+       // Viscosity for fluid flow, ranging from 1 to 7, with
+       // 1 giving almost instantaneous propagation and 7 being
+       // the slowest possible
+       u8 liquid_viscosity;
        // Used currently for flowing liquids
        u8 vertex_alpha;
        // Special irrlicht material, used sometimes
@@ -189,6 +193,7 @@ struct ContentFeatures
                initial_metadata = NULL;
                liquid_alternative_flowing = CONTENT_IGNORE;
                liquid_alternative_source = CONTENT_IGNORE;
+               liquid_viscosity = 0;
                vertex_alpha = 255;
                special_material = NULL;
                special_atlas = NULL;