Skip to content

Instantly share code, notes, and snippets.

@octacian
Created May 23, 2017 20:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save octacian/8bd7f000dfb2748e6802ef6b151f33ea to your computer and use it in GitHub Desktop.
Save octacian/8bd7f000dfb2748e6802ef6b151f33ea to your computer and use it in GitHub Desktop.
Slightly-Broken item entity
-- eden/item_entity.lua
---
--- Water flow functions by QwertyMine3 (MIT)
--- Edited by TenPlus1, Rewritten by octacian
---
local function to_unit_vector(dir_vector)
local inv_roots = {
[0] = 1,
[1] = 1,
[2] = 0.70710678118655,
[4] = 0.5,
[5] = 0.44721359549996,
[8] = 0.35355339059327
}
local sum = dir_vector.x * dir_vector.x + dir_vector.z * dir_vector.z
return {
x = dir_vector.x * inv_roots[sum],
y = dir_vector.y,
z = dir_vector.z * inv_roots[sum]
}
end
local function node_ok(pos)
local node = minetest.get_node_or_nil(pos)
if minetest.registered_nodes[node.name] then
return node
end
end
local function is_liquid(node)
local def = minetest.registered_nodes[node.name]
if def.liquidtype == "flowing" or def.liquidtype == "source" then
return true
end
end
local function quick_flow_logic(node, pos_testing, direction)
local def = minetest.registered_nodes[node.name]
if def.liquidtype == "flowing" then
local node_testing = node_ok(pos_testing)
if not is_liquid(node_testing) then
return 0
end
local param2_testing = node_testing.param2
if param2_testing < node.param2 then
if (node.param2 - param2_testing) > 6 then
return -direction
else
return direction
end
elseif param2_testing > node.param2 then
if (param2_testing - node.param2) > 6 then
return direction
else
return -direction
end
end
end
return 0
end
local function quick_flow(pos, node)
local x, z = 0, 0
if not minetest.registered_nodes[node.name].groups.liquid then
return {x = 0, y = 0, z = 0}
end
x = x + quick_flow_logic(node, {x = pos.x - 1, y = pos.y, z = pos.z},-1)
x = x + quick_flow_logic(node, {x = pos.x + 1, y = pos.y, z = pos.z}, 1)
z = z + quick_flow_logic(node, {x = pos.x, y = pos.y, z = pos.z - 1},-1)
z = z + quick_flow_logic(node, {x = pos.x, y = pos.y, z = pos.z + 1}, 1)
minetest.log(dump(minetest.pos_to_string(to_unit_vector({x =x , y=0, z = z}))))
return to_unit_vector({x = x, y = 0, z = z})
end
---
--- END Water Flow
---
local builtin_item = minetest.registered_entities["__builtin:item"]
local item = {
on_punch = function() end,
set_item = function(self, itemstring)
builtin_item.set_item(self, itemstring)
local stack = ItemStack(itemstring)
local itemdef = minetest.registered_items[stack:get_name()]
if itemdef and itemdef.groups.flammable ~= 0 then
self.flammable = itemdef.groups.flammable
end
end,
burn_up = function(self)
self.object:remove()
local p = self.object:getpos()
minetest.sound_play("eden_item_burn", {
pos = p,
max_hear_distance = 8,
})
minetest.add_particlespawner({
amount = 3,
time = 0.1,
minpos = {x = p.x - 0.1, y = p.y + 0.1, z = p.z - 0.1 },
maxpos = {x = p.x + 0.1, y = p.y + 0.2, z = p.z + 0.1 },
minvel = {x = 0, y = 2.5, z = 0},
maxvel = {x = 0, y = 2.5, z = 0},
minacc = {x = -0.15, y = -0.02, z = -0.15},
maxacc = {x = 0.15, y = -0.01, z = 0.15},
minexptime = 4,
maxexptime = 6,
minsize = 5,
maxsize = 5,
collisiondetection = true,
texture = "eden_item_smoke.png"
})
end,
on_step = function(self, dtime)
builtin_item.on_step(self, dtime)
local object = self.object
local itemstring = self.itemstring
local pos = object:getpos()
local node = minetest.get_node_or_nil(pos)
if node and node.name ~= "air" then
local def = minetest.registered_nodes[node.name]
-- Droplift
if def.liquidtype == "none" and def.drawtype == "normal" then
local new_pos = minetest.find_node_near(object:get_pos(), 1, "air")
if new_pos then
object:move_to(new_pos)
else
object:remove()
end
end
-- Move in flowing liquids
if def.liquidtype == "flowing" then
local vec = quick_flow(pos, node)
if vec then
object:set_velocity(vec)
self.flowing = true
end
end
-- Burning
if minetest.get_item_group(node.name, "lava") > 0 then
if self.flammable then
self:burn_up()
else -- else, Ignite after a maximum of 10 seconds
self.ignite_timer = (self.ignite_timer or 0) + dtime
if self.ignite_timer > math.random(2, 10) then
self.ignite_timer = 0
self:burn_up()
end
end
elseif self.flammable then
-- Otherwise there'll be a chance based on its igniter value
local burn_chance = self.flammable
* minetest.get_item_group(node.name, "igniter")
if burn_chance > 0 and math.random(0, burn_chance) ~= 0 then
self:burn_up()
end
end
end
--minetest.log(dump(node.name)..": "..dump(minetest.pos_to_string(object:get_velocity())).." - "..dump(object:get_properties().physical))
-- Stop water flow
if self.flowing and node then
local def = minetest.registered_nodes[node.name]
if def.liquidtype ~= "flowing" then
local def = minetest.registered_nodes[node.name]
object:setvelocity({x = 0, y = 0, z = 0})
object:move_to(vector.round(pos))
self.flowing = false
end
end
if self.age > 1 then
local radius_magnet = 2 -- Magnet radius (minimum: 1.7)
local radius_collect = 0.2 -- Collection radius
local liquid_modifier = 2
-- Collection
for _, player in ipairs(minetest.get_objects_inside_radius(pos, radius_magnet)) do
if player:is_player() then
local inv = player:get_inventory()
if inv and inv:room_for_item("main", ItemStack(itemstring)) then
local ppos = player:getpos()
ppos.y = ppos.y + 1.6
if node then
local def = minetest.registered_nodes[node.name]
if def.liquidtype == "flowing" or def.liquidtype == "source" then
radius_magnet = radius_magnet / liquid_modifier
radius_collect = radius_collect / liquid_modifier
end
end
if vector.distance(pos, ppos) <= radius_collect then
if self.itemstring ~= "" then
inv:add_item("main", ItemStack(itemstring))
minetest.sound_play("eden_item_pickup", {
pos = ppos,
max_hear_distance = 8,
})
self.itemstring = ""
object:remove()
end
elseif math.floor(vector.distance(pos, ppos)) <= radius_magnet then
local vec = vector.subtract(ppos, pos)
vec = vector.add(pos, vector.divide(vec, 2))
object:moveto(vec)
--self.physical_state = false
--object:set_properties({
--physical = false
--})
end
end
end
end
end
end,
}
function minetest.handle_node_drops(pos, drops, digger)
if not digger or not digger:is_player() then
return
end
local inv = digger:get_inventory()
local mode = eden.get_gamemode_def(eden.get_gamemode(digger))
for _, item in ipairs(drops) do
local count, name
if type(item) == "string" then
count = 1
name = item
else
count = item:get_count()
name = item:get_name()
end
if mode.item_drops == "auto" then
item = ItemStack(item):get_name()
if not inv:contains_item("main", item) then
inv:add_item("main", item)
end
else
for i=1, count do
minetest.add_item(pos, name)
end
end
end
end
function minetest.item_drop(itemstack, player, pos)
-- Use modified item drop only if dropped by a player
if player and player:is_player() then
local dir = player:get_look_dir()
local vel = player:get_player_velocity()
local cs = itemstack:get_count()
pos.y = pos.y + 1.3
if player:get_player_control().sneak then
cs = 1
end
local item = itemstack:take_item(cs)
local obj = core.add_item(pos, item)
if obj then
dir = vector.add(vector.multiply(dir, 5), vel)
dir.y = dir.y + 2
obj:set_velocity(dir)
obj:get_luaentity().dropped_by = player:get_player_name()
return itemstack
end
else -- else, Machine - use default item drop
if core.add_item(pos, itemstack) then
return itemstack
end
end
end
-- set defined item as new __builtin:item, with the old one as fallback table
setmetatable(item, builtin_item)
minetest.register_entity(":__builtin:item", item)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment