Actions: Replace "action" for "command".
Add declarative and control commands comments and function signature (no implementation yet).
This commit is contained in:
parent
221cfa3105
commit
9125aa334a
@ -1,21 +1,21 @@
|
||||
-- Actions code for Advanced NPC by Zorman2000
|
||||
-- Commands code for Advanced NPC by Zorman2000
|
||||
---------------------------------------------------------------------------------------
|
||||
-- Action functionality
|
||||
-- Command functionality
|
||||
---------------------------------------------------------------------------------------
|
||||
-- The NPCs will be able to perform six fundamental actions that will allow
|
||||
-- The NPCs will be able to perform six fundamental commands that will allow
|
||||
-- for them to perform any other kind of interaction in the world. These
|
||||
-- fundamental actions are: place a node, dig a node, put items on an inventory,
|
||||
-- fundamental commands are: place a node, dig a node, put items on an inventory,
|
||||
-- take items from an inventory, find a node closeby (radius 3) and
|
||||
-- walk a step on specific direction. These actions will be set on an action queue.
|
||||
-- walk a step on specific direction. These commands will be set on an command queue.
|
||||
-- The queue will have the specific steps, in order, for the NPC to be able to do
|
||||
-- something (example, go to a specific place and put a chest there). The
|
||||
-- fundamental actions are added to the action queue to make a complete task for the NPC.
|
||||
-- fundamental commands are added to the command queue to make a complete task for the NPC.
|
||||
|
||||
npc.actions = {}
|
||||
npc.commands = {}
|
||||
|
||||
npc.actions.default_interval = 1
|
||||
npc.commands.default_interval = 1
|
||||
|
||||
npc.actions.dir_data = {
|
||||
npc.commands.dir_data = {
|
||||
-- North
|
||||
[0] = {
|
||||
yaw = 0,
|
||||
@ -58,10 +58,10 @@ npc.actions.dir_data = {
|
||||
}
|
||||
}
|
||||
|
||||
-- Describes actions with doors or openable nodes
|
||||
npc.actions.const = {
|
||||
-- Describes commands with doors or openable nodes
|
||||
npc.commands.const = {
|
||||
doors = {
|
||||
action = {
|
||||
command = {
|
||||
OPEN = 1,
|
||||
CLOSE = 2
|
||||
},
|
||||
@ -80,7 +80,13 @@ npc.actions.const = {
|
||||
}
|
||||
}
|
||||
|
||||
npc.actions.cmd = {
|
||||
npc.commands.internal_values = {
|
||||
POS = "self_pos",
|
||||
-- Note: The following is by mobs_redo.
|
||||
STANDING_IN = "node_standing_in"
|
||||
}
|
||||
|
||||
npc.commands.cmd = {
|
||||
SET_INTERVAL = 0,
|
||||
FREEZE = 1,
|
||||
ROTATE = 2,
|
||||
@ -100,16 +106,16 @@ npc.actions.cmd = {
|
||||
PLACE = 16
|
||||
}
|
||||
|
||||
--npc.actions.one_nps_speed = 0.98
|
||||
--npc.actions.one_half_nps_speed = 1.40
|
||||
--npc.actions.two_nps_speed = 1.90'
|
||||
npc.actions.one_nps_speed = 1
|
||||
npc.actions.one_half_nps_speed = 1.5
|
||||
npc.actions.two_nps_speed = 2
|
||||
--npc.commands.one_nps_speed = 0.98
|
||||
--npc.commands.one_half_nps_speed = 1.40
|
||||
--npc.commands.two_nps_speed = 1.90'
|
||||
npc.commands.one_nps_speed = 1
|
||||
npc.commands.one_half_nps_speed = 1.5
|
||||
npc.commands.two_nps_speed = 2
|
||||
|
||||
npc.actions.take_from_inventory = "take_from_inventory"
|
||||
npc.actions.take_from_inventory_forced = "take_from_inventory_forced"
|
||||
npc.actions.force_place = "force_place"
|
||||
npc.commands.take_from_inventory = "take_from_inventory"
|
||||
npc.commands.take_from_inventory_forced = "take_from_inventory_forced"
|
||||
npc.commands.force_place = "force_place"
|
||||
|
||||
--------------
|
||||
-- Executor --
|
||||
@ -120,100 +126,207 @@ npc.actions.force_place = "force_place"
|
||||
-- Using constants to refer to each method of this API and a function that
|
||||
-- understands those constants and executes the proper function is the way to avoid
|
||||
-- this frequent crashes.
|
||||
function npc.actions.execute(self, command, args)
|
||||
if command == npc.actions.cmd.SET_INTERVAL then
|
||||
function npc.commands.execute(self, command, args)
|
||||
if command == npc.commands.cmd.SET_INTERVAL then
|
||||
--
|
||||
return npc.actions.set_interval(self, args)
|
||||
elseif command == npc.actions.cmd.FREEZE then
|
||||
return npc.commands.set_interval(self, args)
|
||||
elseif command == npc.commands.cmd.FREEZE then
|
||||
--
|
||||
return npc.actions.freeze(self, args)
|
||||
elseif command == npc.actions.cmd.ROTATE then
|
||||
return npc.commands.freeze(self, args)
|
||||
elseif command == npc.commands.cmd.ROTATE then
|
||||
--
|
||||
return npc.actions.rotate(self, args)
|
||||
elseif command == npc.actions.cmd.WALK_STEP then
|
||||
return npc.commands.rotate(self, args)
|
||||
elseif command == npc.commands.cmd.WALK_STEP then
|
||||
--
|
||||
return npc.actions.walk_step(self, args)
|
||||
elseif command == npc.actions.cmd.STAND then
|
||||
return npc.commands.walk_step(self, args)
|
||||
elseif command == npc.commands.cmd.STAND then
|
||||
--
|
||||
return npc.actions.stand(self, args)
|
||||
elseif command == npc.actions.cmd.SIT then
|
||||
return npc.commands.stand(self, args)
|
||||
elseif command == npc.commands.cmd.SIT then
|
||||
--
|
||||
return npc.actions.sit(self, args)
|
||||
elseif command == npc.actions.cmd.LAY then
|
||||
return npc.commands.sit(self, args)
|
||||
elseif command == npc.commands.cmd.LAY then
|
||||
--
|
||||
return npc.actions.lay(self, args)
|
||||
elseif command == npc.actions.cmd.PUT_ITEM then
|
||||
return npc.commands.lay(self, args)
|
||||
elseif command == npc.commands.cmd.PUT_ITEM then
|
||||
--
|
||||
return npc.actions.put_item_on_external_inventory(self, args)
|
||||
elseif command == npc.actions.cmd.TAKE_ITEM then
|
||||
return npc.commands.put_item_on_external_inventory(self, args)
|
||||
elseif command == npc.commands.cmd.TAKE_ITEM then
|
||||
--
|
||||
return npc.actions.take_item_from_external_inventory(self, args)
|
||||
elseif command == npc.actions.cmd.CHECK_ITEM then
|
||||
return npc.commands.take_item_from_external_inventory(self, args)
|
||||
elseif command == npc.commands.cmd.CHECK_ITEM then
|
||||
--
|
||||
return npc.actions.check_external_inventory_contains_item(self, args)
|
||||
elseif command == npc.actions.cmd.USE_OPENABLE then
|
||||
return npc.commands.check_external_inventory_contains_item(self, args)
|
||||
elseif command == npc.commands.cmd.USE_OPENABLE then
|
||||
--
|
||||
return npc.actions.use_openable(self, args)
|
||||
elseif command == npc.actions.cmd.USE_FURNACE then
|
||||
return npc.commands.use_openable(self, args)
|
||||
elseif command == npc.commands.cmd.USE_FURNACE then
|
||||
--
|
||||
return npc.actions.use_furnace(self, args)
|
||||
elseif command == npc.actions.cmd.USE_BED then
|
||||
return npc.commands.use_furnace(self, args)
|
||||
elseif command == npc.commands.cmd.USE_BED then
|
||||
--
|
||||
return npc.actions.use_bed(self, args)
|
||||
elseif command == npc.actions.cmd.USE_SITTABLE then
|
||||
return npc.commands.use_bed(self, args)
|
||||
elseif command == npc.commands.cmd.USE_SITTABLE then
|
||||
-- Call use sittable task
|
||||
return npc.actions.use_sittable(self, args)
|
||||
elseif command == npc.actions.cmd.WALK_TO_POS then
|
||||
return npc.commands.use_sittable(self, args)
|
||||
elseif command == npc.commands.cmd.WALK_TO_POS then
|
||||
-- Call walk to position task
|
||||
--minetest.log("Self: "..dump(self)..", Command: "..dump(command)..", args: "..dump(args))
|
||||
return npc.actions.walk_to_pos(self, args)
|
||||
elseif command == npc.actions.cmd.DIG then
|
||||
-- Call dig node action
|
||||
return npc.actions.dig(self, args)
|
||||
elseif command == npc.actions.cmd.PLACE then
|
||||
-- Call place node action
|
||||
return npc.actions.place(self, args)
|
||||
return npc.commands.walk_to_pos(self, args)
|
||||
elseif command == npc.commands.cmd.DIG then
|
||||
-- Call dig node command
|
||||
return npc.commands.dig(self, args)
|
||||
elseif command == npc.commands.cmd.PLACE then
|
||||
-- Call place node command
|
||||
return npc.commands.place(self, args)
|
||||
end
|
||||
end
|
||||
|
||||
-- TODO: Thanks to executor function, all the functions for Actions and Tasks
|
||||
-- TODO: Thanks to executor function, all the functions for Commands and Tasks
|
||||
-- should be made into private API
|
||||
|
||||
---------------------------------------------------------------------------------------
|
||||
-- Actions
|
||||
-- Commands
|
||||
---------------------------------------------------------------------------------------
|
||||
-- The following action alters the timer interval for executing actions, therefore
|
||||
-- making waits and pauses possible, or increase timing when some actions want to
|
||||
|
||||
--------------------------
|
||||
-- Declarative commands --
|
||||
--------------------------
|
||||
-- These commands declare, assign and fetch variable values
|
||||
|
||||
-- This command sets the value of a variable in the execution context.
|
||||
-- If the variable doesn't exists, then it creates the variable and
|
||||
-- sets its value.
|
||||
-- Arguments:
|
||||
-- - key: variable name
|
||||
-- - value: variable value
|
||||
-- Returns: Nothing
|
||||
function npc.commands.set_var(self, args)
|
||||
|
||||
end
|
||||
|
||||
-- This command returns the value of a variable in the execution context.
|
||||
-- If the variable doesn't exists, returns nil.
|
||||
-- Arguments:
|
||||
-- - key: variable name
|
||||
-- Returns: variable value if found, nil otherwise
|
||||
function npc.commands.get_var(self, args)
|
||||
|
||||
end
|
||||
|
||||
-- This command returns the value of an internal NPC variable.
|
||||
-- These variables are the self.* variables, limited for security
|
||||
-- purposes. The list of retrievable values is defined in
|
||||
-- npc.commands.internal_values.*
|
||||
-- Arguments:
|
||||
-- - key: internal value as specified in npc.commands.internal_values.*
|
||||
-- Returns: internal value
|
||||
function npc.commands.get_internal_var(self, args)
|
||||
local key = args.key
|
||||
if key then
|
||||
if key == npc.commands.internal_values.POS then
|
||||
return self.object:getpos()
|
||||
elseif key == npc.commands.internal_values.STANDING_IN then
|
||||
return self.standing_in
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------
|
||||
-- Control commands --
|
||||
-----------------------
|
||||
-- The following command alters the timer interval for executing commands, therefore
|
||||
-- making waits and pauses possible, or increase timing when some commands want to
|
||||
-- be performed faster, like walking.
|
||||
function npc.actions.set_interval(self, args)
|
||||
function npc.commands.set_interval(self, args)
|
||||
local self_actions = args.self_actions
|
||||
local new_interval = args.interval
|
||||
local freeze_mobs_api = args.freeze
|
||||
|
||||
self.actions.action_interval = new_interval
|
||||
self.commands.action_interval = new_interval
|
||||
return not freeze_mobs_api
|
||||
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
|
||||
-- The following command is for allowing the rest of mobs redo API to be executed
|
||||
-- after this command ends. This is useful for times when no command is needed
|
||||
-- and the NPC is allowed to roam freely.
|
||||
function npc.actions.freeze(self, args)
|
||||
function npc.commands.freeze(self, args)
|
||||
local freeze_mobs_api = args.freeze
|
||||
local disable_rightclick = args.disable_rightclick
|
||||
if disable_rightclick ~= nil then
|
||||
npc.log("INFO", "Enabling interactions for NPC "..self.npc_name..": "..dump(not(disable_rightclick)))
|
||||
self.enable_rightclick_interaction = not(disable_rightclick)
|
||||
end
|
||||
-- minetest.log("Received: "..dump(freeze_mobs_api))
|
||||
-- minetest.log("Returning: "..dump(not(freeze_mobs_api)))
|
||||
|
||||
return not(freeze_mobs_api)
|
||||
end
|
||||
|
||||
-- This action digs the node at the given position
|
||||
-- This command allows the conditional execution of two array of commands
|
||||
-- depending on the evaluation of a certain condition. This is the typical
|
||||
-- if-else statement of a programming language. If-else can be nested.
|
||||
-- Arguments:
|
||||
-- - `condition`: Lua boolean expression, any expression or value that evaluates
|
||||
-- to either `true` or `false`.
|
||||
-- - `true_commands`: an array of commands to be executed when the condition
|
||||
-- evaluates to `true`
|
||||
-- - `false_commands`: an array of commands to be executed when the condition
|
||||
-- evaluates to `false`
|
||||
function npc.commands.if_else(self, args)
|
||||
|
||||
end
|
||||
|
||||
-- This command works as the types of loops, depending on the arguments
|
||||
-- given. It can work as a while, a for and a for-each loop. Loops can
|
||||
-- be nested.
|
||||
-- While-loop arguments:
|
||||
-- - `name`: string, a key-name for this loop. Default is nil. If given,
|
||||
-- it gives access to the number of times the loop has executed.
|
||||
-- - `condition`: boolean, the loop will be executed as long as this condition
|
||||
-- evaluates to `true`
|
||||
-- - `commands`: array, array of commands to be executed during the loop
|
||||
--
|
||||
-- For-loop arguments:
|
||||
-- - `name`: string, a key-name for this loop. Default is `nil`. If given, it
|
||||
-- gives access to the number of times this loop has executed.
|
||||
-- - `initial_value`: integer, the starting value of the for-loop. If left
|
||||
-- blank, default value is `1`.
|
||||
-- - `condition`: boolean, the loop will be executed as long as this condition
|
||||
-- evaluates to `true`.
|
||||
-- - `modifier`: function, the loop will execute this modifier at the end of
|
||||
-- every iteration. If left blank, default is: initial_value + 1
|
||||
-- - `commands`: array, array of commands to be executed during the loop
|
||||
--
|
||||
-- Both of these loops store how many times they have been executed. To
|
||||
-- access it, it is required to give pass the argument `name`. Then the
|
||||
-- value will be stored on the execution context and the value retrievable
|
||||
-- with `npc.commands.get_context(key)`, where `key` is the `name` argument.
|
||||
--
|
||||
-- For-each-loop arguments:
|
||||
-- - `name`: string, a key-name for this loop. Default is `nil`. If given, it
|
||||
-- gives access to the number of times this loop has executed and the current
|
||||
-- value of the array/table being evaluated.
|
||||
-- - `iterable`: array or table of key-value pairs, this is an iterable array
|
||||
-- or table for which the loop will execute commands at every element in the
|
||||
-- iterable array/table.
|
||||
-- - `commands`: array, array of commands to be executed during the loop
|
||||
-- To get the current element being iterated in a for-each loop, you need to define
|
||||
-- the `name` argument. Then, the value will be stored in the execution context and
|
||||
-- will be retrievable with `npc.commands.get_context(key)`. It will return a table
|
||||
-- like this: {loop_count = x, current_value = y}
|
||||
function npc.commands.loop(self, args)
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
-------------------------
|
||||
-- Interaction commands --
|
||||
-------------------------
|
||||
-- This command digs the node at the given position
|
||||
-- If 'add_to_inventory' is true, it will put the digged node in the NPC
|
||||
-- inventory.
|
||||
-- Returns true if dig is successful, otherwise false
|
||||
function npc.actions.dig(self, args)
|
||||
function npc.commands.dig(self, args)
|
||||
local pos = args.pos
|
||||
local add_to_inventory = args.add_to_inventory
|
||||
local bypass_protection = args.bypass_protection
|
||||
@ -281,7 +394,7 @@ function npc.actions.dig(self, args)
|
||||
end
|
||||
|
||||
|
||||
-- This action places a given node at the given position
|
||||
-- This command places a given node at the given position
|
||||
-- There are three ways to source the node:
|
||||
-- 1. take_from_inventory: takes node from inventory. If not in inventory,
|
||||
-- node isn't placed.
|
||||
@ -289,7 +402,7 @@ end
|
||||
-- inventory, node will be placed anyways.
|
||||
-- 3. force_place: places node regardless of inventory - will not touch
|
||||
-- the NPCs inventory
|
||||
function npc.actions.place(self, args)
|
||||
function npc.commands.place(self, args)
|
||||
local pos = args.pos
|
||||
local node = args.node
|
||||
local source = args.source
|
||||
@ -304,14 +417,14 @@ function npc.actions.place(self, args)
|
||||
or bypass_protection == true then
|
||||
-- Take from inventory if necessary
|
||||
local place_item = false
|
||||
if source == npc.actions.take_from_inventory then
|
||||
if source == npc.commands.take_from_inventory then
|
||||
if npc.take_item_from_inventory(self, node, 1) then
|
||||
place_item = true
|
||||
end
|
||||
elseif source == npc.actions.take_from_inventory_forced then
|
||||
elseif source == npc.commands.take_from_inventory_forced then
|
||||
npc.take_item_from_inventory(self, node, 1)
|
||||
place_item = true
|
||||
elseif source == npc.actions.force_place then
|
||||
elseif source == npc.commands.force_place then
|
||||
place_item = true
|
||||
end
|
||||
-- Place node
|
||||
@ -338,6 +451,37 @@ function npc.actions.place(self, args)
|
||||
end
|
||||
end
|
||||
|
||||
-- This function allows to query for nodes and entities within a radius.
|
||||
-- Parameters:
|
||||
-- - query_type: string, specifies whether to query nodes or entities.
|
||||
-- Default value is "node". Accepted values are:
|
||||
-- - "node"
|
||||
-- - "entity"
|
||||
-- - position: table or string, specifies the starting position
|
||||
-- for query. This should be the center of a square box. If
|
||||
-- given a String, the string should be the place type.
|
||||
-- Two types of tables are accepted:
|
||||
-- - A simple position table, {x=1, y=1, z=1}
|
||||
-- - An improved position table in this format:
|
||||
-- {
|
||||
-- place_category = "",
|
||||
-- place_type = "",
|
||||
-- index = 1, (specific index in the places map)
|
||||
-- use_access_node = false|true,
|
||||
-- }
|
||||
-- - radius: integer, specifies the radius of the square box to search
|
||||
-- around the starting position.
|
||||
-- - result_type: string, specifies how to return results. Accepted
|
||||
-- values are:
|
||||
-- - "first": Get the first result found (default if left blank),
|
||||
-- - "nearest": Get the result nearest to the NPC,
|
||||
-- - "all": Return array of all results
|
||||
function npc.commands.query(self, args)
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- This function allows to move into directions that are walkable. It
|
||||
-- avoids fences and allows to move on plants.
|
||||
-- This will make for nice wanderings, making the NPC move smartly instead
|
||||
@ -346,7 +490,7 @@ local function random_dir_helper(start_pos, speed, dir_start, dir_end)
|
||||
-- Limit the number of tries - otherwise it could become an infinite loop
|
||||
for i = 1, 8 do
|
||||
local dir = math.random(dir_start, dir_end)
|
||||
local vel = vector.multiply(npc.actions.dir_data[dir].vel, speed)
|
||||
local vel = vector.multiply(npc.commands.dir_data[dir].vel, speed)
|
||||
local pos = vector.add(start_pos, vel)
|
||||
local node = minetest.get_node(pos)
|
||||
if node then
|
||||
@ -364,16 +508,16 @@ local function random_dir_helper(start_pos, speed, dir_start, dir_end)
|
||||
return -1
|
||||
end
|
||||
|
||||
-- This action is to rotate to mob to a specifc direction. Currently, the code
|
||||
-- This command 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(self, args)
|
||||
function npc.commands.rotate(self, args)
|
||||
local dir = args.dir
|
||||
local yaw = args.yaw or 0
|
||||
local start_pos = args.start_pos
|
||||
local end_pos = args.end_pos
|
||||
-- Calculate dir if positions are given
|
||||
if start_pos and end_pos and not dir then
|
||||
dir = npc.actions.get_direction(start_pos, end_pos)
|
||||
dir = npc.commands.get_direction(start_pos, end_pos)
|
||||
end
|
||||
-- Only yaw was given
|
||||
if yaw and not dir and not start_pos and not end_pos then
|
||||
@ -405,7 +549,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(self, args)
|
||||
function npc.commands.walk_step(self, args)
|
||||
local dir = args.dir
|
||||
local step_into_air_only = args.step_into_air_only
|
||||
local speed = args.speed
|
||||
@ -415,7 +559,7 @@ function npc.actions.walk_step(self, args)
|
||||
|
||||
-- Set default node per seconds
|
||||
if speed == nil then
|
||||
speed = npc.actions.one_nps_speed
|
||||
speed = npc.commands.one_nps_speed
|
||||
end
|
||||
|
||||
-- Check if dir should be random
|
||||
@ -449,13 +593,13 @@ function npc.actions.walk_step(self, args)
|
||||
|
||||
-- If there is a target position to reach, set it and set walking to true
|
||||
if target_pos ~= nil then
|
||||
self.actions.walking.target_pos = target_pos
|
||||
self.commands.walking.target_pos = target_pos
|
||||
-- Set is_walking = true
|
||||
self.actions.walking.is_walking = true
|
||||
self.commands.walking.is_walking = true
|
||||
end
|
||||
|
||||
-- Rotate NPC
|
||||
npc.actions.rotate(self, {dir=dir})
|
||||
npc.commands.rotate(self, {dir=dir})
|
||||
-- Set velocity so that NPC walks
|
||||
self.object:setvelocity(vel)
|
||||
-- Set walk animation
|
||||
@ -465,12 +609,12 @@ function npc.actions.walk_step(self, args)
|
||||
self.animation.speed_normal, 0)
|
||||
end
|
||||
|
||||
-- This action makes the NPC stand and remain like that
|
||||
function npc.actions.stand(self, args)
|
||||
-- This command makes the NPC stand and remain like that
|
||||
function npc.commands.stand(self, args)
|
||||
local pos = args.pos
|
||||
local dir = args.dir
|
||||
-- Set is_walking = false
|
||||
self.actions.walking.is_walking = false
|
||||
self.commands.walking.is_walking = false
|
||||
-- Stop NPC
|
||||
self.object:setvelocity({x=0, y=0, z=0})
|
||||
-- If position given, set to that position
|
||||
@ -479,7 +623,7 @@ function npc.actions.stand(self, args)
|
||||
end
|
||||
-- If dir given, set to that dir
|
||||
if dir ~= nil then
|
||||
npc.actions.rotate(self, {dir=dir})
|
||||
npc.commands.rotate(self, {dir=dir})
|
||||
end
|
||||
-- Set stand animation
|
||||
self.object:set_animation({
|
||||
@ -488,8 +632,8 @@ function npc.actions.stand(self, args)
|
||||
self.animation.speed_normal, 0)
|
||||
end
|
||||
|
||||
-- This action makes the NPC sit on the node where it is
|
||||
function npc.actions.sit(self, args)
|
||||
-- This command makes the NPC sit on the node where it is
|
||||
function npc.commands.sit(self, args)
|
||||
local pos = args.pos
|
||||
local dir = args.dir
|
||||
-- Stop NPC
|
||||
@ -500,7 +644,7 @@ function npc.actions.sit(self, args)
|
||||
end
|
||||
-- If dir given, set to that dir
|
||||
if dir ~= nil then
|
||||
npc.actions.rotate(self, {dir=dir})
|
||||
npc.commands.rotate(self, {dir=dir})
|
||||
end
|
||||
-- Set sit animation
|
||||
self.object:set_animation({
|
||||
@ -509,8 +653,8 @@ function npc.actions.sit(self, args)
|
||||
self.animation.speed_normal, 0)
|
||||
end
|
||||
|
||||
-- This action makes the NPC lay on the node where it is
|
||||
function npc.actions.lay(self, args)
|
||||
-- This command makes the NPC lay on the node where it is
|
||||
function npc.commands.lay(self, args)
|
||||
local pos = args.pos
|
||||
-- Stop NPC
|
||||
self.object:setvelocity({x=0, y=0, z=0})
|
||||
@ -529,7 +673,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(self, args)
|
||||
function npc.commands.put_item_on_external_inventory(self, args)
|
||||
local player = args.player
|
||||
local pos = args.pos
|
||||
local inv_list = args.inv_list
|
||||
@ -566,7 +710,7 @@ function npc.actions.put_item_on_external_inventory(self, args)
|
||||
return false
|
||||
end
|
||||
|
||||
function npc.actions.take_item_from_external_inventory(self, args)
|
||||
function npc.commands.take_item_from_external_inventory(self, args)
|
||||
local player = args.player
|
||||
local pos = args.pos
|
||||
local inv_list = args.inv_list
|
||||
@ -592,7 +736,7 @@ function npc.actions.take_item_from_external_inventory(self, args)
|
||||
return false
|
||||
end
|
||||
|
||||
function npc.actions.check_external_inventory_contains_item(self, args)
|
||||
function npc.commands.check_external_inventory_contains_item(self, args)
|
||||
local player = args.player
|
||||
local pos = args.pos
|
||||
local inv_list = args.inv_list
|
||||
@ -613,9 +757,9 @@ end
|
||||
|
||||
-- TODO: Refactor this function so that it uses a table to check
|
||||
-- for doors instead of having separate logic for each door type
|
||||
function npc.actions.get_openable_node_state(node, pos, npc_dir)
|
||||
function npc.commands.get_openable_node_state(node, pos, npc_dir)
|
||||
--minetest.log("Node name: "..dump(node.name))
|
||||
local state = npc.actions.const.doors.state.CLOSED
|
||||
local state = npc.commands.const.doors.state.CLOSED
|
||||
-- Check for MTG doors and gates
|
||||
local mtg_door_closed = false
|
||||
if minetest.get_item_group(node.name, "door") > 0 then
|
||||
@ -633,7 +777,7 @@ function npc.actions.get_openable_node_state(node, pos, npc_dir)
|
||||
half_door_is_closed = (node.param2 + 2) % 4 == npc_dir
|
||||
end
|
||||
if mtg_door_closed == false and open_i1 == nil and half_door_is_closed == false then
|
||||
state = npc.actions.const.doors.state.OPEN
|
||||
state = npc.commands.const.doors.state.OPEN
|
||||
end
|
||||
--minetest.log("Door state: "..dump(state))
|
||||
return state
|
||||
@ -642,15 +786,15 @@ 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_openable(self, args)
|
||||
function npc.commands.use_openable(self, args)
|
||||
local pos = args.pos
|
||||
local action = args.action
|
||||
local command = args.command
|
||||
local dir = args.dir
|
||||
local node = minetest.get_node(pos)
|
||||
local state = npc.actions.get_openable_node_state(node, pos, dir)
|
||||
local state = npc.commands.get_openable_node_state(node, pos, dir)
|
||||
|
||||
local clicker = self.object
|
||||
if action ~= state then
|
||||
if command ~= state then
|
||||
minetest.registered_nodes[node.name].on_rightclick(pos, node, clicker, nil, nil)
|
||||
end
|
||||
end
|
||||
@ -659,7 +803,7 @@ end
|
||||
---------------------------------------------------------------------------------------
|
||||
-- Tasks functionality
|
||||
---------------------------------------------------------------------------------------
|
||||
-- Tasks are operations that require many actions to perform. Basic tasks, like
|
||||
-- Tasks are operations that require many commands to perform. Basic tasks, like
|
||||
-- walking from one place to another, operating a furnace, storing or taking
|
||||
-- items from a chest, are provided here.
|
||||
|
||||
@ -748,7 +892,7 @@ end
|
||||
-- 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, args)
|
||||
function npc.commands.use_furnace(self, args)
|
||||
local pos = get_pos_argument(self, args.pos)
|
||||
if pos == nil then
|
||||
npc.log("WARNING", "Got nil position in 'use_furnace' using args.pos: "..dump(args.pos))
|
||||
@ -831,7 +975,7 @@ function npc.actions.use_furnace(self, args)
|
||||
item_name = npc.get_item_name(fuel_item.item_string),
|
||||
count = fuel_amount
|
||||
}
|
||||
npc.add_action(self, npc.actions.cmd.PUT_ITEM, args)
|
||||
npc.add_action(self, npc.commands.cmd.PUT_ITEM, args)
|
||||
-- Put the item that we want to cook on the furnace
|
||||
args = {
|
||||
player = nil,
|
||||
@ -841,20 +985,20 @@ function npc.actions.use_furnace(self, args)
|
||||
count = npc.get_item_count(item),
|
||||
is_furnace = true
|
||||
}
|
||||
npc.add_action(self, npc.actions.cmd.PUT_ITEM, args)
|
||||
npc.add_action(self, npc.commands.cmd.PUT_ITEM, args)
|
||||
|
||||
-- Now, set NPC to wait until furnace is done.
|
||||
npc.log("DEBUG", "Setting wait action for "..dump(total_cook_time))
|
||||
npc.add_action(self, npc.actions.cmd.SET_INTERVAL, {interval=total_cook_time, freeze=freeze})
|
||||
npc.log("DEBUG", "Setting wait command for "..dump(total_cook_time))
|
||||
npc.add_action(self, npc.commands.cmd.SET_INTERVAL, {interval=total_cook_time, freeze=freeze})
|
||||
|
||||
-- Reset timer
|
||||
npc.add_action(self, npc.actions.cmd.SET_INTERVAL, {interval=1, freeze=true})
|
||||
npc.add_action(self, npc.commands.cmd.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
|
||||
npc.log("DEBUG", "Adding walk to position to wandering: "..dump(pos))
|
||||
npc.add_task(self, npc.actions.cmd.WALK_TO_POS, {end_pos=pos, walkable={}})
|
||||
npc.add_task(self, npc.commands.cmd.WALK_TO_POS, {end_pos=pos, walkable={}})
|
||||
end
|
||||
|
||||
-- Take cooked items back
|
||||
@ -868,7 +1012,7 @@ function npc.actions.use_furnace(self, args)
|
||||
is_furnace = false
|
||||
}
|
||||
npc.log("DEBUG", "Taking item back: "..minetest.pos_to_string(pos))
|
||||
npc.add_action(self, npc.actions.cmd.TAKE_ITEM, args)
|
||||
npc.add_action(self, npc.commands.cmd.TAKE_ITEM, args)
|
||||
|
||||
npc.log("DEBUG", "Inventory: "..dump(self.inventory))
|
||||
|
||||
@ -886,51 +1030,51 @@ function npc.actions.use_furnace(self, args)
|
||||
end
|
||||
|
||||
-- This function makes the NPC lay or stand up from a bed. The
|
||||
-- pos is the location of the bed, action can be lay or get up
|
||||
function npc.actions.use_bed(self, args)
|
||||
-- pos is the location of the bed, command can be lay or get up
|
||||
function npc.commands.use_bed(self, args)
|
||||
local pos = get_pos_argument(self, args.pos)
|
||||
if pos == nil then
|
||||
npc.log("WARNING", "Got nil position in 'use_bed' using args.pos: "..dump(args.pos))
|
||||
return
|
||||
end
|
||||
local action = args.action
|
||||
local command = args.command
|
||||
local enable_usage_marking = args.enable_usage_marking or true
|
||||
local node = minetest.get_node(pos)
|
||||
--minetest.log(dump(node))
|
||||
local dir = minetest.facedir_to_dir(node.param2)
|
||||
|
||||
if action == npc.actions.const.beds.LAY then
|
||||
if command == npc.commands.const.beds.LAY then
|
||||
-- Get position
|
||||
-- Error here due to ignore. Need to come up with better solution
|
||||
if node.name == "ignore" then
|
||||
return
|
||||
end
|
||||
local bed_pos = npc.actions.nodes.beds[node.name].get_lay_pos(pos, dir)
|
||||
local bed_pos = npc.commands.nodes.beds[node.name].get_lay_pos(pos, dir)
|
||||
-- Sit down on bed, rotate to correct direction
|
||||
npc.add_action(self, npc.actions.cmd.SIT, {pos=bed_pos, dir=(node.param2 + 2) % 4})
|
||||
npc.add_action(self, npc.commands.cmd.SIT, {pos=bed_pos, dir=(node.param2 + 2) % 4})
|
||||
-- Lay down
|
||||
npc.add_action(self, npc.actions.cmd.LAY, {})
|
||||
npc.add_action(self, npc.commands.cmd.LAY, {})
|
||||
if enable_usage_marking then
|
||||
-- Set place as used
|
||||
npc.places.mark_place_used(pos, npc.places.USE_STATE.USED)
|
||||
end
|
||||
self.actions.move_state.is_laying = true
|
||||
self.commands.move_state.is_laying = true
|
||||
else
|
||||
-- Calculate position to get up
|
||||
-- Error here due to ignore. Need to come up with better solution
|
||||
if node.name == "ignore" then
|
||||
return
|
||||
end
|
||||
local bed_pos_y = npc.actions.nodes.beds[node.name].get_lay_pos(pos, dir).y
|
||||
local bed_pos_y = npc.commands.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.cmd.SIT, {pos=bed_pos})
|
||||
npc.add_action(self, npc.commands.cmd.SIT, {pos=bed_pos})
|
||||
-- Initialize direction: Default is front of bottom of bed
|
||||
local dir = (node.param2 + 2) % 4
|
||||
-- Find empty node around node
|
||||
-- Take into account that mats are close to the floor, so y adjustmen is zero
|
||||
local y_adjustment = -1
|
||||
if npc.actions.nodes.beds[node.name].type == "mat" then
|
||||
if npc.commands.nodes.beds[node.name].type == "mat" then
|
||||
y_adjustment = 0
|
||||
end
|
||||
|
||||
@ -938,7 +1082,7 @@ function npc.actions.use_bed(self, args)
|
||||
local empty_nodes = npc.places.find_node_orthogonally(bed_pos, {"air", "cottages:bench"}, y_adjustment)
|
||||
if empty_nodes ~= nil and #empty_nodes > 0 then
|
||||
-- Get direction to the empty node
|
||||
dir = npc.actions.get_direction(bed_pos, empty_nodes[1].pos)
|
||||
dir = npc.commands.get_direction(bed_pos, empty_nodes[1].pos)
|
||||
|
||||
-- Calculate position to get out of bed
|
||||
pos_out_of_bed =
|
||||
@ -959,43 +1103,43 @@ function npc.actions.use_bed(self, args)
|
||||
|
||||
end
|
||||
-- Stand out of bed
|
||||
npc.add_action(self, npc.actions.cmd.STAND, {pos=pos_out_of_bed, dir=dir})
|
||||
npc.add_action(self, npc.commands.cmd.STAND, {pos=pos_out_of_bed, dir=dir})
|
||||
if enable_usage_marking then
|
||||
-- Set place as unused
|
||||
npc.places.mark_place_used(pos, npc.places.USE_STATE.NOT_USED)
|
||||
end
|
||||
self.actions.move_state.is_laying = false
|
||||
self.commands.move_state.is_laying = false
|
||||
end
|
||||
end
|
||||
|
||||
-- This function makes the NPC lay or stand up from a bed. The
|
||||
-- pos is the location of the bed, action can be lay or get up
|
||||
function npc.actions.use_sittable(self, args)
|
||||
-- pos is the location of the bed, command can be lay or get up
|
||||
function npc.commands.use_sittable(self, args)
|
||||
local pos = get_pos_argument(self, args.pos)
|
||||
if pos == nil then
|
||||
npc.log("WARNING", "Got nil position in 'use_sittable' using args.pos: "..dump(args.pos))
|
||||
return
|
||||
end
|
||||
local action = args.action
|
||||
local command = args.command
|
||||
local enable_usage_marking = args.enable_usage_marking or true
|
||||
local node = minetest.get_node(pos)
|
||||
|
||||
if action == npc.actions.const.sittable.SIT then
|
||||
if command == npc.commands.const.sittable.SIT then
|
||||
-- Calculate position depending on bench
|
||||
-- Error here due to ignore. Need to come up with better solution
|
||||
if node.name == "ignore" then
|
||||
return
|
||||
end
|
||||
local sit_pos = npc.actions.nodes.sittable[node.name].get_sit_pos(pos, node.param2)
|
||||
local sit_pos = npc.commands.nodes.sittable[node.name].get_sit_pos(pos, node.param2)
|
||||
-- Sit down on bench/chair/stairs
|
||||
npc.add_action(self, npc.actions.cmd.SIT, {pos=sit_pos, dir=(node.param2 + 2) % 4})
|
||||
npc.add_action(self, npc.commands.cmd.SIT, {pos=sit_pos, dir=(node.param2 + 2) % 4})
|
||||
if enable_usage_marking then
|
||||
-- Set place as used
|
||||
npc.places.mark_place_used(pos, npc.places.USE_STATE.USED)
|
||||
end
|
||||
self.actions.move_state.is_sitting = true
|
||||
self.commands.move_state.is_sitting = true
|
||||
else
|
||||
if self.actions.move_state.is_sitting == false then
|
||||
if self.commands.move_state.is_sitting == false then
|
||||
npc.log("DEBUG_ACTION", "NPC "..self.npc_name.." attempted to get up from sit when it is not sitting.")
|
||||
return
|
||||
end
|
||||
@ -1007,28 +1151,28 @@ function npc.actions.use_sittable(self, args)
|
||||
local empty_nodes = npc.places.find_node_orthogonally(pos, {"air"}, 0)
|
||||
if empty_nodes ~= nil and #empty_nodes > 0 then
|
||||
--minetest.log("Empty nodes: "..dump(empty_nodes))
|
||||
--minetest.log("Npc.actions.get_direction: "..dump(npc.actions.get_direction))
|
||||
--minetest.log("Npc.commands.get_direction: "..dump(npc.commands.get_direction))
|
||||
--minetest.log("Pos: "..dump(pos))
|
||||
-- Get direction to the empty node
|
||||
dir = npc.actions.get_direction(pos, empty_nodes[1].pos)
|
||||
dir = npc.commands.get_direction(pos, empty_nodes[1].pos)
|
||||
-- Calculate position to get out of sittable node
|
||||
pos_out_of_sittable =
|
||||
{x=empty_nodes[1].pos.x, y=empty_nodes[1].pos.y + 1, z=empty_nodes[1].pos.z}
|
||||
end
|
||||
-- Stand
|
||||
npc.add_action(self, npc.actions.cmd.STAND, {pos=pos_out_of_sittable, dir=dir})
|
||||
npc.add_action(self, npc.commands.cmd.STAND, {pos=pos_out_of_sittable, dir=dir})
|
||||
minetest.log("Setting sittable at "..minetest.pos_to_string(pos).." as not used")
|
||||
if enable_usage_marking then
|
||||
-- Set place as unused
|
||||
npc.places.mark_place_used(pos, npc.places.USE_STATE.NOT_USED)
|
||||
end
|
||||
self.actions.move_state.is_sitting = false
|
||||
self.commands.move_state.is_sitting = false
|
||||
end
|
||||
end
|
||||
|
||||
-- This function returns the direction enum
|
||||
-- for the moving from v1 to v2
|
||||
function npc.actions.get_direction(v1, v2)
|
||||
function npc.commands.get_direction(v1, v2)
|
||||
local vector_dir = vector.direction(v1, v2)
|
||||
local dir = vector.round(vector_dir)
|
||||
|
||||
@ -1063,7 +1207,7 @@ 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(self, args)
|
||||
function npc.commands.walk_to_pos(self, args)
|
||||
-- Get arguments for this task
|
||||
local use_access_node = args.use_access_node or true
|
||||
local end_pos, node_pos = get_pos_argument(self, args.end_pos, use_access_node)
|
||||
@ -1081,11 +1225,11 @@ function npc.actions.walk_to_pos(self, args)
|
||||
|
||||
-- Check if start_pos and end_pos are the same
|
||||
if vector.equals(start_pos, end_pos) == true then
|
||||
-- Check if it was using access node, if it was, add action to
|
||||
-- Check if it was using access node, if it was, add command to
|
||||
-- rotate NPC into that direction
|
||||
if use_access_node == true then
|
||||
local dir = npc.actions.get_direction(end_pos, node_pos)
|
||||
npc.add_action(self, npc.actions.cmd.STAND, {dir = dir})
|
||||
local dir = npc.commands.get_direction(end_pos, node_pos)
|
||||
npc.add_action(self, npc.commands.cmd.STAND, {dir = dir})
|
||||
end
|
||||
npc.log("WARNING", "walk_to_pos Found start_pos == end_pos")
|
||||
return
|
||||
@ -1103,56 +1247,56 @@ function npc.actions.walk_to_pos(self, args)
|
||||
if path ~= nil and #path > 1 then
|
||||
npc.log("INFO", "walk_to_pos Found path to node: "..minetest.pos_to_string(end_pos))
|
||||
-- Store path
|
||||
self.actions.walking.path = path
|
||||
self.commands.walking.path = path
|
||||
|
||||
-- Local variables
|
||||
local door_opened = false
|
||||
local speed = npc.actions.two_nps_speed
|
||||
local speed = npc.commands.two_nps_speed
|
||||
|
||||
-- Set the action timer interval to half second. This is to account for
|
||||
-- Set the command timer interval to half second. This is to account for
|
||||
-- the increased speed when walking.
|
||||
npc.add_action(self, npc.actions.cmd.SET_INTERVAL, {interval=0.5, freeze=true})
|
||||
npc.add_action(self, npc.commands.cmd.SET_INTERVAL, {interval=0.5, freeze=true})
|
||||
|
||||
-- Set the initial last and target positions
|
||||
self.actions.walking.target_pos = path[1].pos
|
||||
self.commands.walking.target_pos = path[1].pos
|
||||
|
||||
-- Add steps to path
|
||||
for i = 1, #path do
|
||||
-- Do not add an extra step if reached the goal node
|
||||
if (i+1) == #path then
|
||||
-- Add direction to last node
|
||||
local dir = npc.actions.get_direction(path[i].pos, end_pos)
|
||||
local dir = npc.commands.get_direction(path[i].pos, end_pos)
|
||||
-- Add the last step
|
||||
npc.add_action(self, npc.actions.cmd.WALK_STEP, {dir = dir, speed = speed, target_pos = path[i+1].pos})
|
||||
npc.add_action(self, npc.commands.cmd.WALK_STEP, {dir = dir, speed = speed, target_pos = path[i+1].pos})
|
||||
-- Add stand animation at end
|
||||
if use_access_node == true then
|
||||
dir = npc.actions.get_direction(end_pos, node_pos)
|
||||
dir = npc.commands.get_direction(end_pos, node_pos)
|
||||
end
|
||||
minetest.log("Dir: "..dump(dir))
|
||||
-- Change dir if using access_node
|
||||
npc.add_action(self, npc.actions.cmd.STAND, {dir = dir})
|
||||
npc.add_action(self, npc.commands.cmd.STAND, {dir = dir})
|
||||
break
|
||||
end
|
||||
-- Get direction to move from path[i] to path[i+1]
|
||||
local dir = npc.actions.get_direction(path[i].pos, path[i+1].pos)
|
||||
local dir = npc.commands.get_direction(path[i].pos, path[i+1].pos)
|
||||
-- Check if next node is a door, if it is, open it, then walk
|
||||
if path[i+1].type == npc.pathfinder.node_types.openable then
|
||||
-- Check if door is already open
|
||||
local node = minetest.get_node(path[i+1].pos)
|
||||
if npc.actions.get_openable_node_state(node, path[i+1].pos, dir) == npc.actions.const.doors.state.CLOSED then
|
||||
--minetest.log("Opening action to open door")
|
||||
if npc.commands.get_openable_node_state(node, path[i+1].pos, dir) == npc.commands.const.doors.state.CLOSED then
|
||||
--minetest.log("Opening command to open door")
|
||||
-- Stop to open door, this avoids misplaced movements later on
|
||||
npc.add_action(self, npc.actions.cmd.STAND, {dir=dir})
|
||||
npc.add_action(self, npc.commands.cmd.STAND, {dir=dir})
|
||||
-- Open door
|
||||
npc.add_action(self, npc.actions.cmd.USE_OPENABLE, {pos=path[i+1].pos, dir=dir, action=npc.actions.const.doors.action.OPEN})
|
||||
npc.add_action(self, npc.commands.cmd.USE_OPENABLE, {pos=path[i+1].pos, dir=dir, command=npc.commands.const.doors.command.OPEN})
|
||||
|
||||
door_opened = true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Add walk action to action queue
|
||||
npc.add_action(self, npc.actions.cmd.WALK_STEP, {dir = dir, speed = speed, target_pos = path[i+1].pos})
|
||||
-- Add walk command to command queue
|
||||
npc.add_action(self, npc.commands.cmd.WALK_STEP, {dir = dir, speed = speed, target_pos = path[i+1].pos})
|
||||
|
||||
if door_opened then
|
||||
-- Stop to close door, this avoids misplaced movements later on
|
||||
@ -1168,20 +1312,20 @@ function npc.actions.walk_to_pos(self, args)
|
||||
-- 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}
|
||||
-- Add extra walk step to ensure that one is standing at other side of openable node
|
||||
-- npc.add_action(self, npc.actions.cmd.WALK_STEP, {dir = dir, speed = speed, target_pos = path[i+2].pos})
|
||||
-- npc.add_action(self, npc.commands.cmd.WALK_STEP, {dir = dir, speed = speed, target_pos = path[i+2].pos})
|
||||
-- Stop to close the door
|
||||
npc.add_action(self, npc.actions.cmd.STAND, {dir=(dir + 2) % 4 })--, pos=pos_on_close})
|
||||
npc.add_action(self, npc.commands.cmd.STAND, {dir=(dir + 2) % 4 })--, pos=pos_on_close})
|
||||
-- Close door
|
||||
npc.add_action(self, npc.actions.cmd.USE_OPENABLE, {pos=path[i+1].pos, action=npc.actions.const.doors.action.CLOSE})
|
||||
npc.add_action(self, npc.commands.cmd.USE_OPENABLE, {pos=path[i+1].pos, command=npc.commands.const.doors.command.CLOSE})
|
||||
|
||||
door_opened = false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Return the action interval to default interval of 1 second
|
||||
-- Return the command interval to default interval of 1 second
|
||||
-- By default, always freeze.
|
||||
npc.add_action(self, npc.actions.cmd.SET_INTERVAL, {interval=1, freeze=true})
|
||||
npc.add_action(self, npc.commands.cmd.SET_INTERVAL, {interval=1, freeze=true})
|
||||
|
||||
else
|
||||
-- Unable to find path
|
||||
|
Loading…
Reference in New Issue
Block a user