More tweaks and fixes

master
Ciaran Gultnieks 2014-11-26 18:18:30 +00:00
parent 93091fe3a6
commit bcdc792990
8 changed files with 185 additions and 77 deletions

View File

@ -4,15 +4,17 @@ if moddebug then dbg=moddebug.dbg("people") else dbg={v1=function() end,v2=funct
people.actions.face = function(state) people.actions.face = function(state)
if state.action.pos and state.action.pos.x and state.action.pos.y and state.action.pos.z then if state.action.pos and state.action.pos.x and state.action.pos.y and state.action.pos.z then
state.yaw = vector.get_yaw(statepos, state.action.pos) state.yaw = vector.get_yaw(state.pos, state.action.pos)
dbg.v3(state.ent.name.." setting calculated yaw to "..state.action.yaw) dbg.v3(state.ent.name.." setting calculated yaw to "..state.yaw)
elseif state.action.yaw then return true, true
dbg.v3(state.ent.name.." setting yaw to "..state.action.yaw) elseif state.action.yaw then
state.yaw = state.action.yaw dbg.v3(state.ent.name.." setting yaw to "..state.action.yaw)
else state.yaw = state.action.yaw
dbg.v1(state.ent.name.." has invalid face action "..dump(state.action)) return true, true
end end
return true, true
dbg.v1(state.ent.name.." has invalid face action "..dump(state.action))
return true, false
end end

View File

@ -2,11 +2,15 @@
local dbg local dbg
if moddebug then dbg=moddebug.dbg("people") else dbg={v1=function() end,v2=function() end,v3=function() end} end if moddebug then dbg=moddebug.dbg("people") else dbg={v1=function() end,v2=function() end,v3=function() end} end
-- "Path Node To Pos". Footpath nodes are 1x1 areas ABOVE the path. People -- "Area Node To Pos". Footpath area nodes are 1x1 areas ABOVE the path. People
-- positions (to match player positions) are 0.5 above the node they are -- positions (to match player positions) are 0.5 above the node they are
-- standing on. Add this to the Y coordinate to convert from a path node -- standing on. Add this to the Y coordinate to convert from a path node
-- position to a people position. -- position to a people position.
local PNTP = -0.5 local ANTP = -0.5
-- "Path Node To Pos". But the nodes that form the actual path are below.
-- This is all very messy and needs rationalising!!
local PNTP = 0.5
people.actions.go = function(state) people.actions.go = function(state)
@ -38,7 +42,7 @@ people.actions.go = function(state)
if pathstartarea then if pathstartarea then
dbg.v2(state.ent.name.." selected path start "..pathstartarea.name.." at "..minetest.pos_to_string(pathstartarea.pos1)) dbg.v2(state.ent.name.." selected path start "..pathstartarea.name.." at "..minetest.pos_to_string(pathstartarea.pos1))
state.action.pos = vector.new(pathstartarea.pos1) state.action.pos = vector.new(pathstartarea.pos1)
state.action.pos.y = state.action.pos.y + PNTP state.action.pos.y = state.action.pos.y + ANTP
state.action.footpathdest = pathdestarea state.action.footpathdest = pathdestarea
return false return false
end end
@ -97,7 +101,7 @@ people.actions.go = function(state)
return true, false return true, false
end end
dbg.v2(state.ent.name.." leaving junction via "..nextpathdest.name) dbg.v2(state.ent.name.." leaving junction via "..nextpathdest.name)
state.action.pos = vector.add(nextpathdest.pos1, {x=0, y=PNTP, z=0}) state.action.pos = vector.add(nextpathdest.pos1, {x=0, y=ANTP, z=0})
return false return false
end end
@ -111,6 +115,11 @@ people.actions.go = function(state)
local thispathpos = vector.round({x=state.pos.x, y=state.pos.y + 0.5, z=state.pos.z}) local thispathpos = vector.round({x=state.pos.x, y=state.pos.y + 0.5, z=state.pos.z})
thispathpos.y = thispathpos.y - 1 thispathpos.y = thispathpos.y - 1
local nextpathpos = people.footpath_findnext(thispathpos, state.action.lastpathpos, false) local nextpathpos = people.footpath_findnext(thispathpos, state.action.lastpathpos, false)
if nextpathpos == "unloaded" then
state.wait = 1
dbg.v3(state.ent.name.." waiting for block load")
return false
end
if not nextpathpos then if not nextpathpos then
dbg.v1(state.ent.name.." can't find next footpath node at ".. dbg.v1(state.ent.name.." can't find next footpath node at "..
minetest.pos_to_string(thispathpos).." after ".. minetest.pos_to_string(thispathpos).." after "..
@ -118,10 +127,15 @@ people.actions.go = function(state)
return true, false return true, false
end end
if not distance then distance = 10 end if not distance or distance > 10 then distance = 10 end
while distance > 2 do while distance > 2 do
-- Look ahead a bit while going in a straight line, to increase speed -- Look ahead a bit while going in a straight line, to increase speed
local aheadpathpos = people.footpath_findnext(nextpathpos, thispathpos, true) local aheadpathpos = people.footpath_findnext(nextpathpos, thispathpos, true)
if aheadpathpos == "unloaded" then
state.wait = 1
dbg.v3(state.ent.name.." waiting for block load for lookahead")
return false
end
if aheadpathpos then if aheadpathpos then
thispathpos = nextpathpos thispathpos = nextpathpos
nextpathpos = aheadpathpos nextpathpos = aheadpathpos
@ -131,7 +145,7 @@ people.actions.go = function(state)
end end
end end
state.action.lastpathpos = thispathpos state.action.lastpathpos = thispathpos
state.action.pos = vector.add(nextpathpos, {x=0, y=PNTP, z=0}) state.action.pos = vector.add(nextpathpos, {x=0, y=0.5, z=0})
dbg.v3(state.ent.name.." set next footpath dest "..minetest.pos_to_string(state.action.pos)) dbg.v3(state.ent.name.." set next footpath dest "..minetest.pos_to_string(state.action.pos))
return false return false
@ -167,7 +181,7 @@ people.actions.go = function(state)
if pathdestarea and psdist < distance then if pathdestarea and psdist < distance then
state.action.endpos = state.action.pos state.action.endpos = state.action.pos
state.action.pos = vector.new(pathstartarea.pos1) state.action.pos = vector.new(pathstartarea.pos1)
state.action.pos.y = state.action.pos.y + PNTP state.action.pos.y = state.action.pos.y + ANTP
state.action.footpathdest = pathdestarea state.action.footpathdest = pathdestarea
dbg.v2(state.ent.name.." using footpath from "..pathstartarea.name.." to "..pathdestarea.name.." for intermediate route") dbg.v2(state.ent.name.." using footpath from "..pathstartarea.name.." to "..pathdestarea.name.." for intermediate route")
return false return false
@ -188,12 +202,13 @@ people.actions.go = function(state)
dbg.v2(state.ent.name.." arrived near "..minetest.pos_to_string(curdest)) dbg.v2(state.ent.name.." arrived near "..minetest.pos_to_string(curdest))
state.setpos = vector.round(curdest) state.setpos = vector.round(curdest)
state.setpos.y = state.pos.y state.setpos.y = state.pos.y
if state.action.footpathdest or state.action.intermediate then -- If we arrived at the pos, but we still have a
-- If we arrived at the pos, but we still have a -- pathdest or intermediate dest, we carry on to do that.
-- pathdest or intermediate dest, we carry on to do that. if state.action.intermediate then
if state.action.footpathdest then state.action.pos = state.action.intermediate[1]
state.action.pos = nil return false
end elseif state.action.footpathdest then
state.action.pos = nil
return false return false
end end
-- We've finished! -- We've finished!
@ -215,25 +230,29 @@ people.actions.go = function(state)
-- Apply some damage for bashing into something. Apart from being -- Apply some damage for bashing into something. Apart from being
-- the right thing to do, it will also kill of things that get -- the right thing to do, it will also kill of things that get
-- stuck in a wall. ;) -- stuck in a wall. ;)
state.damage = 0.5 state.damage = 0.4
end end
if not unwholesome and distance > 1 then if not unwholesome and distance > 1 then
local erk = nil local erk = nil
local ahead = state.speed local ahead = state.speed
if ahead > 1 then ahead = 1 end if ahead > 1 then ahead = 1 end
local nd = vector.from_speed_yaw(ahead, state.yaw) local nd = vector.from_speed_yaw(ahead, state.yaw)
local nextpos = vector.add(vector.round(state.pos), nd) local nextpos = vector.add(vector.round(state.pos), nd)
nextpos.y = nextpos.y + 1 nextpos.y = nextpos.y + 2
-- How far down we'll look, which needs to be at least this to -- How far down we'll look, which needs to be at least this to
-- be able to descend stairs. -- be able to descend stairs.
local ncount = 5 local ncount = 6
local diags = "at:" ..minetest.pos_to_string(state.pos) local diags = "at:" ..minetest.pos_to_string(state.pos)
local notwalkable = 0
local unloaded = false
diags = diags .. " next+1:" ..minetest.pos_to_string(nextpos) diags = diags .. " next+1:" ..minetest.pos_to_string(nextpos)
while ncount > 0 do while ncount > 0 do
local nn = minetest.get_node(nextpos).name local nn = minetest.get_node(nextpos).name
diags = diags .. ":" .. nn diags = diags .. ":" .. nn
if nn == "default:water_flowing" or nn == "default:water_source" or nn == "default:lava_flowing" or nn == "default:lava_source" then if nn == "ignore" then
unloaded = true
elseif nn == "default:water_flowing" or nn == "default:water_source" or nn == "default:lava_flowing" or nn == "default:lava_source" then
erk = nn erk = nn
break break
end end
@ -242,13 +261,26 @@ people.actions.go = function(state)
erk = "mysterious " .. nn erk = "mysterious " .. nn
break break
end end
if nd.walkable then if nd.walkable and ncount < 6 then
break break
end end
if not nd.walkable then
notwalkable = notwalkable + 1
end
nextpos.y = nextpos.y - 1 nextpos.y = nextpos.y - 1
ncount = ncount - 1 ncount = ncount - 1
end end
if ncount == 0 then erk = "fall" end if unloaded then
-- If we hit an unloaded block, just wait until it loads.
dbg.v3(state.ent.name.." waiting for unloaded to check ahead")
state.wait = 1
return false
end
if ncount == 0 then
erk = "fall"
elseif notwalkable < 2 then
erk = "bump"
end
if erk then if erk then
dbg.v1(state.ent.name.." aborted go due to fear of " .. dbg.v1(state.ent.name.." aborted go due to fear of " ..
erk .. " - " .. diags) erk .. " - " .. diags)
@ -258,7 +290,17 @@ people.actions.go = function(state)
if unwholesome then if unwholesome then
if distance < 32 then if distance < 32 then
local path = minetest.find_path(state.pos, curdest,
if state.action.triedpath then
dbg.v2(state.ent.name.." is not trying a path to "..minetest.pos_to_string(curdest).." again")
return true, false
end
local spos = vector.new(state.pos)
if state.ent.yoffset then
spos.y = spos.y - state.ent.yoffset
end
local path = minetest.find_path(spos, curdest,
distance + 16, 1, 3, "A*_noprefetch") distance + 16, 1, 3, "A*_noprefetch")
if not path then if not path then
@ -272,13 +314,21 @@ people.actions.go = function(state)
return true, false return true, false
else else
if not state.action.intermediate or #state.action.intermediate > 10 then if not state.action.intermediate or #state.action.intermediate > 10 then
state.action.intermediate = {} state.action.intermediate = {}
end end
for i = #path, 2, -1 do
table.insert(state.action.intermediate, 1, {x=path[i].x, y=path[i].y + PNTP, z=path[i].z}) -- Start following the path from the rounded position, in case
-- we're off centre and will collide immediately...
table.insert(state.action.intermediate, vector.round(state.pos))
for i = 2, #path do
table.insert(state.action.intermediate, {x=path[i].x, y=path[i].y -0.5, z=path[i].z})
end end
dbg.v3(state.ent.name.." found path: "..dump(path))
dbg.v3(state.ent.name.." found path to "..minetest.pos_to_string(curdest).." : "..dump(path))
state.action.triedpath = true
return false return false
end end
end end
@ -307,6 +357,12 @@ people.actions.go = function(state)
else else
state.speed = 3 state.speed = 3
end end
-- Apply max speed if there is one
if state.ent.maxspeed and state.speed > state.ent.maxspeed then
state.speed = state.ent.maxspeed
end
state.yaw = vector.get_yaw(state.pos, curdest) state.yaw = vector.get_yaw(state.pos, curdest)
return false return false

View File

@ -101,6 +101,30 @@ subcmd.create = {
end end
} }
subcmd.forget = {
params = "<name>",
desc = "Completely forget the person with the given name. If activated, they will be deleted.",
exec = function(playername, args)
local person, person_name
person_name, person, args = get_person(args)
if not person then
return false, "Specify a valid person"
end
if not minetest.check_player_privs(playername, {server=true}) then
if playername ~= ent.owner then
return false, person_name.." isn't yours, so so can't do that"
end
end
local ent = people.people[person_name].entity
if ent then
ent.object:remove()
end
people.people[person_name] = nil
return true, "Forgot "..person_name
end
}
subcmd.delete = { subcmd.delete = {
params = "<name>", params = "<name>",
desc = "Delete the person with the given name", desc = "Delete the person with the given name",

View File

@ -240,7 +240,9 @@ end
-- @param curpos The position of a current footpath node -- @param curpos The position of a current footpath node
-- @param lastpos The position of the previous footpath node -- @param lastpos The position of the previous footpath node
-- @param samedironly True to only look in the current direction of travel -- @param samedironly True to only look in the current direction of travel
-- @return The position of the next footpath node, or nil -- @return The position of the next footpath node, or nil if there isn't
-- one, or "unloaded" if there may or may not be one, but we can't
-- tell because of unloaded blocks.
people.footpath_findnext = function(curpos, lastpos, samedironly) people.footpath_findnext = function(curpos, lastpos, samedironly)
--dbg.v3("footpath_findnext, cur="..minetest.pos_to_string(curpos)..", last="..minetest.pos_to_string(lastpos)..", same="..dump(samedironly)) --dbg.v3("footpath_findnext, cur="..minetest.pos_to_string(curpos)..", last="..minetest.pos_to_string(lastpos)..", same="..dump(samedironly))
local xz local xz
@ -260,7 +262,9 @@ people.footpath_findnext = function(curpos, lastpos, samedironly)
local npos = vector.add(curpos, vector.new(x, y, z)) local npos = vector.add(curpos, vector.new(x, y, z))
if not vector.equals(npos, lastpos) then if not vector.equals(npos, lastpos) then
local n = minetest.get_node(npos) local n = minetest.get_node(npos)
if n.name == "ignore" then return "unloaded" end
if n.name == 'default:cobble' or if n.name == 'default:cobble' or
n.name == 'default:mossycobble' or
n.name == 'stairs:stair_cobble' or n.name == 'stairs:stair_cobble' or
n.name == 'default:wood' or n.name == 'default:wood' or
n.name == 'stairs:stair_wood' then n.name == 'stairs:stair_wood' then

View File

@ -141,42 +141,35 @@ minetest.register_entity("people:person" ,{
mesh = "people_character.x", mesh = "people_character.x",
textures = {"people_character.png"}, textures = {"people_character.png"},
makes_footstep_sound = true, makes_footstep_sound = true,
name = "APerson",
owner = "", owner = "",
code = "@"..people.presets[1].name, code = "@"..people.presets[1].name,
memory = {},
-- Current action. A table, as described in README.md -- Current action. A table, as described in README.md
-- Is nil when it's time for the person to select a new action. -- Is nil when it's time for the person to select a new action.
action = nil, action = nil,
-- The following controls gathering, which is the digging of nodes and
-- picking up of items, which happens in parallel with any other action.
--
gather = {
nodes = {}, -- list of nodes to dig up
topnodes = {}, -- list of topnodes to dig
items = {}, -- list of items to pick up
plant = nil, -- name of seed to plant, or nil
},
-- Time (game time) to wait until before doing anything else -- Time (game time) to wait until before doing anything else
wait = 0, wait = 0,
-- Lua environment
env = {},
stepheight = 1.1, stepheight = 1.1,
-- Customised properties
props = {},
on_activate = function(self, staticdata) on_activate = function(self, staticdata)
local setactive = false local setactive = false
self.memory = {}
self.env = {}
self.props = {}
-- The following controls gathering, which is the digging of nodes and
-- picking up of items, which happens in parallel with any other action.
--
self.gather = {
nodes = {}, -- list of nodes to dig up
topnodes = {}, -- list of topnodes to dig
items = {}, -- list of items to pick up
plant = nil, -- name of seed to plant, or nil
}
self.name = "<new person>"
dbg.v3("on_activate, staticdata = "..dump(staticdata))
local restored local restored
if staticdata and staticdata ~= "" then if staticdata and staticdata ~= "" then
restored = minetest.deserialize(staticdata) restored = minetest.deserialize(staticdata)
@ -251,6 +244,8 @@ minetest.register_entity("people:person" ,{
local err = people.exec_event(self, event) local err = people.exec_event(self, event)
if err then dbg.v1("Lua error "..err) end if err then dbg.v1("Lua error "..err) end
dbg.v3("Done on_activate for "..self.name)
end, end,
update_props = function(self) update_props = function(self)
@ -318,11 +313,16 @@ minetest.register_entity("people:person" ,{
on_step = function(self, dtime) on_step = function(self, dtime)
if self.wait ~= 0 then if self.wait ~= 0 then
if minetest.get_gametime() < self.wait then return end if minetest.get_gametime() < self.wait then
self.object:setvelocity({x=0,y=-10,z=0})
return
end
dbg.v3(self.name.." finished wait at "..minetest.get_gametime()) dbg.v3(self.name.." finished wait at "..minetest.get_gametime())
self.wait = 0 self.wait = 0
end end
local pos = self.object:getpos()
-- If we don't have a current action, we let the lua code choose one... -- If we don't have a current action, we let the lua code choose one...
if not self.action then if not self.action then
@ -333,14 +333,12 @@ minetest.register_entity("people:person" ,{
if err then dbg.v1("Lua error "..err) end if err then dbg.v1("Lua error "..err) end
if not self.action then if not self.action then
self.action = {"wait", time=120} self.action = {"wait", time=120}
dbg.v2(self.name.." failed to choose action - setting wait") dbg.v2(self.name.." failed to choose action - setting wait, at "..minetest.pos_to_string(pos))
else else
dbg.v1(self.name.." set new action: "..dump(self.action)) dbg.v1(self.name.." set new action: "..dump(self.action))
end end
end end
local pos = self.object:getpos()
-- Handle gathering -- Handle gathering
-- TODO: Only happens during go and follow currently. Can't happen -- TODO: Only happens during go and follow currently. Can't happen
-- during "dig" or any subaction that "dig" might set - which poses -- during "dig" or any subaction that "dig" might set - which poses

View File

@ -37,15 +37,40 @@ if event.type == "program" then
{"gather"}, {"gather"},
-- ********************
-- Head f0r the cactus farm, but get some flowers on the way
--
{"go", name="Jeiffel Station"},
{"gather", nodes={"flowers:geranium",
"flowers:rose",
"flowers:dandelion_white",
"flowers:dandelion_yellow",
"flowers:viola",
"flowers:tulip"}},
{"go", name="Cactus Approach"},
{"gather"},
-- ******************** -- ********************
-- Cactus Farm -- Cactus Farm
{"go", name="Cactus Farm"}, {"go", name="Cactus Farm"},
{"wait", time=10}, {"wait", time=10},
{"gather", topnodes={"default:cactus"}}, {"gather", topnodes={"default:cactus"}},
{"go", pos={x=-40, y=11.5, z=-462}}, {"go", pos={x=-34, y=11.5, z=-462}},
{"go", pos={x=-34, y=11.5, z=-459}},
{"go", pos={x=-40, y=11.5, z=-459}},
{"go", pos={x=-40, y=11.5, z=-465}},
{"go", pos={x=-33, y=11.5, z=-465}},
{"go", pos={x=-34, y=11.5, z=-462}},
{"gather"}, {"gather"},
{"go", name="Cactusville Square"}, {"go", name="Cactusville Square"},
{"stash", items={"*default:cactus"}, dest="default:chest"}, {"stash", items={"*default:cactus",
"*flowers:geranium",
"*flowers:rose",
"*flowers:dandelion_white",
"*flowers:dandelion_yellow",
"*flowers:viola",
"*flowers:tulip",
}, dest="default:chest"},
-- ***************** -- *****************
@ -76,6 +101,7 @@ if event.type == "program" then
"farming:seed_cotton 20", "farming:seed_cotton 20",
"farming_plus:carrot_seed 20", "farming_plus:carrot_seed 20",
"farming_plus:tomato_seed 20", "farming_plus:tomato_seed 20",
"farming_plus:potato_seed 20",
"farming_plus:strawberry_seed 20"}}, "farming_plus:strawberry_seed 20"}},
{"go", name="Ciaran's Farm"}, {"go", name="Ciaran's Farm"},

View File

@ -1,28 +1,26 @@
if event.type == "program" then if event.type == "program" then
if not mem.cur then mem.positions = {pos}
mem.cur = 1
mem.dir = 1
mem.wait = true
elseif event.type == "tell" then
if event.message == "here" then
mem.positions = {event.senderpos}
mem.wait = false
mem.cur = 1 mem.cur = 1
elseif event.message == "then here" then
table.insert(mem.positions, event.senderpos)
end end
if not mem.dir then
mem.dir = 1
end
mem.positions = {
{x=182, y=6.5, z=214},
"wait",
{x=163, y=6.5, z=213},
"wait",
{x=163, y=6.5, z=194},
"wait",
{x=181, y=6.5, z=194},
}
elseif event.type == "act" then elseif event.type == "act" then
if mem.positions[mem.cur] ~= "wait" then if mem.wait then
action = {"go", pos=mem.positions[mem.cur]}
else
action = {"wait", time=20} action = {"wait", time=20}
mem.wait = false
return
end end
action = {"go", pos=mem.positions[mem.cur]}
mem.wait = true
mem.cur = mem.cur + mem.dir mem.cur = mem.cur + mem.dir
if mem.cur > #mem.positions then if mem.cur > #mem.positions then
mem.cur = #mem.positions mem.cur = #mem.positions

View File

@ -120,7 +120,7 @@ people.people_wake = function()
-- Wake the entity by (yuk) setting a forceload. The activation -- Wake the entity by (yuk) setting a forceload. The activation
-- of the entity will cause the forceload to be freed. -- of the entity will cause the forceload to be freed.
dbg.v2("Set forceload for "..minetest.pos_to_string(v.pos)) dbg.v2("Set forceload for "..minetest.pos_to_string(v.pos).." to activate "..k)
minetest.forceload_block(v.pos) minetest.forceload_block(v.pos)
-- Only one at a time, even though this will introduce some -- Only one at a time, even though this will introduce some