Actions: (WIP) Add locks, unlocks and re-execution of actions if there are interruptions. Need to improve the lock/unlock mechanism.
Dialogues, trading: Add lock and unlock upon starting/finishing an interaction. Updated README with progress. Pathfinding: Fix slight bug that avoid a map being generated if the difference of start and end positions' z coordinate is zero.
This commit is contained in:
parent
e265bc283e
commit
60b847a02a
@ -42,8 +42,8 @@ __Phase 3__: Trading: In progress
|
|||||||
- [ ] Dedicated traders are traders that, when talked to, always make buy and sell offers. They have a greater variety too.
|
- [ ] Dedicated traders are traders that, when talked to, always make buy and sell offers. They have a greater variety too.
|
||||||
- [ ] NPCs will also be able to offer "services", for example, repairing tools, by receiving an item and a payment, and then returning a specific item.
|
- [ ] NPCs will also be able to offer "services", for example, repairing tools, by receiving an item and a payment, and then returning a specific item.
|
||||||
|
|
||||||
__Phase 4__: Actions: In progress
|
__Phase 4__: Actions: Main functionality complete
|
||||||
- [ ] NPCs should be able to use chests, furnaces, doors, beds and sit on "sittable" nodes (in progress)
|
- [x] NPCs should be able to use chests, furnaces, doors, beds and sit on "sittable" nodes (in progress)
|
||||||
- [x] NPCs should be able to walk to specific places. Should also be able to open doors, fence gates and any other type of openable node while going to a place.
|
- [x] NPCs should be able to walk to specific places. Should also be able to open doors, fence gates and any other type of openable node while going to a place.
|
||||||
- [x] NPCs should have the ability to identify nodes that belong to him/her, and recall them/
|
- [x] NPCs should have the ability to identify nodes that belong to him/her, and recall them/
|
||||||
|
|
||||||
|
@ -55,6 +55,10 @@ pathfinder.nodes = {
|
|||||||
-- of the Jumper library to find a path from start_pos to end_pos. The range is
|
-- of the Jumper library to find a path from start_pos to end_pos. The range is
|
||||||
-- an extra amount of nodes to search in both the x and z coordinates.
|
-- an extra amount of nodes to search in both the x and z coordinates.
|
||||||
function pathfinder.find_path(start_pos, end_pos, range, walkable_nodes)
|
function pathfinder.find_path(start_pos, end_pos, range, walkable_nodes)
|
||||||
|
-- Check that start and end position are not the same
|
||||||
|
if start_pos.x == end_pos.x and start_pos.z == end_pos.z then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
-- Set walkable nodes to empty if parameter wasn't used
|
-- Set walkable nodes to empty if parameter wasn't used
|
||||||
if walkable_nodes == nil then
|
if walkable_nodes == nil then
|
||||||
walkable_nodes = {}
|
walkable_nodes = {}
|
||||||
@ -145,7 +149,8 @@ function pathfinder.create_map(start_pos, end_pos, extra_range, walkables)
|
|||||||
local grid = {}
|
local grid = {}
|
||||||
|
|
||||||
-- Loop through the area and classify nodes
|
-- Loop through the area and classify nodes
|
||||||
for z = 1, math.abs(pos1.z - pos2.z) do
|
-- The +2 addition tries to ensure the loop runs at least one.
|
||||||
|
for z = 1, math.abs(pos1.z - pos2.z) + 2 do
|
||||||
local current_row = {}
|
local current_row = {}
|
||||||
for x = 1, math.abs(pos1.x - pos2.x) do
|
for x = 1, math.abs(pos1.x - pos2.x) do
|
||||||
-- Calculate current position
|
-- Calculate current position
|
||||||
|
36
dialogue.lua
36
dialogue.lua
@ -55,13 +55,16 @@ function npc.dialogue.show_options_dialogue(self,
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- This function is used for showing a yes/no dialogue formspec
|
-- This function is used for showing a yes/no dialogue formspec
|
||||||
function npc.dialogue.show_yes_no_dialogue(prompt,
|
function npc.dialogue.show_yes_no_dialogue(self,
|
||||||
|
prompt,
|
||||||
positive_answer_label,
|
positive_answer_label,
|
||||||
positive_callback,
|
positive_callback,
|
||||||
negative_answer_label,
|
negative_answer_label,
|
||||||
negative_callback,
|
negative_callback,
|
||||||
player_name)
|
player_name)
|
||||||
|
|
||||||
|
npc.lock_actions(self)
|
||||||
|
|
||||||
local formspec = "size[7,3]"..
|
local formspec = "size[7,3]"..
|
||||||
"label[0.5,0.1;"..prompt.."]"..
|
"label[0.5,0.1;"..prompt.."]"..
|
||||||
"button_exit[0.5,1.15;6,0.5;yes_option;"..positive_answer_label.."]"..
|
"button_exit[0.5,1.15;6,0.5;yes_option;"..positive_answer_label.."]"..
|
||||||
@ -69,6 +72,7 @@ function npc.dialogue.show_yes_no_dialogue(prompt,
|
|||||||
|
|
||||||
-- Create entry into responses table
|
-- Create entry into responses table
|
||||||
npc.dialogue.dialogue_results.yes_no_dialogue[player_name] = {
|
npc.dialogue.dialogue_results.yes_no_dialogue[player_name] = {
|
||||||
|
npc = self,
|
||||||
yes_callback = positive_callback,
|
yes_callback = positive_callback,
|
||||||
no_callback = negative_callback
|
no_callback = negative_callback
|
||||||
}
|
}
|
||||||
@ -176,9 +180,20 @@ end
|
|||||||
-- This function processes a dialogue object and performs
|
-- This function processes a dialogue object and performs
|
||||||
-- actions depending on what is defined in the object
|
-- actions depending on what is defined in the object
|
||||||
function npc.dialogue.process_dialogue(self, dialogue, player_name)
|
function npc.dialogue.process_dialogue(self, dialogue, player_name)
|
||||||
|
|
||||||
|
-- Freeze NPC actions
|
||||||
|
npc.lock_actions(self)
|
||||||
|
|
||||||
-- Send dialogue line
|
-- Send dialogue line
|
||||||
if dialogue.text then
|
if dialogue.text then
|
||||||
minetest.chat_send_player(player_name, dialogue.text)
|
minetest.chat_send_player(player_name, self.nametag..": "..dialogue.text)
|
||||||
|
-- Check if dialogue has responses. If it doesn't, unlock the actions
|
||||||
|
-- queue and reset actions timer.'
|
||||||
|
minetest.log("Responses: "..dump(dialogue.responses))
|
||||||
|
minetest.log("Condition: "..dump(not dialogue.responses))
|
||||||
|
if not dialogue.responses then
|
||||||
|
npc.unlock_actions(self)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check if there are responses, then show multi-option dialogue if there are
|
-- Check if there are responses, then show multi-option dialogue if there are
|
||||||
@ -196,7 +211,8 @@ function npc.dialogue.process_dialogue(self, dialogue, player_name)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- Functions for rotating NPC to look at player (taken from the API itself)
|
-- Functions for rotating NPC to look at player
|
||||||
|
-- (taken from the mobs_redo API)
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local atan = function(x)
|
local atan = function(x)
|
||||||
if x ~= x then
|
if x ~= x then
|
||||||
@ -206,8 +222,7 @@ local atan = function(x)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function npc.dialogue.rotate_npc_to_player(self)
|
||||||
local function rotate_npc_to_player(self)
|
|
||||||
local s = self.object:getpos()
|
local s = self.object:getpos()
|
||||||
local objs = minetest.get_objects_inside_radius(s, 4)
|
local objs = minetest.get_objects_inside_radius(s, 4)
|
||||||
local lp = nil
|
local lp = nil
|
||||||
@ -244,6 +259,10 @@ minetest.register_on_player_receive_fields(function (player, formname, fields)
|
|||||||
|
|
||||||
if fields then
|
if fields then
|
||||||
local player_response = npc.dialogue.dialogue_results.yes_no_dialogue[player_name]
|
local player_response = npc.dialogue.dialogue_results.yes_no_dialogue[player_name]
|
||||||
|
|
||||||
|
-- Unlock queue, reset action timer and unfreeze NPC.
|
||||||
|
npc.unlock_actions(player_response.npc)
|
||||||
|
|
||||||
if fields.yes_option then
|
if fields.yes_option then
|
||||||
player_response.yes_callback()
|
player_response.yes_callback()
|
||||||
elseif fields.no_option then
|
elseif fields.no_option then
|
||||||
@ -288,14 +307,13 @@ minetest.register_on_player_receive_fields(function (player, formname, fields)
|
|||||||
npc.trade.CASUAL_TRADE_BUY_DIALOGUE
|
npc.trade.CASUAL_TRADE_BUY_DIALOGUE
|
||||||
.responses[player_response.options[i].response_id]
|
.responses[player_response.options[i].response_id]
|
||||||
.action(player_response.npc, player)
|
.action(player_response.npc, player)
|
||||||
|
|
||||||
elseif player_response.casual_trade_type == npc.trade.OFFER_SELL == true then
|
elseif player_response.casual_trade_type == npc.trade.OFFER_SELL == true then
|
||||||
-- Get functions from casual sell dialogue
|
-- Get functions from casual sell dialogue
|
||||||
npc.trade.CASUAL_TRADE_SELL_DIALOGUE
|
npc.trade.CASUAL_TRADE_SELL_DIALOGUE
|
||||||
.responses[player_response.options[i].response_id]
|
.responses[player_response.options[i].response_id]
|
||||||
.action(player_response.npc, player)
|
.action(player_response.npc, player)
|
||||||
end
|
end
|
||||||
|
return
|
||||||
else
|
else
|
||||||
-- Get dialogues for sex and phase
|
-- Get dialogues for sex and phase
|
||||||
local dialogues = npc.data.DIALOGUES[player_response.npc.sex][phase]
|
local dialogues = npc.data.DIALOGUES[player_response.npc.sex][phase]
|
||||||
@ -304,6 +322,10 @@ minetest.register_on_player_receive_fields(function (player, formname, fields)
|
|||||||
dialogues[player_response.options[i].dialogue_id]
|
dialogues[player_response.options[i].dialogue_id]
|
||||||
.responses[player_response.options[i].response_id]
|
.responses[player_response.options[i].response_id]
|
||||||
.action(player_response.npc, player)
|
.action(player_response.npc, player)
|
||||||
|
|
||||||
|
-- Unlock queue, reset action timer and unfreeze NPC.
|
||||||
|
npc.unlock_actions(player_response.npc)
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
|
119
npc.lua
119
npc.lua
@ -27,6 +27,12 @@ npc.direction = {
|
|||||||
west = 3
|
west = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
npc.action_state = {
|
||||||
|
none = 0,
|
||||||
|
executing = 1,
|
||||||
|
interrupted = 2
|
||||||
|
}
|
||||||
|
|
||||||
---------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------
|
||||||
-- General functions
|
-- General functions
|
||||||
---------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------
|
||||||
@ -203,8 +209,20 @@ end
|
|||||||
-- This function removes the first action in the action queue
|
-- This function removes the first action in the action queue
|
||||||
-- and then executes it
|
-- and then executes it
|
||||||
function npc.execute_action(self)
|
function npc.execute_action(self)
|
||||||
|
-- Check if an action was interrupted
|
||||||
|
if self.actions.current_action_state == npc.action_state.interrupted then
|
||||||
|
minetest.log("Inserting interrupted action: ")
|
||||||
|
-- Insert into queue the interrupted action
|
||||||
|
table.insert(self.actions.queue, 1, self.actions.state_before_lock.interrupted_action)
|
||||||
|
-- Clear the action
|
||||||
|
self.actions.state_before_lock.interrupted_action = {}
|
||||||
|
-- Clear the position
|
||||||
|
self.actions.state_before_lock.pos = {}
|
||||||
|
end
|
||||||
local result = nil
|
local result = nil
|
||||||
if table.getn(self.actions.queue) == 0 then
|
if table.getn(self.actions.queue) == 0 then
|
||||||
|
-- Set state to none
|
||||||
|
self.actions.current_action_state = npc.action_state.none
|
||||||
-- Keep state the same if there are no more actions in actions queue
|
-- Keep state the same if there are no more actions in actions queue
|
||||||
return self.freeze
|
return self.freeze
|
||||||
end
|
end
|
||||||
@ -213,10 +231,10 @@ function npc.execute_action(self)
|
|||||||
-- stack fashion
|
-- stack fashion
|
||||||
if action_obj.is_task == true then
|
if action_obj.is_task == true then
|
||||||
minetest.log("Executing task")
|
minetest.log("Executing task")
|
||||||
-- Remove from queue
|
|
||||||
table.remove(self.actions.queue, 1)
|
|
||||||
-- Backup current queue
|
-- Backup current queue
|
||||||
local backup_queue = self.actions.queue
|
local backup_queue = self.actions.queue
|
||||||
|
-- Remove this "task" action from queue
|
||||||
|
table.remove(self.actions.queue, 1)
|
||||||
-- Clear queue
|
-- Clear queue
|
||||||
self.actions.queue = {}
|
self.actions.queue = {}
|
||||||
-- Now, execute the task with its arguments
|
-- Now, execute the task with its arguments
|
||||||
@ -226,17 +244,77 @@ function npc.execute_action(self)
|
|||||||
for i = 1, #backup_queue do
|
for i = 1, #backup_queue do
|
||||||
table.insert(self.actions.queue, backup_queue[i])
|
table.insert(self.actions.queue, backup_queue[i])
|
||||||
end
|
end
|
||||||
minetest.log("New actions queue: "..dump(self))
|
|
||||||
else
|
else
|
||||||
minetest.log("Executing action")
|
minetest.log("Executing action")
|
||||||
|
-- Store the action that is being executed
|
||||||
|
self.actions.state_before_lock.interrupted_action = action_obj
|
||||||
|
-- Store current position
|
||||||
|
self.actions.state_before_lock.pos = self.object:getpos()
|
||||||
-- Execute action as normal
|
-- Execute action as normal
|
||||||
result = action_obj.action(action_obj.args)
|
result = action_obj.action(action_obj.args)
|
||||||
-- Remove executed action from queue
|
-- Remove task
|
||||||
table.remove(self.actions.queue, 1)
|
table.remove(self.actions.queue, 1)
|
||||||
|
-- Set state
|
||||||
|
self.actions.current_action_state = npc.action_state.executing
|
||||||
end
|
end
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function npc.lock_actions(self)
|
||||||
|
|
||||||
|
-- Avoid re-locking if already locked
|
||||||
|
if self.actions.action_timer_lock == true then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local pos = self.object:getpos()
|
||||||
|
|
||||||
|
if self.freeze == false then
|
||||||
|
-- Round current pos to avoid the NPC being stopped on positions
|
||||||
|
-- where later on can't walk to the correct positions
|
||||||
|
-- Choose which position is to be taken as start position
|
||||||
|
if self.actions.state_before_lock.pos ~= {} then
|
||||||
|
pos = vector.round(self.actions.state_before_lock.pos)
|
||||||
|
else
|
||||||
|
pos = vector.round(self.object:getpos())
|
||||||
|
end
|
||||||
|
pos.y = self.object:getpos().y
|
||||||
|
end
|
||||||
|
-- Stop NPC
|
||||||
|
npc.actions.stand({self=self, pos=pos})
|
||||||
|
-- Avoid all timer execution
|
||||||
|
self.actions.action_timer_lock = true
|
||||||
|
-- Reset timer so that it has some time after interaction is done
|
||||||
|
self.actions.action_timer = 0
|
||||||
|
-- Check if there are is an action executing
|
||||||
|
if self.actions.current_action_state == npc.action_state.executing
|
||||||
|
and self.freeze == false then
|
||||||
|
-- Store the current action state
|
||||||
|
self.actions.state_before_lock.action_state = self.actions.current_action_state
|
||||||
|
-- Set current action state to interrupted
|
||||||
|
self.actions.current_action_state = npc.action_state.interrupted
|
||||||
|
end
|
||||||
|
-- Store the current freeze variable
|
||||||
|
self.actions.state_before_lock.freeze = self.freeze
|
||||||
|
-- Freeze mobs_redo API
|
||||||
|
self.freeze = false
|
||||||
|
|
||||||
|
minetest.log("Locking")
|
||||||
|
end
|
||||||
|
|
||||||
|
function npc.unlock_actions(self)
|
||||||
|
-- Allow timers to execute
|
||||||
|
self.actions.action_timer_lock = false
|
||||||
|
-- Restore the value of self.freeze
|
||||||
|
self.freeze = self.actions.state_before_lock.freeze
|
||||||
|
|
||||||
|
if table.getn(self.actions.queue) == 0 then
|
||||||
|
-- Allow mobs_redo API to execute since action queue is empty
|
||||||
|
self.freeze = true
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.log("Unlocked")
|
||||||
|
end
|
||||||
|
|
||||||
---------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------
|
||||||
-- Spawning functions
|
-- Spawning functions
|
||||||
@ -307,7 +385,7 @@ local function npc_spawn(self, pos)
|
|||||||
local ent = self:get_luaentity()
|
local ent = self:get_luaentity()
|
||||||
|
|
||||||
-- Set name
|
-- Set name
|
||||||
ent.nametag = ""
|
ent.nametag = "Kio"
|
||||||
|
|
||||||
-- Set ID
|
-- Set ID
|
||||||
ent.npc_id = tostring(math.random(1000, 9999))..":"..ent.nametag
|
ent.npc_id = tostring(math.random(1000, 9999))..":"..ent.nametag
|
||||||
@ -366,7 +444,7 @@ local function npc_spawn(self, pos)
|
|||||||
select_casual_trade_offers(ent)
|
select_casual_trade_offers(ent)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Action queue
|
-- Actions data
|
||||||
ent.actions = {
|
ent.actions = {
|
||||||
-- The queue is a queue of actions to be performed on each interval
|
-- The queue is a queue of actions to be performed on each interval
|
||||||
queue = {},
|
queue = {},
|
||||||
@ -374,7 +452,20 @@ local function npc_spawn(self, pos)
|
|||||||
action_timer = 0,
|
action_timer = 0,
|
||||||
-- Determines the interval for each action in the action queue
|
-- Determines the interval for each action in the action queue
|
||||||
-- Default is 1. This can be changed via actions
|
-- Default is 1. This can be changed via actions
|
||||||
action_interval = 1
|
action_interval = 1,
|
||||||
|
-- Avoid the execution of the action timer
|
||||||
|
action_timer_lock = false,
|
||||||
|
-- Defines the state of the current action
|
||||||
|
current_action_state = npc.action_state.none,
|
||||||
|
-- Store information about action on state before lock
|
||||||
|
state_before_lock = {
|
||||||
|
-- State of the mobs_redo API
|
||||||
|
freeze = false,
|
||||||
|
-- State of execution
|
||||||
|
action_state = npc.action_state.none,
|
||||||
|
-- Action executed while on lock
|
||||||
|
interrupted_action = {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
-- This flag is checked on every step. If it is true, the rest of
|
-- This flag is checked on every step. If it is true, the rest of
|
||||||
@ -396,7 +487,7 @@ local function npc_spawn(self, pos)
|
|||||||
--npc.add_action(ent, npc.actions.stand, {self = ent})
|
--npc.add_action(ent, npc.actions.stand, {self = ent})
|
||||||
if nodes[1] ~= nil then
|
if nodes[1] ~= nil then
|
||||||
npc.add_task(ent, npc.actions.walk_to_pos, {self=ent, end_pos=nodes[1], walkable={}})
|
npc.add_task(ent, npc.actions.walk_to_pos, {self=ent, end_pos=nodes[1], walkable={}})
|
||||||
npc.actions.use_furnace(ent, nodes[1], "default:cobble 10", false)
|
npc.actions.use_furnace(ent, nodes[1], "default:cobble 5", false)
|
||||||
--npc.add_action(ent, npc.actions.sit, {self = ent})
|
--npc.add_action(ent, npc.actions.sit, {self = ent})
|
||||||
-- npc.add_action(ent, npc.actions.lay, {self = ent})
|
-- npc.add_action(ent, npc.actions.lay, {self = ent})
|
||||||
-- npc.add_action(ent, npc.actions.lay, {self = ent})
|
-- npc.add_action(ent, npc.actions.lay, {self = ent})
|
||||||
@ -497,10 +588,14 @@ mobs:register_mob("advanced_npc:npc", {
|
|||||||
},
|
},
|
||||||
on_rightclick = function(self, clicker)
|
on_rightclick = function(self, clicker)
|
||||||
|
|
||||||
|
-- Rotate NPC toward its clicker
|
||||||
|
npc.dialogue.rotate_npc_to_player(self)
|
||||||
|
|
||||||
|
-- Get information from clicker
|
||||||
local item = clicker:get_wielded_item()
|
local item = clicker:get_wielded_item()
|
||||||
local name = clicker:get_player_name()
|
local name = clicker:get_player_name()
|
||||||
|
|
||||||
minetest.log(dump(self))
|
--minetest.log(dump(self))
|
||||||
|
|
||||||
-- Receive gift or start chat. If player has no item in hand
|
-- Receive gift or start chat. If player has no item in hand
|
||||||
-- then it is going to start chat directly
|
-- then it is going to start chat directly
|
||||||
@ -511,6 +606,7 @@ mobs:register_mob("advanced_npc:npc", {
|
|||||||
|
|
||||||
-- Show dialogue to confirm that player is giving item as gift
|
-- Show dialogue to confirm that player is giving item as gift
|
||||||
npc.dialogue.show_yes_no_dialogue(
|
npc.dialogue.show_yes_no_dialogue(
|
||||||
|
self,
|
||||||
"Do you want to give "..item_name.." to "..self.nametag.."?",
|
"Do you want to give "..item_name.." to "..self.nametag.."?",
|
||||||
npc.dialogue.POSITIVE_GIFT_ANSWER_PREFIX..item_name,
|
npc.dialogue.POSITIVE_GIFT_ANSWER_PREFIX..item_name,
|
||||||
function()
|
function()
|
||||||
@ -576,8 +672,12 @@ mobs:register_mob("advanced_npc:npc", {
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Action queue timer
|
-- Action queue timer
|
||||||
|
-- Check if actions and timers aren't locked
|
||||||
|
if self.actions.action_timer_lock == false then
|
||||||
|
-- Increment action timer
|
||||||
self.actions.action_timer = self.actions.action_timer + dtime
|
self.actions.action_timer = self.actions.action_timer + dtime
|
||||||
if self.actions.action_timer >= self.actions.action_interval then
|
if self.actions.action_timer >= self.actions.action_interval then
|
||||||
|
minetest.log("Current action state = "..dump(self.actions.current_action_state))
|
||||||
-- Reset action timer
|
-- Reset action timer
|
||||||
self.actions.action_timer = 0
|
self.actions.action_timer = 0
|
||||||
-- Execute action
|
-- Execute action
|
||||||
@ -586,6 +686,7 @@ mobs:register_mob("advanced_npc:npc", {
|
|||||||
if self.freeze == nil and table.getn(self.actions.queue) > 0 then
|
if self.freeze == nil and table.getn(self.actions.queue) > 0 then
|
||||||
self.freeze = false
|
self.freeze = false
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -258,11 +258,15 @@ minetest.register_on_player_receive_fields(function (player, formname, fields)
|
|||||||
|
|
||||||
if fields then
|
if fields then
|
||||||
local player_response = npc.trade.results.single_trade_offer[player_name]
|
local player_response = npc.trade.results.single_trade_offer[player_name]
|
||||||
|
-- Unlock the action timer
|
||||||
|
npc.unlock_actions(player_response.npc)
|
||||||
|
|
||||||
if fields.yes_option then
|
if fields.yes_option then
|
||||||
npc.trade.perform_trade(player_response.npc, player_name, player_response.trade_offer)
|
npc.trade.perform_trade(player_response.npc, player_name, player_response.trade_offer)
|
||||||
elseif fields.no_option then
|
elseif fields.no_option then
|
||||||
minetest.chat_send_player(player_name, "Talk to me if you change your mind!")
|
minetest.chat_send_player(player_name, "Talk to me if you change your mind!")
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user