Villagers - Work, sleep and wander. Check and claim beds etc.

This commit is contained in:
ancientmarinerdev 2022-10-18 23:59:53 +01:00
parent 53dd88eaea
commit d148e6d4ba
2 changed files with 266 additions and 29 deletions

View File

@ -2486,6 +2486,8 @@ local function check_gowp(self,dtime)
self._target = nil self._target = nil
self.current_target = nil self.current_target = nil
self.state = "stand" self.state = "stand"
self.object:set_velocity({x = 0, y = 0, z = 0})
self.object:set_acceleration({x = 0, y = 0, z = 0})
if self.callback_arrived then return self.callback_arrived(self) end if self.callback_arrived then return self.callback_arrived(self) end
return true return true
end end
@ -2556,8 +2558,8 @@ local do_states = function(self, dtime)
end end
-- npc's ordered to stand stay standing -- npc's ordered to stand stay standing
if self.type ~= "npc" if self.type ~= "npc" or
or self.order ~= "stand" then (self.order ~= "stand" and self.order ~= "sleep" and self.order ~= "work") then
if self.walk_chance ~= 0 if self.walk_chance ~= 0
and self.facing_fence ~= true and self.facing_fence ~= true

View File

@ -492,6 +492,9 @@ local professions = {
} }
} }
local WORK = "work"
local SLEEP = "sleep"
local profession_names = {} local profession_names = {}
for id, _ in pairs(professions) do for id, _ in pairs(professions) do
table.insert(profession_names, id) table.insert(profession_names, id)
@ -499,9 +502,16 @@ end
local jobsites={} local jobsites={}
for _,n in pairs(profession_names) do for _,n in pairs(profession_names) do
if n then
if professions[n].jobsite then
table.insert(jobsites,professions[n].jobsite) table.insert(jobsites,professions[n].jobsite)
end
end
end end
local spawnable_bed={}
table.insert(spawnable_bed, "mcl_beds:bed_red_bottom")
local function stand_still(self) local function stand_still(self)
self.walk_chance = 0 self.walk_chance = 0
self.jump = false self.jump = false
@ -532,23 +542,124 @@ local function set_textures(self)
self.object:set_properties({textures=get_badge_textures(self)}) self.object:set_properties({textures=get_badge_textures(self)})
end end
local function go_home(entity)
entity.state = "go_home" function get_activity(tod)
local b=entity._bed -- night hours = tod > 18541 or tod < 5458
if not b then return end if not tod then
mcl_mobs:gopath(entity,b,function(entity,b) tod = minetest.get_timeofday()
end
tod = ( tod * 24000 ) % 24000
local lunch_start = 12000
local lunch_end = 13300
local work_start = 8300
local work_end = 16300
local activity = nil
if (tod > work_start and tod < lunch_start) or (tod > lunch_end and tod < work_end) then
activity = WORK
elseif mcl_beds.is_night() then
activity = SLEEP
elseif tod > lunch_start and tod < lunch_end then
activity = "chill"
else
activity = "undefined"
end
--minetest.log("Time is " .. tod ..". Activity is: ".. activity)
return activity
end
local function go_home(entity, sleep)
local b = entity._bed
if not b then
return
end
local bed_node = minetest.get_node(b)
if not bed_node then
entity._bed = nil
--minetest.log("Cannot find bed. Unset it")
return
end
if vector.distance(entity.object:get_pos(),b) < 2 then if vector.distance(entity.object:get_pos(),b) < 2 then
entity.state = "stand" if sleep then
set_velocity(entity,0) entity.order = SLEEP
entity.object:set_pos(b) --minetest.log("Sleep time!")
local n=minetest.get_node(b) end
if n and n.name ~= "mcl_beds:bed_red_bottom" then else
entity._bed=nil --the stormtroopers have killed uncle owen if sleep and entity.order == SLEEP then
entity.order = nil
return
end
mcl_mobs:gopath(entity,b,function(entity,b)
local b = entity._bed
if not b then
--minetest.log("NO BED, problem")
return false return false
end end
if not minetest.get_node(b) then
--minetest.log("NO BED NODE, problem")
return false
end
if vector.distance(entity.object:get_pos(),b) < 2 then
--minetest.log("Managed to walk home callback!")
return true return true
else
--minetest.log("Need to walk to home")
end end
end) end)
end
end
local function check_bed (entity)
local b = entity._bed
if not b then
--minetest.log("No bed set on villager")
return false
end
local n = minetest.get_node(b)
if n and n.name ~= "mcl_beds:bed_red_bottom" then
--minetest.log("Where did my bed go?!")
entity._bed = nil --the stormtroopers have killed uncle owen
return false
else
return true
end
end
local function take_bed (entity)
if not entity then return end
local p = entity.object:get_pos()
local nn = minetest.find_nodes_in_area(vector.offset(p,-48,-48,-48), vector.offset(p,48,48,48), spawnable_bed)
for _,n in pairs(nn) do
local m=minetest.get_meta(n)
--minetest.log("Bed owner: ".. m:get_string("villager"))
if m:get_string("villager") == "" then
--minetest.log("Can we path to bed: "..minetest.pos_to_string(n) )
local gp = mcl_mobs:gopath(entity,n,function()
--minetest.log("We did path to bed. This is great: "..minetest.pos_to_string(n) )
end)
if gp then
--minetest.log("Nice bed. I'll defintely take it as I can path")
m:set_string("villager", entity._id)
entity._bed = n
break
else
--minetest.log("Awww. I can't find my bed.")
end
end
end
end end
local function has_golem(pos) local function has_golem(pos)
@ -608,11 +719,14 @@ local function employ(self,jobsite_pos)
local m = minetest.get_meta(jobsite_pos) local m = minetest.get_meta(jobsite_pos)
local p = get_profession_by_jobsite(n.name) local p = get_profession_by_jobsite(n.name)
if p and m:get_string("villager") == "" then if p and m:get_string("villager") == "" then
minetest.log("Taking this job")
self._profession=p self._profession=p
m:set_string("villager",self._id) m:set_string("villager",self._id)
self._jobsite = jobsite_pos self._jobsite = jobsite_pos
set_textures(self) set_textures(self)
return true return true
else
--minetest.log("I can not steal someone's job!")
end end
end end
@ -621,10 +735,12 @@ local function look_for_job(self)
self.last_jobhunt = os.time() + math.random(0,60) self.last_jobhunt = os.time() + math.random(0,60)
local p = self.object:get_pos() local p = self.object:get_pos()
local nn = minetest.find_nodes_in_area(vector.offset(p,-48,-48,-48),vector.offset(p,48,48,48),jobsites) local nn = minetest.find_nodes_in_area(vector.offset(p,-48,-48,-48),vector.offset(p,48,48,48),jobsites)
--minetest.log("Looking for jobs")
for _,n in pairs(nn) do for _,n in pairs(nn) do
local m=minetest.get_meta(n) local m=minetest.get_meta(n)
--minetest.log("Job owner: ".. m:get_string("villager"))
if m:get_string("villager") == "" then if m:get_string("villager") == "" then
--minetest.log("goingt to jobsite "..minetest.pos_to_string(n) ) --minetest.log("It's a free job for me (".. minetest.pos_to_string(p) .. ")! I'll take: "..minetest.pos_to_string(n) )
local gp = mcl_mobs:gopath(self,n,function() local gp = mcl_mobs:gopath(self,n,function()
--minetest.log("arrived jobsite "..minetest.pos_to_string(n) ) --minetest.log("arrived jobsite "..minetest.pos_to_string(n) )
end) end)
@ -634,24 +750,99 @@ local function look_for_job(self)
end end
local function get_a_job(self) local function get_a_job(self)
--minetest.log("In get a job")
if self.child then return end if self.child then return end
local p = self.object:get_pos() local p = self.object:get_pos()
local n = minetest.find_node_near(p,1,jobsites) local n = minetest.find_node_near(p,1,jobsites)
if not n then
--minetest.log("Job hunt failed. No job block near.")
else
--minetest.log("Found job block near. Is it free though?")
end
if n and employ(self,n) then return true end if n and employ(self,n) then return true end
if self.state ~= "gowp" then look_for_job(self) end if self.state ~= "gowp" then look_for_job(self) end
end end
local function check_jobsite(self) local function find_jobsite (self)
if self._traded or not self._jobsite then return end if not self or not self._jobsite then
--minetest.log("find_jobsite. Invalid params")
return
end
local n = mcl_vars.get_node(self._jobsite) local n = mcl_vars.get_node(self._jobsite)
local m = minetest.get_meta(self._jobsite) local m = minetest.get_meta(self._jobsite)
if m:get_string("villager") ~= self._id then if m:get_string("villager") == self._id then
--minetest.log("find_jobsite. is my job.")
return n
else
--minetest.log("find_jobsite. Not my job")
end
return
end
local function check_jobsite(self)
if self._traded then
return false
end
if not find_jobsite (self) then
self._profession = "unemployed" self._profession = "unemployed"
self._trades = nil self._trades = nil
set_textures(self) set_textures(self)
return false
else
return true
end end
end end
local function do_work (self)
local jobsite2 = find_jobsite (self)
local jobsite = self._jobsite
if self and jobsite2 and self._jobsite then
if self.order == WORK then
--minetest.log("I'm already working, boss!")
self.object:set_velocity({x = 0, y = 0, z = 0})
--minetest.log("[mobs_mc] Villager velocity is: ".. minetest.pos_to_string(self.object:get_velocity()))
return
end
if vector.distance(self.object:get_pos(),self._jobsite) < 2 then
--minetest.log("Made it to work ok!")
self.order = WORK
else
--self.state = "go_to_work"
mcl_mobs:gopath(self, jobsite, function(self,jobsite)
if not self then
--minetest.log("missing self. not good")
return false
end
if not self._jobsite then
--minetest.log("Jobsite not valid")
return false
end
if vector.distance(self.object:get_pos(),self._jobsite) < 2 then
--minetest.log("Made it to work ok callback!")
return true
else
--minetest.log("Need to walk to work. Not sure we can get here.")
end
end)
end
else
--minetest.log("Cannot find the jobsite in do_work. Do nothing.")
end
end
local function update_max_tradenum(self) local function update_max_tradenum(self)
if not self._trades then if not self._trades then
return return
@ -724,7 +915,7 @@ local function set_trade(trader, player, inv, concrete_tradenum)
init_trades(trader) init_trades(trader)
trades = minetest.deserialize(trader._trades) trades = minetest.deserialize(trader._trades)
if not trades then if not trades then
minetest.log("error", "[mobs_mc] Failed to select villager trade!") --minetest.log("error", "[mobs_mc] Failed to select villager trade!")
return return
end end
end end
@ -1345,18 +1536,21 @@ mcl_mobs:register_mob("mobs_mc:villager", {
_trading_players = {}, -- list of playernames currently trading with villager (open formspec) _trading_players = {}, -- list of playernames currently trading with villager (open formspec)
do_custom = function(self, dtime) do_custom = function(self, dtime)
check_summon(self,dtime) check_summon(self,dtime)
-- Stand still if player is nearby. -- Stand still if player is nearby.
if not self._player_scan_timer then if not self._player_scan_timer then
self._player_scan_timer = 0 self._player_scan_timer = 0
end end
self._player_scan_timer = self._player_scan_timer + dtime self._player_scan_timer = self._player_scan_timer + dtime
-- Check infrequently to keep CPU load low -- Check infrequently to keep CPU load low
if self._player_scan_timer > PLAYER_SCAN_INTERVAL then if self._player_scan_timer > PLAYER_SCAN_INTERVAL then
self._player_scan_timer = 0 self._player_scan_timer = 0
local selfpos = self.object:get_pos() local selfpos = self.object:get_pos()
local objects = minetest.get_objects_inside_radius(selfpos, PLAYER_SCAN_RADIUS) local objects = minetest.get_objects_inside_radius(selfpos, PLAYER_SCAN_RADIUS)
local has_player = false local has_player = false
for o, obj in pairs(objects) do for o, obj in pairs(objects) do
if obj:is_player() then if obj:is_player() then
has_player = true has_player = true
@ -1367,18 +1561,59 @@ mcl_mobs:register_mob("mobs_mc:villager", {
minetest.log("verbose", "[mobs_mc] Player near villager found!") minetest.log("verbose", "[mobs_mc] Player near villager found!")
stand_still(self) stand_still(self)
else else
minetest.log("verbose", "[mobs_mc] No player near villager found!") --minetest.log("verbose", "[mobs_mc] No player near villager found!")
self.walk_chance = DEFAULT_WALK_CHANCE self.walk_chance = DEFAULT_WALK_CHANCE
self.jump = true self.jump = true
end end
if self._bed and ( self.state ~= "go_home" and vector.distance(self.object:get_pos(),self._bed) > 50 ) then
go_home(self) if not self._bed then
--minetest.log("[mobs_mc] Villager has no bed. Currently at location: "..minetest.pos_to_string(self.object:get_pos()))
take_bed (self)
end end
if check_bed (self) then
--self.state ~= "go_home"
local wandered_too_far = ( self.state ~= "gowp" ) and (vector.distance(self.object:get_pos(),self._bed) > 50 )
if wandered_too_far then minetest.log("[mobs_mc] Wandered too far! Return home ") end
if wandered_too_far then
go_home(self, false)
return
elseif mcl_beds.is_night() then
--minetest.log("[mobs_mc] It's night. Better get to bed ")
go_home(self, true)
return
else
-- work
-- or gossip at town bell
end
else
--minetest.log("[mobs_mc] check bed failed ")
end
-- Daytime is work and play time
if not mcl_beds.is_night() then
if self.order == SLEEP then self.order = nil end
if self._profession == "unemployed" then if self._profession == "unemployed" then
--minetest.log("[mobs_mc] I'm unemployed. Can I get a job?")
get_a_job(self) get_a_job(self)
else else
check_jobsite(self) if get_activity() == WORK then
--minetest.log("[mobs_mc] Time for work")
if check_jobsite(self) then
--minetest.log("[mobs_mc] My jobsite is valid. Let's do work ")
do_work(self)
-- at night or thunder, go to safety (bed)
else
--minetest.log("[mobs_mc] My job site is invalid or i'm already working. I cannot work.")
end end
else
self.order = nil
end
end
else
if self.order == WORK then self.order = nil end
end
end end
end, end,