Actions: added experimental, still WIP path-finding code in Lua
This commit is contained in:
parent
646b422082
commit
d78fee695e
@ -19,13 +19,13 @@ function npc.actions.rotate(args)
|
|||||||
local yaw = 0
|
local yaw = 0
|
||||||
self.rotate = 0
|
self.rotate = 0
|
||||||
if dir == npc.direction.north then
|
if dir == npc.direction.north then
|
||||||
yaw = 315
|
yaw = 0
|
||||||
elseif dir == npc.direction.east then
|
elseif dir == npc.direction.east then
|
||||||
yaw = 225
|
yaw = (3 * math.pi) / 2
|
||||||
elseif dir == npc.direction.south then
|
elseif dir == npc.direction.south then
|
||||||
yaw = 135
|
yaw = math.pi
|
||||||
elseif dir == npc.direction.west then
|
elseif dir == npc.direction.west then
|
||||||
yaw = 45
|
yaw = math.pi / 2
|
||||||
end
|
end
|
||||||
self.object:setyaw(yaw)
|
self.object:setyaw(yaw)
|
||||||
end
|
end
|
||||||
@ -47,7 +47,7 @@ function npc.actions.walk_step(args)
|
|||||||
vel = {x=-1, y=0, z=0}
|
vel = {x=-1, y=0, z=0}
|
||||||
end
|
end
|
||||||
set_animation(self, "walk")
|
set_animation(self, "walk")
|
||||||
npc.rotate({self=self, dir=dir})
|
npc.actions.rotate({self=self, dir=dir})
|
||||||
self.object:setvelocity(vel)
|
self.object:setvelocity(vel)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -83,3 +83,387 @@ function npc.actions.lay(args)
|
|||||||
y = npc.ANIMATION_LAY_END},
|
y = npc.ANIMATION_LAY_END},
|
||||||
self.animation.speed_normal, 0)
|
self.animation.speed_normal, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Inventory functions for players and for nodes
|
||||||
|
-- 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
|
||||||
|
local player = args.player
|
||||||
|
local pos = args.pos
|
||||||
|
local inv_list = args.inv_list
|
||||||
|
local item_name = args.item_name
|
||||||
|
local count = args.count
|
||||||
|
local is_furnace = args.is_furnace
|
||||||
|
local inv
|
||||||
|
if player ~= nil then
|
||||||
|
inv = minetest.get_inventory({type="player", name=player})
|
||||||
|
else
|
||||||
|
inv = minetest.get_inventory({type="node", pos=pos})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create ItemStack to put on external inventory
|
||||||
|
local item = ItemStack(item_name.." "..count)
|
||||||
|
-- Check if there is enough room to add the item on external invenotry
|
||||||
|
if inv:room_for_item(inv_list, item) then
|
||||||
|
-- Take item from NPC's inventory
|
||||||
|
if npc.take_item_from_inventory_itemstring(self, item) then
|
||||||
|
-- NPC doesn't have item and/or specified quantity
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
-- Add items to external inventory
|
||||||
|
inv:add_item(inv_list, item)
|
||||||
|
|
||||||
|
-- If this is a furnace, start furnace timer
|
||||||
|
if is_furnace == true then
|
||||||
|
minetest.get_node_timer(pos):start(1.0)
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
-- Not able to put on external inventory
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function npc.actions.take_item_from_external_inventory(args)
|
||||||
|
local self = args.self
|
||||||
|
local player = args.player
|
||||||
|
local pos = args.pos
|
||||||
|
local inv_list = args.inv_list
|
||||||
|
local item_name = args.item_name
|
||||||
|
local count = args.count
|
||||||
|
local inv
|
||||||
|
if player ~= nil then
|
||||||
|
inv = minetest.get_inventory({type="player", name=player})
|
||||||
|
else
|
||||||
|
inv = minetest.get_inventory({type="node", pos})
|
||||||
|
end
|
||||||
|
-- Create ItemSTack to take from external inventory
|
||||||
|
local item = ItemStack(item_name.." "..count)
|
||||||
|
-- Check if there is enough of the item to take
|
||||||
|
if inv:contains_item(inv_list, item) then
|
||||||
|
-- Add item to NPC's inventory
|
||||||
|
npc.add_item_to_inventory_itemstring(self, item)
|
||||||
|
-- Add items to external inventory
|
||||||
|
inv:remove_item(inv_list, item)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
-- Not able to put on external inventory
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------------------
|
||||||
|
-- Tasks functionality
|
||||||
|
---------------------------------------------------------------------------------------
|
||||||
|
-- Tasks are operations that require many actions to perform. Basic tasks, like
|
||||||
|
-- walking from one place to another, operating a furnace, storing or taking
|
||||||
|
-- items from a chest, opening/closing doors, etc. are provided here.
|
||||||
|
|
||||||
|
-- This function allows a NPC to use a furnace using only items from
|
||||||
|
-- its own inventory. Fuel is not provided. Once the furnace is finished
|
||||||
|
-- with the fuel items the NPC will take whatever was cooked and whatever
|
||||||
|
-- remained to cook. The function received the position of the furnace
|
||||||
|
-- to use, and the item to cook in furnace. Item is an itemstring
|
||||||
|
function npc.actions.use_furnace(self, pos, item)
|
||||||
|
-- Check if any item in the NPC inventory serve as fuel
|
||||||
|
-- For now, just use some specific items as fuel
|
||||||
|
local fuels = {"default:leaves", "default:tree"}
|
||||||
|
-- Check if NPC has a fuel item
|
||||||
|
for i = 1,2 do
|
||||||
|
local fuel_item = npc.inventory_contains(self, fuels[i])
|
||||||
|
local src_item = npc.inventory_contains(self, item)
|
||||||
|
|
||||||
|
if fuel_item ~= nil and src_item ~= nil then
|
||||||
|
-- Put this item on the fuel inventory list of the furnace
|
||||||
|
local args = {
|
||||||
|
self = self,
|
||||||
|
player = nil,
|
||||||
|
pos = pos,
|
||||||
|
inv_list = "fuel",
|
||||||
|
item_name = npc.get_item_name(fuel_item.item_string),
|
||||||
|
count = npc.get_item_count(fuel_item.item_string)
|
||||||
|
}
|
||||||
|
minetest.log("Adding fuel action")
|
||||||
|
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",
|
||||||
|
item_name = npc.get_item_name(src_item.item_string),
|
||||||
|
count = npc.get_item_count(src_item.item_string),
|
||||||
|
is_furnace = true
|
||||||
|
}
|
||||||
|
minetest.log("Adding src action")
|
||||||
|
npc.add_action(self, npc.actions.put_item_on_external_inventory, args)
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Couldn't use the furnace due to lack of items
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function npc.actions.walk_to_pos(self, end_pos)
|
||||||
|
|
||||||
|
local start_pos = self.object:getpos()
|
||||||
|
|
||||||
|
minetest.log("Starting pos: "..dump(start_pos))
|
||||||
|
|
||||||
|
-- Use Minetest built-in pathfinding algorithm, A*
|
||||||
|
local path = npc.actions.find_path({x=start_pos.x, y=start_pos.y-1, z=start_pos.z}, end_pos)
|
||||||
|
|
||||||
|
if path ~= nil then
|
||||||
|
minetest.log("Found path to node: "..dump(end_pos))
|
||||||
|
for i = 1, #path do
|
||||||
|
minetest.log("Path: (i) "..dump(path[i])..": Path i+1 "..dump(path[i+1]))
|
||||||
|
local dir = npc.actions.get_direction(path[i].pos, path[i+1].pos)
|
||||||
|
-- Add walk action to action queue
|
||||||
|
npc.add_action(self, npc.actions.walk_step, {self = self, dir = dir})
|
||||||
|
if i+1 == #path then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add stand animation at end
|
||||||
|
npc.add_action(self, npc.actions.stand, {self = self})
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
local function vector_add(p1, p2)
|
||||||
|
return {x=p1.x+p2.x, y=p1.y+p2.y, z=p1.z+p2.z}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function vector_diff(p1, p2)
|
||||||
|
return {x=p1.x-p2.x, y=p1.y-p2.y, z=p1.z-p2.z}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function vector_opposite(v)
|
||||||
|
return vector.multiply(v, -1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function get_unit_dir_vector_based_on_diff(v)
|
||||||
|
if math.abs(v.x) > math.abs(v.z) then
|
||||||
|
return {x=(v.x/math.abs(v.x)) * -1, y=0, z=0}
|
||||||
|
elseif math.abs(v.z) > math.abs(v.x) then
|
||||||
|
return {x=0, y=0, z=(v.z/math.abs(v.z)) * -1}
|
||||||
|
elseif math.abs(v.x) == math.abs(v.z) then
|
||||||
|
return {x=(v.x/math.abs(v.x)) * -1, y=0, z=0}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function npc.actions.get_direction(v1, v2)
|
||||||
|
local dir = vector.subtract(v2, v1)
|
||||||
|
if dir.x ~= 0 then
|
||||||
|
if dir.x > 0 then
|
||||||
|
return npc.direction.east
|
||||||
|
else
|
||||||
|
return npc.direction.west
|
||||||
|
end
|
||||||
|
elseif dir.z ~= 0 then
|
||||||
|
if dir.z > 0 then
|
||||||
|
return npc.direction.north
|
||||||
|
else
|
||||||
|
return npc.direction.south
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
DIFF_LIMIT = 125
|
||||||
|
|
||||||
|
-- Finds paths ignoring vertical obstacles
|
||||||
|
-- This function is recursive and attempts to move all the time on
|
||||||
|
-- the direction that will definetely lead to the end position.
|
||||||
|
local function find_path_recursive(start_pos, end_pos, path_nodes, last_dir, last_good_dir)
|
||||||
|
minetest.log("Start pos: "..dump(start_pos))
|
||||||
|
-- Find difference. The purpose of this is to weigh movement, attempting
|
||||||
|
-- the largest difference first, or both if equal.
|
||||||
|
|
||||||
|
local diff = vector_diff(start_pos, end_pos)
|
||||||
|
minetest.log("Difference: "..dump(diff))
|
||||||
|
-- End if difference is larger than max difference possible (limit)
|
||||||
|
if math.abs(diff.x) > DIFF_LIMIT or math.abs(diff.z) > DIFF_LIMIT then
|
||||||
|
-- Cannot find feasable path
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
-- Determine direction to move
|
||||||
|
local dir_vector = get_unit_dir_vector_based_on_diff(diff)
|
||||||
|
minetest.log("Direction vector: "..dump(dir_vector))
|
||||||
|
|
||||||
|
if last_good_dir ~= nil then
|
||||||
|
dir_vector = last_good_dir
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get next position based on direction
|
||||||
|
local next_pos = vector_add(start_pos, dir_vector)
|
||||||
|
|
||||||
|
minetest.log("Next pos: "..dump(next_pos))
|
||||||
|
-- Check if next_pos is actually within one block from the
|
||||||
|
-- expected position. If so, finish
|
||||||
|
local diff_to_end = vector_diff(next_pos, end_pos)
|
||||||
|
if math.abs(diff_to_end.x) < 1 and math.abs(diff_to_end.y) < 1 and math.abs(diff_to_end.z) < 1 then
|
||||||
|
minetest.log("Diff to end: "..dump(diff_to_end))
|
||||||
|
table.insert(path_nodes, {pos=next_pos, type="E"})
|
||||||
|
minetest.log("Found path to end.")
|
||||||
|
return path_nodes
|
||||||
|
end
|
||||||
|
-- Check if movement is possible on the calculated direction
|
||||||
|
local next_node = minetest.get_node(next_pos)
|
||||||
|
-- If direction vector is opposite to the last dir, then do not attempt to walk into it
|
||||||
|
minetest.log("Next node is walkable: "..dump(not minetest.registered_nodes[next_node.name].walkable))
|
||||||
|
local attempted_to_go_opposite = false
|
||||||
|
if last_dir ~= nil and vector.equals(dir_vector, vector_opposite(last_dir)) then
|
||||||
|
attempted_to_go_opposite = true
|
||||||
|
minetest.log("Last dir: "..dump(last_dir))
|
||||||
|
minetest.log("Calculated dir vector is the opposite of last dir: "..dump(vector.equals(dir_vector, vector_opposite(last_dir))))
|
||||||
|
end
|
||||||
|
if minetest.registered_nodes[next_node.name].walkable == false
|
||||||
|
and (not attempted_to_go_opposite) then
|
||||||
|
table.insert(path_nodes, {pos=next_pos, type="W"})
|
||||||
|
return find_path_recursive(next_pos, end_pos, path_nodes, nil, nil)
|
||||||
|
else
|
||||||
|
minetest.log("------------ Second attempt ------------")
|
||||||
|
-- If not walkable, attempt turn into the other coordinate
|
||||||
|
-- Store last good direction to retry at all times
|
||||||
|
minetest.log("Last known good dir: "..dump(last_good_dir))
|
||||||
|
local step = 0
|
||||||
|
if last_good_dir == nil then
|
||||||
|
last_good_dir = dir_vector
|
||||||
|
if dir_vector.x == 0 then
|
||||||
|
minetest.log("Choosing x direction")
|
||||||
|
step = diff.x/math.abs(diff.x) * -1
|
||||||
|
if diff.x == 0 then
|
||||||
|
if last_dir ~= nil then
|
||||||
|
step = last_dir.x
|
||||||
|
else
|
||||||
|
-- Set a default step to avoid locks
|
||||||
|
step = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
dir_vector = {x = step, y = 0, z = 0}
|
||||||
|
elseif dir_vector.z == 0 then
|
||||||
|
minetest.log("Choosing z direction")
|
||||||
|
step = diff.z/math.abs(diff.z) * -1
|
||||||
|
minetest.log("Step: "..dump(step)..". Diff: "..dump(diff))
|
||||||
|
minetest.log("Last dir: ".. dump(last_dir))
|
||||||
|
if diff.z == 0 then
|
||||||
|
if last_dir ~= nil then
|
||||||
|
step = last_dir.z
|
||||||
|
else
|
||||||
|
-- Set a default step to avoid locks
|
||||||
|
step = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
dir_vector = {x = 0, y = 0, z = step}
|
||||||
|
end
|
||||||
|
minetest.log("Re-calculated dir vector: "..dump(dir_vector))
|
||||||
|
next_pos = vector.add(start_pos, dir_vector)
|
||||||
|
else
|
||||||
|
dir_vector = last_good_dir
|
||||||
|
if dir_vector.x == 0 then
|
||||||
|
minetest.log("Moving into x direction")
|
||||||
|
step = last_dir.x
|
||||||
|
elseif dir_vector.z == 0 then
|
||||||
|
minetest.log("Moving into z direction")
|
||||||
|
step = last_dir.z
|
||||||
|
end
|
||||||
|
dir_vector = last_dir
|
||||||
|
next_pos = vector.add(start_pos, dir_vector)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- if dir_vector.x == 0 then
|
||||||
|
-- minetest.log("Moving into x direction")
|
||||||
|
-- local step = diff.x/math.abs(diff.x) * -1
|
||||||
|
-- if diff.x == 0 then
|
||||||
|
-- -- If the difference for x with end position is zero, then try
|
||||||
|
-- -- to move in the last known direction
|
||||||
|
-- if last_dir ~= nil then
|
||||||
|
-- step = last_dir.x
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
-- next_pos = {x = start_pos.x + step, y = start_pos.y, z = start_pos.z}
|
||||||
|
-- dir_vector = {x = step, y = 0, z = 0}
|
||||||
|
-- elseif dir_vector.z == 0 then
|
||||||
|
-- minetest.log("Moving into z direction")
|
||||||
|
-- local step = diff.z/math.abs(diff.z) * -1
|
||||||
|
-- if diff.z == 0 then
|
||||||
|
-- -- If the difference for z with end position is zero, then try
|
||||||
|
-- -- to move in the last known direction
|
||||||
|
-- if last_dir ~= nil then
|
||||||
|
-- step = last_dir.z
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
-- next_pos = {x = start_pos.x, y = start_pos.y, z = start_pos.z + step}
|
||||||
|
-- dir_vector = {x = 0, y = 0, z = step}
|
||||||
|
-- end
|
||||||
|
minetest.log("Next calculated position: "..dump(next_pos))
|
||||||
|
|
||||||
|
-- Check if new node is walkable
|
||||||
|
next_node = minetest.get_node(next_pos)
|
||||||
|
minetest.log("Next node is walkable: "..dump(not minetest.registered_nodes[next_node.name].walkable))
|
||||||
|
if last_dir ~= nil and vector.equals(dir_vector, vector_opposite(last_dir)) then
|
||||||
|
attempted_to_go_opposite = true
|
||||||
|
minetest.log("Last dir: "..dump(last_dir))
|
||||||
|
minetest.log("Calculated dir vector is the opposite of last dir: "..dump(vector.equals(dir_vector, vector_opposite(last_dir))))
|
||||||
|
end
|
||||||
|
if minetest.registered_nodes[next_node.name].walkable == false then
|
||||||
|
table.insert(path_nodes, {pos=next_pos, type="W"})
|
||||||
|
return find_path_recursive(next_pos, end_pos, path_nodes, dir_vector, last_good_dir)
|
||||||
|
else
|
||||||
|
last_good_dir = dir_vector
|
||||||
|
minetest.log("------------ Third attempt ------------")
|
||||||
|
-- If not walkable, then try the next node
|
||||||
|
if dir_vector.x ~= 0 then
|
||||||
|
minetest.log("Move into opposite z dir")
|
||||||
|
dir_vector = get_unit_dir_vector_based_on_diff(start_pos, diff)
|
||||||
|
vector.multiply(dir_vector, -1)
|
||||||
|
elseif dir_vector.z ~= 0 then
|
||||||
|
minetest.log("Move into opposite x dir")
|
||||||
|
dir_vector = get_unit_dir_vector_based_on_diff(start_pos, diff)
|
||||||
|
vector.multiply(dir_vector, -1)
|
||||||
|
end
|
||||||
|
minetest.log("New direction: "..dump(dir_vector))
|
||||||
|
|
||||||
|
next_pos = vector_add(start_pos, dir_vector)
|
||||||
|
minetest.log("New next_pos: "..dump(next_pos))
|
||||||
|
next_node = minetest.get_node(next_pos)
|
||||||
|
minetest.log("Next node is walkable: "..dump(not minetest.registered_nodes[next_node.name].walkable))
|
||||||
|
-- if last_dir ~= nil and vector.equals(dir_vector, vector_opposite(last_dir)) then
|
||||||
|
-- attempted_to_go_opposite = true
|
||||||
|
-- minetest.log("Last dir: "..dump(last_dir))
|
||||||
|
-- minetest.log("Calculated dir vector is the opposite of last dir: "..dump(vector.equals(dir_vector, vector_opposite(last_dir))))
|
||||||
|
-- end
|
||||||
|
if minetest.registered_nodes[next_node.name].walkable == false then
|
||||||
|
--and (not attempted_to_go_opposite) then
|
||||||
|
table.insert(path_nodes, {pos=next_pos, type="W"})
|
||||||
|
return find_path_recursive(next_pos, end_pos, path_nodes, dir_vector, last_good_dir)
|
||||||
|
else
|
||||||
|
--return back, opposite of last dir. For now return nil as this code is not
|
||||||
|
-- good
|
||||||
|
return nil
|
||||||
|
-- minetest.log("Have to go back")
|
||||||
|
-- local return_dir = vector_opposite(last_dir)
|
||||||
|
-- -- If it is returning back already, continue on that direction
|
||||||
|
-- if attempted_to_go_opposite then
|
||||||
|
-- return_dir = last_dir
|
||||||
|
-- end
|
||||||
|
-- minetest.log("Opposite dir: "..dump(return_dir))
|
||||||
|
-- next_pos = vector_add(start_pos, return_dir)
|
||||||
|
-- minetest.log("Calculated pos: "..dump(next_pos))
|
||||||
|
-- return find_path(next_pos, end_pos, return_dir)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function npc.actions.find_path(start_pos, end_pos)
|
||||||
|
return find_path_recursive(start_pos, end_pos, {}, nil, nil)
|
||||||
|
end
|
@ -36,7 +36,7 @@ npc.places.PLACE_TYPE = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function npc.places.add(self, place_name, place_type, pos)
|
function npc.places.add_public(self, place_name, place_type, pos)
|
||||||
self.places_map[place_name] = {type=place_type, pos=pos}
|
self.places_map[place_name] = {type=place_type, pos=pos}
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -80,3 +80,8 @@ function npc.places.find_new_nearby(self, type, radius)
|
|||||||
|
|
||||||
return nodes
|
return nodes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function npc.places.find_in_area(start_pos, end_pos, type)
|
||||||
|
local nodes = minetest.find_nodes_in_area(start_pos, end_pos, type)
|
||||||
|
return nodes
|
||||||
|
end
|
71
npc.lua
71
npc.lua
@ -76,7 +76,6 @@ function npc.add_item_to_inventory(self, item_name, count)
|
|||||||
local existing_item = npc.inventory_contains(self, item_name)
|
local existing_item = npc.inventory_contains(self, item_name)
|
||||||
if existing_item ~= nil and existing_item.item_string ~= nil then
|
if existing_item ~= nil and existing_item.item_string ~= nil then
|
||||||
-- NPC already has item. Get count and see
|
-- NPC already has item. Get count and see
|
||||||
minetest.log("What is this? "..dump(existing_item))
|
|
||||||
local existing_count = npc.get_item_count(existing_item.item_string)
|
local existing_count = npc.get_item_count(existing_item.item_string)
|
||||||
if (existing_count + count) < npc.INVENTORY_ITEM_MAX_STACK then
|
if (existing_count + count) < npc.INVENTORY_ITEM_MAX_STACK then
|
||||||
-- Set item here
|
-- Set item here
|
||||||
@ -136,7 +135,7 @@ function npc.take_item_from_inventory(self, item_name, count)
|
|||||||
local existing_item = npc.inventory_contains(self, item_name)
|
local existing_item = npc.inventory_contains(self, item_name)
|
||||||
if existing_item ~= nil then
|
if existing_item ~= nil then
|
||||||
-- Found item
|
-- Found item
|
||||||
local existing_count = get_item_count(existing_item.item_string)
|
local existing_count = npc.get_item_count(existing_item.item_string)
|
||||||
local new_count = existing_count
|
local new_count = existing_count
|
||||||
if existing_count - count < 0 then
|
if existing_count - count < 0 then
|
||||||
-- Remove item first
|
-- Remove item first
|
||||||
@ -146,7 +145,11 @@ function npc.take_item_from_inventory(self, item_name, count)
|
|||||||
return item_name.." "..tostring(new_count)
|
return item_name.." "..tostring(new_count)
|
||||||
else
|
else
|
||||||
new_count = existing_count - count
|
new_count = existing_count - count
|
||||||
|
if new_count == 0 then
|
||||||
|
self.inventory[existing_item.slot] = ""
|
||||||
|
else
|
||||||
self.inventory[existing_item.slot] = item_name.." "..new_count
|
self.inventory[existing_item.slot] = item_name.." "..new_count
|
||||||
|
end
|
||||||
return item_name.." "..tostring(count)
|
return item_name.." "..tostring(count)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -162,57 +165,6 @@ function npc.take_item_from_inventory_itemstring(self, item_string)
|
|||||||
npc.take_item_from_inventory(self, item_name, item_count)
|
npc.take_item_from_inventory(self, item_name, item_count)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Inventory functions for players and for nodes
|
|
||||||
-- 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.put_item_on_external_inventory(player, pos, inv_list, item_name, count)
|
|
||||||
local inv
|
|
||||||
if player_name ~= nil then
|
|
||||||
inv = minetest.get_inventory({type="player", name=player:get_player_name()})
|
|
||||||
else
|
|
||||||
inv = minetest.get_inventory({type="node", pos})
|
|
||||||
end
|
|
||||||
-- Create ItemSTack to put on external inventory
|
|
||||||
local item = ItemStack(item_name.." "..count)
|
|
||||||
-- Check if there is enough room to add the item on external invenotry
|
|
||||||
if inv:room_for_item(inv_list, price_stack) then
|
|
||||||
-- Take item from NPC's inventory
|
|
||||||
if npc.take_item_from_inventory_itemstring(self, item) then
|
|
||||||
-- NPC doesn't have item and/or specified quantity
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
-- Add items to external inventory
|
|
||||||
inv:add_item(inv_list, item)
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
-- Not able to put on external inventory
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
function npc.take_item_from_external_inventory(player, pos, item_name, count)
|
|
||||||
local inv
|
|
||||||
if player_name ~= nil then
|
|
||||||
inv = minetest.get_inventory({type="player", name=player:get_player_name()})
|
|
||||||
else
|
|
||||||
inv = minetest.get_inventory({type="node", pos})
|
|
||||||
end
|
|
||||||
-- Create ItemSTack to take from external inventory
|
|
||||||
local item = ItemStack(item_name.." "..count)
|
|
||||||
-- Check if there is enough of the item to take
|
|
||||||
if inv:contains_item(inv_list, item) then
|
|
||||||
-- Add item to NPC's inventory
|
|
||||||
npc.add_item_to_inventory_itemstring(self, item)
|
|
||||||
-- Add items to external inventory
|
|
||||||
inv:remove_item(inv_list, item)
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
-- Not able to put on external inventory
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Dialogue functions
|
-- Dialogue functions
|
||||||
function npc.start_dialogue(self, clicker, show_married_dialogue)
|
function npc.start_dialogue(self, clicker, show_married_dialogue)
|
||||||
|
|
||||||
@ -233,7 +185,7 @@ function npc.add_action(self, action, arguments)
|
|||||||
self.freeze = true
|
self.freeze = true
|
||||||
minetest.log("Current Pos: "..dump(self.object:getpos()))
|
minetest.log("Current Pos: "..dump(self.object:getpos()))
|
||||||
local action_entry = {action=action, args=arguments}
|
local action_entry = {action=action, args=arguments}
|
||||||
minetest.log(dump(action_entry))
|
--minetest.log(dump(action_entry))
|
||||||
table.insert(self.actions.queue, action_entry)
|
table.insert(self.actions.queue, action_entry)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -316,7 +268,7 @@ local function npc_spawn(self, pos)
|
|||||||
local ent = self:get_luaentity()
|
local ent = self:get_luaentity()
|
||||||
|
|
||||||
-- Set name
|
-- Set name
|
||||||
ent.nametag = "Kio"
|
ent.nametag = ""
|
||||||
|
|
||||||
-- Set ID
|
-- Set ID
|
||||||
ent.npc_id = tostring(math.random(1000, 9999))..":"..ent.nametag
|
ent.npc_id = tostring(math.random(1000, 9999))..":"..ent.nametag
|
||||||
@ -394,6 +346,10 @@ local function npc_spawn(self, pos)
|
|||||||
ent.places_map = {}
|
ent.places_map = {}
|
||||||
|
|
||||||
-- Temporary initialization of actions for testing
|
-- Temporary initialization of actions for testing
|
||||||
|
local nodes = npc.places.find_new_nearby(ent, {"default:furnace"}, 20)
|
||||||
|
npc.add_action(ent, npc.actions.stand, {self = ent})
|
||||||
|
npc.add_action(ent, npc.actions.stand, {self = ent})
|
||||||
|
npc.actions.walk_to_pos(ent, nodes[1])
|
||||||
-- npc.add_action(ent, npc.action.stand, {self = ent})
|
-- npc.add_action(ent, npc.action.stand, {self = ent})
|
||||||
-- npc.add_action(ent, npc.action.stand, {self = ent})
|
-- npc.add_action(ent, npc.action.stand, {self = ent})
|
||||||
-- npc.add_action(ent, npc.action.walk_step, {self = ent, dir = npc.direction.east})
|
-- npc.add_action(ent, npc.action.walk_step, {self = ent, dir = npc.direction.east})
|
||||||
@ -436,7 +392,8 @@ mobs:register_mob("advanced_npc:npc", {
|
|||||||
hp_min = 10,
|
hp_min = 10,
|
||||||
hp_max = 20,
|
hp_max = 20,
|
||||||
armor = 100,
|
armor = 100,
|
||||||
collisionbox = {-0.35,-1.0,-0.35, 0.35,0.8,0.35},
|
--collisionbox = {-0.35, -1.0, -0.5, 0.35, 0.8, 0.25},
|
||||||
|
collisionbox = {-0.35, -1.0, -0.15, 0.35, 0.8, 0.35},
|
||||||
visual = "mesh",
|
visual = "mesh",
|
||||||
mesh = "character.b3d",
|
mesh = "character.b3d",
|
||||||
drawtype = "front",
|
drawtype = "front",
|
||||||
@ -555,7 +512,7 @@ mobs:register_mob("advanced_npc:npc", {
|
|||||||
relationship.points = relationship.points - 1
|
relationship.points = relationship.points - 1
|
||||||
end
|
end
|
||||||
relationship.relationship_decrease_timer_value = 0
|
relationship.relationship_decrease_timer_value = 0
|
||||||
minetest.log(dump(self))
|
--minetest.log(dump(self))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -27,6 +27,7 @@ npc.trade.prices.table["default:stone"] = {tier = npc.trade.prices.curre
|
|||||||
npc.trade.prices.table["farming:seed_cotton"] = {tier = npc.trade.prices.currency.tier3, count = 3}
|
npc.trade.prices.table["farming:seed_cotton"] = {tier = npc.trade.prices.currency.tier3, count = 3}
|
||||||
npc.trade.prices.table["farming:seed_wheat"] = {tier = npc.trade.prices.currency.tier3, count = 3}
|
npc.trade.prices.table["farming:seed_wheat"] = {tier = npc.trade.prices.currency.tier3, count = 3}
|
||||||
npc.trade.prices.table["default:clay_lump"] = {tier = npc.trade.prices.currency.tier3, count = 3}
|
npc.trade.prices.table["default:clay_lump"] = {tier = npc.trade.prices.currency.tier3, count = 3}
|
||||||
|
npc.trade.prices.table["default:wood"] = {tier = npc.trade.prices.currency.tier3, count = 3}
|
||||||
npc.trade.prices.table["mobs:meat_raw"] = {tier = npc.trade.prices.currency.tier3, count = 4}
|
npc.trade.prices.table["mobs:meat_raw"] = {tier = npc.trade.prices.currency.tier3, count = 4}
|
||||||
npc.trade.prices.table["default:sapling"] = {tier = npc.trade.prices.currency.tier3, count = 5}
|
npc.trade.prices.table["default:sapling"] = {tier = npc.trade.prices.currency.tier3, count = 5}
|
||||||
npc.trade.prices.table["mobs:meat"] = {tier = npc.trade.prices.currency.tier3, count = 5}
|
npc.trade.prices.table["mobs:meat"] = {tier = npc.trade.prices.currency.tier3, count = 5}
|
||||||
|
@ -22,7 +22,7 @@ npc.trade.CASUAL_TRADE_BUY_DIALOGUE = {
|
|||||||
casual_trade_type = npc.trade.OFFER_BUY,
|
casual_trade_type = npc.trade.OFFER_BUY,
|
||||||
responses = {
|
responses = {
|
||||||
[1] = {
|
[1] = {
|
||||||
text = "Yes, let's see what are you looking for",
|
text = "Yes, let's see what you are looking for",
|
||||||
action_type = "function",
|
action_type = "function",
|
||||||
response_id = 1,
|
response_id = 1,
|
||||||
action = function(self, player)
|
action = function(self, player)
|
||||||
|
Loading…
Reference in New Issue
Block a user