2022-09-23 05:41:52 +02:00
mcl_entity_invs = { }
2022-09-27 04:59:13 +02:00
local open_invs = { }
2022-09-23 05:41:52 +02:00
local function check_distance ( inv , player , count )
for _ , o in pairs ( minetest.get_objects_inside_radius ( player : get_pos ( ) , 5 ) ) do
local l = o : get_luaentity ( )
if l and l._inv_id and inv : get_location ( ) . name == l._inv_id then return count end
end
return 0
end
local inv_callbacks = {
allow_take = function ( inv , listname , index , stack , player )
return check_distance ( inv , player , stack : get_count ( ) )
end ,
allow_move = function ( inv , from_list , from_index , to_list , to_index , count , player )
return check_distance ( inv , player , count )
end ,
allow_put = function ( inv , listname , index , stack , player )
return check_distance ( inv , player , stack : get_count ( ) )
end ,
}
local function load_inv ( ent , size )
if not ent._inv_id then return end
local inv = minetest.get_inventory ( { type = " detached " , name = ent._inv_id } )
if not inv then
inv = minetest.create_detached_inventory ( ent._inv_id , inv_callbacks )
inv : set_size ( " main " , size )
if ent._items then
inv : set_list ( " main " , ent._items )
end
end
return inv
end
2022-09-25 22:20:05 +02:00
local function save_inv ( ent )
if ent._inv then
ent._items = { }
for i , it in ipairs ( ent._inv : get_list ( " main " ) ) do
ent._items [ i ] = it : to_string ( )
end
2022-09-27 04:59:13 +02:00
minetest.remove_detached_inventory ( ent._inv_id )
ent._inv = nil
2022-09-25 22:20:05 +02:00
end
end
2022-10-01 23:47:06 +02:00
function mcl_entity_invs . show_inv_form ( ent , player , text )
2022-09-23 05:41:52 +02:00
if not ent._inv_id then return end
2022-09-25 22:20:05 +02:00
if not open_invs [ ent ] then
2022-09-27 04:59:13 +02:00
open_invs [ ent ] = 0
2022-09-25 22:20:05 +02:00
end
2022-10-01 23:47:06 +02:00
text = text or " "
2022-09-27 04:59:13 +02:00
ent._inv = load_inv ( ent , ent._inv_size )
open_invs [ ent ] = open_invs [ ent ] + 1
2022-09-23 05:41:52 +02:00
local playername = player : get_player_name ( )
2022-09-24 00:05:37 +02:00
local rows = 3
2022-09-27 04:59:13 +02:00
local cols = ( math.ceil ( ent._inv_size / rows ) )
2022-09-24 00:05:37 +02:00
local spacing = ( 9 - cols ) / 2
2022-09-23 05:41:52 +02:00
local formspec = " size[9,8.75] "
.. " label[0,0; " .. minetest.formspec_escape (
2022-10-01 23:47:06 +02:00
minetest.colorize ( " #313131 " , ent._inv_title .. " " .. text ) ) .. " ] "
2022-09-24 00:05:37 +02:00
.. " list[detached: " .. ent._inv_id .. " ;main; " .. spacing .. " ,0.5; " .. cols .. " , " .. rows .. " ;] "
.. mcl_formspec.get_itemslot_bg ( spacing , 0.5 , cols , rows )
2022-09-23 05:41:52 +02:00
.. " label[0,4.0; " .. minetest.formspec_escape (
minetest.colorize ( " #313131 " , " Inventory " ) ) .. " ] "
.. " list[current_player;main;0,4.5;9,3;9] "
.. mcl_formspec.get_itemslot_bg ( 0 , 4.5 , 9 , 3 )
.. " list[current_player;main;0,7.74;9,1;] "
.. mcl_formspec.get_itemslot_bg ( 0 , 7.74 , 9 , 1 )
.. " listring[detached: " .. ent._inv_id .. " ;main] "
.. " listring[current_player;main] "
minetest.show_formspec ( playername , ent._inv_id , formspec )
end
2022-09-23 18:17:03 +02:00
local function drop_inv ( ent )
2022-10-01 00:31:06 +02:00
if not ent._items then return end
2022-09-23 18:17:03 +02:00
local pos = ent.object : get_pos ( )
2022-09-25 22:20:05 +02:00
for i , it in pairs ( ent._items ) do
2022-09-23 18:17:03 +02:00
local p = vector.add ( pos , vector.new ( math.random ( ) - 0.5 , math.random ( ) - 0.5 , math.random ( ) - 0.5 ) )
2022-09-25 22:20:05 +02:00
minetest.add_item ( p , it )
2022-09-23 18:17:03 +02:00
end
2022-10-06 20:53:52 +02:00
ent._items = nil
2022-09-23 18:17:03 +02:00
end
2022-09-29 02:03:46 +02:00
local function on_remove ( self , killer , oldf )
save_inv ( self )
drop_inv ( self )
if oldf then return oldf ( self , killer ) end
end
2022-09-25 22:20:05 +02:00
minetest.register_on_player_receive_fields ( function ( player , formname , fields )
for k , v in pairs ( open_invs ) do
if formname == k._inv_id then
2022-09-27 04:59:13 +02:00
open_invs [ k ] = open_invs [ k ] - 1
if open_invs [ k ] < 1 then
2022-09-25 22:20:05 +02:00
save_inv ( k )
open_invs [ k ] = nil
end
end
end
end )
2022-09-27 04:59:13 +02:00
function mcl_entity_invs . register_inv ( entity_name , show_name , size , no_on_righclick )
2022-09-24 00:05:37 +02:00
assert ( minetest.registered_entities [ entity_name ] , " mcl_entity_invs.register_inv called with invalid entity: " .. tostring ( entity_name ) )
2022-09-27 04:59:13 +02:00
minetest.registered_entities [ entity_name ] . _inv_size = size
2022-10-01 23:47:06 +02:00
minetest.registered_entities [ entity_name ] . _inv_title = show_name
2022-09-27 04:59:13 +02:00
2022-09-23 05:41:52 +02:00
local old_oa = minetest.registered_entities [ entity_name ] . on_activate
minetest.registered_entities [ entity_name ] . on_activate = function ( self , staticdata , dtime_s )
2022-09-24 00:05:37 +02:00
local r
2022-09-27 11:39:04 +02:00
if old_oa then r = old_oa ( self , staticdata , dtime_s ) end
2022-09-23 05:41:52 +02:00
local d = minetest.deserialize ( staticdata )
if type ( d ) == " table " and d._inv_id then
self._inv_id = d._inv_id
self._items = d._items
2022-09-27 04:59:13 +02:00
self._inv_size = d._inv_size
2022-09-23 05:41:52 +02:00
else
self._inv_id = " entity_inv_ " .. minetest.sha1 ( minetest.get_gametime ( ) .. minetest.pos_to_string ( self.object : get_pos ( ) ) .. tostring ( math.random ( ) ) )
--gametime and position for collision safety and math.random salt to protect against position brute-force
end
2022-09-24 00:05:37 +02:00
return r
2022-09-23 05:41:52 +02:00
end
2022-09-27 04:59:13 +02:00
if not no_on_righclick then
local old_rc = minetest.registered_entities [ entity_name ] . on_rightclick
minetest.registered_entities [ entity_name ] . on_rightclick = function ( self , clicker )
mcl_entity_invs.show_inv_form ( self , clicker , show_name )
if old_rc then return old_rc ( self , clicker ) end
end
2022-09-23 05:41:52 +02:00
end
2022-09-27 04:59:13 +02:00
2022-09-23 05:41:52 +02:00
local old_gsd = minetest.registered_entities [ entity_name ] . get_staticdata
minetest.registered_entities [ entity_name ] . get_staticdata = function ( self )
local old_sd = old_gsd ( self )
local d = minetest.deserialize ( old_sd )
2022-09-24 00:05:37 +02:00
assert ( type ( d ) == " table " , " mcl_entity_invs currently only works with entities that return a (serialized) table in get_staticdata. " .. tostring ( self.name ) .. " returned: " .. tostring ( old_sd ) )
2022-09-23 05:41:52 +02:00
d._inv_id = self._inv_id
2022-09-27 04:59:13 +02:00
d._inv_size = self._inv_size
2022-09-23 05:41:52 +02:00
d._items = { }
2022-09-25 22:20:05 +02:00
if self._items then
for i , it in ipairs ( self._items ) do
d._items [ i ] = it
end
2022-09-23 05:41:52 +02:00
end
return minetest.serialize ( d )
end
2022-09-23 18:17:03 +02:00
local old_ode = minetest.registered_entities [ entity_name ] . on_deactivate
minetest.registered_entities [ entity_name ] . on_deactivate = function ( self , removal )
2022-09-27 04:59:13 +02:00
save_inv ( self )
2022-09-29 02:03:46 +02:00
if removal then
on_remove ( self )
end
2022-09-23 18:17:03 +02:00
if old_ode then return old_ode ( self , removal ) end
end
local old_od = minetest.registered_entities [ entity_name ] . on_death
2022-09-27 11:39:04 +02:00
minetest.registered_entities [ entity_name ] . on_death = function ( self , killer )
2022-09-29 02:03:46 +02:00
if not self.is_mob then
on_remove ( self , killer , old_od )
end
end
local old_odi = minetest.registered_entities [ entity_name ] . on_die
minetest.registered_entities [ entity_name ] . on_die = function ( self , killer )
if self.is_mob then
on_remove ( self , killer , old_od )
end
2022-09-23 18:17:03 +02:00
end
2022-09-23 05:41:52 +02:00
end