Actions: No longer have 'self' as part of the arguments object for each action. This caused an error with Lua serialization that crashed Minetest while the NPC was executing actions and it got unloaded (like exit game or mapblock unloaded).

This commit is contained in:
zorman2000 2017-01-19 20:42:46 -05:00
parent dd4d445b3a
commit 5d2c820d88
3 changed files with 52 additions and 63 deletions

View File

@ -42,7 +42,7 @@ __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.
- [ ] 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: Main functionality complete
__Phase 4__: Actions: Complete
- [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 have the ability to identify nodes that belong to him/her, and recall them/

View File

@ -45,8 +45,8 @@ npc.actions.two_nps_speed = 1.90
-- The following action alters the timer interval for executing actions, therefore
-- making waits and pauses possible, or increase timing when some actions want to
-- be performed faster, like walking.
function npc.actions.set_interval(args)
local self = args.self
function npc.actions.set_interval(self, args)
local self_actions = args.self_actions
local new_interval = args.interval
local freeze_mobs_api = args.freeze
@ -57,7 +57,7 @@ end
-- The following action is for allowing the rest of mobs redo API to be executed
-- after this action ends. This is useful for times when no action is needed
-- and the NPC is allowed to roam freely.
function npc.actions.freeze(args)
function npc.actions.freeze(self, args)
local freeze_mobs_api = args.freeze
minetest.log("Received: "..dump(freeze_mobs_api))
minetest.log("Returning: "..dump(not(freeze_mobs_api)))
@ -66,8 +66,7 @@ end
-- This action is to rotate to mob to a specifc direction. Currently, the code
-- contains also for diagonals, but remaining in the orthogonal domain is preferrable.
function npc.actions.rotate(args)
local self = args.self
function npc.actions.rotate(self, args)
local dir = args.dir
local yaw = 0
self.rotate = 0
@ -94,8 +93,7 @@ end
-- This function will make the NPC walk one step on a
-- specifc direction. One step means one node. It returns
-- true if it can move on that direction, and false if there is an obstacle
function npc.actions.walk_step(args)
local self = args.self
function npc.actions.walk_step(self, args)
local dir = args.dir
local speed = args.speed
local vel = {}
@ -113,7 +111,7 @@ function npc.actions.walk_step(args)
vel = {x=-speed, y=0, z=0}
end
-- Rotate NPC
npc.actions.rotate({self=self, dir=dir})
npc.actions.rotate(self, {dir=dir})
-- Set velocity so that NPC walks
self.object:setvelocity(vel)
-- Set walk animation
@ -124,8 +122,7 @@ function npc.actions.walk_step(args)
end
-- This action makes the NPC stand and remain like that
function npc.actions.stand(args)
local self = args.self
function npc.actions.stand(self, args)
local pos = args.pos
local dir = args.dir
-- Stop NPC
@ -136,7 +133,7 @@ function npc.actions.stand(args)
end
-- If dir given, set to that dir
if dir ~= nil then
npc.actions.rotate({self=self, dir=dir})
npc.actions.rotate(self, {dir=dir})
end
-- Set stand animation
self.object:set_animation({
@ -146,8 +143,7 @@ function npc.actions.stand(args)
end
-- This action makes the NPC sit on the node where it is
function npc.actions.sit(args)
local self = args.self
function npc.actions.sit(self, args)
local pos = args.pos
local dir = args.dir
-- Stop NPC
@ -158,7 +154,7 @@ function npc.actions.sit(args)
end
-- If dir given, set to that dir
if dir ~= nil then
npc.actions.rotate({self=self, dir=dir})
npc.actions.rotate(self, {dir=dir})
end
-- Set sit animation
self.object:set_animation({
@ -168,8 +164,7 @@ function npc.actions.sit(args)
end
-- This action makes the NPC lay on the node where it is
function npc.actions.lay(args)
local self = args.self
function npc.actions.lay(self, args)
local pos = args.pos
-- Stop NPC
self.object:setvelocity({x=0, y=0, z=0})
@ -188,8 +183,7 @@ end
-- This function is a convenience function to make it easy to put
-- and get items from another inventory (be it a player inv or
-- a node inv)
function npc.actions.put_item_on_external_inventory(args)
local self = args.self
function npc.actions.put_item_on_external_inventory(self, args)
local player = args.player
local pos = args.pos
local inv_list = args.inv_list
@ -226,8 +220,7 @@ function npc.actions.put_item_on_external_inventory(args)
return false
end
function npc.actions.take_item_from_external_inventory(args)
local self = args.self
function npc.actions.take_item_from_external_inventory(self, args)
local player = args.player
local pos = args.pos
local inv_list = args.inv_list
@ -253,8 +246,7 @@ function npc.actions.take_item_from_external_inventory(args)
return false
end
function npc.actions.check_external_inventory_contains_item(args)
local self = args.self
function npc.actions.check_external_inventory_contains_item(self, args)
local player = args.player
local pos = args.pos
local inv_list = args.inv_list
@ -297,8 +289,7 @@ end
-- This function is used to open or close openable nodes.
-- Currently supported openable nodes are: any doors using the
-- default doors API, and the cottages mod gates and doors.
function npc.actions.use_door(args)
local self = args.self
function npc.actions.use_door(self, args)
local pos = args.pos
local action = args.action
local dir = args.dir
@ -386,7 +377,6 @@ function npc.actions.use_furnace(self, pos, item, freeze)
-- Put this item on the fuel inventory list of the furnace
local args = {
self = self,
player = nil,
pos = pos,
inv_list = "fuel",
@ -396,7 +386,6 @@ function npc.actions.use_furnace(self, pos, item, freeze)
npc.add_action(self, npc.actions.put_item_on_external_inventory, args)
-- Put the item that we want to cook on the furnace
args = {
self = self,
player = nil,
pos = pos,
inv_list = "src",
@ -408,21 +397,21 @@ function npc.actions.use_furnace(self, pos, item, freeze)
-- Now, set NPC to wait until furnace is done.
minetest.log("Setting wait action for "..dump(total_cook_time))
npc.add_action(self, npc.actions.set_interval, {self=self, interval=total_cook_time, freeze=freeze})
npc.add_action(self, npc.actions.set_interval, {interval=total_cook_time, freeze=freeze})
-- Reset timer
npc.add_action(self, npc.actions.set_interval, {self=self, interval=1, freeze=true})
npc.add_action(self, npc.actions.set_interval, {interval=1, freeze=true})
-- If freeze is false, then we will have to find the way back to the furnace
-- once cooking is done.
if freeze == false then
minetest.log("Adding walk to position to wandering: "..dump(pos))
npc.add_task(self, npc.actions.walk_to_pos, {self=self, end_pos=pos, walkable={}})
npc.add_task(self, npc.actions.walk_to_pos, {end_pos=pos, walkable={}})
end
-- Take cooked items back
args = {
self = self,
player = nil,
pos = pos,
inv_list = "dst",
@ -453,15 +442,15 @@ function npc.actions.use_bed(self, pos, action)
-- Get position
local bed_pos = npc.actions.nodes.beds[node.name].get_lay_pos(pos, dir)
-- Sit down on bed, rotate to correct direction
npc.add_action(self, npc.actions.sit, {self=self, pos=bed_pos, dir=(node.param2 + 2) % 4})
npc.add_action(self, npc.actions.sit, {pos=bed_pos, dir=(node.param2 + 2) % 4})
-- Lay down
npc.add_action(self, npc.actions.lay, {self=self})
npc.add_action(self, npc.actions.lay, {})
else
-- Calculate position to get up
local bed_pos_y = npc.actions.nodes.beds[node.name].get_lay_pos(pos, dir).y
local bed_pos = {x = pos.x, y = bed_pos_y, z = pos.z}
-- Sit up
npc.add_action(self, npc.actions.sit, {self=self, pos=bed_pos})
npc.add_action(self, npc.actions.sit, {pos=bed_pos})
-- Initialize direction: Default is front of bottom of bed
local dir = (node.param2 + 2) % 4
-- Find empty node around node
@ -492,7 +481,7 @@ function npc.actions.use_bed(self, pos, action)
end
end
-- Stand out of bed
npc.add_action(self, npc.actions.stand, {self=self, pos=pos_out_of_bed, dir=dir})
npc.add_action(self, npc.actions.stand, {pos=pos_out_of_bed, dir=dir})
end
end
@ -506,7 +495,7 @@ function npc.actions.use_sittable(self, pos, action)
minetest.log("Got sit position: "..dump(sit_pos))
local sit_pos = npc.actions.nodes.sittable[node.name].get_sit_pos(pos, node.param2)
-- Sit down on bench/chair/stairs
npc.add_action(self, npc.actions.sit, {self=self, pos=sit_pos, dir=(node.param2 + 2) % 4})
npc.add_action(self, npc.actions.sit, {pos=sit_pos, dir=(node.param2 + 2) % 4})
else
-- Find empty areas around chair
local dir = node.param2 + 2 % 4
@ -519,7 +508,7 @@ function npc.actions.use_sittable(self, pos, action)
local pos_out_of_sittable =
{x=empty_nodes[1].pos.x, y=empty_nodes[1].pos.y + 1, z=empty_nodes[1].pos.z}
-- Stand
npc.add_action(self, npc.actions.stand, {self=self, pos=pos_out_of_sittable, dir=dir})
npc.add_action(self, npc.actions.stand, {pos=pos_out_of_sittable, dir=dir})
end
end
@ -547,9 +536,8 @@ end
-- is included, which is a table of node names, these nodes are
-- going to be considered walkable for the algorithm to find a
-- path.
function npc.actions.walk_to_pos(args)
function npc.actions.walk_to_pos(self, args)
-- Get arguments for this task
local self = args.self
local end_pos = args.end_pos
local walkable_nodes = args.walkable
@ -576,7 +564,7 @@ function npc.actions.walk_to_pos(args)
-- Set the action timer interval to half second. This is to account for
-- the increased speed when walking.
npc.add_action(self, npc.actions.set_interval, {self=self, interval=0.5, freeze=true})
npc.add_action(self, npc.actions.set_interval, {interval=0.5, freeze=true})
-- Add steps to path
for i = 1, #path do
@ -585,7 +573,7 @@ function npc.actions.walk_to_pos(args)
-- Add direction to last node
local dir = npc.actions.get_direction(path[i].pos, end_pos)
-- Add stand animation at end
npc.add_action(self, npc.actions.stand, {self = self, dir = dir})
npc.add_action(self, npc.actions.stand, { dir = dir})
break
end
-- Get direction to move from path[i] to path[i+1]
@ -597,15 +585,15 @@ function npc.actions.walk_to_pos(args)
if npc.actions.get_openable_node_state(node, dir) == npc.actions.const.doors.state.CLOSED then
minetest.log("Opening action to open door")
-- Stop to open door, this avoids misplaced movements later on
npc.add_action(self, npc.actions.stand, {self=self, dir=dir})
npc.add_action(self, npc.actions.stand, {dir=dir})
-- Open door
npc.add_action(self, npc.actions.use_door, {self=self, pos=path[i+1].pos, dir=dir, action=npc.actions.const.doors.action.OPEN})
npc.add_action(self, npc.actions.use_door, {pos=path[i+1].pos, dir=dir, action=npc.actions.const.doors.action.OPEN})
door_opened = true
end
end
-- Add walk action to action queue
npc.add_action(self, npc.actions.walk_step, {self = self, dir = dir, speed = speed})
npc.add_action(self, npc.actions.walk_step, {dir = dir, speed = speed})
if door_opened then
-- Stop to close door, this avoids misplaced movements later on
@ -620,9 +608,9 @@ function npc.actions.walk_to_pos(args)
x_adj = -0.1
end
local pos_on_close = {x=path[i+1].pos.x + x_adj, y=path[i+1].pos.y + 1, z=path[i+1].pos.z + z_adj}
npc.add_action(self, npc.actions.stand, {self=self, dir=(dir + 2)% 4, pos=pos_on_close})
npc.add_action(self, npc.actions.stand, {dir=(dir + 2)% 4, pos=pos_on_close})
-- Close door
npc.add_action(self, npc.actions.use_door, {self=self, pos=path[i+1].pos, action=npc.actions.const.doors.action.CLOSE})
npc.add_action(self, npc.actions.use_door, {pos=path[i+1].pos, action=npc.actions.const.doors.action.CLOSE})
door_opened = false
end
@ -631,7 +619,7 @@ function npc.actions.walk_to_pos(args)
-- Return the action interval to default interval of 1 second
-- By default, always freeze.
npc.add_action(self, npc.actions.set_interval, {self=self, interval=1, freeze=true})
npc.add_action(self, npc.actions.set_interval, {interval=1, freeze=true})
else
minetest.log("Unable to find path.")

33
npc.lua
View File

@ -238,7 +238,7 @@ function npc.execute_action(self)
-- Clear queue
self.actions.queue = {}
-- Now, execute the task with its arguments
action_obj.action(action_obj.args)
action_obj.action(self, action_obj.args)
-- After all new actions has been added by task, add the previously
-- queued actions back
for i = 1, #backup_queue do
@ -251,7 +251,7 @@ function npc.execute_action(self)
-- Store current position
self.actions.state_before_lock.pos = self.object:getpos()
-- Execute action as normal
result = action_obj.action(action_obj.args)
result = action_obj.action(self, action_obj.args)
-- Remove task
table.remove(self.actions.queue, 1)
-- Set state
@ -281,7 +281,7 @@ function npc.lock_actions(self)
pos.y = self.object:getpos().y
end
-- Stop NPC
npc.actions.stand({self=self, pos=pos})
npc.actions.stand({pos=pos})
-- Avoid all timer execution
self.actions.action_timer_lock = true
-- Reset timer so that it has some time after interaction is done
@ -384,6 +384,9 @@ local function npc_spawn(self, pos)
-- Get Lua Entity
local ent = self:get_luaentity()
-- Avoid NPC to be removed by mobs_redo API
ent.remove_ok = false
-- Set name
ent.nametag = "Kio"
@ -486,7 +489,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
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, {end_pos=nodes[1], walkable={}})
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.lay, {self = ent})
@ -625,19 +628,17 @@ mobs:register_mob("advanced_npc:npc", {
end,
do_custom = function(self, dtime)
-- Timer function for casual traders to reset their trade offers
if self.trader_data ~= nil then
self.trader_data.change_offers_timer = self.trader_data.change_offers_timer + dtime
-- Check if time has come to change offers
if self.trader_data.trader_status == npc.trade.CASUAL and
self.trader_data.change_offers_timer >= self.trader_data.change_offers_timer_interval then
-- Reset timer
self.trader_data.change_offers_timer = 0
-- Re-select casual trade offers
select_casual_trade_offers(self)
end
-- Timer function for casual traders to reset their trade offers
self.trader_data.change_offers_timer = self.trader_data.change_offers_timer + dtime
-- Check if time has come to change offers
if self.trader_data.trader_status == npc.trade.CASUAL and
self.trader_data.change_offers_timer >= self.trader_data.change_offers_timer_interval then
-- Reset timer
self.trader_data.change_offers_timer = 0
-- Re-select casual trade offers
select_casual_trade_offers(self)
end
-- Timer function for gifts
for i = 1, #self.relationships do
local relationship = self.relationships[i]