hkzorman/advanced_npc

NPC does not stand still

Closed this issue · 2 comments

I am only try maintain a NPC sleeping (by 10 seconds). He just sits on the bed and gets up. (Apparently)

do_custom = function(self, dtime)	

	-- Inicialize NPC
	if self.initialized == nil then
		npc.initialize(self, self.object:getpos(), true)
		self.tamed = false
		self.owner = nil
	end

	-- Action queue timer
	-- Check if actions and timers aren't locked
	if self.actions.action_timer_lock == false then
		-- Increment action timer
		self.actions.action_timer = self.actions.action_timer + dtime
		if self.actions.action_timer >= self.actions.action_interval then
			-- Reset action timer
			self.actions.action_timer = 0
			-- Check if NPC is walking
			if self.actions.walking.is_walking == true then
				-- Move NPC to expected position to ensure not getting lost
				local pos = self.actions.walking.target_pos
				self.object:moveto({x=pos.x, y=pos.y, z=pos.z})
			end
			-- Execute action
			self.freeze = npc.execute_action(self)
			-- Check if there are still remaining actions in the queue
			if self.freeze == nil and table.getn(self.actions.queue) > 0 then
				self.freeze = false
			end
		end
	end

	-- Lay in the bed
	if not self.tested and minetest.find_node_near(self.object:getpos(), 3, {"beds:bed_bottom"}) then
		self.tested = true
		npc.add_task(self, npc.actions.cmd.USE_BED, {
			pos = minetest.find_node_near(self.object:getpos(), 3, {"beds:bed_bottom"}),
			action = npc.actions.const.beds.LAY,
		})
		npc.add_action(self, npc.actions.cmd.SET_INTERVAL, {
			interval = 10,
			freeze=true,
		})
	end
end,

What is happening is that the mobs_redo mob_step function is kicking in. In order to avoid that you need to return false at the end of the function. In advanced_npc, it is handled by returning self.freeze.

Two things:

  • You need to return the self.freeze at the end of the do_custom() function
  • You also need to add the task to get the NPC up from the bed.

Like this:

do_custom = function(self, dtime)
	-- Inicialize NPC
	if self.initialized == nil then
		npc.initialize(self, self.object:getpos(), true)
		self.tamed = false
		self.owner = nil
	end

	-- Action queue timer
	-- Check if actions and timers aren't locked
	if self.actions.action_timer_lock == false then
		-- Increment action timer
		self.actions.action_timer = self.actions.action_timer + dtime
		if self.actions.action_timer >= self.actions.action_interval then
			-- Reset action timer
			self.actions.action_timer = 0
			-- Check if NPC is walking
			if self.actions.walking.is_walking == true then
				-- Move NPC to expected position to ensure not getting lost
				local pos = self.actions.walking.target_pos
				self.object:moveto({x=pos.x, y=pos.y, z=pos.z})
			end
			-- Execute action
			self.freeze = npc.execute_action(self)
			-- Check if there are still remaining actions in the queue
			if self.freeze == nil and table.getn(self.actions.queue) > 0 then
				self.freeze = false
			end
		end
	end

	-- Lay in the bed
	if not self.tested and minetest.find_node_near(self.object:getpos(), 3, {"beds:bed_bottom"}) then
		self.tested = true
		npc.add_task(self, npc.actions.cmd.USE_BED, {
			pos = minetest.find_node_near(self.object:getpos(), 3, {"beds:bed_bottom"}),
			action = npc.actions.const.beds.LAY
		})
		npc.add_action(self, npc.actions.cmd.SET_INTERVAL, {
			interval = 10,
			freeze = true,
		})
		npc.add_task(self, npc.actions.cmd.USE_BED, {
			pos = minetest.find_node_near(self.object:getpos(), 3, {"beds:bed_bottom"}),
			action = npc.actions.const.beds.GET_UP
		})
	end

	return self.freeze

end,

With the new code you can also do:

-- Lay in the bed
if not self.tested and minetest.find_node_near(self.object:getpos(), 3, {"beds:bed_bottom"}) then
	self.tested = true
	npc.add_task(self, npc.actions.cmd.USE_BED, {
		pos = minetest.find_node_near(self.object:getpos(), 3, {"beds:bed_bottom"}),
		action = npc.actions.const.beds.LAY
	})
	npc.add_action(self, npc.actions.cmd.SET_INTERVAL, {
		interval = 10,
		freeze = true,
	})
	npc.add_task(self, npc.actions.cmd.USE_BED, {
		pos = minetest.find_node_near(self.object:getpos(), 3, {"beds:bed_bottom"}),
		action = npc.actions.const.beds.GET_UP
	})
end

return npc.step(self, dtime)

Thank you. But the method npc.add_task can not be used if NPC not be initialized. So I use on_spawn.

on_spawn = function(self)
	npc.initialize(self, self.object:getpos(), true)
end,

Works fine.