builtin_item/init.lua

150 lines
4.3 KiB
Lua
Raw Normal View History

-- Use the movement gravity for the downwards acceleration.
-- The setting may change in-game but for simplicity we don't support this.
local movement_gravity = tonumber(core.settings:get("movement_gravity")) or 9.81
2014-08-31 14:44:42 +02:00
2020-10-10 17:46:06 +02:00
local function is_flowing_liquid(nodename)
local def = minetest.registered_nodes[nodename]
return def and def.liquidtype == "flowing"
end
-- get_flow_raw determines the fluid flow vector, or returns nothing if
-- the flow is zero
2020-10-08 19:35:12 +02:00
local neighbour_offsets = {
{x=-1, y=0, z=0},
{x=1, y=0, z=0},
{x=0, y=0, z=-1},
{x=0, y=0, z=1}
}
2020-10-10 17:46:06 +02:00
local function get_flow_raw(pos)
-- FIXME: Do we need to treat nodes with special liquid_range differently?
local param2 = minetest.get_node(pos).param2
2020-10-10 17:46:06 +02:00
if param2 == 15 then
-- The liquid has full height and flows downwards
return
2020-10-08 19:35:12 +02:00
end
local neighbours = {}
for n = 1, 4 do
local p = vector.add(pos, neighbour_offsets[n])
2020-10-10 17:46:06 +02:00
neighbours[n] = minetest.get_node(p)
2020-10-08 19:35:12 +02:00
end
2020-10-10 17:46:06 +02:00
if param2 < 8 then
-- The liquid does not flow downwards
for i = 1, 4 do
-- Flow to a neighbouring free space if possible
local node = neighbours[i]
local def = minetest.registered_nodes[node.name]
if def and not def.walkable and def.liquidtype == "none" then
return neighbour_offsets[i]
end
2012-09-25 16:29:37 +02:00
end
2020-10-10 17:46:06 +02:00
-- Find a liquid neighbour with lowest height
local min_height_neig = param2
local min_neighbour
for i = 1, 4 do
local node = neighbours[i]
local height_neigh = node.param2 % 8
if height_neigh < min_height_neig
and is_flowing_liquid(node.name) then
min_height_neig = height_neigh
min_neighbour = neighbour_offsets[i]
end
end
if min_neighbour then
return min_neighbour
2012-09-25 16:29:37 +02:00
end
2020-10-10 17:46:06 +02:00
-- No free neighbour and no flowing liquid neighbour
2014-08-31 14:12:32 +02:00
end
2020-10-10 17:46:06 +02:00
-- The flowing liquid ends here in the XZ plane, so determine the
-- flow from higher neighbour nodes
local flow = {x = 0, y = 0, z = 0}
2020-10-08 19:35:12 +02:00
for i = 1, 4 do
2020-10-10 17:46:06 +02:00
local node = neighbours[i]
local height_neigh = node.param2 % 8
if is_flowing_liquid(node.name) then
-- A higher liquid is coming from there
flow = vector.subtract(flow, neighbour_offsets[i])
2012-09-25 16:29:37 +02:00
end
2014-08-31 14:12:32 +02:00
end
2020-10-10 17:46:06 +02:00
return not vector.equals(flow, {x = 0, y = 0, z = 0}) and flow or nil
end
2020-10-10 17:46:06 +02:00
-- get_flow caches the results from get_flow_raw for 10 s
local flow_cache = {}
setmetatable(flow_cache, {__mode = "kv"})
local function get_flow(pos)
local vi = minetest.hash_node_position(pos)
local t = minetest.get_us_time()
2020-10-10 17:46:06 +02:00
if flow_cache[vi]
and t - flow_cache[vi][1] < 10 * 1000000 then
return flow_cache[vi][2]
end
2020-10-10 17:46:06 +02:00
local flow = get_flow_raw(pos)
flow_cache[vi] = {t, flow}
return flow
2014-08-31 14:12:32 +02:00
end
2012-09-25 16:29:37 +02:00
2014-08-31 14:12:32 +02:00
local item_entity = minetest.registered_entities["__builtin:item"]
local old_on_step = item_entity.on_step
2012-09-25 16:29:37 +02:00
2016-02-18 18:45:59 +01:00
item_entity.makes_footstep_sound = true
-- The "bt_" prefix shows that the value comes from builtin_item
2016-02-21 12:31:33 +01:00
item_entity.bt_timer = 0
item_entity.on_step = function(self, dtime, ...)
-- Remember the velocity before an original on_step can change it
local vel_desired
if self.bt_reset_velocity then
vel_desired = self.object:get_velocity()
end
2015-06-05 11:30:34 +02:00
old_on_step(self, dtime, ...)
2020-10-08 19:35:12 +02:00
-- Ignore the item if it should not interact with physics
if not self.physical_state then
return
2016-05-26 12:17:00 +02:00
end
2020-10-08 19:35:12 +02:00
-- Reset the velocity if needed
if vel_desired
and not vector.equals(self.object:get_velocity(), vel_desired) then
self.object:set_velocity(vel_desired)
2016-05-26 12:17:00 +02:00
end
-- For performance reasons, skip the remaining code in frequent steps
2020-10-08 19:35:12 +02:00
self.bt_timer = self.bt_timer + dtime
if self.bt_timer < 0.1 then
2016-02-21 12:31:33 +01:00
return
end
self.bt_timer = 0
2020-08-01 21:12:24 +02:00
local p = self.object:get_pos()
2016-05-26 12:17:00 +02:00
local pos = vector.round(p)
local nodename = minetest.get_node(pos).name
2015-06-05 11:30:34 +02:00
if self.bt_reset_velocity then
-- Set the item acceleration to its default (changed again below)
self.object:set_acceleration({x=0, y=-movement_gravity, z=0})
self.bt_reset_velocity = nil
2016-05-26 12:17:00 +02:00
end
local def = minetest.registered_nodes[nodename]
if not def or not def.liquidtype or def.liquidtype ~= "flowing" then
2020-10-08 19:35:12 +02:00
return
end
2020-10-10 17:46:06 +02:00
local flow = get_flow(pos)
if not flow then
2020-10-08 19:35:12 +02:00
return
end
local vel_current = vel_desired or self.object:get_velocity()
2020-10-10 17:46:06 +02:00
local acc
if vector.dot(vel_current, flow) < 1.0 then
acc = vector.multiply(flow, 2.0)
else
-- The item is already accelerated by the fluids
acc = {x = 0, y = 0, z = 0}
end
acc.y = -movement_gravity
self.object:set_acceleration(acc)
self.bt_reset_velocity = true
2014-08-31 14:12:32 +02:00
end
minetest.register_entity(":__builtin:item", item_entity)