forked from VoxeLibre/VoxeLibre
Merge pull request 'Villagers will now path through doors. Villagers don't stand around whne not working.' (#2864) from feature/villagers_pt2 into master
Reviewed-on: MineClone2/MineClone2#2864 Reviewed-by: cora <cora@noreply.git.minetest.land>
This commit is contained in:
commit
63a360674d
|
@ -13,6 +13,8 @@ local FLOP_HOR_SPEED = 1.5
|
|||
local ENTITY_CRAMMING_MAX = 24
|
||||
local CRAMMING_DAMAGE = 3
|
||||
|
||||
local PATHFINDING = "gowp"
|
||||
|
||||
-- Localize
|
||||
local S = minetest.get_translator("mcl_mobs")
|
||||
|
||||
|
@ -2484,10 +2486,11 @@ local function check_doors(self)
|
|||
if n.name:find("_b_") then
|
||||
local def = minetest.registered_nodes[n.name]
|
||||
local closed = n.name:find("_b_1")
|
||||
if t < 0.3 or t > 0.8 then
|
||||
if not closed and def.on_rightclick then def.on_rightclick(d,n,self) end
|
||||
else
|
||||
if self.state == PATHFINDING then
|
||||
if closed and def.on_rightclick then def.on_rightclick(d,n,self) end
|
||||
--if not closed and def.on_rightclick then def.on_rightclick(d,n,self) end
|
||||
else
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -2498,7 +2501,7 @@ local gowp_etime = 0
|
|||
|
||||
local function check_gowp(self,dtime)
|
||||
gowp_etime = gowp_etime + dtime
|
||||
if gowp_etime < 0.2 then return end
|
||||
if gowp_etime < 0.1 then return end
|
||||
gowp_etime = 0
|
||||
local p = self.object:get_pos()
|
||||
|
||||
|
@ -2509,7 +2512,7 @@ local function check_gowp(self,dtime)
|
|||
return
|
||||
end
|
||||
|
||||
-- arrived at location
|
||||
-- arrived at location, finish gowp
|
||||
local distance_to_targ = vector.distance(p,self._target)
|
||||
mcl_log("Distance to targ: ".. tostring(distance_to_targ))
|
||||
if distance_to_targ < 2 then
|
||||
|
@ -2525,34 +2528,79 @@ local function check_gowp(self,dtime)
|
|||
return true
|
||||
end
|
||||
|
||||
if self.waypoints and ( not self.current_target or vector.distance(p,self.current_target) < 2 ) then
|
||||
-- More pathing to be done
|
||||
if self.waypoints and #self.waypoints > 0 and ( not self.current_target or vector.distance(p,self.current_target) < 2 ) then
|
||||
-- We have waypoints, and no current target, or we're at it. We need a new current_target.
|
||||
|
||||
if not self.current_target then
|
||||
for i, j in pairs (self.waypoints) do
|
||||
mcl_log("Way: ".. tostring(i))
|
||||
mcl_log("Val: ".. tostring(j))
|
||||
end
|
||||
--mcl_log("nextwp:".. tostring(self.waypoints) )
|
||||
end
|
||||
|
||||
self.current_target = table.remove(self.waypoints, 1)
|
||||
mcl_log("current target:".. tostring(self.current_target) )
|
||||
mcl_log("current target:".. minetest.pos_to_string(self.current_target) )
|
||||
--mcl_log("type:".. type(self.current_target) )
|
||||
go_to_pos(self,self.current_target)
|
||||
return
|
||||
elseif self.current_target then
|
||||
-- No waypoints left, but have current target. Potentially last waypoint to go to.
|
||||
|
||||
mcl_log("self.current_target: ".. minetest.pos_to_string(self.current_target))
|
||||
mcl_log("pos: ".. minetest.pos_to_string(p))
|
||||
go_to_pos(self,self.current_target)
|
||||
-- Do i just delete current_target, and return so we can find final path.
|
||||
else
|
||||
-- Not at target, no current waypoints or current_target. Through the door and should be able to path to target.
|
||||
-- Is a little sensitive and could take 1 - 7 times. A 10 fail count might be a good exit condition.
|
||||
|
||||
mcl_log("We don't have waypoints or a current target. Let's try to path to target")
|
||||
local final_wp = minetest.find_path(p,self._target,150,1,4)
|
||||
if final_wp then
|
||||
mcl_log("We might be able to get to target here.")
|
||||
self.waypoints = final_wp
|
||||
--go_to_pos(self,self._target)
|
||||
else
|
||||
mcl_log("Cannot plot final route to target")
|
||||
end
|
||||
end
|
||||
|
||||
if self.current_target and not minetest.line_of_sight(self.object:get_pos(),self.current_target) then
|
||||
self.waypoints=minetest.find_path(p,self._target,150,1,4)
|
||||
if not self.waypoints then self.state = "walk" end --give up
|
||||
self.current_target = nil
|
||||
--if self.current_target and not minetest.line_of_sight(self.object:get_pos(),self.current_target) then
|
||||
if self.current_target and (self.waypoints and #self.waypoints == 0) then
|
||||
local updated_p = self.object:get_pos()
|
||||
local distance_to_cur_targ = vector.distance(updated_p,self.current_target)
|
||||
|
||||
mcl_log("Distance to current target: ".. tostring(distance_to_cur_targ))
|
||||
mcl_log("Current p: ".. minetest.pos_to_string(updated_p))
|
||||
--if not minetest.line_of_sight(self.object:get_pos(),self._target) then
|
||||
|
||||
-- 1.6 is good. is 1.9 better? It could fail less, but will it path to door when it isn't after door
|
||||
if distance_to_cur_targ > 1.9 then
|
||||
mcl_log("no LOS to target: ".. minetest.pos_to_string(self.current_target))
|
||||
go_to_pos(self,self._current_target)
|
||||
else
|
||||
mcl_log("Let's go to target: ".. minetest.pos_to_string(self.current_target))
|
||||
self.current_target = nil
|
||||
--go_to_pos(self,self._target)
|
||||
self.waypoints=minetest.find_path(updated_p,self._target,150,1,4)
|
||||
--if not self.waypoints then
|
||||
--mcl_log("Give up ")
|
||||
--self.state = "walk"
|
||||
--end --give up
|
||||
end
|
||||
|
||||
--self.waypoints=minetest.find_path(p,self._target,150,1,4)
|
||||
--if not self.waypoints then
|
||||
--mcl_log("Give up ")
|
||||
--self.state = "walk"
|
||||
--end --give up
|
||||
--self.current_target = nil
|
||||
return
|
||||
end
|
||||
if not self.current_target then
|
||||
--mcl_log("no path")
|
||||
self.state = "walk"
|
||||
end
|
||||
--if not self.current_target then
|
||||
--mcl_log("no path. Give up")
|
||||
--self.state = "walk"
|
||||
--end
|
||||
end
|
||||
|
||||
-- execute current state (stand, walk, run, attacks)
|
||||
|
@ -2601,7 +2649,7 @@ local do_states = function(self, dtime)
|
|||
end
|
||||
|
||||
-- npc's ordered to stand stay standing
|
||||
if self.type == "npc" or (self.order == "stand" or self.order == "sleep" or self.order == "work") then
|
||||
if self.order == "stand" or self.order == "sleep" or self.order == "work" then
|
||||
|
||||
else
|
||||
if self.walk_chance ~= 0
|
||||
|
@ -2615,7 +2663,7 @@ local do_states = function(self, dtime)
|
|||
end
|
||||
end
|
||||
|
||||
elseif self.state == "gowp" then
|
||||
elseif self.state == PATHFINDING then
|
||||
check_gowp(self,dtime)
|
||||
|
||||
elseif self.state == "walk" then
|
||||
|
@ -3132,7 +3180,7 @@ local plane_adjacents = {
|
|||
|
||||
local gopath_last = os.time()
|
||||
function mcl_mobs:gopath(self,target,callback_arrived)
|
||||
if self.state == "gowp" then mcl_log("Already set as gowp, don't set another path until done.") return end
|
||||
if self.state == PATHFINDING then mcl_log("Already set as gowp, don't set another path until done.") return end
|
||||
|
||||
if os.time() - gopath_last < 15 then
|
||||
mcl_log("Not ready to path yet")
|
||||
|
@ -3155,11 +3203,15 @@ function mcl_mobs:gopath(self,target,callback_arrived)
|
|||
--mcl_log("Found a door near")
|
||||
for _,v in pairs(plane_adjacents) do
|
||||
local pos = vector.add(d,v)
|
||||
|
||||
local n = minetest.get_node(pos)
|
||||
if n.name == "air" then
|
||||
wp = minetest.find_path(p,pos,150,1,4)
|
||||
if wp then
|
||||
--mcl_log("Found a path to next to door".. minetest.pos_to_string(pos))
|
||||
mcl_log("Found a path to next to door".. minetest.pos_to_string(pos))
|
||||
local other_side_of_door = vector.add(d,-v)
|
||||
mcl_log("Opposite is: ".. minetest.pos_to_string(other_side_of_door))
|
||||
table.insert(wp, other_side_of_door)
|
||||
break
|
||||
|
||||
else
|
||||
|
@ -3179,7 +3231,7 @@ function mcl_mobs:gopath(self,target,callback_arrived)
|
|||
self.callback_arrived = callback_arrived
|
||||
table.remove(wp,1)
|
||||
self.waypoints = wp
|
||||
self.state = "gowp"
|
||||
self.state = PATHFINDING
|
||||
return true
|
||||
else
|
||||
self.state = "walk"
|
||||
|
@ -4140,7 +4192,7 @@ local mob_step = function(self, dtime)
|
|||
-- attack timer
|
||||
self.timer = self.timer + dtime
|
||||
|
||||
if self.state ~= "attack" and self.state ~= "gowp" then
|
||||
if self.state ~= "attack" and self.state ~= PATHFINDING then
|
||||
if self.timer < 1 then
|
||||
return
|
||||
end
|
||||
|
|
|
@ -30,6 +30,8 @@ local DEFAULT_WALK_CHANCE = 33 -- chance to walk in percent, if no player nearby
|
|||
local PLAYER_SCAN_INTERVAL = 5 -- every X seconds, villager looks for players nearby
|
||||
local PLAYER_SCAN_RADIUS = 4 -- scan radius for looking for nearby players
|
||||
|
||||
local PATHFINDING = "gowp"
|
||||
|
||||
--[=======[ TRADING ]=======]
|
||||
|
||||
-- LIST OF VILLAGER PROFESSIONS AND TRADES
|
||||
|
@ -564,7 +566,7 @@ end
|
|||
|
||||
local function set_textures(self)
|
||||
local badge_textures = get_badge_textures(self)
|
||||
mcl_log("Setting textures: " .. tostring(badge_textures))
|
||||
--mcl_log("Setting textures: " .. tostring(badge_textures))
|
||||
self.object:set_properties({textures=badge_textures})
|
||||
end
|
||||
|
||||
|
@ -579,7 +581,7 @@ function get_activity(tod)
|
|||
local lunch_start = 12000
|
||||
local lunch_end = 13500
|
||||
local work_start = 8500
|
||||
local work_end = 16300
|
||||
local work_end = 16500
|
||||
|
||||
|
||||
local activity = nil
|
||||
|
@ -671,7 +673,7 @@ local function take_bed (entity)
|
|||
for _,n in pairs(nn) do
|
||||
local m=minetest.get_meta(n)
|
||||
--mcl_log("Bed owner: ".. m:get_string("villager"))
|
||||
if m:get_string("villager") == "" and not (entity.state == "gowp") then
|
||||
if m:get_string("villager") == "" and not (entity.state == PATHFINDING) then
|
||||
mcl_log("Can we path to bed: "..minetest.pos_to_string(n) )
|
||||
local gp = mcl_mobs:gopath(entity,n,function(self)
|
||||
if self then
|
||||
|
@ -817,7 +819,7 @@ local function look_for_job(self, requested_jobsites)
|
|||
|
||||
local looking_for_type = jobsites
|
||||
if requested_jobsites then
|
||||
mcl_log("Looking for jobs of my type: " .. tostring(requested_jobsites))
|
||||
--mcl_log("Looking for jobs of my type: " .. tostring(requested_jobsites))
|
||||
looking_for_type = requested_jobsites
|
||||
else
|
||||
mcl_log("Looking for any job type")
|
||||
|
@ -863,7 +865,7 @@ local function get_a_job(self)
|
|||
|
||||
local requested_jobsites = jobsites
|
||||
if has_traded (self) then
|
||||
--mcl_log("Has traded")
|
||||
mcl_log("Has traded so look for job of my type")
|
||||
requested_jobsites = populate_jobsites(self._profession)
|
||||
-- Only pass in my jobsite to two functions here
|
||||
else
|
||||
|
@ -884,7 +886,7 @@ local function get_a_job(self)
|
|||
|
||||
if n and employ(self,n) then return true end
|
||||
|
||||
if self.state ~= "gowp" then
|
||||
if self.state ~= PATHFINDING then
|
||||
mcl_log("Nothing near. Need to look for a job")
|
||||
look_for_job(self, requested_jobsites)
|
||||
end
|
||||
|
@ -938,7 +940,7 @@ local function do_work (self)
|
|||
|
||||
-- Don't try if looking_for_work, or gowp possibly
|
||||
if validate_jobsite(self) then
|
||||
mcl_log("My jobsite is valid. Do i need to travel?")
|
||||
--mcl_log("My jobsite is valid. Do i need to travel?")
|
||||
|
||||
local jobsite2 = retrieve_my_jobsite (self)
|
||||
local jobsite = self._jobsite
|
||||
|
@ -947,9 +949,9 @@ local function do_work (self)
|
|||
|
||||
--mcl_log("Villager: ".. minetest.pos_to_string(self.object:get_pos()) .. ", jobsite: " .. minetest.pos_to_string(self._jobsite))
|
||||
if vector.distance(self.object:get_pos(),self._jobsite) < 2 then
|
||||
mcl_log("Made it to work ok!")
|
||||
--mcl_log("Made it to work ok!")
|
||||
|
||||
if not (self.state == "gowp") then
|
||||
if not (self.state == PATHFINDING) then
|
||||
--mcl_log("Setting order to work.")
|
||||
self.order = WORK
|
||||
else
|
||||
|
@ -1461,6 +1463,7 @@ local trade_inventory = {
|
|||
-- END OF SPECIAL HANDLING FOR COMPASS
|
||||
local trader = player_trading_with[name]
|
||||
local tradenum = player_tradenum[name]
|
||||
|
||||
local trades
|
||||
trader._traded = true
|
||||
if trader and trader._trades then
|
||||
|
@ -1643,23 +1646,31 @@ mcl_mobs:register_mob("mobs_mc:villager", {
|
|||
return it
|
||||
end,
|
||||
on_rightclick = function(self, clicker)
|
||||
if self.child or self._profession == "unemployed" or self._profession == "nitwit" then
|
||||
self.order = nil
|
||||
return
|
||||
end
|
||||
|
||||
if self.state == PATHFINDING then
|
||||
self.state = "stand"
|
||||
end
|
||||
-- Can we remove now we possibly have fixed root cause
|
||||
if self.state == "attack" then
|
||||
mcl_log("Somehow villager got into an invalid attack state. Removed.")
|
||||
mcl_log("Somehow villager got into an invalid attack state. Removed attack state.")
|
||||
-- Need to stop villager getting in attack state. This is a workaround to allow players to fix broken villager.
|
||||
self.state = "stand"
|
||||
self.attack = nil
|
||||
end
|
||||
-- Don't do at night. Go to bed? Maybe do_activity needs it's own method
|
||||
if validate_jobsite(self) then
|
||||
mcl_mobs:gopath(self,self._jobsite,function()
|
||||
--minetest.log("arrived at jobsite")
|
||||
end)
|
||||
else
|
||||
self.state = "stand" -- cancel gowp in case it has messed up
|
||||
self.order = nil -- cancel work if working
|
||||
end
|
||||
|
||||
if self.child or self._profession == "unemployed" or self._profession == "nitwit" then
|
||||
return
|
||||
end
|
||||
-- Initiate trading
|
||||
init_trader_vars(self)
|
||||
local name = clicker:get_player_name()
|
||||
|
@ -1733,9 +1744,10 @@ mcl_mobs:register_mob("mobs_mc:villager", {
|
|||
take_bed (self)
|
||||
end
|
||||
|
||||
-- Only check in day or during thunderstorm but wandered_too_far code won't work
|
||||
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 )
|
||||
local wandered_too_far = ( self.state ~= PATHFINDING ) and (vector.distance(self.object:get_pos(),self._bed) > 50 )
|
||||
|
||||
--if wandered_too_far then minetest.log("Wandered too far! Return home ") end
|
||||
if wandered_too_far then
|
||||
|
|
Loading…
Reference in New Issue