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)
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)
dbg.v3(state.ent.name.." setting calculated yaw to "..state.action.yaw)
elseif state.action.yaw then
dbg.v3(state.ent.name.." setting yaw to "..state.action.yaw)
state.yaw = state.action.yaw
else
dbg.v1(state.ent.name.." has invalid face action "..dump(state.action))
state.yaw = vector.get_yaw(state.pos, state.action.pos)
dbg.v3(state.ent.name.." setting calculated yaw to "..state.yaw)
return true, true
elseif state.action.yaw then
dbg.v3(state.ent.name.." setting yaw to "..state.action.yaw)
state.yaw = state.action.yaw
return true, true
end
return true, true
dbg.v1(state.ent.name.." has invalid face action "..dump(state.action))
return true, false
end

View File

@ -2,11 +2,15 @@
local dbg
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
-- standing on. Add this to the Y coordinate to convert from a path node
-- 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)
@ -38,7 +42,7 @@ people.actions.go = function(state)
if pathstartarea then
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.y = state.action.pos.y + PNTP
state.action.pos.y = state.action.pos.y + ANTP
state.action.footpathdest = pathdestarea
return false
end
@ -97,7 +101,7 @@ people.actions.go = function(state)
return true, false
end
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
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})
thispathpos.y = thispathpos.y - 1
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
dbg.v1(state.ent.name.." can't find next footpath node at "..
minetest.pos_to_string(thispathpos).." after "..
@ -118,10 +127,15 @@ people.actions.go = function(state)
return true, false
end
if not distance then distance = 10 end
if not distance or distance > 10 then distance = 10 end
while distance > 2 do
-- Look ahead a bit while going in a straight line, to increase speed
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
thispathpos = nextpathpos
nextpathpos = aheadpathpos
@ -131,7 +145,7 @@ people.actions.go = function(state)
end
end
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))
return false
@ -167,7 +181,7 @@ people.actions.go = function(state)
if pathdestarea and psdist < distance then
state.action.endpos = state.action.pos
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
dbg.v2(state.ent.name.." using footpath from "..pathstartarea.name.." to "..pathdestarea.name.." for intermediate route")
return false
@ -188,12 +202,13 @@ people.actions.go = function(state)
dbg.v2(state.ent.name.." arrived near "..minetest.pos_to_string(curdest))
state.setpos = vector.round(curdest)
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
-- pathdest or intermediate dest, we carry on to do that.
if state.action.footpathdest then
state.action.pos = nil
end
-- If we arrived at the pos, but we still have a
-- pathdest or intermediate dest, we carry on to do that.
if state.action.intermediate then
state.action.pos = state.action.intermediate[1]
return false
elseif state.action.footpathdest then
state.action.pos = nil
return false
end
-- We've finished!
@ -215,25 +230,29 @@ people.actions.go = function(state)
-- Apply some damage for bashing into something. Apart from being
-- the right thing to do, it will also kill of things that get
-- stuck in a wall. ;)
state.damage = 0.5
state.damage = 0.4
end
if not unwholesome and distance > 1 then
if not unwholesome and distance > 1 then
local erk = nil
local ahead = state.speed
if ahead > 1 then ahead = 1 end
local nd = vector.from_speed_yaw(ahead, state.yaw)
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
-- be able to descend stairs.
local ncount = 5
local ncount = 6
local diags = "at:" ..minetest.pos_to_string(state.pos)
local notwalkable = 0
local unloaded = false
diags = diags .. " next+1:" ..minetest.pos_to_string(nextpos)
while ncount > 0 do
local nn = minetest.get_node(nextpos).name
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
break
end
@ -242,13 +261,26 @@ people.actions.go = function(state)
erk = "mysterious " .. nn
break
end
if nd.walkable then
if nd.walkable and ncount < 6 then
break
end
if not nd.walkable then
notwalkable = notwalkable + 1
end
nextpos.y = nextpos.y - 1
ncount = ncount - 1
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
dbg.v1(state.ent.name.." aborted go due to fear of " ..
erk .. " - " .. diags)
@ -258,7 +290,17 @@ people.actions.go = function(state)
if unwholesome 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")
if not path then
@ -272,13 +314,21 @@ people.actions.go = function(state)
return true, false
else
if not state.action.intermediate or #state.action.intermediate > 10 then
state.action.intermediate = {}
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
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
end
end
@ -307,6 +357,12 @@ people.actions.go = function(state)
else
state.speed = 3
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)
return false

View File

@ -101,6 +101,30 @@ subcmd.create = {
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 = {
params = "<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 lastpos The position of the previous footpath node
-- @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)
--dbg.v3("footpath_findnext, cur="..minetest.pos_to_string(curpos)..", last="..minetest.pos_to_string(lastpos)..", same="..dump(samedironly))
local xz
@ -260,7 +262,9 @@ people.footpath_findnext = function(curpos, lastpos, samedironly)
local npos = vector.add(curpos, vector.new(x, y, z))
if not vector.equals(npos, lastpos) then
local n = minetest.get_node(npos)
if n.name == "ignore" then return "unloaded" end
if n.name == 'default:cobble' or
n.name == 'default:mossycobble' or
n.name == 'stairs:stair_cobble' or
n.name == 'default:wood' or
n.name == 'stairs:stair_wood' then

View File

@ -141,42 +141,35 @@ minetest.register_entity("people:person" ,{
mesh = "people_character.x",
textures = {"people_character.png"},
makes_footstep_sound = true,
name = "APerson",
owner = "",
code = "@"..people.presets[1].name,
memory = {},
-- Current action. A table, as described in README.md
-- Is nil when it's time for the person to select a new action.
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
wait = 0,
-- Lua environment
env = {},
stepheight = 1.1,
-- Customised properties
props = {},
on_activate = function(self, staticdata)
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
if staticdata and staticdata ~= "" then
restored = minetest.deserialize(staticdata)
@ -251,6 +244,8 @@ minetest.register_entity("people:person" ,{
local err = people.exec_event(self, event)
if err then dbg.v1("Lua error "..err) end
dbg.v3("Done on_activate for "..self.name)
end,
update_props = function(self)
@ -318,11 +313,16 @@ minetest.register_entity("people:person" ,{
on_step = function(self, dtime)
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())
self.wait = 0
end
local pos = self.object:getpos()
-- If we don't have a current action, we let the lua code choose one...
if not self.action then
@ -333,14 +333,12 @@ minetest.register_entity("people:person" ,{
if err then dbg.v1("Lua error "..err) end
if not self.action then
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
dbg.v1(self.name.." set new action: "..dump(self.action))
end
end
local pos = self.object:getpos()
-- Handle gathering
-- TODO: Only happens during go and follow currently. Can't happen
-- during "dig" or any subaction that "dig" might set - which poses

View File

@ -37,15 +37,40 @@ if event.type == "program" then
{"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
{"go", name="Cactus Farm"},
{"wait", time=10},
{"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"},
{"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_plus:carrot_seed 20",
"farming_plus:tomato_seed 20",
"farming_plus:potato_seed 20",
"farming_plus:strawberry_seed 20"}},
{"go", name="Ciaran's Farm"},

View File

@ -1,28 +1,26 @@
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
elseif event.message == "then here" then
table.insert(mem.positions, event.senderpos)
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
if mem.positions[mem.cur] ~= "wait" then
action = {"go", pos=mem.positions[mem.cur]}
else
if mem.wait then
action = {"wait", time=20}
mem.wait = false
return
end
action = {"go", pos=mem.positions[mem.cur]}
mem.wait = true
mem.cur = mem.cur + mem.dir
if mem.cur > #mem.positions then
mem.cur = #mem.positions

View File

@ -120,7 +120,7 @@ people.people_wake = function()
-- Wake the entity by (yuk) setting a forceload. The activation
-- 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)
-- Only one at a time, even though this will introduce some