Actions: Added some fundamental movement actions.
Places: Added functions for adding and getting places, and for finding places of specific types. Added beds, chairs and chest as places. NPC: Added places map and action queue.
This commit is contained in:
parent
a2e38ab85f
commit
646b422082
85
actions/actions.lua
Normal file
85
actions/actions.lua
Normal file
@ -0,0 +1,85 @@
|
||||
-- Actions code for Advanced NPC by Zorman2000
|
||||
---------------------------------------------------------------------------------------
|
||||
-- Action functionality
|
||||
---------------------------------------------------------------------------------------
|
||||
-- The NPCs will be able to perform five fundamental actions 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,
|
||||
-- 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.
|
||||
-- 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.
|
||||
|
||||
npc.actions = {}
|
||||
|
||||
function npc.actions.rotate(args)
|
||||
local self = args.self
|
||||
local dir = args.dir
|
||||
local yaw = 0
|
||||
self.rotate = 0
|
||||
if dir == npc.direction.north then
|
||||
yaw = 315
|
||||
elseif dir == npc.direction.east then
|
||||
yaw = 225
|
||||
elseif dir == npc.direction.south then
|
||||
yaw = 135
|
||||
elseif dir == npc.direction.west then
|
||||
yaw = 45
|
||||
end
|
||||
self.object:setyaw(yaw)
|
||||
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
|
||||
local dir = args.dir
|
||||
local vel = {}
|
||||
if dir == npc.direction.north then
|
||||
vel = {x=0, y=0, z=1}
|
||||
elseif dir == npc.direction.east then
|
||||
vel = {x=1, y=0, z=0}
|
||||
elseif dir == npc.direction.south then
|
||||
vel = {x=0, y=0, z=-1}
|
||||
elseif dir == npc.direction.west then
|
||||
vel = {x=-1, y=0, z=0}
|
||||
end
|
||||
set_animation(self, "walk")
|
||||
npc.rotate({self=self, dir=dir})
|
||||
self.object:setvelocity(vel)
|
||||
end
|
||||
|
||||
-- This action makes the NPC stand and remain like that
|
||||
function npc.actions.stand(args)
|
||||
local self = args.self
|
||||
-- Stop NPC
|
||||
self.object:setvelocity({x=0, y=0, z=0})
|
||||
-- Set stand animation
|
||||
set_animation(self, "stand")
|
||||
end
|
||||
|
||||
-- This action makes the NPC sit on the node where it is
|
||||
function npc.actions.sit(args)
|
||||
local self = args.self
|
||||
-- Stop NPC
|
||||
self.object:setvelocity({x=0, y=0, z=0})
|
||||
-- Set sit animation
|
||||
self.object:set_animation({
|
||||
x = npc.ANIMATION_SIT_START,
|
||||
y = npc.ANIMATION_SIT_END},
|
||||
self.animation.speed_normal, 0)
|
||||
end
|
||||
|
||||
-- This action makes the NPC lay on the node where it is
|
||||
function npc.actions.lay(args)
|
||||
local self = args.self
|
||||
-- Stop NPC
|
||||
self.object:setvelocity({x=0, y=0, z=0})
|
||||
-- Set sit animation
|
||||
self.object:set_animation({
|
||||
x = npc.ANIMATION_LAY_START,
|
||||
y = npc.ANIMATION_LAY_END},
|
||||
self.animation.speed_normal, 0)
|
||||
end
|
82
actions/places.lua
Normal file
82
actions/places.lua
Normal file
@ -0,0 +1,82 @@
|
||||
-- Places code for Advanced NPC by Zorman2000
|
||||
---------------------------------------------------------------------------------------
|
||||
-- Places functionality
|
||||
---------------------------------------------------------------------------------------
|
||||
-- In addition, the NPCs need to know where some places are, and know
|
||||
-- where there are nodes they can use. For example, they need to know where the
|
||||
-- chest they use is located, both to walk to it and to use it. They also need
|
||||
-- to know where the farm they work is located, or where the bed they sleep is.
|
||||
-- Other mods have to be supported for this to work correctly, as there are
|
||||
-- many sitting nodes, many beds, many tables, chests, etc. For now, by default,
|
||||
-- support for default and cottages is going to be provided.
|
||||
|
||||
npc.places = {}
|
||||
|
||||
npc.places.nodes = {
|
||||
BEDS = {
|
||||
"beds:bed_bottom",
|
||||
"beds:fancy_bed_bottom"
|
||||
},
|
||||
CHAIRS = {
|
||||
"cottages:bench"
|
||||
},
|
||||
CHESTS = {
|
||||
"default:chest",
|
||||
"default:chest_locked"
|
||||
}
|
||||
}
|
||||
|
||||
npc.places.PLACE_TYPE = {
|
||||
"OWN_BED",
|
||||
"OWN_CHEST",
|
||||
"HOUSE_CHAIR",
|
||||
"HOUSE_TABLE",
|
||||
"HOUSE_FURNACE",
|
||||
"HOUSE_ENTRANCE"
|
||||
}
|
||||
|
||||
|
||||
function npc.places.add(self, place_name, place_type, pos)
|
||||
self.places_map[place_name] = {type=place_type, pos=pos}
|
||||
end
|
||||
|
||||
-- Adds a specific node to the NPC places, and modifies the
|
||||
-- node metadata to identify the NPC as the owner. This allows
|
||||
-- other NPCs to avoid to take this as their own.
|
||||
function npc.places.add_owned(self, place_name, place_type, pos)
|
||||
-- Get node metadata
|
||||
local meta = minetest.get_meta(pos)
|
||||
-- Check if it is owned by an NPC?
|
||||
if meta:get_string("npc_owner") == "" then
|
||||
-- Set owned by NPC
|
||||
meta:set_string("npc_owner", self.npc_id)
|
||||
-- Add place to list
|
||||
npc.places.add(self, place_name, place_type, pos)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function npc.places.get_by_type(self, place_type)
|
||||
local result = {}
|
||||
for place_name, place_entry in pairs(self.places_map) do
|
||||
if place_entry.type == place_type then
|
||||
table.insert(result, place_name)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- This function searches on a squared are of the given radius
|
||||
-- for nodes of the given type. The type should be npc.places.nodes
|
||||
function npc.places.find_new_nearby(self, type, radius)
|
||||
-- Get current pos
|
||||
local current_pos = self.object:getpos()
|
||||
-- Determine area points
|
||||
local start_pos = {x=current_pos.x - radius, y=current_pos.y - 1, z=current_pos.z - radius}
|
||||
local end_pos = {x=current_pos.x + radius, y=current_pos.y + 1, z=current_pos.z + radius}
|
||||
-- Get nodes
|
||||
local nodes = minetest.find_nodes_in_area(start_pos, end_pos, type)
|
||||
|
||||
return nodes
|
||||
end
|
6
init.lua
6
init.lua
@ -1,4 +1,4 @@
|
||||
|
||||
-- Advanced NPC mod by Zorman2000
|
||||
local path = minetest.get_modpath("advanced_npc")
|
||||
|
||||
-- Intllib
|
||||
@ -30,5 +30,7 @@ dofile(path .. "/dialogue.lua")
|
||||
dofile(path .. "/random_data.lua")
|
||||
dofile(path .. "/trade/trade.lua")
|
||||
dofile(path .. "/trade/prices.lua")
|
||||
dofile(path .. "/actions/actions.lua")
|
||||
dofile(path .. "/actions/places.lua")
|
||||
|
||||
print (S("[MOD] Advanced NPC loaded"))
|
||||
print (S("[Mod] Advanced NPC loaded"))
|
||||
|
104
npc.lua
104
npc.lua
@ -11,6 +11,18 @@ npc.MALE = "male"
|
||||
|
||||
npc.INVENTORY_ITEM_MAX_STACK = 99
|
||||
|
||||
npc.ANIMATION_SIT_START = 81
|
||||
npc.ANIMATION_SIT_END = 160
|
||||
npc.ANIMATION_LAY_START = 162
|
||||
npc.ANIMATION_LAY_END = 166
|
||||
|
||||
npc.direction = {
|
||||
north = 1,
|
||||
east = 2,
|
||||
south = 3,
|
||||
west = 4
|
||||
}
|
||||
|
||||
---------------------------------------------------------------------------------------
|
||||
-- General functions
|
||||
---------------------------------------------------------------------------------------
|
||||
@ -212,6 +224,32 @@ function npc.start_dialogue(self, clicker, show_married_dialogue)
|
||||
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------------------
|
||||
-- Action functionality
|
||||
---------------------------------------------------------------------------------------
|
||||
-- This function adds a function to the action queue.
|
||||
-- Actions should be added in strict order for tasks to work as expected.
|
||||
function npc.add_action(self, action, arguments)
|
||||
self.freeze = true
|
||||
minetest.log("Current Pos: "..dump(self.object:getpos()))
|
||||
local action_entry = {action=action, args=arguments}
|
||||
minetest.log(dump(action_entry))
|
||||
table.insert(self.actions.queue, action_entry)
|
||||
end
|
||||
|
||||
-- This function removes the first action in the action queue
|
||||
-- and then exexcutes it
|
||||
function npc.execute_action(self)
|
||||
if table.getn(self.actions.queue) == 0 then
|
||||
return false
|
||||
end
|
||||
minetest.log("Executing action")
|
||||
local action_obj = self.actions.queue[1]
|
||||
action_obj.action(action_obj.args)
|
||||
table.remove(self.actions.queue, 1)
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
---------------------------------------------------------------------------------------
|
||||
-- Spawning functions
|
||||
@ -273,8 +311,15 @@ end
|
||||
-- NPC will have and choose random, starting values
|
||||
local function npc_spawn(self, pos)
|
||||
minetest.log("Spawning new NPC:")
|
||||
|
||||
-- Get Lua Entity
|
||||
local ent = self:get_luaentity()
|
||||
|
||||
-- Set name
|
||||
ent.nametag = "Kio"
|
||||
|
||||
-- Set ID
|
||||
ent.npc_id = tostring(math.random(1000, 9999))..":"..ent.nametag
|
||||
|
||||
-- Determine sex based on textures
|
||||
if (is_female_texture(ent.base_texture)) then
|
||||
@ -330,6 +375,44 @@ local function npc_spawn(self, pos)
|
||||
select_casual_trade_offers(ent)
|
||||
end
|
||||
|
||||
-- Action queue
|
||||
ent.actions = {
|
||||
-- The queue is a queue of actions to be performed on each interval
|
||||
queue = {},
|
||||
-- Current value of the action timer
|
||||
action_timer = 0,
|
||||
-- Determines the interval for each action in the action queue
|
||||
action_interval = 1
|
||||
}
|
||||
|
||||
-- This flag is checked on every step. If it is true, the rest of
|
||||
-- Mobs Redo API is not executed
|
||||
ent.freeze = false
|
||||
|
||||
-- This map will hold all the places for the NPC
|
||||
-- Map entries should be like: "bed" = {x=1, y=1, z=1}
|
||||
ent.places_map = {}
|
||||
|
||||
-- Temporary initialization of actions for testing
|
||||
-- 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})
|
||||
-- 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})
|
||||
-- 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})
|
||||
-- npc.add_action(ent, npc.action.sit, {self = ent})
|
||||
-- npc.add_action(ent, npc.action.rotate, {self = ent, dir = npc.direction.south})
|
||||
-- npc.add_action(ent, npc.action.lay, {self = ent})
|
||||
|
||||
-- Temporary initialization of places
|
||||
local bed_nodes = npc.places.find_new_nearby(ent, npc.places.nodes.BEDS, 8)
|
||||
minetest.log("Number of bed nodes: "..dump(#bed_nodes))
|
||||
if #bed_nodes > 0 then
|
||||
npc.places.add_owned(ent, "bed1", npc.places.PLACE_TYPE.OWN_BED, bed_nodes[1])
|
||||
end
|
||||
|
||||
minetest.log(dump(ent))
|
||||
|
||||
-- Refreshes entity
|
||||
@ -432,6 +515,7 @@ mobs:register_mob("advanced_npc:npc", {
|
||||
|
||||
end,
|
||||
do_custom = function(self, dtime)
|
||||
|
||||
-- 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
|
||||
@ -474,7 +558,23 @@ mobs:register_mob("advanced_npc:npc", {
|
||||
minetest.log(dump(self))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Action queue timer
|
||||
self.actions.action_timer = self.actions.action_timer + dtime
|
||||
if self.actions.action_timer >= self.actions.action_interval then
|
||||
-- Reset action timer
|
||||
self.actions.action_timer = 0
|
||||
-- Execute action
|
||||
npc.execute_action(self)
|
||||
-- Check if there are more actions to execute
|
||||
if table.getn(self.actions.queue) == 0 then
|
||||
-- Unfreeze NPC so the rest of Mobs API work
|
||||
--self.freeze = false
|
||||
end
|
||||
end
|
||||
|
||||
return not self.freeze
|
||||
end
|
||||
})
|
||||
|
||||
@ -494,7 +594,7 @@ mobs:spawn({
|
||||
-- Item definitions
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
mobs:register_egg("advanced_npc:npc", S("Npc"), "default_brick.png", 1)
|
||||
mobs:register_egg("advanced_npc:npc", S("NPC"), "default_brick.png", 1)
|
||||
|
||||
-- compatibility
|
||||
mobs:alias_mob("mobs:npc", "advanced_npc:npc")
|
||||
|
@ -1,3 +1,4 @@
|
||||
-- Relationships code for Advanced NPC by Zorman2000
|
||||
---------------------------------------------------------------------------------------
|
||||
-- Gift and relationship system
|
||||
---------------------------------------------------------------------------------------
|
||||
|
@ -1,4 +1,4 @@
|
||||
-- NPC trading abilities by Zorman2000
|
||||
-- Trading code for Advanced NPC by Zorman2000
|
||||
|
||||
npc.trade = {}
|
||||
|
||||
@ -125,8 +125,6 @@ end
|
||||
|
||||
-- This function will return an offer object, based
|
||||
-- on the items the NPC has.
|
||||
-- Criteria: The NPC will offer to sell its items
|
||||
-- if it doesn't has any currency.
|
||||
function npc.trade.get_casual_trade_offer(self, offer_type)
|
||||
local result = {}
|
||||
-- Check offer type
|
||||
|
Loading…
Reference in New Issue
Block a user