2017-02-16 00:57:35 +01:00
--basic settings
2017-02-17 02:44:33 +01:00
local item_drop_settings = { } --settings table
2017-06-03 17:03:22 +02:00
item_drop_settings.age = 1.0 --how old a dropped item (_insta_collect==false) has to be before collecting
item_drop_settings.radius_magnet = 2.0 --radius of item magnet. MUST BE LARGER THAN radius_collect!
2017-06-03 17:27:58 +02:00
item_drop_settings.radius_collect = 0.2 --radius of collection
2017-05-29 18:50:57 +02:00
item_drop_settings.player_collect_height = 1.0 --added to their pos y value
2017-02-16 00:57:35 +01:00
item_drop_settings.collection_safety = false --do this to prevent items from flying away on laggy servers
item_drop_settings.random_item_velocity = true --this sets random item velocity if velocity is 0
2017-02-18 21:59:24 +01:00
item_drop_settings.drop_single_item = false --if true, the drop control drops 1 item instead of the entire stack, and sneak+drop drops the stack
-- drop_single_item is disabled by default because it is annoying to throw away items from the intentory screen
2017-02-16 00:57:35 +01:00
2017-05-29 17:39:01 +02:00
item_drop_settings.magnet_time = 0.75 -- how many seconds an item follows the player before giving up
2017-05-27 15:17:03 +02:00
2017-05-27 15:22:28 +02:00
local get_gravity = function ( )
2017-08-09 16:17:00 +02:00
return tonumber ( minetest.settings : get ( " movement_gravity " ) ) or 9.81
2017-05-27 15:22:28 +02:00
end
2017-03-05 22:33:09 +01:00
local check_pickup_achievements = function ( object , player )
local itemname = ItemStack ( object : get_luaentity ( ) . itemstring ) : get_name ( )
2017-03-05 22:52:19 +01:00
if minetest.get_item_group ( itemname , " tree " ) ~= 0 then
awards.unlock ( player : get_player_name ( ) , " mcl:mineWood " )
elseif itemname == " mcl_mobitems:blaze_rod " then
2017-03-05 22:33:09 +01:00
awards.unlock ( player : get_player_name ( ) , " mcl:blazeRod " )
2017-03-05 22:52:19 +01:00
elseif itemname == " mcl_mobitems:leather " then
awards.unlock ( player : get_player_name ( ) , " mcl:killCow " )
2017-03-05 22:33:09 +01:00
elseif itemname == " mcl_core:diamond " then
awards.unlock ( player : get_player_name ( ) , " mcl:diamonds " )
end
end
2017-02-16 00:57:35 +01:00
2017-06-10 20:56:53 +02:00
local enable_physics = function ( object , luaentity , ignore_check )
if luaentity.physical_state == false or ignore_check == true then
2017-06-10 20:37:17 +02:00
luaentity.physical_state = true
object : set_properties ( {
physical = true
} )
object : set_velocity ( { x = 0 , y = 0 , z = 0 } )
object : set_acceleration ( { x = 0 , y =- get_gravity ( ) , z = 0 } )
end
end
2017-06-10 20:56:53 +02:00
local disable_physics = function ( object , luaentity , ignore_check , reset_movement )
if luaentity.physical_state == true or ignore_check == true then
2017-06-10 20:37:17 +02:00
luaentity.physical_state = false
object : set_properties ( {
physical = false
} )
if reset_movement ~= false then
object : set_velocity ( { x = 0 , y = 0 , z = 0 } )
object : set_acceleration ( { x = 0 , y = 0 , z = 0 } )
end
end
end
2015-06-29 19:55:56 +02:00
minetest.register_globalstep ( function ( dtime )
2017-02-16 00:57:35 +01:00
for _ , player in ipairs ( minetest.get_connected_players ( ) ) do
2017-08-09 16:17:00 +02:00
if player : get_hp ( ) > 0 or not minetest.settings : get_bool ( " enable_damage " ) then
2017-02-16 00:57:35 +01:00
local pos = player : getpos ( )
local inv = player : get_inventory ( )
2017-06-03 17:03:22 +02:00
local checkpos = { x = pos.x , y = pos.y + item_drop_settings.player_collect_height , z = pos.z }
2017-02-16 00:57:35 +01:00
2017-06-03 17:03:22 +02:00
--magnet and collection
for _ , object in ipairs ( minetest.get_objects_inside_radius ( checkpos , item_drop_settings.radius_magnet ) ) do
if not object : is_player ( ) and object : get_luaentity ( ) and object : get_luaentity ( ) . name == " __builtin:item " and ( object : get_luaentity ( ) . _insta_collect or ( object : get_luaentity ( ) . age > item_drop_settings.age ) ) then
object : get_luaentity ( ) . _magnet_timer = object : get_luaentity ( ) . _magnet_timer + dtime
2017-06-10 17:23:14 +02:00
local collected = false
2017-06-03 17:03:22 +02:00
if object : get_luaentity ( ) . _magnet_timer >= 0 and object : get_luaentity ( ) . _magnet_timer < item_drop_settings.magnet_time and inv and inv : room_for_item ( " main " , ItemStack ( object : get_luaentity ( ) . itemstring ) ) then
2017-02-16 00:57:35 +01:00
2017-06-03 17:03:22 +02:00
-- Collection
2017-09-05 17:25:15 +02:00
if vector.distance ( checkpos , object : getpos ( ) ) <= item_drop_settings.radius_collect and not object : get_luaentity ( ) . _removed then
2017-02-16 00:57:35 +01:00
if object : get_luaentity ( ) . itemstring ~= " " then
inv : add_item ( " main " , ItemStack ( object : get_luaentity ( ) . itemstring ) )
minetest.sound_play ( " item_drop_pickup " , {
pos = pos ,
2017-06-10 21:20:41 +02:00
max_hear_distance = 16 ,
gain = 1.0 ,
2017-02-16 00:57:35 +01:00
} )
2017-03-05 22:33:09 +01:00
check_pickup_achievements ( object , player )
2017-09-02 18:43:02 +02:00
-- If this happens, itemstring was "" (=hand). This is always a bug, the hand must never drop as item.
else
-- Scream this to the error log because this is bad.
2017-09-02 19:00:04 +02:00
minetest.log ( " error " , " Player " .. player : get_player_name ( ) .. " collected a hand at " .. minetest.pos_to_string ( object : getpos ( ) ) .. " (age= " .. object : get_luaentity ( ) . age .. " )! " )
2017-09-02 18:43:02 +02:00
2017-02-16 00:57:35 +01:00
end
2017-09-02 18:43:02 +02:00
-- Destroy entity
-- This just prevents this sectino to be run again because object:remove() doesn't remove the item immediately.
2017-09-05 17:25:15 +02:00
object : get_luaentity ( ) . _removed = true
2017-09-02 18:43:02 +02:00
object : remove ( )
collected = true
2017-06-03 17:03:22 +02:00
-- Magnet
else
2017-02-16 00:57:35 +01:00
2017-05-27 17:53:36 +02:00
object : get_luaentity ( ) . _magnet_active = true
object : get_luaentity ( ) . _collector_timer = 0
2017-06-03 17:36:43 +02:00
-- Move object to player
2017-06-10 21:39:26 +02:00
disable_physics ( object , object : get_luaentity ( ) )
2017-06-03 17:36:43 +02:00
local opos = object : getpos ( )
local vec = vector.subtract ( checkpos , opos )
vec = vector.add ( opos , vector.divide ( vec , 2 ) )
2017-06-03 17:27:58 +02:00
object : moveto ( vec )
2017-02-16 00:57:35 +01:00
--fix eternally falling items
2017-05-27 15:17:03 +02:00
minetest.after ( 0 , function ( object )
local lua = object : get_luaentity ( )
if lua then
object : setacceleration ( { x = 0 , y = 0 , z = 0 } )
end
end , object )
2017-02-16 00:57:35 +01:00
--this is a safety to prevent items flying away on laggy servers
if item_drop_settings.collection_safety == true then
if object : get_luaentity ( ) . init ~= true then
object : get_luaentity ( ) . init = true
minetest.after ( 1 , function ( args )
2017-05-30 05:51:48 +02:00
local player = args [ 1 ]
local object = args [ 2 ]
2017-02-16 00:57:35 +01:00
local lua = object : get_luaentity ( )
2017-05-27 15:17:03 +02:00
if player == nil or not player : is_player ( ) or object == nil or lua == nil or lua.itemstring == nil then
2017-02-16 00:57:35 +01:00
return
end
if inv : room_for_item ( " main " , ItemStack ( object : get_luaentity ( ) . itemstring ) ) then
inv : add_item ( " main " , ItemStack ( object : get_luaentity ( ) . itemstring ) )
2017-09-05 17:25:15 +02:00
if not object : get_luaentity ( ) . _removed then
2017-02-16 00:57:35 +01:00
minetest.sound_play ( " item_drop_pickup " , {
pos = pos ,
2017-06-10 21:20:41 +02:00
max_hear_distance = 16 ,
gain = 1.0 ,
2017-02-16 00:57:35 +01:00
} )
end
2017-03-05 22:33:09 +01:00
check_pickup_achievements ( object , player )
2017-09-05 17:25:15 +02:00
object : get_luaentity ( ) . _removed = true
2017-02-16 00:57:35 +01:00
object : remove ( )
else
2017-06-10 20:37:17 +02:00
enable_physics ( object , object : get_luaentity ( ) )
2017-02-16 00:57:35 +01:00
end
end , { player , object } )
end
end
end
end
2017-05-27 17:02:17 +02:00
2017-06-03 17:03:22 +02:00
if not collected then
if object : get_luaentity ( ) . _magnet_timer > 1 then
object : get_luaentity ( ) . _magnet_timer = - item_drop_settings.magnet_time
2017-06-10 21:10:15 +02:00
object : get_luaentity ( ) . _magnet_active = false
2017-06-03 17:03:22 +02:00
elseif object : get_luaentity ( ) . _magnet_timer < 0 then
object : get_luaentity ( ) . _magnet_timer = object : get_luaentity ( ) . _magnet_timer + dtime
end
2017-05-27 17:02:17 +02:00
end
2017-02-16 00:57:35 +01:00
end
end
2017-05-27 17:02:17 +02:00
2017-02-16 00:57:35 +01:00
end
end
2015-06-29 19:55:56 +02:00
end )
2017-08-03 01:01:44 +02:00
local minigroups = { " shearsy " , " swordy " , " shearsy_wool " , " swordy_cobweb " }
local basegroups = { " pickaxey " , " axey " , " shovely " }
local materials = { " wood " , " gold " , " stone " , " iron " , " diamond " }
-- Checks if the given node would drop its useful drop if dug by a tool
-- with the given tool capabilities. Returns true if it will yield its useful
-- drop, false otherwise.
local check_can_drop = function ( node_name , tool_capabilities )
local handy = minetest.get_item_group ( node_name , " handy " )
local dig_immediate = minetest.get_item_group ( node_name , " dig_immediate " )
if handy == 1 or dig_immediate == 2 or dig_immediate == 3 then
return true
else
local toolgroupcaps
if tool_capabilities then
toolgroupcaps = tool_capabilities.groupcaps
else
return false
end
-- Compare node groups with tool capabilities
for m = 1 , # minigroups do
local minigroup = minigroups [ m ]
local g = minetest.get_item_group ( node_name , minigroup )
if g ~= 0 then
local plus = minigroup .. " _dig "
if toolgroupcaps [ plus ] then
return true
end
end
end
for b = 1 , # basegroups do
local basegroup = basegroups [ b ]
local g = minetest.get_item_group ( node_name , basegroup )
if g ~= 0 then
for m = g , # materials do
local plus = basegroup .. " _dig_ " .. materials [ m ]
if toolgroupcaps [ plus ] then
return true
end
end
end
end
return false
end
end
2015-06-29 19:55:56 +02:00
function minetest . handle_node_drops ( pos , drops , digger )
2017-08-09 16:17:00 +02:00
local doTileDrops = minetest.settings : get_bool ( " mcl_doTileDrops " ) or true
if minetest.settings : get_bool ( " creative_mode " ) or doTileDrops == false then
2017-05-23 19:32:20 +02:00
return
2015-06-29 19:55:56 +02:00
end
2017-08-03 01:01:44 +02:00
-- Check if node will yield its useful drop by the digger's tool
local dug_node = minetest.get_node ( pos )
local tool = digger : get_wielded_item ( )
local toolcaps = tool : get_tool_capabilities ( )
if not check_can_drop ( dug_node.name , toolcaps ) then
return
end
2017-08-03 02:27:55 +02:00
--[[ Special node drops when dug by shears by reading _mcl_shears_drop
from the node definition .
Definition of _mcl_shears_drop :
* true : Drop itself when dug by shears
* table : Drop every itemstring in this table when dub by shears
] ]
local nodedef = minetest.registered_nodes [ dug_node.name ]
if toolcaps.groupcaps and toolcaps.groupcaps . shearsy_dig and nodedef._mcl_shears_drop then
if nodedef._mcl_shears_drop == true then
drops = { dug_node.name }
else
drops = nodedef._mcl_shears_drop
end
end
2015-06-29 19:55:56 +02:00
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
2017-05-23 19:32:20 +02:00
for i = 1 , count do
2017-09-05 17:25:15 +02:00
local obj = core.add_item ( pos , name )
2017-05-23 19:32:20 +02:00
if obj ~= nil then
local x = math.random ( 1 , 5 )
if math.random ( 1 , 2 ) == 1 then
x = - x
end
local z = math.random ( 1 , 5 )
if math.random ( 1 , 2 ) == 1 then
z = - z
2015-06-29 19:55:56 +02:00
end
2017-05-23 19:32:20 +02:00
obj : setvelocity ( { x = 1 / x , y = obj : getvelocity ( ) . y , z = 1 / z } )
2015-06-29 19:55:56 +02:00
end
end
end
end
2017-05-29 17:13:58 +02:00
-- Drop single items by default
function minetest . item_drop ( itemstack , dropper , pos )
if dropper and dropper : is_player ( ) then
local v = dropper : get_look_dir ( )
local p = { x = pos.x , y = pos.y + 1.2 , z = pos.z }
local cs = itemstack : get_count ( )
if dropper : get_player_control ( ) . sneak then
cs = 1
end
local item = itemstack : take_item ( cs )
local obj = core.add_item ( p , item )
if obj then
v.x = v.x * 4
v.y = v.y * 4 + 2
v.z = v.z * 4
obj : setvelocity ( v )
2017-05-30 18:16:36 +02:00
-- Force collection delay
obj : get_luaentity ( ) . _insta_collect = false
2017-05-29 17:13:58 +02:00
return itemstack
2017-02-16 00:57:35 +01:00
end
end
end
--modify builtin:item
local time_to_live = tonumber ( core.setting_get ( " item_entity_ttl " ) )
if not time_to_live then
2017-05-29 17:18:43 +02:00
time_to_live = 300
2017-02-16 00:57:35 +01:00
end
core.register_entity ( " :__builtin:item " , {
initial_properties = {
hp_max = 1 ,
physical = true ,
collide_with_objects = false ,
collisionbox = { - 0.3 , - 0.3 , - 0.3 , 0.3 , 0.3 , 0.3 } ,
visual = " wielditem " ,
visual_size = { x = 0.4 , y = 0.4 } ,
textures = { " " } ,
spritediv = { x = 1 , y = 1 } ,
initial_sprite_basepos = { x = 0 , y = 0 } ,
is_visible = false ,
infotext = " " ,
} ,
itemstring = ' ' ,
physical_state = true ,
2017-06-10 20:47:12 +02:00
_flowing = false , -- item entity is currently flowing
-- States:
-- * "magnet": Attracted to a nearby player or item
-- * "flowing": Moving in a flowing liquid
-- * "normal": Affected by gravitiy
2017-02-16 00:57:35 +01:00
age = 0 ,
set_item = function ( self , itemstring )
self.itemstring = itemstring
local stack = ItemStack ( itemstring )
local count = stack : get_count ( )
local max_count = stack : get_stack_max ( )
if count > max_count then
count = max_count
self.itemstring = stack : get_name ( ) .. " " .. max_count
end
local s = 0.2 + 0.1 * ( count / max_count )
local c = s
local itemtable = stack : to_table ( )
local itemname = nil
local description = " "
if itemtable then
itemname = stack : to_table ( ) . name
end
local item_texture = nil
local item_type = " "
if core.registered_items [ itemname ] then
item_texture = core.registered_items [ itemname ] . inventory_image
item_type = core.registered_items [ itemname ] . type
description = core.registered_items [ itemname ] . description
end
local prop = {
is_visible = true ,
visual = " wielditem " ,
textures = { itemname } ,
visual_size = { x = s , y = s } ,
collisionbox = { - c , - c , - c , c , c , c } ,
automatic_rotate = math.pi * 0.5 ,
infotext = description ,
}
self.object : set_properties ( prop )
if item_drop_settings.random_item_velocity == true then
2017-05-27 15:17:03 +02:00
minetest.after ( 0 , function ( self )
if not self or not self.object or not self.object : get_luaentity ( ) then
return
end
2017-02-16 00:57:35 +01:00
local vel = self.object : getvelocity ( )
2017-02-18 02:06:21 +01:00
if vel and vel.x == 0 and vel.z == 0 then
2017-02-16 00:57:35 +01:00
local x = math.random ( 1 , 5 )
if math.random ( 1 , 2 ) == 1 then
x = - x
end
local z = math.random ( 1 , 5 )
if math.random ( 1 , 2 ) == 1 then
z = - z
end
local y = math.random ( 2 , 4 )
self.object : setvelocity ( { x = 1 / x , y = y , z = 1 / z } )
end
2017-05-27 15:17:03 +02:00
end , self )
2017-02-16 00:57:35 +01:00
end
end ,
get_staticdata = function ( self )
return core.serialize ( {
itemstring = self.itemstring ,
always_collect = self.always_collect ,
age = self.age ,
2017-05-29 23:31:41 +02:00
_insta_collect = self._insta_collect ,
2017-06-10 20:47:12 +02:00
_flowing = self._flowing ,
2017-09-05 17:25:15 +02:00
_removed = self._removed ,
2017-02-16 00:57:35 +01:00
} )
end ,
on_activate = function ( self , staticdata , dtime_s )
if string.sub ( staticdata , 1 , string.len ( " return " ) ) == " return " then
local data = core.deserialize ( staticdata )
if data and type ( data ) == " table " then
self.itemstring = data.itemstring
self.always_collect = data.always_collect
if data.age then
self.age = data.age + dtime_s
else
self.age = dtime_s
end
--remember collection data
2017-05-30 00:58:14 +02:00
-- If true, can collect item without delay
self._insta_collect = data._insta_collect
2017-06-10 20:47:12 +02:00
self._flowing = data._flowing
2017-09-05 17:25:15 +02:00
self._removed = data._removed
2017-02-16 00:57:35 +01:00
end
else
self.itemstring = staticdata
end
2017-09-05 17:25:15 +02:00
if self._removed then
self._removed = true
self.object : remove ( )
return
end
2017-05-30 18:16:36 +02:00
if self._insta_collect == nil then
-- Intentionally default, since delayed collection is rare
self._insta_collect = true
end
2017-06-10 20:47:12 +02:00
if self._flowing == nil then
self._flowing = false
end
2017-05-27 17:02:17 +02:00
self._magnet_timer = 0
2017-05-27 17:53:36 +02:00
self._magnet_active = false
-- How long ago the last possible collector was detected. nil = none in this session
self._collector_timer = nil
2017-05-30 00:58:14 +02:00
-- Used to apply additional force
self._force = nil
self._forcestart = nil
self._forcetimer = 0
2017-02-16 00:57:35 +01:00
self.object : set_armor_groups ( { immortal = 1 } )
self.object : setvelocity ( { x = 0 , y = 2 , z = 0 } )
2017-05-27 15:22:28 +02:00
self.object : setacceleration ( { x = 0 , y = - get_gravity ( ) , z = 0 } )
2017-02-16 00:57:35 +01:00
self : set_item ( self.itemstring )
end ,
2017-09-05 19:17:40 +02:00
try_merge_with = function ( self , own_stack , object , entity )
if self.age == entity.age or entity._removed then
-- Can not merge with itself and remove entity
return false
2017-02-16 00:57:35 +01:00
end
2017-09-05 19:17:40 +02:00
local stack = ItemStack ( entity.itemstring )
local name = stack : get_name ( )
if own_stack : get_name ( ) ~= name or
own_stack : get_meta ( ) ~= stack : get_meta ( ) or
own_stack : get_wear ( ) ~= stack : get_wear ( ) or
own_stack : get_free_space ( ) == 0 then
-- Can not merge different or full stack
return false
end
local count = own_stack : get_count ( )
local total_count = stack : get_count ( ) + count
local max_count = stack : get_stack_max ( )
if total_count > max_count then
return false
end
-- Merge the remote stack into this one
local pos = object : get_pos ( )
pos.y = pos.y + ( ( total_count - count ) / max_count ) * 0.15
self.object : move_to ( pos )
self.age = 0 -- Handle as new entity
own_stack : set_count ( total_count )
self : set_item ( own_stack : to_string ( ) )
entity._removed = true
object : remove ( )
return true
2017-02-16 00:57:35 +01:00
end ,
on_step = function ( self , dtime )
2017-09-05 17:25:15 +02:00
if self._removed then
return
end
2017-02-16 00:57:35 +01:00
self.age = self.age + dtime
2017-05-27 17:53:36 +02:00
if self._collector_timer ~= nil then
self._collector_timer = self._collector_timer + dtime
end
2017-02-16 00:57:35 +01:00
if time_to_live > 0 and self.age > time_to_live then
2017-09-05 17:25:15 +02:00
self._removed = true
2017-02-16 00:57:35 +01:00
self.object : remove ( )
return
end
2017-09-02 18:43:02 +02:00
-- If, for some reason, an item entity with itemstring == "" (hand) appears, this is very bad.
if not self._hand_bug_detected and self.age > 1 and self.itemstring == " " then
-- We must this scream this into the error console. The bug is rare an
minetest.log ( " error " , " A hand item entity appeared at " .. minetest.pos_to_string ( self.object : getpos ( ) ) .. " ! " )
self._hand_bug_detected = true
end
2017-02-16 00:57:35 +01:00
local p = self.object : getpos ( )
local node = core.get_node_or_nil ( p )
local in_unloaded = ( node == nil )
2017-05-27 17:53:36 +02:00
-- If no collector was found for a long enough time, declare the magnet as disabled
if self._magnet_active and ( self._collector_timer == nil or ( self._collector_timer > item_drop_settings.magnet_time ) ) then
self._magnet_active = false
2017-06-10 20:37:17 +02:00
enable_physics ( self.object , self )
2017-05-30 06:00:26 +02:00
return
2017-05-27 17:53:36 +02:00
end
2017-05-30 13:59:26 +02:00
if in_unloaded then
2017-06-10 20:37:17 +02:00
-- Don't infinetly fall into unloaded map
disable_physics ( self.object , self )
2017-02-16 00:57:35 +01:00
return
end
2017-02-16 18:26:38 +01:00
2017-02-16 19:32:42 +01:00
-- Destroy item in lava or special nodes
2017-02-16 00:57:35 +01:00
local nn = node.name
2017-02-16 19:32:42 +01:00
local def = minetest.registered_nodes [ nn ]
if ( def and def.groups and ( def.groups . lava or def.groups . destroys_items == 1 ) ) then
-- Special effect for lava
if def.groups . lava then
minetest.sound_play ( " builtin_item_lava " , { pos = self.object : getpos ( ) , gain = 0.5 } )
end
2017-09-05 17:25:15 +02:00
self._removed = true
2017-02-16 18:26:38 +01:00
self.object : remove ( )
return
end
2017-05-29 22:51:13 +02:00
-- Push item out when stuck inside solid opaque node
if def and def.walkable and def.groups and def.groups . opaque == 1 then
local shootdir
local cx = p.x % 1
local cz = p.z % 1
local order = { }
-- First prepare the order in which the 4 sides are to be checked.
-- 1st: closest
-- 2nd: other direction
-- 3rd and 4th: other axis
local cxcz = function ( o , cw , one , zero )
if cw > 0 then
table.insert ( o , { [ one ] = 1 , y = 0 , [ zero ] = 0 } )
table.insert ( o , { [ one ] =- 1 , y = 0 , [ zero ] = 0 } )
else
table.insert ( o , { [ one ] =- 1 , y = 0 , [ zero ] = 0 } )
table.insert ( o , { [ one ] = 1 , y = 0 , [ zero ] = 0 } )
end
return o
end
if math.abs ( cx ) > math.abs ( cz ) then
order = cxcz ( order , cx , " x " , " z " )
order = cxcz ( order , cz , " z " , " x " )
else
order = cxcz ( order , cz , " z " , " x " )
order = cxcz ( order , cx , " x " , " z " )
end
-- Check which one of the 4 sides is free
for o = 1 , # order do
local nn = minetest.get_node ( vector.add ( p , order [ o ] ) ) . name
local def = minetest.registered_nodes [ nn ]
if def and def.walkable == false and nn ~= " ignore " then
shootdir = order [ o ]
2017-05-29 22:56:53 +02:00
break
2017-05-29 22:51:13 +02:00
end
end
-- If none of the 4 sides is free, shoot upwards
if shootdir == nil then
shootdir = { x = 0 , y = 1 , z = 0 }
local nn = minetest.get_node ( vector.add ( p , shootdir ) ) . name
if nn == " ignore " then
-- Do not push into ignore
return
end
end
-- Set new item moving speed accordingly
local newv = vector.multiply ( shootdir , 3 )
self.object : setacceleration ( { x = 0 , y = 0 , z = 0 } )
self.object : setvelocity ( newv )
2017-06-10 20:56:53 +02:00
disable_physics ( self.object , self , false , false )
2017-05-30 00:58:14 +02:00
if shootdir.y == 0 then
self._force = newv
p.x = math.floor ( p.x )
p.y = math.floor ( p.y )
p.z = math.floor ( p.z )
self._forcestart = p
self._forcetimer = 1
end
return
end
-- This code is run after the entity got a push from above “push away” code.
-- It is responsible for making sure the entity is entirely outside the solid node
-- (with its full collision box), not just its center.
if self._forcetimer > 0 then
local cbox = self.object : get_properties ( ) . collisionbox
local ok = false
if self._force . x > 0 and ( p.x > ( self._forcestart . x + 0.5 + ( cbox [ 4 ] - cbox [ 1 ] ) / 2 ) ) then ok = true
elseif self._force . x < 0 and ( p.x < ( self._forcestart . x + 0.5 - ( cbox [ 4 ] - cbox [ 1 ] ) / 2 ) ) then ok = true
elseif self._force . z > 0 and ( p.z > ( self._forcestart . z + 0.5 + ( cbox [ 6 ] - cbox [ 3 ] ) / 2 ) ) then ok = true
elseif self._force . z < 0 and ( p.z < ( self._forcestart . z + 0.5 - ( cbox [ 6 ] - cbox [ 3 ] ) / 2 ) ) then ok = true end
-- Item was successfully forced out. No more pushing
if ok then
self._forcetimer = - 1
self._force = nil
2017-06-10 20:37:17 +02:00
enable_physics ( self.object , self )
2017-05-30 00:58:14 +02:00
else
self._forcetimer = self._forcetimer - dtime
end
return
elseif self._force then
self._force = nil
2017-06-10 20:37:17 +02:00
enable_physics ( self.object , self )
2017-05-29 22:51:13 +02:00
return
end
2017-02-16 18:26:38 +01:00
-- Move item around on flowing liquids
2017-05-29 21:42:24 +02:00
if def and def.liquidtype == " flowing " then
2017-02-16 18:26:38 +01:00
2017-02-19 23:41:46 +01:00
--[[ Get flowing direction (function call from flowlib), if there's a liquid.
NOTE : According to Qwertymine , flowlib.quickflow is only reliable for liquids with a flowing distance of 7.
Luckily , this is exactly what we need if we only care about water , which has this flowing distance . ] ]
2017-05-29 21:42:24 +02:00
local vec = flowlib.quick_flow ( p , node )
2017-02-19 23:41:46 +01:00
-- Just to make sure we don't manipulate the speed for no reason
if vec.x ~= 0 or vec.y ~= 0 or vec.z ~= 0 then
2017-02-16 18:26:38 +01:00
-- Minecraft Wiki: Flowing speed is "about 1.39 meters per second"
local f = 1.39
2017-02-19 23:41:46 +01:00
-- Set new item moving speed into the direciton of the liquid
local newv = vector.multiply ( vec , f )
self.object : setacceleration ( { x = 0 , y = 0 , z = 0 } )
self.object : setvelocity ( { x = newv.x , y = - 0.22 , z = newv.z } )
2017-02-16 18:26:38 +01:00
self.physical_state = true
2017-06-10 20:47:12 +02:00
self._flowing = true
2017-02-16 18:26:38 +01:00
self.object : set_properties ( {
physical = true
} )
return
end
2017-06-10 20:47:12 +02:00
elseif self._flowing == true then
-- Disable flowing physics if not on/in flowing liquid
self._flowing = false
2017-06-10 20:56:53 +02:00
enable_physics ( self.object , self , true )
2017-06-10 20:47:12 +02:00
return
2017-02-16 18:26:38 +01:00
end
2017-02-16 00:57:35 +01:00
-- If node is not registered or node is walkably solid and resting on nodebox
2017-05-29 20:10:51 +02:00
local nn = minetest.get_node ( { x = p.x , y = p.y - 0.5 , z = p.z } ) . name
2017-02-16 00:57:35 +01:00
local v = self.object : getvelocity ( )
2017-02-16 18:26:38 +01:00
2017-02-16 00:57:35 +01:00
if not core.registered_nodes [ nn ] or core.registered_nodes [ nn ] . walkable and v.y == 0 then
if self.physical_state then
local own_stack = ItemStack ( self.object : get_luaentity ( ) . itemstring )
-- Merge with close entities of the same item
for _ , object in ipairs ( core.get_objects_inside_radius ( p , 0.8 ) ) do
local obj = object : get_luaentity ( )
if obj and obj.name == " __builtin:item "
and obj.physical_state == false then
if self : try_merge_with ( own_stack , object , obj ) then
return
end
end
end
2017-06-10 20:37:17 +02:00
disable_physics ( self.object , self )
2017-02-16 00:57:35 +01:00
end
else
2017-06-10 20:37:17 +02:00
if self._magnet_active == false then
enable_physics ( self.object , self )
2017-02-16 00:57:35 +01:00
end
end
end ,
2017-02-17 02:47:29 +01:00
-- Note: on_punch intentionally left out. The player should *not* be able to collect items by punching
2017-02-16 00:57:35 +01:00
} )
2017-08-09 16:17:00 +02:00
if minetest.settings : get_bool ( " log_mods " ) then
2017-02-17 02:44:33 +01:00
minetest.log ( " action " , " mcl_item_entity loaded " )
2017-02-16 00:57:35 +01:00
end