smart_villages/async_actions.lua

214 lines
7.1 KiB
Lua

function smart_villages.villager:go_to(pos)
self.destination=vector.round(pos)
if smart_villages.func.walkable_pos(self.destination) then
self.destination=smart_villages.pathfinder.get_ground_level(vector.round(self.destination))
end
local val_pos = smart_villages.func.validate_pos(self.object:getpos())
self.path = smart_villages.pathfinder.get_reachable(val_pos,self.destination,self)
self:set_timer("go_to:find_path",0) -- find path interval
self:set_timer("go_to:change_dir",0)
self:set_timer("go_to:give_up",0)
if self.path == nil then
--TODO: actually no path shouldn't be accepted
--we'd have to check whether we can find a shorter path in the right direction
self.path = {self.destination}
end
--print("the first waypiont on his path:" .. minetest.pos_to_string(self.path[1]))
self:change_direction(self.path[1])
self:set_animation(smart_villages.animation_frames.WALK)
while #self.path ~= 0 do
self:count_timer("go_to:find_path")
self:count_timer("go_to:change_dir")
if self:timer_exceeded("go_to:find_path",100) then
val_pos = smart_villages.func.validate_pos(self.object:getpos())
local path = smart_villages.pathfinder.get_reachable(val_pos,self.destination,self)
if path == nil then
self:count_timer("go_to:give_up")
if self:timer_exceeded("go_to:give_up",3) then
self.destination=vector.round(self.destination)
if smart_villages.func.walkable_pos(self.destination) then
self.destination=smart_villages.pathfinder.get_ground_level(vector.round(self.destination))
end
print("villager can't find path")
--FIXME: we ought to give up at this point
end
else
self.path = path
end
end
if self:timer_exceeded("go_to:change_dir",30) then
self:change_direction(self.path[1])
end
-- follow path
if self:is_near({x=self.path[1].x,y=self.object:getpos().y,z=self.path[1].z}, 1) then
table.remove(self.path, 1)
if #self.path == 0 then -- end of path
break
else -- else next step, follow next path.
self:set_timer("go_to:find_path",0)
self:change_direction(self.path[1])
end
end
-- if vilager is stopped by obstacles, the villager must jump.
self:handle_obstacles()
-- end step
coroutine.yield()
end
self.object:setvelocity{x = 0, y = 0, z = 0}
self.path = nil
self:set_animation(smart_villages.animation_frames.STAND)
end
function smart_villages.villager:dig(pos)
self.object:setvelocity{x = 0, y = 0, z = 0}
self:set_animation(smart_villages.animation_frames.MINE)
self:set_yaw_by_direction(vector.subtract(pos, self.object:getpos()))
for _=0,30 do coroutine.yield() end --wait 30 steps
local destnode = minetest.get_node(pos)
minetest.remove_node(pos)
local stacks = minetest.get_node_drops(destnode.name)
for _, stack in ipairs(stacks) do
local leftover = self:add_item_to_main(stack)
minetest.add_item(pos, leftover)
end
local sounds = minetest.registered_nodes[destnode.name].sounds
if sounds then
local sound = sounds.dug
if sound then
minetest.sound_play(sound,{object=self.object, max_hear_distance = 10})
end
end
self:set_animation(smart_villages.animation_frames.STAND)
end
function smart_villages.villager:place(item,pos)
if type(pos)~="table" then
error("no target position given")
end
local pred
if type(item)=="string" then
pred = function (name) return name == item end
elseif type(item)=="function" then
pred = item
else
error("no item to place given")
end
local wield_stack = self:get_wield_item_stack()
--move item to wield
if pred(wield_stack:get_name()) or self:move_main_to_wield(pred) then
--set animation
if self.object:getvelocity().x==0 and self.object:getvelocity().z==0 then
self:set_animation(smart_villages.animation_frames.MINE)
else
self:set_animation(smart_villages.animation_frames.WALK_MINE)
end
--turn to target
self:set_yaw_by_direction(vector.subtract(pos, self.object:getpos()))
--wait 15 steps
for _=0,15 do coroutine.yield() end
--get wielded item
local stack = self:get_wield_item_stack()
--create pointed_thing
local pointed_thing = {
type = "node",
above = pos,
under = vector.add(pos, {x = 0, y = -1, z = 0}),
}
local itemname = stack:get_name()
--place item
--minetest.item_place(stack, minetest.get_player_by_name(self.owner_name), pointed_thing)
minetest.set_node(pointed_thing.above, {name = itemname})
--take item
stack:take_item(1)
self:set_wield_item_stack(stack)
--handle sounds
local sounds = minetest.registered_nodes[itemname].sounds
if sounds then
local sound = sounds.place
if sound then
minetest.sound_play(sound,{object=self.object, max_hear_distance = 10})
end
end
--reset animation
if self.object:getvelocity().x==0 and self.object:getvelocity().z==0 then
self:set_animation(smart_villages.animation_frames.STAND)
else
self:set_animation(smart_villages.animation_frames.WALK)
end
else
minetest.chat_send_player(self.owner_name,"villager couldn't place item")
end
end
function smart_villages.villager.wait_until_dawn()
local daytime = minetest.get_timeofday()
while (daytime < 0.2 or daytime > 0.76) do
coroutine.yield()
daytime = minetest.get_timeofday()
end
--print("wake up:"..daytime)
end
function smart_villages.villager:sleep()
minetest.log("action","a villager is laying down")
self.object:setvelocity{x = 0, y = 0, z = 0}
local bed_pos=self:get_home():get_bed()
local bed_top = smart_villages.func.find_adjacent_pos(bed_pos,
function(p) return string.find(minetest.get_node(p).name,"_top") end)
local bed_bottom = smart_villages.func.find_adjacent_pos(bed_pos,
function(p) return string.find(minetest.get_node(p).name,"_bottom") end)
if bed_top and bed_bottom then
self:set_yaw_by_direction(vector.subtract(bed_bottom, bed_top))
else
minetest.log("info","no bed found")
end
self:set_animation(smart_villages.animation_frames.LAY)
self.object:setpos(bed_pos)
self.pause="sleeping"
self:update_infotext()
self.wait_until_dawn()
local pos=self.object:getpos()
self.object:setpos({x=pos.x,y=pos.y+0.5,z=pos.z})
minetest.log("action","a villager gets up")
self:set_animation(smart_villages.animation_frames.STAND)
self.pause="active"
self:update_infotext()
end
function smart_villages.villager:goto_bed()
if smart_villages.debug_logging then
minetest.log("action",self.inventory_name.." is going home")
end
if not self:has_home() then
self:set_animation(smart_villages.animation_frames.SIT)
self.pause="sleeping"
self:update_infotext()
self.wait_until_dawn()
self:set_animation(smart_villages.animation_frames.STAND)
self.pause="active"
self:update_infotext()
else
local bed_pos = self:get_home():get_bed()
if not bed_pos then
minetest.log("warning","villager couldn't find his bed")
--perhaps go home
self:set_animation(smart_villages.animation_frames.SIT)
self.wait_until_dawn()
else
if smart_villages.debug_logging then
minetest.log("info","his bed is at:" .. bed_pos.x .. ",".. bed_pos.y .. ",".. bed_pos.z)
end
self:go_to(bed_pos)
self:sleep()
--TODO: perhaps go back to the position we were at before going home
self:go_to(self:get_home():get_door())
end
end
end