From 5fecab3ed7a959d2d2cfe1ecc9b0c9e5ad815be0 Mon Sep 17 00:00:00 2001 From: Sokomine Date: Sat, 19 Jun 2021 02:23:43 +0200 Subject: [PATCH] implemented part of npc_gives/npc_wants item handling --- fs_edit_actions.lua | 152 +++++++++++++++++++++++++++++++++++++++----- trade_simple.lua | 9 +++ 2 files changed, 144 insertions(+), 17 deletions(-) diff --git a/fs_edit_actions.lua b/fs_edit_actions.lua index 5529de3..322ceed 100644 --- a/fs_edit_actions.lua +++ b/fs_edit_actions.lua @@ -162,6 +162,9 @@ yl_speak_up.execute_next_action = function(player, a_id, result_of_a_id) yl_speak_up.debug_msg(player, n_id, o_id, "Action ".. tostring(a_id).." failed. Switching to dialog ".. tostring(this_action.a_on_failure)..".") + yl_speak_up.speak_to[pname].d_id = this_action.a_on_failure + yl_speak_up.speak_to[pname].o_id = nil + yl_speak_up.speak_to[pname].a_id = nil yl_speak_up.show_fs(player, "talk", {n_id = n_id, d_id = this_action.a_on_failure}) return @@ -192,6 +195,8 @@ yl_speak_up.execute_next_action = function(player, a_id, result_of_a_id) "Doing effects/results now.") -- execute all effects/results local target_dialog = yl_speak_up.execute_all_relevant_effects(player, effects, o_id, true) + yl_speak_up.speak_to[pname].o_id = nil + yl_speak_up.speak_to[pname].a_id = nil -- the function above returns a target dialog; show that to the player yl_speak_up.show_fs(player, "talk", {n_id = n_id, d_id = target_dialog}) end @@ -222,6 +227,80 @@ yl_speak_up.execute_action = function(player, n_id, o_id, a) end +-- helper function; +-- returns the action the player is currently faced with (or nil if none) +yl_speak_up.get_action_by_player = function(player) + local pname = player:get_player_name() + local dialog = yl_speak_up.speak_to[pname].dialog + local n_id = yl_speak_up.speak_to[pname].n_id + local d_id = yl_speak_up.speak_to[pname].d_id + local o_id = yl_speak_up.speak_to[pname].o_id + local a_id = yl_speak_up.speak_to[pname].a_id + if(not(dialog) or not(d_id) or not(o_id) or not(a_id) + or not(dialog.n_dialogs) + or not(dialog.n_dialogs[d_id]) + or not(dialog.n_dialogs[d_id].d_options) + or not(dialog.n_dialogs[d_id].d_options[o_id]) + or not(dialog.n_dialogs[d_id].d_options[o_id].actions) + or not(dialog.n_dialogs[d_id].d_options[o_id].actions[a_id])) then + return nil + end + return dialog.n_dialogs[d_id].d_options[o_id].actions[a_id] +end + + +-- Create the quest item by taking a raw item (i.e. a general piece of paper) out +-- of the NPC's inventory, applying a description (if given) and quest id (if +-- given); place the quest item in the trade inv of the player in the npc_gives slot. +-- The npc_gives inv is managed mostly by the NPC, except when in edit mode. We can +-- just overwrite anything old in there. +-- Returns false if the creation of the quest item wasn't possible (i.e. the +-- NPC had no paper left). +yl_speak_up.action_quest_item_prepare = function(player) + -- which action are we talking about? + local a = yl_speak_up.get_action_by_player(player) + if(not(a) or not(a.a_id) or not(a.a_value)) then + return false + end + local pname = player:get_player_name() + local n_id = yl_speak_up.speak_to[pname].n_id + -- what shall the NPC give? + local stack = ItemStack(a.a_value) + -- get the inventory of the NPC + local npc_inv = minetest.get_inventory({type="detached", name="yl_speak_up_npc_"..tostring(n_id)}) + -- does the NPC have the item we are looking for? + if(not(npc_inv:contains_item("npc_main", stack))) then + local o_id = yl_speak_up.speak_to[pname].o_id + yl_speak_up.debug_msg(player, n_id, o_id, "Action "..tostring(a.a_id)..": NPC ran out of ".. + tostring(a.a_value)..".") + return false + end + -- get the items from the NPCs inventory + local new_stack = npc_inv:remove_item("npc_main", stack) + local meta = new_stack:get_meta() + -- if given: set the item stack description + if(a.a_item_desc and a.a_item_desc ~= "") then + meta:set_string("description", a.a_item_desc) + end + if(a.a_item_quest_id and a.a_item_quest_id ~= "") then + -- which player got this quest item? + meta:set_string("yl_speak_up:quest_item_for", pname) + -- include the NPC id so that we know which NPC gave it + meta:set_string("yl_speak_up:quest_item_from", tostring(n_id)) + -- extend quest_id by NPC id so that it becomes more uniq + meta:set_string("yl_speak_up:quest_id", + tostring(n_id).." "..tostring(a.a_item_quest_id)) + end + -- put the stack in the npc_gives-slot of the trade inventory of the player + -- (as that slot is managed by the NPC alone we don't have to worry about + -- anything else in the slot) + local trade_inv = minetest.get_inventory({type="detached", name="yl_speak_up_player_"..pname}) + -- actually put the stack in there + trade_inv:set_stack("npc_gives", 1, new_stack) + return true +end + + -- strip the quest information from the item and give it back to the NPC; -- returns the modified stack (but also places it in the NPC's inventory) yl_speak_up.action_quest_item_take_back = function(stack, player) @@ -229,17 +308,54 @@ yl_speak_up.action_quest_item_take_back = function(stack, player) end --- the buy inv is managed by the NPC; we can just overwrite anything old in there; --- TODO: find out what we are talking about --- TODO: does the npc have the necessary item(s) in his inventory? --- TODO: take the items from the NPC's inventory -yl_speak_up.action_quest_item_prepare = function(player) - -- TODO: implement action_quest_item_prepare -end - - +-- check if the item in the npc_gives slot is the one the NPC wants yl_speak_up.action_quest_item_check = function(stack, player) - -- TODO: implement action_quest_item_check + -- which action are we talking about? + local a = yl_speak_up.get_action_by_player(player) + if(not(a) or not(a.a_id) or not(a.a_value)) then + return false + end + local pname = player:get_player_name() + local n_id = yl_speak_up.speak_to[pname].n_id + local o_id = yl_speak_up.speak_to[pname].o_id + -- get the item that needs to be checked + local trade_inv = minetest.get_inventory({type="detached", name="yl_speak_up_player_"..pname}) + local stack = trade_inv:get_stack("npc_wants", 1) + -- nothing there? + if(stack:is_empty()) then + yl_speak_up.debug_msg(player, n_id, o_id, "Action "..tostring(a.a_id)..": No item found.") + return false + end + local cmp = tostring(stack:get_name()).." "..(stack:get_count()) + -- wrong item or wrong amount? + if(cmp ~= a.a_value) then + yl_speak_up.debug_msg(player, n_id, o_id, "Action "..tostring(a.a_id).. + ": Wrong item given. Got: "..stack:to_string().. + " Expected: "..tostring(a.a_value)..".") + return false + end + local meta = stack:get_meta() + -- the description is not checked; just the quest id (if given) + if(a.a_item_quest_id and a.a_item_quest_id ~= "") then + -- we don't check here if the item was given by the right NPC; + -- only the quest id has to fit + if(meta:get_string("yl_speak_up:quest_id") ~= a.a_item_quest_id) then + yl_speak_up.debug_msg(player, n_id, o_id, "Action "..tostring(a.a_id).. + ": Wrong quest item (wrong ID).") + return false + end + -- was this quest item given to another player? + if(meta:get_string("yl_speak_up:quest_item_for") ~= pname) then + yl_speak_up.debug_msg(player, n_id, o_id, "Action "..tostring(a.a_id).. + ": Quest item was given to ".. + tostring(meta:get_string("yl_speak_up:quest_item_for")).. + ", but "..tostring(pname).." gave it.") + return false + end + end + yl_speak_up.debug_msg(player, n_id, o_id, "Action "..tostring(a.a_id).. + ": Quest item checked ok.") + return true end @@ -261,17 +377,17 @@ yl_speak_up.input_fs_action_npc_gives = function(player, formname, fields) yl_speak_up.execute_next_action(player, a_id, false) return end - -- is the buy inv empty? then all went as expected. + -- is the npc_gives inv empty? then all went as expected. -- (it does not really matter which button the player pressed in this case) - if(trade_inv:is_empty("buy")) then + if(trade_inv:is_empty("npc_gives")) then -- the action was a success; the NPC managed to give the item to the player yl_speak_up.execute_next_action(player, a_id, true) return end - -- the buy slot does not accept input - so we don't have to check for any misplaced items + -- the npc_gives slot does not accept input - so we don't have to check for any misplaced items -- but if the player aborts, give the item back to the NPC if(fields.back_to_talk) then - local stack = trade_inv:get_stack("buy", 1) + local stack = trade_inv:get_stack("npc_gives", 1) -- strip the quest item info from the stack (so that it may stack again) -- and give that (hopefully) stackable stack back to the NPC yl_speak_up.action_quest_item_take_back(stack, player) @@ -322,8 +438,8 @@ yl_speak_up.get_fs_action_npc_gives = function(player, param) "label[1.5,0.7;"..minetest.formspec_escape(dialog.n_npc or "- ? -").. " offers to you:]".. -- unlike the npc_gives slot - which is used for setting up the NPC - the - -- buy slot does not allow putting something in - "list[detached:yl_speak_up_player_"..pname..";buy;3.25,1.5;1,1;]" .. + -- npc_gives slot does not allow putting something in + "list[detached:yl_speak_up_player_"..pname..";npc_gives;3.25,1.5;1,1;]" .. "label[1.5,2.7;Take the offered item and click on \"Done\" to proceed.]" end @@ -398,6 +514,7 @@ end yl_speak_up.get_fs_action_text_input = function(player, param) + -- TODO implement text input formspec end @@ -406,7 +523,8 @@ yl_speak_up.input_fs_action_custom = function(player, formname, fields) end -yl_speak_up.get_fs_actioncustom = function(player, param) +yl_speak_up.get_fs_action_custom = function(player, param) + -- TODO implemnt custom formspec end diff --git a/trade_simple.lua b/trade_simple.lua index f1365b5..2e58db8 100644 --- a/trade_simple.lua +++ b/trade_simple.lua @@ -727,6 +727,15 @@ minetest.register_on_joinplayer(function(player, last_login) return yl_speak_up.inventory_allow_item(player, stack, "yl_speak_up:add_trade_simple") end + -- allow putting something in in edit mode - but not otherwise + if(listname == "npc_gives") then + local pname = player:get_player_name() + local n_id = yl_speak_up.speak_to[pname].n_id + -- only in edit mode! else the NPC manages this slot + if(not(n_id) or yl_speak_up.edit_mode[pname] ~= n_id) then + return 0 + end + end return stack:get_count() end, allow_take = function(inv, listname, index, stack, player)