missions/steps/chestput.lua
Riceball LEE 2a8f0916e8 feat: add resetChest and showCount options to PutInChest Step
Do not show count hint could be used in the puzzle problem
2022-08-14 12:19:37 +02:00

353 lines
8.5 KiB
Lua

local HUD_POSITION = {x = missions.hud.posx, y = missions.hud.posy }
local HUD_ALIGNMENT = {x = 1, y = 0}
local hud = {} -- playerName -> {}
local remainingItems = {} -- playerName -> ItemStack: the target item and count, eg, "default:stone 50"
local remainingCount = {} -- playerName -> count: the player put items in chest
local function cleanItemInChest(inv, stackItem, inv_name)
stackItem:set_count(1)
local maxRun = 99
while inv:contains_item(inv_name, stackItem) and maxRun > 0 do
stackItem:set_count(100*100)
inv:remove_item(inv_name, stackItem)
maxRun = maxRun - 1
end
--[[
if inv_name == nil then inv_name = "main" end
for i = 1, inv:get_size(inv_name) do
local vStack = inv:get_stack(inv_name, i)
if vStack:get_name() == stack:get_name() then
vStack:set_count(0)
-- inv:set_stack(inv_name, i)
end
end
--]]
end
missions.register_step({
type = "chestput",
name = "Put in chest",
create = function()
return {stack="", pos=nil, name="", visible=1, resetChest=false, showCount=false}
end,
get_status = function(ctx)
local player = ctx.player
local stepdata = ctx.step.data
local count = remainingCount[player:get_player_name()]
if type(count) == "number" then
local stack = ItemStack(stepdata.stack)
if not stepdata.showCount then count = "n" end
return "Put " .. count .. " x " .. stack:get_name() .. " into the chest"
else
return ""
end
end,
validate = function(ctx)
local meta = minetest.get_meta(ctx.pos)
local stepdata = ctx.step.data
local inv = meta:get_inventory()
local removeStack = ItemStack(stepdata.stack)
if stepdata.pos == nil then
return {
success=false,
failed=true,
msg="No position defined"
}
end
if inv:room_for_item("main", removeStack) then
return {success=true}
else
return {
success=false,
failed=true,
msg="Chest has no space for items: " .. stepdata.stack ..
" chest-location: " .. stepdata.pos.x .. "/" .. stepdata.pos.y .. "/" .. stepdata.pos.z
}
end
end,
allow_inv_stack_put = function(listname, index, stack)
-- allow position wand on pos 1 of main inv
if listname == "main" then
if index == 2 and stack:get_name() == "missions:wand_chest" then
return true
end
if index == 1 then
return true
end
end
return false
end,
edit_formspec = function(ctx)
local stepdata = ctx.step.data
local pos = ctx.pos
local resetChest = "false"
local showCount = "false"
if stepdata.resetChest then resetChest = "true" end
if stepdata.showCount then showCount = "true" end
ctx.inv:set_stack("main", 1, ItemStack(stepdata.stack))
local name = ""
if stepdata.pos then
local distance = vector.distance(ctx.pos, stepdata.pos)
name = name .. "Position(" .. stepdata.pos.x .. "/" ..
stepdata.pos.y .. "/" .. stepdata.pos.z ..") " ..
"Distance: " .. math.floor(distance) .. " m"
end
if stepdata.name then
name = name .. " with name '" .. stepdata.name .. "'"
end
local visibleText
if stepdata.visible == 1 then
visibleText = "Waypoint: Visible"
else
visibleText = "Waypoint: Hidden"
end
local formspec = "size[8,8;]" ..
"label[0,0;Put items in chest]" ..
"checkbox[4,-0.2;showCount;Show Count;".. showCount .. "]" ..
"label[0,1;Items]" ..
"list[nodemeta:" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ";main;2,1;1,1;0]" ..
"label[3,1;Target]" ..
"list[nodemeta:" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ";main;4,1;1,1;1]" ..
"label[0,2;" .. name .. "]" ..
"button_exit[0,6.5;8,1;togglevisible;" .. visibleText .. "]" ..
"list[current_player;main;0,2.5;8,4;]listring[]" ..
"button[0,7.3;4,1;save;Save]" ..
"checkbox[4.5,7.3;resetChest;Reset Chest;".. resetChest .. "]"
return formspec;
end,
update = function(ctx)
local fields = ctx.fields
local inv = ctx.inv
local stepdata = ctx.step.data
if fields.resetChest == "true" then
stepdata.resetChest = true
elseif fields.resetChest == "false" then
stepdata.resetChest = false
end
if fields.showCount == "true" then
stepdata.showCount = true
elseif fields.showCount == "false" then
stepdata.showCount = false
end
if fields.togglevisible then
if stepdata.visible == 1 then
stepdata.visible = 0
else
stepdata.visible = 1
end
ctx.show_editor()
end
if fields.save then
local stack = inv:get_stack("main", 1)
if not stack:is_empty() then
stepdata.stack = stack:to_string()
end
stack = inv:get_stack("main", 2)
if not stack:is_empty() then
local meta = stack:get_meta()
local pos = minetest.string_to_pos(meta:get_string("pos"))
local name = meta:get_string("name")
stepdata.pos = pos
stepdata.name = name
end
ctx.show_mission()
end
end,
on_step_enter = function(ctx)
local stepdata = ctx.step.data
local player = ctx.player
local playerName = player:get_player_name()
-- set stack
remainingItems[playerName] = stepdata.stack
local stack =ItemStack(stepdata.stack)
remainingCount[playerName] = stack:get_count()
if stepdata.resetChest then
local meta = minetest.get_meta(stepdata.pos)
local inv = meta:get_inventory()
local removeStack = ItemStack(stepdata.stack)
cleanItemInChest(inv, removeStack, "main")
end
local hud_data = {}
hud[playerName] = hud_data;
hud_data.counter = player:hud_add({
hud_elem_type = "text",
position = HUD_POSITION,
offset = {x = 0, y = 140},
text = "",
alignment = HUD_ALIGNMENT,
scale = {x = 100, y = 100},
number = 0x00FF00
})
hud_data.image = player:hud_add({
hud_elem_type = "image",
position = HUD_POSITION,
offset = {x = 32, y = 140},
text = missions.get_image(stack:get_name()),
alignment = HUD_ALIGNMENT,
scale = {x = 0.5, y = 0.5},
})
-- set waypoint, if enabled
if stepdata.visible == 1 then
hud_data.target = player:hud_add({
hud_elem_type = "waypoint",
name = "Chest: " .. stepdata.name,
text = "m",
number = 0xFF0000,
world_pos = stepdata.pos
})
end
end,
on_step_interval = function(ctx)
local player = ctx.player
local playerName = player:get_player_name()
local stepdata = ctx.step.data
local count = remainingCount[playerName]
if type(count) == "number" then
if count == 0 then
ctx.on_success()
end
local hud_data = hud[player:get_player_name()]
if not stepdata.showCount then count = "n " end
player:hud_change(hud_data.counter, "text", count .. "x")
else
ctx.on_success()
end
end,
on_step_exit = function(ctx)
local player = ctx.player
local playerName = player:get_player_name()
remainingItems[playerName] = ""
remainingCount[playerName] = nil
local hud_data = hud[playerName]
if hud_data and hud_data.image then
player:hud_remove(hud_data.image)
end
if hud_data and hud_data.counter then
player:hud_remove(hud_data.counter)
end
if hud_data and hud_data.target then
player:hud_remove(hud_data.target)
end
hud[playerName] = nil
end
})
local intercept_chest = function(name)
local def = minetest.registered_nodes[name]
if def ~= nil then
local delegate_put = def.on_metadata_inventory_put
local delegate_take = def.on_metadata_inventory_take
def.on_metadata_inventory_put = function(pos, listname, index, stack, player)
if player and player:is_player() then
local playerName = player:get_player_name()
local remStack = ItemStack(remainingItems[playerName])
if remStack:get_name() == stack:get_name() then
local count = remainingCount[playerName] or remStack:get_count()
count = count - stack:get_count()
remainingCount[playerName] = count
end
--print("Put Stack: " .. stack:get_name())
end
--delegate
delegate_put(pos, listname, index, stack, player)
end
def.on_metadata_inventory_take = function(pos, listname, index, stack, player)
if player and player:is_player() then
local playerName = player:get_player_name()
local remStack = ItemStack(remainingItems[playerName])
if remStack:get_name() == stack:get_name() then
local count = remainingCount[playerName] or remStack:get_count()
count = count + stack:get_count()
remainingCount[playerName] = count
end
--print("Take Stack: " .. stack:get_name())
end
--delegate
delegate_take(pos, listname, index, stack, player)
end
else
print("Definition not found: " .. name)
end
end
local has_more_chests_mod = minetest.get_modpath("more_chests")
intercept_chest("default:chest")
intercept_chest("default:chest_open")
if has_more_chests_mod then
intercept_chest("more_chests:dropbox")
end
-- TODO: technic-chests