96 lines
3.0 KiB
Lua
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)
|