More work in progress

master
Ciaran Gultnieks 2014-11-19 21:46:17 +00:00
parent dd48fe72e6
commit 93091fe3a6
14 changed files with 216 additions and 162 deletions

View File

@ -6,13 +6,13 @@ people.actions.attackplayer = function(state)
if not state.action.name or type(state.action.name) ~= "string" then
dbg.v1(state.ent.name.." has invalid attack target")
return true
return true, false
end
local player = minetest.get_player_by_name(state.action.name)
if not player then
dbg.v1(state.ent.name.." can't find "..state.action.name.." to follow them")
return true
return true, false
end
local targetpos = player:getpos()
@ -20,7 +20,7 @@ people.actions.attackplayer = function(state)
local dist = vector.length(dir)
if dist > 30 then
dbg.v1(state.ent.name.." target out of range")
return true
return true, false
end
if dist < 2 then
-- We're near enough...

View File

@ -5,14 +5,14 @@ if moddebug then dbg=moddebug.dbg("people") else dbg={v1=function() end,v2=funct
people.actions.dig = function(state)
if not state.action.pos or type(state.action.pos) ~= "table" then
dbg.v1(state.ent.name.." has invalid dig action")
return true
return true, false
end
local distance = vector.distance(state.pos, state.action.pos)
if distance > 7 then
dbg.v1(state.ent.name.." too far away to dig "..minetest.pos_to_string(state.action.pos)..
" from "..minetest.pos_to_string(state.pos).." - "..distance)
return true
return true, false
end
local yaw = vector.get_yaw(state.pos, state.action.pos)
@ -58,7 +58,7 @@ people.actions.dig = function(state)
end
end
return true
return true, false
end
for _, item in pairs(minetest.get_node_drops(n.name, "")) do
state.ent.inventory:add_item("main", ItemStack(item))
@ -66,7 +66,7 @@ people.actions.dig = function(state)
end
dbg.v1(state.ent.name.." dug "..n.name.." at "..minetest.pos_to_string(state.action.pos))
return true
return true, true
end

View File

@ -5,7 +5,7 @@ if moddebug then dbg=moddebug.dbg("people") else dbg={v1=function() end,v2=funct
people.actions.drop = function(state)
if not state.action.item or type(state.action.item) ~= "string" then
dbg.v1(state.ent.name.." has invalid drop action")
return true
return true, false
end
local item = state.action.item
@ -28,7 +28,7 @@ people.actions.drop = function(state)
local stack = state.ent.inventory:remove_item("main", item)
if not stack then
dbg.v1(state.ent.name.." couldn't drop "..item)
return true
return true, false
end
local v = vector.from_speed_yaw(1, state.yaw)
@ -42,6 +42,6 @@ people.actions.drop = function(state)
end
dbg.v1(state.ent.name.." dropped "..item)
return true
return true, true
end

View File

@ -12,7 +12,7 @@ people.actions.face = function(state)
else
dbg.v1(state.ent.name.." has invalid face action "..dump(state.action))
end
return true
return true, true
end

View File

@ -6,13 +6,13 @@ people.actions.follow = function(state)
if not state.action.name or type(state.action.name) ~= "string" then
dbg.v1(state.ent.name.." has invalid follow target")
return true
return true, false
end
local player = minetest.get_player_by_name(state.action.name)
if not player then
dbg.v1(state.ent.name.." can't find "..state.action.name.." to follow them")
return true
return true, false
end
local targetpos = player:getpos()

View File

@ -5,7 +5,7 @@ people.actions.gather = function(state)
state.gather.topnodes = state.action.topnodes or {}
state.gather.items = state.action.items or {}
state.gather.plant = state.action.plant
return true
return true, true
end

View File

@ -2,34 +2,54 @@
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
-- 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
people.actions.go = function(state)
if (not state.action.pos) and (not state.action.footpathdest) and state.action.name and areas and type(state.action.name) == "string" then
if (not state.action.pos) and (not state.action.footpathdest) and state.action.name then
-- Look for a path node with the right name
-- The action says to go to a named place. We're going to convert this
-- into a position, ready for the next call...
if not areas then
dbg.v1(state.ent.name.." can't go to named destination without areas mod")
return true, false
end
if type(state.action.name) ~= "string" then
dbg.v1(state.ent.name.." can't go to a named destination that isn't a string")
return true, false
end
-- Look for a footpath node with the right name
local pathdestarea = areas:findNearestArea(state.pos, "^path_"..people.escape_pattern(state.action.name).."$")
if pathdestarea then
dbg.v2(state.ent.name.." selected path destination "..pathdestarea.name)
-- Find the nearest footpath junction to us. We'll head to that
-- first (as a pos) and then follow the footpath network from
-- there.
local pathstartarea = areas:findNearestArea(state.pos, "^path_.+")
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 + 0.5
state.action.pos.y = state.action.pos.y + PNTP
state.action.footpathdest = pathdestarea
return false
end
end
-- No path node, so look for any area with the actual name and
-- just go there. (TODO: could then find the nearest path junction
-- to it and head for that)
-- just go there.
local nearest = areas:findNearestArea(state.pos, "^"..people.escape_pattern(state.action.name).."$")
if not nearest then
dbg.v2(state.ent.name.." couldn't find location "..state.action.name)
return true
return true, false
end
dbg.v2(state.ent.name.." set destination for centre of area "..nearest.name)
@ -43,8 +63,8 @@ people.actions.go = function(state)
-- path handling - only comes here when we've arrived at a new path square
-- (note, the range passed to findNearestArea determines our lookahead distance
local curpatharea, distance = areas:findNearestArea(state.pos, "^path_.+", nil, 10)
dbg.v3(state.ent.name.." at new footpath node at "..minetest.pos_to_string(state.pos))
local curpatharea, distance = areas:findNearestArea(state.pos, "^path_.+", nil, 10)
if curpatharea and curpatharea.pos1.x == state.pos.x and curpatharea.pos1.z == state.pos.z then
if curpatharea.name == state.action.footpathdest.name then
@ -54,37 +74,37 @@ people.actions.go = function(state)
state.action.pos = state.action.endpos
return false
end
return true
return true, true
end
if not state.action.name then
dbg.v1(state.ent.name.." unexpectedly missing destination name - aborting go action - fix this!")
return true
return true, false
end
-- We're at a junction
dbg.v2(state.ent.name.." is at footpath junction "..curpatharea.name.." - looking for route to "..state.action.name)
state.action.lastpathpos = vector.new(state.pos.x, state.pos.y - 0.5, state.pos.z)
state.action.lastpathpos = vector.new(state.pos.x, state.pos.y - PNTP, state.pos.z)
local nextpathdest = people.get_footpath_route(curpatharea.name, "path_"..state.action.name)
if not nextpathdest then
dbg.v2(state.ent.name.." can't find route")
return true
return true, false
end
local tonodename = "^to_"..string.sub(nextpathdest[2], 6).."$"
nextpathdest = areas:findNearestArea(state.pos, tonodename)
if not nextpathdest then
dbg.v2(state.ent.name.." can't find first route node "..tonodename)
return true
return true, false
end
dbg.v2(state.ent.name.." leaving junction via "..nextpathdest.name)
state.action.pos = vector.add(nextpathdest.pos1, {x=0, y=-0.5, z=0})
state.action.pos = vector.add(nextpathdest.pos1, {x=0, y=PNTP, z=0})
return false
end
if not state.action.lastpathpos then
dbg.v1(state.ent.name.." should have lastpathpos")
return true
return true, false
end
-- extra 0.5 allowing for dodgy step-ups, for now...
@ -95,7 +115,7 @@ people.actions.go = function(state)
dbg.v1(state.ent.name.." can't find next footpath node at "..
minetest.pos_to_string(thispathpos).." after "..
minetest.pos_to_string(state.action.lastpathpos))
return true
return true, false
end
if not distance then distance = 10 end
@ -111,7 +131,7 @@ people.actions.go = function(state)
end
end
state.action.lastpathpos = thispathpos
state.action.pos = vector.add(nextpathpos, {x=0, y=0.5, z=0})
state.action.pos = vector.add(nextpathpos, {x=0, y=PNTP, z=0})
dbg.v3(state.ent.name.." set next footpath dest "..minetest.pos_to_string(state.action.pos))
return false
@ -119,7 +139,7 @@ people.actions.go = function(state)
if not state.action.pos or not state.action.pos.x or not state.action.pos.y or not state.action.pos.z then
dbg.v1(state.ent.name.." has invalid go action "..dump(state.action))
return true
return true, false
end
-- Get our current destination, which might be either our
@ -147,7 +167,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 + 0.5
state.action.pos.y = state.action.pos.y + PNTP
state.action.footpathdest = pathdestarea
dbg.v2(state.ent.name.." using footpath from "..pathstartarea.name.." to "..pathdestarea.name.." for intermediate route")
return false
@ -178,111 +198,117 @@ people.actions.go = function(state)
end
-- We've finished!
dbg.v1(state.ent.name.." completed go action at "..minetest.pos_to_string(curdest))
return true
return true, true
end
else
-- Ok, we're actually walking towards a point!
-- See if we've hit something last step, or if we're about to venture
-- somewhere unwholesome...
local colres = state.ent.object:get_last_collision_result()
if colres.collides_xz then
dbg.v3(state.ent.name.." collided at "..minetest.pos_to_string(state.pos).." : "..dump(colres))
-- We've hit something...
local unwholesome = false
local colres = state.ent.object:get_last_collision_result()
if colres.collides_xz then
dbg.v3(state.ent.name.." collided at "..minetest.pos_to_string(state.pos).." : "..dump(colres))
unwholesome = true
-- We've hit something...
-- 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
-- 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
end
if distance < 32 then
local path = minetest.find_path(state.pos, curdest,
distance + 6, 1, 3, "A*_noprefetch")
if not path 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
-- How far down we'll look, which needs to be at least this to
-- be able to descend stairs.
local ncount = 5
local diags = "at:" ..minetest.pos_to_string(state.pos)
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
erk = nn
break
end
nd = minetest.registered_nodes[nn]
if not nd then
erk = "mysterious " .. nn
break
end
if nd.walkable then
break
end
nextpos.y = nextpos.y - 1
ncount = ncount - 1
end
if ncount == 0 then erk = "fall" end
if erk then
dbg.v1(state.ent.name.." aborted go due to fear of " ..
erk .. " - " .. diags)
unwholesome = true
end
end
dbg.v2(state.ent.name.." cannot find path from "..
minetest.pos_to_string(state.pos).." to "..
minetest.pos_to_string(curdest))
if state.action.intermediate then
state.action.intermediate = nil
end
state.wait = 2
return true
if unwholesome then
if distance < 32 then
local path = minetest.find_path(state.pos, curdest,
distance + 16, 1, 3, "A*_noprefetch")
if not path then
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 + 0.5, z=path[i].z})
end
dbg.v3(state.ent.name.." found path: "..dump(path))
dbg.v2(state.ent.name.." cannot find path from "..
minetest.pos_to_string(state.pos).." to "..
minetest.pos_to_string(curdest))
if state.action.intermediate then
state.action.intermediate = nil
end
state.wait = 2
return true, false
else
-- pick a couple of nearby points and walk to them, then try again
local randomdir = math.random(math.pi * 2)
vec = vector.from_speed_yaw(24, randomdir)
local rpos = {x=math.floor(state.pos.x + vec.x + 0.5), y=state.pos.y, z=math.floor(state.pos.z + vec.z + 0.5)}
randomdir = math.random(math.pi * 2)
vec = vector.from_speed_yaw(24, randomdir)
local rpos2 = {x=math.floor(rpos.x + vec.x + 0.5), y=state.pos.y, z=math.floor(rpos.z + vec.z + 0.5)}
if not state.action.intermediate or #state.action.intermediate > 10 then
state.action.intermediate = {}
end
table.insert(state.action.intermediate, 1, rpos2)
table.insert(state.action.intermediate, 1, rpos)
dbg.v2(state.ent.name.." hit something, far from destination - talking a random detour")
end
else
if distance < 1.5 then
state.speed = distance * 1.5
else
state.speed = 3
end
state.yaw = vector.get_yaw(state.pos, curdest)
-- Abort if we're going to walk somewhere unpleasant
if 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
-- How far down we'll look, which needs to be at least this to
-- be able to descend stairs.
local ncount = 5
local diags = "at:" ..minetest.pos_to_string(state.pos)
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
erk = nn
break
end
nd = minetest.registered_nodes[nn]
if not nd then
erk = "mysterious " .. nn
break
end
if nd.walkable then
break
end
nextpos.y = nextpos.y - 1
ncount = ncount - 1
end
if ncount == 0 then erk = "fall" end
if erk then
dbg.v1(state.ent.name.." aborted go due to fear of " ..
erk .. " - " .. diags)
state.speed = 0
state.wait = 2
return true
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})
end
dbg.v3(state.ent.name.." found path: "..dump(path))
return false
end
end
-- We hit something, and we're too far from our destination to try
-- pathfinding. Pick a couple of nearby points and walk to them,
-- then try again
local randomdir = math.random(math.pi * 2)
vec = vector.from_speed_yaw(8, randomdir)
local rpos = {x=math.floor(state.pos.x + vec.x + 0.5), y=state.pos.y, z=math.floor(state.pos.z + vec.z + 0.5)}
randomdir = math.random(math.pi * 2)
vec = vector.from_speed_yaw(8, randomdir)
local rpos2 = {x=math.floor(rpos.x + vec.x + 0.5), y=state.pos.y, z=math.floor(rpos.z + vec.z + 0.5)}
if not state.action.intermediate or #state.action.intermediate > 10 then
state.action.intermediate = {}
end
table.insert(state.action.intermediate, 1, rpos2)
table.insert(state.action.intermediate, 1, rpos)
dbg.v2(state.ent.name.." hit something, far from destination - talking a random detour")
return false
end
if distance < 1.5 then
state.speed = distance * 1.5
else
state.speed = 3
end
state.yaw = vector.get_yaw(state.pos, curdest)
return false
end

View File

@ -5,14 +5,14 @@ if moddebug then dbg=moddebug.dbg("people") else dbg={v1=function() end,v2=funct
people.actions.pickup = function(state)
if not state.action.pos or type(state.action.pos) ~= "table" or not state.action.item then
dbg.v1(state.ent.name.." has invalid pickup action")
return true
return true, false
end
local distance = vector.distance(state.pos, state.action.pos)
if distance > 8 then
dbg.v1(state.ent.name.." too far away to pickup "..minetest.pos_to_string(state.action.pos)..
" from "..minetest.pos_to_string(state.pos).." - "..distance)
return true
return true, false
end
local yaw = vector.get_yaw(state.pos, state.action.pos)
@ -51,13 +51,13 @@ people.actions.pickup = function(state)
-- its itemstring so we don't see it again!
ent.itemstring = ""
dbg.v1(state.ent.name.." picked up "..state.action.item.." at "..minetest.pos_to_string(state.action.pos))
return true
return true, true
end
end
end
end
dbg.v1(state.ent.name.." could not pick up "..state.action.item.." at "..minetest.pos_to_string(state.action.pos))
return true
return true, false
end

View File

@ -42,13 +42,13 @@ end
people.actions.place = function(state)
if not state.action.pos or type(state.action.pos) ~= "table" or not state.action.item then
dbg.v1(state.ent.name.." has invalid place action")
return true
return true, false
end
local distance = vector.distance(state.pos, state.action.pos)
if distance > 5 then
dbg.v1(state.ent.name.." too far away to place "..minetest.pos_to_string(foundpos))
return true
return true, false
end
local yaw = vector.get_yaw(state.pos, state.action.pos)
@ -77,7 +77,7 @@ people.actions.place = function(state)
local ii = ItemStack(state.action.item.." 1")
if not inv:contains_item("main", ii) then
dbg.v1(state.ent.name.." doesn't have "..state.action.item.." to place")
return true
return true, false
end
local pointed_thing = {type="node",
under={x=state.action.pos.x,y=state.action.pos.y-1,z=state.action.pos.z},
@ -88,7 +88,7 @@ people.actions.place = function(state)
inv:remove_item("main", ItemStack(state.action.item.." 1"))
dbg.v1(state.ent.name.." placed "..state.action.item.." at "..minetest.pos_to_string(state.action.pos))
return true
return true, true
end

View File

@ -37,7 +37,7 @@ people.actions.stash = function(state)
if not (state.action.dest or state.action.pos) or
not state.action.items or type(state.action.items) ~= "table" then
dbg.v1(state.ent.name.." has invalid stash action")
return true
return true, false
end
local foundpos = state.action.pos
@ -46,7 +46,7 @@ people.actions.stash = function(state)
end
if not foundpos then
dbg.v1(state.ent.name.." can't find "..state.action.dest.." to stash in")
return true
return true, false
end
local yaw = vector.get_yaw(state.pos, foundpos)
@ -73,7 +73,7 @@ people.actions.stash = function(state)
local meta = minetest.get_meta(foundpos)
if not meta then
dbg.v1(state.ent.name.." can't get stash node meta")
return true
return true, false
end
local itemname, count = move_items(state.ent.inventory,
@ -84,7 +84,7 @@ people.actions.stash = function(state)
if #state.action.items > 0 then return false end
dbg.v2(state.ent.name.." finished stashing")
return true
return true, true
end
@ -92,7 +92,7 @@ people.actions.retrieve = function(state)
if not (state.action.dest or state.action.pos) or
not state.action.items or type(state.action.items) ~= "table" then
dbg.v1(state.ent.name.." has invalid retrieve action")
return true
return true, false
end
local foundpos = state.action.pos
@ -101,7 +101,7 @@ people.actions.retrieve = function(state)
end
if not foundpos then
dbg.v1(state.ent.name.." can't find "..state.action.dest.." to retrieve from")
return true
return true, false
end
local yaw = vector.get_yaw(state.pos, foundpos)
@ -128,7 +128,7 @@ people.actions.retrieve = function(state)
local meta = minetest.get_meta(foundpos)
if not meta then
dbg.v1(state.ent.name.." can't get retrieve node meta")
return true
return true, false
end
local itemname, count = move_items(meta:get_inventory(),
@ -139,7 +139,7 @@ people.actions.retrieve = function(state)
if #state.action.items > 0 then return false end
dbg.v2(state.ent.name.." finished retrieving")
return true
return true, true
end

View File

@ -3,7 +3,7 @@ people.actions.wait = function(state)
if state.action.time and tonumber(state.action.time) then
state.wait = tonumber(state.action.time)
end
return true
return true, true
end

View File

@ -95,14 +95,8 @@ subcmd.create = {
return false, "people create can only be used by a player"
end
local pos = player:getpos()
local obj = minetest.add_entity(pos, "people:person")
if not obj then
return false, "Failed to add_entity"
end
local ent = obj:get_luaentity()
ent.name = person_name
ent.owner = playername
people.people_add(ent)
local err = people.create(pos, person_name, playername)
if err then return false, err end
return true, "Created "..person_name
end
}

View File

@ -111,6 +111,20 @@ function people.get_inv(self, name)
return st
end
function people.create(pos, name, owner)
local obj = minetest.add_entity(pos, "people:person")
if not obj then
return "Failed to add_entity"
end
local ent = obj:get_luaentity()
ent.name = name
ent.owner = owner
ent.inventory = minetest.create_detached_inventory("people_"..name, nil)
ent.inventory:set_size("main", 8*4);
people.people_add(ent)
return nil
end
minetest.register_entity("people:person" ,{
hp_max = 20,
physical = true,
@ -153,7 +167,7 @@ minetest.register_entity("people:person" ,{
-- Lua environment
env = {},
stepheight = 0.6,
stepheight = 1.1,
-- Customised properties
props = {},
@ -205,27 +219,28 @@ minetest.register_entity("people:person" ,{
items = {},
}
end
end
if not people.is_valid_name(self.name) then
self.object:remove()
dbg.v1("Removing badly named person")
return
self.inventory = minetest.create_detached_inventory("people_"..self.name, nil)
self.inventory:set_size("main", 8*4);
if restored.inv_main then
local inv_main = restored.inv_main
for i=1,#inv_main,1 do
self.inventory:set_stack("main", i, inv_main[i])
end
end
if not people.is_valid_name(self.name) then
self.object:remove()
dbg.v1("Removing badly named person")
return
end
end
-- Entity becomes active.
people.people_set_active(self)
end
self.inventory = minetest.create_detached_inventory("people_"..self.name, nil)
self.inventory:set_size("main", 8*4);
if restored and restored.inv_main then
local inv_main = restored.inv_main
for i=1,#inv_main,1 do
self.inventory:set_stack("main", i, inv_main[i])
end
end
self.env = people.create_environment(self)
self:update_props()
@ -476,9 +491,10 @@ minetest.register_entity("people:person" ,{
-- Run the appropriate handler for the current action...
local action_done = false
local action_success = false
local handler = people.actions[state.action[1]]
if handler then
action_done = handler(state)
action_done, action_success = handler(state)
-- Because state.action can be replaced...
if state.action ~= self.action then
dbg.v3(state.ent.name.." action handler replaced action with "..dump(state.action))
@ -498,7 +514,18 @@ minetest.register_entity("people:person" ,{
dbg.v3(state.ent.name.." completed action - setting previous action")
self.action = state.action.prevaction
else
dbg.v3(state.ent.name.." completed action")
if(action_success) then
dbg.v3(state.ent.name.." completed action")
else
dbg.v3(state.ent.name.." failed action")
end
if not action_success then
local event = {type="actfail"}
local err = people.exec_event(self, event)
if err then dbg.v1("Lua error "..err) end
end
self.action = nil
end
end

View File

@ -1,6 +1,7 @@
if event.type == "program" then
mem.cur = 1
mem.failed = false
mem.actions = {
-- *****************
@ -152,6 +153,8 @@ if event.type == "program" then
elseif event.type == "act" then
if mem.failed then return end
action = mem.actions[mem.cur]
mem.cur = mem.cur + 1
@ -159,4 +162,8 @@ elseif event.type == "act" then
mem.cur = 1
end
elseif event.type == "actfail" then
mem.failed = true
end