96 lines
3.0 KiB
Lua

-- This mod disallows changing blocks in certain game modes.
-- In Editor mode, out-of-bounds blocks cannot be changed.
-- This can be bypassed with the server or protection_bypass privileges.
-- This also disallows taking blocks in the game when the inventory is full.
-- How many seconds to flash the hotbar if the inventory was full
local HOTBAR_FLASH_TIME = 0.5
-- Checks if the player would have room for the given node
-- in inventory and returns true. Or false if inventory has
-- no room left. Exception:
-- When player wields a non-digging tool, always returns
-- true.
local function has_room_for_node_drops(player, node)
local tool = player:get_wielded_item()
local tooldef = tool:get_definition()
-- This is not a digging tool as it would do
-- something else on dig
if tooldef.on_use then
return true
end
local inv = player:get_inventory()
local def = minetest.registered_nodes[node.name]
-- This assumes drops aren't random (which wouldn't
-- make sense in this game anyway)
local drops = minetest.get_node_drops(node, tool)
for d=1, #drops do
local drop = drops[d]
if not inv:room_for_item("main", drop) then
return false
end
end
return true
end
local old_is_protected = minetest.is_protected
minetest.is_protected = function(pos, name)
local state = lzr_gamestate.get_state()
-- Can't dig if inventory is full! (unless in editor)
if state ~= lzr_gamestate.EDITOR then
local player = minetest.get_player_by_name(name)
local node = minetest.get_node(pos)
if not has_room_for_node_drops(player, node) then
return true
end
end
if minetest.check_player_privs(name, { server = true, protection_bypass = true }) then
return false
end
if state == lzr_gamestate.LEVEL_COMPLETE or state == lzr_gamestate.MENU then
return true
elseif state == lzr_gamestate.EDITOR then
return not lzr_editor.is_in_level_bounds(pos)
end
return old_is_protected(pos, name)
end
local flash_jobs = {}
minetest.register_on_protection_violation(function(pos, name)
local state = lzr_gamestate.get_state()
if state ~= lzr_gamestate.EDITOR then
local player = minetest.get_player_by_name(name)
local node = minetest.get_node(pos)
if not has_room_for_node_drops(player, node) then
-- If there is already a job running, cancel it
if flash_jobs[name] then
flash_jobs[name]:cancel()
flash_jobs[name] = nil
end
-- Play warning sound and highlight the hotbar
minetest.sound_play({name = "lzr_protection_inventory_full", gain = 0.3}, {to_player=name}, true)
lzr_gui.set_hotbar_highlight(player, true)
-- Disable flashing after a brief moment
local job = minetest.after(HOTBAR_FLASH_TIME, function(player)
if player and player:is_player() then
lzr_gui.set_hotbar_highlight(player, false)
end
end, player)
-- Remember this 'after' job
flash_jobs[name] = job
end
end
end)
minetest.register_on_leaveplayer(function(player)
local pname = player:get_player_name()
if flash_jobs[pname] then
flash_jobs[pname]:cancel()
flash_jobs[pname] = nil
end
end)