summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/game/falling.lua58
-rw-r--r--doc/lua_api.txt10
-rw-r--r--src/mapnode.cpp21
-rw-r--r--src/mapnode.h6
-rw-r--r--src/nodedef.cpp6
-rw-r--r--src/nodedef.h4
-rw-r--r--src/script/common/c_content.cpp4
-rw-r--r--src/script/lua_api/l_env.cpp4
8 files changed, 79 insertions, 34 deletions
diff --git a/builtin/game/falling.lua b/builtin/game/falling.lua
index 7037ae885..cdbb13acc 100644
--- a/builtin/game/falling.lua
+++ b/builtin/game/falling.lua
@@ -109,6 +109,7 @@ core.register_entity(":__builtin:falling_node", {
if core.is_colored_paramtype(def.paramtype2) then
itemstring = core.itemstring_with_palette(itemstring, node.param2)
end
+ -- FIXME: solution needed for paramtype2 == "leveled"
local vsize
if def.visual_scale then
local s = def.visual_scale * SCALE
@@ -122,6 +123,24 @@ core.register_entity(":__builtin:falling_node", {
})
end
+ -- Set collision box (certain nodeboxes only for now)
+ local nb_types = {fixed=true, leveled=true, connected=true}
+ if def.drawtype == "nodebox" and def.node_box and
+ nb_types[def.node_box.type] then
+ local box = table.copy(def.node_box.fixed)
+ if type(box[1]) == "table" then
+ box = #box == 1 and box[1] or nil -- We can only use a single box
+ end
+ if box then
+ if def.paramtype2 == "leveled" and (self.node.level or 0) > 0 then
+ box[5] = -0.5 + self.node.level / 64
+ end
+ self.object:set_properties({
+ collisionbox = box
+ })
+ end
+ end
+
-- Rotate entity
if def.drawtype == "torchlike" then
self.object:set_yaw(math.pi*0.25)
@@ -196,13 +215,16 @@ core.register_entity(":__builtin:falling_node", {
try_place = function(self, bcp, bcn)
local bcd = core.registered_nodes[bcn.name]
-- Add levels if dropped on same leveled node
- if bcd and bcd.leveled and
+ if bcd and bcd.paramtype2 == "leveled" and
bcn.name == self.node.name then
local addlevel = self.node.level
- if not addlevel or addlevel <= 0 then
+ if (addlevel or 0) <= 0 then
addlevel = bcd.leveled
end
- if core.add_node_level(bcp, addlevel) == 0 then
+ if core.add_node_level(bcp, addlevel) < addlevel then
+ return true
+ elseif bcd.buildable_to then
+ -- Node level has already reached max, don't place anything
return true
end
end
@@ -351,6 +373,7 @@ local function convert_to_falling_node(pos, node)
if not obj then
return false
end
+ -- remember node level, the entities' set_node() uses this
node.level = core.get_node_level(pos)
local meta = core.get_meta(pos)
local metatable = meta and meta:to_table() or {}
@@ -436,18 +459,23 @@ function core.check_single_for_falling(p)
-- Only spawn falling node if node below is loaded
local n_bottom = core.get_node_or_nil(p_bottom)
local d_bottom = n_bottom and core.registered_nodes[n_bottom.name]
- if d_bottom and
-
- (core.get_item_group(n.name, "float") == 0 or
- d_bottom.liquidtype == "none") and
-
- (n.name ~= n_bottom.name or (d_bottom.leveled and
- core.get_node_level(p_bottom) <
- core.get_node_max_level(p_bottom))) and
-
- (not d_bottom.walkable or d_bottom.buildable_to) then
- convert_to_falling_node(p, n)
- return true
+ if d_bottom then
+ local same = n.name == n_bottom.name
+ -- Let leveled nodes fall if it can merge with the bottom node
+ if same and d_bottom.paramtype2 == "leveled" and
+ core.get_node_level(p_bottom) <
+ core.get_node_max_level(p_bottom) then
+ convert_to_falling_node(p, n)
+ return true
+ end
+ -- Otherwise only if the bottom node is considered "fall through"
+ if not same and
+ (not d_bottom.walkable or d_bottom.buildable_to) and
+ (core.get_item_group(n.name, "float") == 0 or
+ d_bottom.liquidtype == "none") then
+ convert_to_falling_node(p, n)
+ return true
+ end
end
end
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index 9c7c42436..8b7c412ab 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -4882,7 +4882,7 @@ Environment access
* `minetest.add_node_level(pos, level)`
* increase level of leveled node by level, default `level` equals `1`
* if `totallevel > maxlevel`, returns rest (`total-max`)
- * can be negative for decreasing
+ * `level` must be between -127 and 127
* `minetest.fix_light(pos1, pos2)`: returns `true`/`false`
* resets the light in a cuboid-shaped part of
the map and removes lighting bugs.
@@ -7012,11 +7012,15 @@ Used by `minetest.register_node`.
-- If true, a new liquid source can be created by placing two or more
-- sources nearby
- leveled = 16,
+ leveled = 0,
-- Only valid for "nodebox" drawtype with 'type = "leveled"'.
-- Allows defining the nodebox height without using param2.
-- The nodebox height is 'leveled' / 64 nodes.
- -- The maximum value of 'leveled' is 127.
+ -- The maximum value of 'leveled' is `leveled_max`.
+
+ leveled_max = 127,
+ -- Maximum value for `leveled` (0-127), enforced in
+ -- `minetest.set_node_level` and `minetest.add_node_level`.
liquid_range = 8, -- Number of flowing nodes around source (max. 8)
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index bf7e79a71..24d62b504 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -584,7 +584,7 @@ u8 MapNode::getMaxLevel(const NodeDefManager *nodemgr) const
if( f.liquid_type == LIQUID_FLOWING || f.param_type_2 == CPT2_FLOWINGLIQUID)
return LIQUID_LEVEL_MAX;
if(f.leveled || f.param_type_2 == CPT2_LEVELED)
- return LEVELED_MAX;
+ return f.leveled_max;
return 0;
}
@@ -603,14 +603,15 @@ u8 MapNode::getLevel(const NodeDefManager *nodemgr) const
if (level)
return level;
}
- if (f.leveled > LEVELED_MAX)
- return LEVELED_MAX;
+ // Return static value from nodedef if param2 isn't used for level
+ if (f.leveled > f.leveled_max)
+ return f.leveled_max;
return f.leveled;
}
-u8 MapNode::setLevel(const NodeDefManager *nodemgr, s8 level)
+s8 MapNode::setLevel(const NodeDefManager *nodemgr, s16 level)
{
- u8 rest = 0;
+ s8 rest = 0;
const ContentFeatures &f = nodemgr->get(*this);
if (f.param_type_2 == CPT2_FLOWINGLIQUID
|| f.liquid_type == LIQUID_FLOWING
@@ -631,18 +632,18 @@ u8 MapNode::setLevel(const NodeDefManager *nodemgr, s8 level)
if (level < 0) { // zero means default for a leveled nodebox
rest = level;
level = 0;
- } else if (level > LEVELED_MAX) {
- rest = level - LEVELED_MAX;
- level = LEVELED_MAX;
+ } else if (level > f.leveled_max) {
+ rest = level - f.leveled_max;
+ level = f.leveled_max;
}
setParam2((level & LEVELED_MASK) | (getParam2() & ~LEVELED_MASK));
}
return rest;
}
-u8 MapNode::addLevel(const NodeDefManager *nodemgr, s8 add)
+s8 MapNode::addLevel(const NodeDefManager *nodemgr, s16 add)
{
- s8 level = getLevel(nodemgr);
+ s16 level = getLevel(nodemgr);
level += add;
return setLevel(nodemgr, level);
}
diff --git a/src/mapnode.h b/src/mapnode.h
index 7a3d30ddc..32ac1b4f6 100644
--- a/src/mapnode.h
+++ b/src/mapnode.h
@@ -268,12 +268,12 @@ struct MapNode
std::vector<aabb3f> *boxes, u8 neighbors = 0) const;
/*
- Liquid helpers
+ Liquid/leveled helpers
*/
u8 getMaxLevel(const NodeDefManager *nodemgr) const;
u8 getLevel(const NodeDefManager *nodemgr) const;
- u8 setLevel(const NodeDefManager *nodemgr, s8 level = 1);
- u8 addLevel(const NodeDefManager *nodemgr, s8 add = 1);
+ s8 setLevel(const NodeDefManager *nodemgr, s16 level = 1);
+ s8 addLevel(const NodeDefManager *nodemgr, s16 add = 1);
/*
Serialization functions
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index 65199830f..b8211fceb 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -368,6 +368,7 @@ void ContentFeatures::reset()
floodable = false;
rightclickable = true;
leveled = 0;
+ leveled_max = LEVELED_MAX;
liquid_type = LIQUID_NONE;
liquid_alternative_flowing = "";
liquid_alternative_source = "";
@@ -478,6 +479,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
writeU8(os, legacy_wallmounted);
os << serializeString(node_dig_prediction);
+ writeU8(os, leveled_max);
}
void ContentFeatures::correctAlpha(TileDef *tiles, int length)
@@ -586,6 +588,10 @@ void ContentFeatures::deSerialize(std::istream &is)
try {
node_dig_prediction = deSerializeString(is);
+ u8 tmp_leveled_max = readU8(is);
+ if (is.eof()) /* readU8 doesn't throw exceptions so we have to do this */
+ throw SerializationError("");
+ leveled_max = tmp_leveled_max;
} catch(SerializationError &e) {};
}
diff --git a/src/nodedef.h b/src/nodedef.h
index 0fce6eab1..497e7ee0e 100644
--- a/src/nodedef.h
+++ b/src/nodedef.h
@@ -326,8 +326,10 @@ struct ContentFeatures
std::vector<content_t> connects_to_ids;
// Post effect color, drawn when the camera is inside the node.
video::SColor post_effect_color;
- // Flowing liquid or snow, value = default level
+ // Flowing liquid or leveled nodebox, value = default level
u8 leveled;
+ // Maximum value for leveled nodes
+ u8 leveled_max;
// --- LIGHTING-RELATED ---
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index de9634c42..116a59c09 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -694,6 +694,8 @@ ContentFeatures read_content_features(lua_State *L, int index)
f.liquid_range = getintfield_default(L, index,
"liquid_range", f.liquid_range);
f.leveled = getintfield_default(L, index, "leveled", f.leveled);
+ f.leveled_max = getintfield_default(L, index,
+ "leveled_max", f.leveled_max);
getboolfield(L, index, "liquid_renewable", f.liquid_renewable);
f.drowning = getintfield_default(L, index,
@@ -860,6 +862,8 @@ void push_content_features(lua_State *L, const ContentFeatures &c)
lua_setfield(L, -2, "post_effect_color");
lua_pushnumber(L, c.leveled);
lua_setfield(L, -2, "leveled");
+ lua_pushnumber(L, c.leveled_max);
+ lua_setfield(L, -2, "leveled_max");
lua_pushboolean(L, c.sunlight_propagates);
lua_setfield(L, -2, "sunlight_propagates");
lua_pushnumber(L, c.light_source);
diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp
index b8a8a5ce1..89ec9dc7e 100644
--- a/src/script/lua_api/l_env.cpp
+++ b/src/script/lua_api/l_env.cpp
@@ -529,13 +529,13 @@ int ModApiEnvMod::l_set_node_level(lua_State *L)
// add_node_level(pos, level)
// pos = {x=num, y=num, z=num}
-// level: 0..63
+// level: -127..127
int ModApiEnvMod::l_add_node_level(lua_State *L)
{
GET_ENV_PTR;
v3s16 pos = read_v3s16(L, 1);
- u8 level = 1;
+ s16 level = 1;
if(lua_isnumber(L, 2))
level = lua_tonumber(L, 2);
MapNode n = env->getMap().getNode(pos);