A ton of stuff
parent
fac95b47af
commit
a5c2ff2ee1
131
README.md
131
README.md
|
@ -134,7 +134,14 @@ it fails to do so, the person will do an automatic wait.
|
|||
|
||||
### actfail
|
||||
|
||||
This happens when an action fails.
|
||||
This happens when an action fails, unless there is a 'prevaction' set. (To
|
||||
get a fail, but still have a follow-on action, use 'successaction' instead!)
|
||||
|
||||
There is also event.failedaction available, which is the action that actually
|
||||
failed, and event.failcode which is the failure code that the action returned.
|
||||
That is normally just false, but some action handlers can return special
|
||||
values here (anything non-true would be a fail) to indicate particular
|
||||
things.
|
||||
|
||||
### tell
|
||||
|
||||
|
@ -186,14 +193,21 @@ position.
|
|||
|
||||
The following actions are currently defined:
|
||||
|
||||
#### go, with pos={x,y,z}
|
||||
Walks to the given position.
|
||||
#### go
|
||||
|
||||
#### go, with name="string"
|
||||
Walks to a named position - names are looked up using the areas module, if
|
||||
present This converts to go, pos={x,y,z}, with name retained for reference.
|
||||
Go (walk) to a location. This generally decomposes into a more complex set
|
||||
of actions, the ultimate aim of which is to get to the given destination
|
||||
somehow.
|
||||
|
||||
Names are most frequently used in conjunction with footpaths.
|
||||
One of the following parameters is needed:
|
||||
|
||||
* pos={x,y,z} - specifies an absolute position to go to
|
||||
* rel={x,y,z} - to go a relative offset from the current position
|
||||
* name=string - specifies a footpath node or area (see the Navigation
|
||||
section
|
||||
|
||||
Many other parameters are handled by the go action, but these are used
|
||||
internally only.
|
||||
|
||||
#### follow, with name="playername"
|
||||
Follows the given player indefinitely (or at least until they log off).
|
||||
|
@ -220,12 +234,17 @@ Dig the node at the given position. Must be within range.
|
|||
#### rightclicknode, with pos={x,y,z}
|
||||
Right-click the node at the given position. Must be within range.
|
||||
|
||||
#### place, with pos={x,y,z} and item=name
|
||||
Places the given item. Must be in the inventory, and in range.
|
||||
#### place
|
||||
Places an item (node). Must be in the inventory, and in range.
|
||||
|
||||
* Required parameter: pos={x,y,z}
|
||||
* Required parameter: item=itemname
|
||||
* Optional parameter: param2=value (e.g. for setting facedir)
|
||||
* Optional parameter: againstdir={x,y,z}
|
||||
|
||||
#### stash
|
||||
|
||||
* Required parameter: items={"item1", ..."itemn"}
|
||||
* Required parameter: items={item1, ..., itemn"}
|
||||
* Optional parameter: pos={x,y,z} - position of node to stash in
|
||||
* Optional parameter: dest="node" - node name to stash in
|
||||
(e.g. "default:chest")
|
||||
|
@ -237,22 +256,24 @@ Specifically, it needs to be a node with a "main" inventory list. So for a
|
|||
normal chest, use "default:chest" for the nodename.
|
||||
|
||||
Each item in the list can be:
|
||||
* Just the item name (e.g. "default:cobble") to put one item in
|
||||
* Just the item name (e.g. "default:cobble") to put all held in
|
||||
* Item name and count (e.g. "default:cobble 50") to put that many in
|
||||
* Item name preceded by an asterisk (e.g. "\*default:cobble") , to put all
|
||||
carried in
|
||||
* Table ({"default:cobble", keep=5}) to keep 5 but put the rest in
|
||||
|
||||
#### retrieve, with src="nodename" and items={"item1", "itemn"}
|
||||
#### retrieve
|
||||
|
||||
Gets items from a source node, which should be something like a chest.
|
||||
Specifically, it needs to be a node with a "main" inventory list. So for a
|
||||
normal chest, use "default:chest" for the nodename.
|
||||
|
||||
Each item in the list can be:
|
||||
* Just the item name (e.g. "default:cobble") to get one item out
|
||||
* Item name and count (e.g. "default:cobble 50") to get that many out
|
||||
* Item name preceded by an asterisk (e.g. "\*default:cobble") , to get all
|
||||
of that kind of item out
|
||||
* Required parameter: items={item1, ..., itemn"}
|
||||
* Optional parameter: pos={x,y,z} - position of node to stash in
|
||||
* Optional parameter: src="node" - node name to retrieve from
|
||||
(e.g. "default:chest")
|
||||
|
||||
(You need either pos or dest, or nothing will happen)
|
||||
|
||||
The items in the list are defined in the same way as for the stash action.
|
||||
|
||||
#### sell
|
||||
|
||||
|
@ -266,13 +287,32 @@ afford to buy it all.
|
|||
|
||||
#### buy
|
||||
|
||||
* Required parameter: item="itemstring"
|
||||
* Required parameter: item="itemname"
|
||||
* Required parameter: num=amount
|
||||
|
||||
Need to be standing within range of a shop (barrel mod) that sells the item
|
||||
in question, and have enough money. If the person doesn't have enough money
|
||||
to buy the amount specified, a lesser amount may be bought instead.
|
||||
|
||||
#### obtain
|
||||
|
||||
Meta-action to obtain some of an item by whatever means possible. This could
|
||||
use crafting, buying, mining, whatever, the only aim is to get it.
|
||||
|
||||
The specified amount is the total amount we want to end up having - so if we
|
||||
already have that many, the action will not do anything. Otherwise, it could
|
||||
use one or more of the available methods until the total is achieved.
|
||||
|
||||
* Required paramter: item="itemname"
|
||||
* Required parameter: num=amount
|
||||
|
||||
#### craft
|
||||
|
||||
Craft an item.
|
||||
|
||||
* Required paramter: item="itemname"
|
||||
* Required parameter: num=amount
|
||||
|
||||
#### gather
|
||||
Changes current gathering settings.
|
||||
|
||||
|
@ -322,6 +362,57 @@ The correct item should already be wielded. This is normally used in
|
|||
conjunction with gathering, in which case the wielding is already
|
||||
handled.
|
||||
|
||||
#### tunnel
|
||||
|
||||
Tunnel, from the current position. Also builds bridges!
|
||||
|
||||
Parameters:
|
||||
|
||||
* `dir = {x,y,z}` - direction - either x or z must be 0. and the
|
||||
other +/-1, while y can be 0 or +/-1.
|
||||
* 'distance = n` - distance to go for (reduces as the action
|
||||
proceeds)
|
||||
* `floor=item` - material to use for floor - optional
|
||||
* `wall=item` - material to use for wall linings - optional
|
||||
* `ceiling=item` - material to use for ceiling - optional
|
||||
* `steps=item` - material to use for steps, on slopes.
|
||||
* `lighting=item` - material (most likely default:torch) to use for
|
||||
lighting, which is placed against walls at
|
||||
4 metre intervals. Optional.
|
||||
* `support_top=item` - material to use for top supports, which are placed
|
||||
against the ceiling at 8 metre intervals. Optional.
|
||||
* `support_ceiling=item` - like support_top, but at ceiling level, not below.
|
||||
* `support_side=item` - material to use for side supports. Optional.
|
||||
* `support_side_facein=? - set to true to make the side supports face in
|
||||
towards the tunnel centre. (Try it with slabs, for
|
||||
example!)
|
||||
* `support_wall=item` - like support_side, but at wall level, not within.
|
||||
|
||||
#### building
|
||||
|
||||
Make a building, from current position.
|
||||
|
||||
The current position is designated as the entrance to the building.
|
||||
|
||||
Parameters:
|
||||
|
||||
* `dir = {x,y,z}` - direction - either x or z must be 0. and the
|
||||
other +/-1, while y can be 0 or +/-1.
|
||||
* `width = n` - the width of the building
|
||||
* `depth = n` - the depth of the building
|
||||
* `height = n` - the height of the building
|
||||
* `wall = item` - material to use for walls
|
||||
* `outside_floor = item` - material to use for the floor outside the walls.
|
||||
Optional. Does not include the entrance.
|
||||
This can also be a table, with two entries, in
|
||||
which case the floor can be either of those, and
|
||||
if it's not it's replaced with the first. (Example
|
||||
use case of that is if it's dirt, in which case
|
||||
it can change to dirt_with_grass, and be left
|
||||
alone!)
|
||||
* `door=item` - Door to use. Doorways will be left open if not
|
||||
specified.
|
||||
|
||||
#### step
|
||||
Allow's the person's lua code to handle on_step itself. It will receive
|
||||
"step" events (with dtime) and should reset the action when it no longer
|
||||
|
|
|
@ -0,0 +1,213 @@
|
|||
|
||||
local dbg
|
||||
if moddebug then dbg=moddebug.dbg("people") else dbg={v1=function() end,v2=function() end,v3=function() end} end
|
||||
|
||||
local function rotate(rel, dir)
|
||||
if dir.z < 0 then
|
||||
return {x=-rel.x, y=rel.y, z=-rel.z}
|
||||
elseif dir.z > 0 then
|
||||
return {x=rel.x, y=rel.y, z=rel.z}
|
||||
elseif dir.x > 0 then
|
||||
return {x=rel.z, y=rel.y, z=-rel.x}
|
||||
else
|
||||
return {x=-rel.z, y=rel.y, z=rel.x}
|
||||
end
|
||||
end
|
||||
|
||||
people.actions.building = function(state)
|
||||
|
||||
if type(state.action.dir) ~= "table" then
|
||||
dbg.v1(state.ent.name.." has invalid dir for building action")
|
||||
return true, false
|
||||
end
|
||||
if state.action.dir.y ~= 0 then
|
||||
dbg.v1(state.ent.name.." has invalid y component of dir for building action")
|
||||
return true, false
|
||||
end
|
||||
if math.abs(state.action.dir.x) + math.abs(state.action.dir.z) ~= 1 then
|
||||
dbg.v1(state.ent.name.." has invalid x/z components of dir for building action")
|
||||
return true, false
|
||||
end
|
||||
if type(state.action.height) ~= "number" or state.action.height < 1
|
||||
or state.action.height > 5 then
|
||||
dbg.v1(state.ent.name.." has invalid height for building action")
|
||||
return true, false
|
||||
end
|
||||
if type(state.action.width) ~= "number" or state.action.width < 1
|
||||
or state.action.width > 15 or state.action.width % 2 == 0 then
|
||||
dbg.v1(state.ent.name.." has invalid width for building action")
|
||||
return true, false
|
||||
end
|
||||
if type(state.action.depth) ~= "number" or state.action.depth < 1
|
||||
or state.action.depth > 15 then
|
||||
dbg.v1(state.ent.name.." has invalid depth for building action")
|
||||
return true, false
|
||||
end
|
||||
|
||||
if not state.action.startpos then
|
||||
state.action.startpos = vector.round(state.pos)
|
||||
end
|
||||
|
||||
if not state.action.cpos then
|
||||
state.action.cpos = 0
|
||||
end
|
||||
|
||||
-- The following only pans out if the width is an odd
|
||||
-- number! TODO
|
||||
local toleft = math.ceil(state.action.width / 2)
|
||||
local toback = state.action.depth + 1
|
||||
local toright = state.action.width + 1
|
||||
local tofront = toback
|
||||
local toleft2 = toleft
|
||||
|
||||
if state.action.atcpos then
|
||||
|
||||
-- So we're at a position, cpos...
|
||||
-- 0 = in front of the entrance
|
||||
-- 1 - (toleft - 1) = along front wall, including corner
|
||||
|
||||
if state.action.wall then
|
||||
local wallpos
|
||||
local starty = 0
|
||||
if state.action.cpos > 0 and state.action.cpos < toleft then
|
||||
wallpos = {x=0, z=1}
|
||||
elseif state.action.cpos > toleft and state.action.cpos < toleft + toback - 1 then
|
||||
-- Wall down left side of building...
|
||||
wallpos = {x=1, z=0}
|
||||
elseif state.action.cpos > toleft + toback and state.action.cpos < toleft + toback + toright then
|
||||
-- Back wall
|
||||
wallpos = {x=0, z=-1}
|
||||
elseif state.action.cpos > toleft + toback + toright and state.action.cpos < toleft + toback + toright + tofront then
|
||||
-- Wall down right side of building...
|
||||
wallpos = {x=-1, z=0}
|
||||
elseif state.action.cpos >= toleft + toback + toright + tofront + 1 and state.action.cpos < toleft + toback + toright + tofront + toleft2 then
|
||||
wallpos = {x=0, z=1}
|
||||
elseif state.action.cpos == toleft + toback + toright + tofront + toleft2 then
|
||||
-- This should be the very last point on the circuit, which is
|
||||
-- in front of the door!
|
||||
wallpos = {x=0, z=1}
|
||||
starty = 2
|
||||
end
|
||||
|
||||
if wallpos then
|
||||
|
||||
for y = 0, state.action.height - 1 do
|
||||
local thisoff = {x=wallpos.x, y=y, z=wallpos.z}
|
||||
local woff = rotate(thisoff, state.action.dir)
|
||||
local thispos = vector.add(state.pos, woff)
|
||||
local dignode = minetest.get_node(thispos)
|
||||
-- Note that we have to substring the dignode, because
|
||||
-- the placed bottom half of the door doesn't have the
|
||||
-- same name as the item it came from.
|
||||
if y == 0 and starty == 2 and state.action.door and
|
||||
dignode.name:sub(1, state.action.door:len())
|
||||
~= state.action.door then
|
||||
-- We place the door against the side, just to allow for
|
||||
-- there being a right-click handling node (e.g.
|
||||
-- junction) below it.
|
||||
todir = {x=-1,y=0,z=0}
|
||||
todir = rotate(todir, state.action.dir)
|
||||
state.action = {"place", pos=thispos,
|
||||
item=state.action.door,
|
||||
successaction=state.action,
|
||||
againstdir=todir}
|
||||
return false
|
||||
elseif y == starty and starty > 0 and dignode.name == "air" then
|
||||
-- Similarly, we have to watch out if we're placing
|
||||
-- above a door (it will open/shut!), or above a hole
|
||||
-- where a door would go. Maybe the auto-against-dir
|
||||
-- code in the place action should just be detecting
|
||||
-- right-clickable things and avoiding them, to save
|
||||
-- all this. Or 'holding shift'??
|
||||
todir = {x=-1,y=0,z=0}
|
||||
todir = rotate(todir, state.action.dir)
|
||||
state.action = {"place", pos=thispos,
|
||||
item=state.action.wall,
|
||||
successaction=state.action,
|
||||
againstdir=todir}
|
||||
return false
|
||||
elseif y >= starty and dignode.name == "air" then
|
||||
state.action = {"place", pos=thispos, item=state.action.wall, successaction=state.action}
|
||||
return false
|
||||
elseif (y >= starty and dignode.name ~= state.action.wall)
|
||||
or (y < starty and dignode.name ~= "air" and
|
||||
dignode.name:sub(1, state.action.door:len())
|
||||
~= state.action.door) then
|
||||
state.action = {"dig", pos=thispos, successaction=state.action}
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
state.action.atcpos = false
|
||||
state.action.cpos = state.action.cpos + 1
|
||||
if state.action.cpos > toleft + toback + toright + tofront + toleft2 then
|
||||
dbg.v1(state.ent.name.." has completed outer circuit of walls")
|
||||
return true, true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Calculate RELATIVE direction to move
|
||||
local movedir
|
||||
if state.action.cpos == 0 then
|
||||
movedir = {x=0, z=-1}
|
||||
elseif state.action.cpos <= toleft then
|
||||
movedir = {x=-1, z=0}
|
||||
elseif state.action.cpos <= toleft + toback then
|
||||
movedir = {x=0, z=1}
|
||||
elseif state.action.cpos <= toleft + toback + toright then
|
||||
movedir = {x=1, z=0}
|
||||
elseif state.action.cpos <= toleft + toback + toright + tofront then
|
||||
movedir = {x=0, z=-1}
|
||||
else
|
||||
movedir = {x=-1, z=0}
|
||||
end
|
||||
movedir.y = 0
|
||||
|
||||
-- Rotate the movement direction to world orientation...
|
||||
local wmovedir = rotate(movedir, state.action.dir)
|
||||
|
||||
local newdest = vector.add(vector.round(state.pos), wmovedir)
|
||||
|
||||
if state.action.outside_floor and state.action.cpos > 1 and
|
||||
state.action.cpos < toleft + toback + toright + tofront + toleft2 then
|
||||
|
||||
local floor = state.action.outside_floor
|
||||
local altfloor = nil
|
||||
if type(floor) == "table" then
|
||||
floor = state.action.outside_floor[1]
|
||||
altfloor = state.action.outside_floor[2]
|
||||
end
|
||||
|
||||
local thispos = {x=newdest.x, y=newdest.y - 1, z=newdest.z}
|
||||
local dignode = minetest.get_node(thispos)
|
||||
if dignode.name == "air" then
|
||||
state.action = {"place", pos=thispos, item=floor, successaction=state.action}
|
||||
return false
|
||||
elseif dignode.name ~= floor and dignode.name ~= altfloor then
|
||||
state.action = {"dig", pos=thispos, successaction=state.action}
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- Make sure the area outside the walls is clear as we go round
|
||||
for y = 0, state.action.height - 1 do
|
||||
local thispos = {x=newdest.x, y=newdest.y + y, z=newdest.z}
|
||||
local dignode = minetest.get_node(thispos)
|
||||
if dignode.name ~= "air" then
|
||||
state.action = {"dig", pos=thispos, successaction=state.action}
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
dbg.v3(state.ent.name.." circling to "..minetest.pos_to_string(newdest)..
|
||||
", cpos="..state.action.cpos..", movedir="..minetest.pos_to_string(movedir)..
|
||||
", wmovedir="..minetest.pos_to_string(wmovedir))
|
||||
state.action.atcpos = true
|
||||
state.action = {"go", pos=newdest, successaction=state.action}
|
||||
return false
|
||||
|
||||
end
|
||||
|
|
@ -75,6 +75,7 @@ people.actions.buy = function(state)
|
|||
local repeats = math.ceil(state.action.num / shopinfo.saleunit)
|
||||
local cashneeded = repeats * shopinfo.price
|
||||
|
||||
dbg.v3(state.ent.name.." trying to put $"..cashneeded.." into shop")
|
||||
if not currency.remove_from_inv(state.ent.inventory, "main", cashneeded) then
|
||||
dbg.v1(state.ent.name.." doesn't have enough money to buy")
|
||||
return true, false
|
||||
|
@ -83,8 +84,14 @@ people.actions.buy = function(state)
|
|||
-- to check and roll back, as we do for getting money
|
||||
currency.put_to_inv(shopinv, "exchange", cashneeded)
|
||||
|
||||
local bought = 0
|
||||
while repeats > 0 do
|
||||
if not barrel.do_buy(shopinfo.pos) then break end
|
||||
local success, msg = barrel.do_buy(shopinfo.pos)
|
||||
if not success then
|
||||
dbg.v3(state.ent.name.." failed during buy loop - shop said: "..msg)
|
||||
break
|
||||
end
|
||||
bought = bought + shopinfo.saleunit
|
||||
repeats = repeats - 1
|
||||
end
|
||||
|
||||
|
@ -92,12 +99,12 @@ people.actions.buy = function(state)
|
|||
dbg.v1(state.ent.name.." couldn't retrieve everything from shop inventory")
|
||||
end
|
||||
|
||||
dbg.v1(state.ent.name.." finished buy action")
|
||||
dbg.v1(state.ent.name.." finished buy action - bought "..bought.." "..state.action.item)
|
||||
return true, true
|
||||
end
|
||||
|
||||
people.actions.sell = function(state)
|
||||
if not (state.action.item) then
|
||||
if not state.action.item then
|
||||
dbg.v1(state.ent.name.." has invalid sell action")
|
||||
return true, false
|
||||
end
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
|
||||
local dbg
|
||||
if moddebug then dbg=moddebug.dbg("people") else dbg={v1=function() end,v2=function() end,v3=function() end} end
|
||||
|
||||
people.actions.claimplot = function(state)
|
||||
|
||||
if not state.action.name or type(state.action.name) ~= "string" then
|
||||
dbg.v1(state.ent.name.." has invalid claimplot action")
|
||||
return true, false
|
||||
end
|
||||
|
||||
local destpos = footpath.get_nodepos(name)
|
||||
if destpos then
|
||||
dbg.v1(state.ent.name.." can't claim "..state.action.name.." - it already exists")
|
||||
return true, false
|
||||
end
|
||||
|
||||
if not state.action.at then
|
||||
local plot = footpath.nearest_vacant_plot(state.pos)
|
||||
if not plot then
|
||||
dbg.v1(state.ent.name.." can't claim "..state.action.name.." - there are no free plots")
|
||||
return true, false
|
||||
end
|
||||
state.action.at = plot.name
|
||||
state.action = {"go", name=plot.name, successaction=state.action}
|
||||
return false
|
||||
end
|
||||
|
||||
local result = footpath.claim_plot(state.action.at, state.action.name)
|
||||
if result ~= true then
|
||||
dbg.v1(state.ent.name.." failed to claim plot "..state.action.name.." at "..state.action.at.." - "..result)
|
||||
return true, false
|
||||
end
|
||||
|
||||
dbg.v1(state.ent.name.." claimed plot "..state.action.name.." at "..state.action.at)
|
||||
return true, true
|
||||
|
||||
end
|
|
@ -0,0 +1,80 @@
|
|||
|
||||
local dbg
|
||||
if moddebug then dbg=moddebug.dbg("people") else dbg={v1=function() end,v2=function() end,v3=function() end} end
|
||||
|
||||
people.actions.craft = function(state)
|
||||
|
||||
if type(state.action.num) ~= "number" then
|
||||
dbg.v1(state.ent.name.." has invalid num for craft action")
|
||||
return true, false
|
||||
end
|
||||
if type(state.action.item) ~= "string" then
|
||||
dbg.v1(state.ent.name.." has invalid item for craft action")
|
||||
return true, false
|
||||
end
|
||||
-- TODO check it's a real item too!
|
||||
|
||||
local recipes = minetest.get_all_craft_recipes(state.action.item)
|
||||
if not recipes or #recipes == 0 then
|
||||
dbg.v2(state.ent.name.." can't craft "..state.action.item.. " - no recipes")
|
||||
return true, false
|
||||
end
|
||||
|
||||
local tomake = state.action.num
|
||||
for _, recipe in pairs(recipes) do
|
||||
dbg.v3(state.ent.name.." trying recipe "..minetest.serialize(recipe))
|
||||
if recipe.type == "normal" then
|
||||
local output = ItemStack(recipe.output)
|
||||
local needed = {}
|
||||
for _, item in pairs(recipe.items) do
|
||||
|
||||
-- TODO - we can't handle groups in recipes here yet, so
|
||||
-- we'll just translate things as we come across
|
||||
-- them for now.
|
||||
if item == "group:stick" then
|
||||
item = "default:stick"
|
||||
elseif item == "group:wood" then
|
||||
item = "default:wood"
|
||||
end
|
||||
|
||||
if needed[item] then
|
||||
needed[item] = needed[item] + 1
|
||||
else
|
||||
needed[item] = 1
|
||||
end
|
||||
end
|
||||
|
||||
while tomake > 0 do
|
||||
local gotingredients = true
|
||||
for item, count in pairs(needed) do
|
||||
if not state.ent.inventory:contains_item("main", ItemStack(item.." "..count)) then
|
||||
dbg.v3(state.ent.name.." doesn't have the "..count.." "..item.." needed")
|
||||
gotingredients = false
|
||||
break
|
||||
end
|
||||
end
|
||||
if not gotingredients then break end
|
||||
for item, count in pairs(needed) do
|
||||
state.ent.inventory:remove_item("main", ItemStack(item.." "..count))
|
||||
end
|
||||
state.ent.inventory:add_item("main", output)
|
||||
dbg.v3(state.ent.name.." crafted "..output:get_count().." "..state.action.item)
|
||||
tomake = tomake - output:get_count()
|
||||
end
|
||||
|
||||
else
|
||||
dbg.v3(state.ent.name.." doesn't know how to do '"..recipe.type.."'")
|
||||
end
|
||||
end
|
||||
|
||||
if tomake <= 0 then
|
||||
dbg.v1(state.ent.name.." successfully crafted "..state.action.num.." "..state.action.item)
|
||||
return true, true
|
||||
end
|
||||
|
||||
dbg.v1(state.ent.name.." couldn't craft (any or enough) "..state.action.item)
|
||||
return true, false
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -40,6 +40,7 @@ people.actions.dig = function(state)
|
|||
-- * selecting correct tool
|
||||
-- * proper drops (e.g. custom handlers in other mods)
|
||||
local n = minetest.get_node(state.action.pos)
|
||||
local dign = n.name
|
||||
|
||||
|
||||
if false then
|
||||
|
@ -94,7 +95,7 @@ people.actions.dig = function(state)
|
|||
return true, false
|
||||
end
|
||||
end
|
||||
dbg.v1(state.ent.name.." dug "..n.name.." at "..minetest.pos_to_string(state.action.pos))
|
||||
dbg.v1(state.ent.name.." dug "..dign.." at "..minetest.pos_to_string(state.action.pos))
|
||||
|
||||
return true, true
|
||||
|
||||
|
|
180
actions/go.lua
180
actions/go.lua
|
@ -14,6 +14,12 @@ local PNTP = 0.5
|
|||
|
||||
people.actions.go = function(state)
|
||||
|
||||
if state.action.rel then
|
||||
state.action.pos = vector.add(vector.round(state.pos), state.action.rel)
|
||||
dbg.v2(state.ent.name.." converted relative go to destination "..minetest.pos_to_string(state.action.pos))
|
||||
state.action.rel = nil
|
||||
end
|
||||
|
||||
if (not state.action.pos) and (not state.action.footpathdest) and state.action.name then
|
||||
|
||||
-- The action says to go to a named place. We're going to convert this
|
||||
|
@ -35,7 +41,7 @@ people.actions.go = function(state)
|
|||
-- 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 pathstartnode = footpath.nearest_node(state.pos)
|
||||
local pathstartnode = footpath.nearest_junction(state.pos)
|
||||
if pathstartnode then
|
||||
dbg.v2(state.ent.name.." selected path start "..pathstartnode.name.." at "..minetest.pos_to_string(pathstartnode.pos))
|
||||
state.action.pos = vector.new(pathstartnode.pos)
|
||||
|
@ -65,9 +71,9 @@ people.actions.go = function(state)
|
|||
if not state.action.pos and state.action.footpathdest then
|
||||
|
||||
-- path handling - only comes here when we've arrived at a new path square
|
||||
-- (note, the range passed to nearest_node determines our lookahead distance
|
||||
-- (note, the range passed to nearest_junction determines our lookahead distance
|
||||
dbg.v3(state.ent.name.." at new footpath node at "..minetest.pos_to_string(state.pos))
|
||||
local curpathnode, distance = footpath.nearest_node(state.pos, nil, 10)
|
||||
local curpathnode, distance = footpath.nearest_junction(state.pos, nil, 10)
|
||||
if curpathnode and curpathnode.pos.x == state.pos.x and curpathnode.pos.z == state.pos.z then
|
||||
|
||||
if curpathnode.name == state.action.footpathdest then
|
||||
|
@ -77,6 +83,36 @@ people.actions.go = function(state)
|
|||
state.action.pos = state.action.endpos
|
||||
return false
|
||||
end
|
||||
if state.action.faceexit then
|
||||
local jct = footpath.get_junction(curpathnode.name)
|
||||
if not jct then
|
||||
dbg.v1(state.ent.name.." couldn't do faceexit at "..curpathnode.name.." - no such junction")
|
||||
return true, false
|
||||
end
|
||||
local fdir = nil
|
||||
for dir, exit in pairs(jct.exits) do
|
||||
if exit == state.action.faceexit then
|
||||
fdir = dir
|
||||
break
|
||||
end
|
||||
end
|
||||
if not fdir then
|
||||
dbg.v1(state.ent.name.." couldn't do faceexit at "..curpathnode.name.." - no such exit")
|
||||
return truen, false
|
||||
end
|
||||
local fpos
|
||||
if fdir == "n" then
|
||||
fpos = vector.add(state.pos, {x=0, y=0, z=1})
|
||||
elseif fdir == "s" then
|
||||
fpos = vector.add(state.pos, {x=0, y=0, z=-1})
|
||||
elseif fdir == "e" then
|
||||
fpos = vector.add(state.pos, {x=1, y=0, z=0})
|
||||
else
|
||||
fpos = vector.add(state.pos, {x=-1, y=0, z=0})
|
||||
end
|
||||
state.yaw = vector.get_yaw(state.pos, fpos)
|
||||
dbg.v2(state.ent.name.." set faceexit yaw of "..state.yaw)
|
||||
end
|
||||
return true, true
|
||||
end
|
||||
|
||||
|
@ -129,7 +165,7 @@ people.actions.go = function(state)
|
|||
-- extra 0.5 allowing for dodgy step-ups, for now...
|
||||
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 = footpath.findnext(thispathpos, state.action.lastpathpos, false)
|
||||
local nextpathpos, digit = footpath.findnext(thispathpos, state.action.lastpathpos, false)
|
||||
if nextpathpos == "unloaded" then
|
||||
state.wait = 1
|
||||
dbg.v3(state.ent.name.." waiting for block load")
|
||||
|
@ -143,15 +179,15 @@ people.actions.go = function(state)
|
|||
end
|
||||
|
||||
if not distance or distance > 10 then distance = 10 end
|
||||
while distance > 2 do
|
||||
while distance > 2 and not digit do
|
||||
-- Look ahead a bit while going in a straight line, to increase speed
|
||||
local aheadpathpos = footpath.findnext(nextpathpos, thispathpos, true)
|
||||
local aheadpathpos, digit = 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 and not digit then
|
||||
thispathpos = nextpathpos
|
||||
nextpathpos = aheadpathpos
|
||||
distance = distance - 1
|
||||
|
@ -161,6 +197,10 @@ people.actions.go = function(state)
|
|||
end
|
||||
state.action.lastpathpos = thispathpos
|
||||
state.action.pos = vector.add(nextpathpos, {x=0, y=0.5, z=0})
|
||||
if digit then
|
||||
dbg.v3(state.ent.name.." clearing snow from path at "..minetest.pos_to_string(state.action.pos))
|
||||
state.action={"go", pos=state.action.pos, prevaction={"dig", pos=vector.add(nextpathpos, {x=0, y=1, z=0}), prevaction=state.action}}
|
||||
end
|
||||
dbg.v3(state.ent.name.." set next footpath dest "..minetest.pos_to_string(state.action.pos))
|
||||
return false
|
||||
|
||||
|
@ -190,9 +230,9 @@ people.actions.go = function(state)
|
|||
-- If it's a long way to the destination position, see if we can find
|
||||
-- a route using a footpath instead.
|
||||
if footpath and distance > 30 and not state.action.footpathdest then
|
||||
local pathstartnode = footpath.nearest_node(state.pos, nil, distance)
|
||||
local pathstartnode = footpath.nearest_junction(state.pos, nil, distance)
|
||||
if pathstartnode then
|
||||
local pathdestnode = footpath.nearest_node(state.action.pos, nil, distance)
|
||||
local pathdestnode = footpath.nearest_junction(state.action.pos, nil, distance)
|
||||
if pathdestarea then
|
||||
state.action.endpos = state.action.pos
|
||||
state.action.pos = vector.new(pathstartnode.pos)
|
||||
|
@ -271,66 +311,70 @@ people.actions.go = function(state)
|
|||
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 + 2
|
||||
-- How far down we'll look, which needs to be at least this to
|
||||
-- be able to descend stairs.
|
||||
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 == "ignore" then
|
||||
unloaded = true
|
||||
break
|
||||
end
|
||||
nd = minetest.registered_nodes[nn]
|
||||
if not nd then
|
||||
erk = "mysterious " .. nn
|
||||
break
|
||||
end
|
||||
local gg = nd.groups or {}
|
||||
if gg.water or gg.lava then
|
||||
erk = nn
|
||||
break
|
||||
end
|
||||
-- Don't look at the ahead position if it's the same node we're
|
||||
-- already at...
|
||||
if not vector.equals(vector.round(state.pos), nextpos) then
|
||||
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 = 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 == "ignore" then
|
||||
unloaded = true
|
||||
break
|
||||
end
|
||||
nd = minetest.registered_nodes[nn]
|
||||
if not nd then
|
||||
erk = "mysterious " .. nn
|
||||
break
|
||||
end
|
||||
local gg = nd.groups or {}
|
||||
if gg.water or gg.lava then
|
||||
erk = nn
|
||||
break
|
||||
end
|
||||
|
||||
-- Use 'walkable' to decide if we will bump into, and/or can stand
|
||||
-- on the node. But with a bit of variation. We ignore doors so we
|
||||
-- bump into them on purpose!?
|
||||
local iswalkable = nd.walkable
|
||||
if iswalkable and state.ent.can_use_doors and (
|
||||
(nd.groups.door and nd.groups.door ~= 0) or
|
||||
(nd.groups.gate and nd.groups.gate ~= 0)) then
|
||||
iswalkable = false
|
||||
end
|
||||
-- Use 'walkable' to decide if we will bump into, and/or can stand
|
||||
-- on the node. But with a bit of variation. We ignore doors so we
|
||||
-- bump into them on purpose!?
|
||||
local iswalkable = nd.walkable
|
||||
if iswalkable and state.ent.can_use_doors and (
|
||||
(nd.groups.door and nd.groups.door ~= 0) or
|
||||
(nd.groups.gate and nd.groups.gate ~= 0)) then
|
||||
iswalkable = false
|
||||
end
|
||||
|
||||
if iswalkable and ncount < 6 then
|
||||
break
|
||||
if iswalkable and ncount < 6 then
|
||||
break
|
||||
end
|
||||
if not iswalkable then
|
||||
notwalkable = notwalkable + 1
|
||||
end
|
||||
nextpos.y = nextpos.y - 1
|
||||
ncount = ncount - 1
|
||||
end
|
||||
if not iswalkable then
|
||||
notwalkable = notwalkable + 1
|
||||
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)
|
||||
unwholesome = true
|
||||
end
|
||||
nextpos.y = nextpos.y - 1
|
||||
ncount = ncount - 1
|
||||
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)
|
||||
unwholesome = true
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -338,8 +382,10 @@ people.actions.go = function(state)
|
|||
if distance < 32 then
|
||||
|
||||
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
|
||||
state.action.triedpath = false
|
||||
dbg.v2(state.ent.name.." is waiting before trying a path again ")
|
||||
state.action = {"wait", time=30, prevaction=state.action}
|
||||
return false
|
||||
end
|
||||
|
||||
local spos = vector.new(state.pos)
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
|
||||
local dbg
|
||||
if moddebug then dbg=moddebug.dbg("people") else dbg={v1=function() end,v2=function() end,v3=function() end} end
|
||||
|
||||
people.actions.obtain = function(state)
|
||||
|
||||
if type(state.action.num) ~= "number" then
|
||||
dbg.v1(state.ent.name.." has invalid num for obtain action")
|
||||
return true, false
|
||||
end
|
||||
if type(state.action.item) ~= "string" then
|
||||
dbg.v1(state.ent.name.." has invalid item for obtain action")
|
||||
return true, false
|
||||
end
|
||||
-- TODO check it's a real item too!
|
||||
|
||||
-- See how many we've got, and therefore how many we need...
|
||||
local inv = state.ent.inventory
|
||||
local count = 0
|
||||
for i, stack in ipairs(inv:get_list("main")) do
|
||||
local nn = stack:get_name()
|
||||
if nn == state.action.item then
|
||||
count = count + stack:get_count()
|
||||
end
|
||||
end
|
||||
local needed = state.action.num - count
|
||||
if needed <= 0 then
|
||||
dbg.v2(state.ent.name.." has "..count.." "..state.action.item)
|
||||
return true, true
|
||||
end
|
||||
|
||||
if not state.action.crafted then
|
||||
state.action.crafted = true
|
||||
state.action = {"craft", item=state.action.item, num=needed,
|
||||
prevaction=state.action}
|
||||
return false
|
||||
end
|
||||
|
||||
if not state.action.bought then
|
||||
state.action.bought = true
|
||||
|
||||
-- TODO - Here is where we need knowledge or memory of what goods can
|
||||
-- be purchased where. Before we have that, we're just going to hard
|
||||
-- code a few things to test the concept...
|
||||
local where = nil
|
||||
if state.action.item == "default:wood" then
|
||||
where = "Building Supplies 2"
|
||||
elseif state.action.item == "default:stone" then
|
||||
where = "Building Supplies 1"
|
||||
end
|
||||
if where then
|
||||
state.action = {"go", name=where, prevaction=
|
||||
{"buy", item=state.action.item, num=needed, prevaction=
|
||||
state.action}}
|
||||
return false
|
||||
else
|
||||
dbg.v3(state.ent.name.." doesn't know where to buy "..state.action.item)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
dbg.v1(state.ent.name.." can't obtain "..state.action.item)
|
||||
return true, false
|
||||
|
||||
end
|
||||
|
|
@ -11,7 +11,7 @@ people.actions.place = function(state)
|
|||
end
|
||||
|
||||
local distance = vector.distance(state.pos, state.action.pos)
|
||||
if distance > 5 then
|
||||
if distance > 5.5 then
|
||||
dbg.v1(state.ent.name.." too far away to place - distance is "..distance)
|
||||
return true, false
|
||||
end
|
||||
|
@ -42,15 +42,47 @@ 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, false
|
||||
return true, {"need", item=state.action.item}
|
||||
end
|
||||
|
||||
-- We need a node to build against...
|
||||
local todir = state.action.againstdir
|
||||
if not todir then
|
||||
local trydirs
|
||||
if state.action.againstdir then
|
||||
trydirs = {againstdir}
|
||||
else
|
||||
trydirs = {{x=0, y=-1, z=0},
|
||||
{x=0, y=1, z=0},
|
||||
{x=-1, y=0, z=0},
|
||||
{x=1, y=0, z=0},
|
||||
{x=0, y=0, z=-1},
|
||||
{x=0, y=0, z=1}}
|
||||
end
|
||||
for _, trydir in pairs(trydirs) do
|
||||
local n = minetest.get_node(vector.add(state.action.pos, trydir))
|
||||
if n.name ~= "air" then
|
||||
todir = trydir
|
||||
break
|
||||
end
|
||||
end
|
||||
if not todir then
|
||||
dbg.v1(state.ent.name.." can't place - nothing to build against")
|
||||
return true, false
|
||||
end
|
||||
end
|
||||
|
||||
local pointed_thing = {type="node",
|
||||
under={x=state.action.pos.x,y=state.action.pos.y-1,z=state.action.pos.z},
|
||||
under=vector.add(state.action.pos, todir),
|
||||
above=vector.new(state.action.pos)}
|
||||
onplace = minetest.registered_items[state.action.item].on_place
|
||||
if not onplace then onplace = minetest.item_place end
|
||||
rstack = onplace(ii, people.get_fake_player(state.ent), pointed_thing)
|
||||
-- Setting the param2 here, but nil is acceptable if it wasn't given as a
|
||||
-- parameter to the action (normally it shouldn't need to be - maybe just
|
||||
-- for stairs?)
|
||||
rstack = onplace(ii, people.get_fake_player(state.ent), pointed_thing, state.action.param2)
|
||||
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, true
|
||||
|
|
|
@ -4,32 +4,43 @@ if moddebug then dbg=moddebug.dbg("people") else dbg={v1=function() end,v2=funct
|
|||
|
||||
local function move_items(srcinv, destinv, itemspec)
|
||||
|
||||
local itemname
|
||||
local count = 0
|
||||
if string.sub(itemspec, 1, 1) == "*" then
|
||||
itemname = string.sub(itemspec, 2)
|
||||
itemspec = itemname .. " 99"
|
||||
while true do
|
||||
local stack = srcinv:remove_item("main", ItemStack(itemspec))
|
||||
if stack:get_count() == 0 then break end
|
||||
count = count + stack:get_count()
|
||||
stack = destinv:add_item("main", stack)
|
||||
count = count - stack:get_count()
|
||||
if stack:get_count() ~= 0 then
|
||||
srcinv:add_item("main", stack)
|
||||
break
|
||||
end
|
||||
end
|
||||
local removespec
|
||||
local single = true
|
||||
local keepstack = nil
|
||||
|
||||
if type(itemspec) == "string" then
|
||||
removespec = itemspec
|
||||
else
|
||||
local stack = srcinv:remove_item("main", ItemStack(itemspec))
|
||||
count = count + stack:get_count()
|
||||
itemname = stack:get_name()
|
||||
stack = destinv:add_item("main", stack)
|
||||
count = count - stack:get_count()
|
||||
srcinv:add_item("main", stack)
|
||||
removespec = itemspec[1]
|
||||
if itemspec.keep then
|
||||
keepstack = srcinv:remove_item("main", ItemStack(removespec.." "..itemspec.keep))
|
||||
end
|
||||
end
|
||||
if not removespec:find(" ") then
|
||||
removespec = removespec.." 99"
|
||||
single = false
|
||||
end
|
||||
|
||||
return itemname, count
|
||||
local count = 0
|
||||
while true do
|
||||
local stack = srcinv:remove_item("main", ItemStack(removespec))
|
||||
dbg.v3("remove_item of '"..removespec.."' removed a stack of "..stack:get_count())
|
||||
if stack:get_count() == 0 then break end
|
||||
count = count + stack:get_count()
|
||||
local leftover = destinv:add_item("main", stack)
|
||||
count = count - leftover:get_count()
|
||||
if leftover:get_count() ~= 0 then
|
||||
srcinv:add_item("main", stack)
|
||||
break
|
||||
end
|
||||
if single then break end
|
||||
end
|
||||
|
||||
if keepstack then
|
||||
srcinv:add_item("main", keepstack)
|
||||
end
|
||||
|
||||
return removespec, count
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,268 @@
|
|||
|
||||
local dbg
|
||||
if moddebug then dbg=moddebug.dbg("people") else dbg={v1=function() end,v2=function() end,v3=function() end} end
|
||||
|
||||
local function rotate(rel, dir)
|
||||
if dir.z < 0 then
|
||||
return {x=-rel.x, y=rel.y, z=-rel.z}
|
||||
elseif dir.z > 0 then
|
||||
return {x=rel.x, y=rel.y, z=rel.z}
|
||||
elseif dir.x > 0 then
|
||||
return {x=rel.z, y=rel.y, z=-rel.x}
|
||||
else
|
||||
return {x=-rel.z, y=rel.y, z=rel.x}
|
||||
end
|
||||
end
|
||||
|
||||
people.actions.tunnel = function(state)
|
||||
|
||||
if type(state.action.distance) ~= "number" then
|
||||
dbg.v1(state.ent.name.." has invalid distance for tunnel action")
|
||||
return true, false
|
||||
end
|
||||
if type(state.action.dir) ~= "table" then
|
||||
dbg.v1(state.ent.name.." has invalid dir for tunnel action")
|
||||
return true, false
|
||||
end
|
||||
if state.action.dir.y ~= 0 then
|
||||
dbg.v1(state.ent.name.." has invalid y component of dir for tunnel action")
|
||||
return true, false
|
||||
end
|
||||
if math.abs(state.action.dir.x) + math.abs(state.action.dir.z) ~= 1 then
|
||||
dbg.v1(state.ent.name.." has invalid x/z components of dir for tunnel action")
|
||||
return true, false
|
||||
end
|
||||
|
||||
-- On starting, keep the original position and distance. This will allow
|
||||
-- us to break off and resume if, for example, we run out of materials or
|
||||
-- room to carry the spoils.
|
||||
if not state.action.startpos then
|
||||
state.action.startpos = vector.round(state.pos)
|
||||
state.action.startdist = state.action.distance
|
||||
end
|
||||
|
||||
if(state.action.distance <= 0) then
|
||||
dbg.v1(state.ent.name.." completed tunnelling")
|
||||
return true, true
|
||||
end
|
||||
|
||||
-- digpos will be the base centre of the new cross-sectional area
|
||||
-- we're going to dig.
|
||||
local digpos = vector.add(vector.round(state.pos), state.action.dir)
|
||||
|
||||
-- Tweak (hack) because if we're laying steps, we're standing on them as
|
||||
-- we go down. This sucks, and even more so because we might want to
|
||||
-- skip the steps until another time if we don't have the materials
|
||||
if state.action.dir.y == -1 and state.action.steps and state.action.distance ~= state.action.startdist then
|
||||
digpos.y = digpos.y - 1
|
||||
end
|
||||
|
||||
local relxaxis
|
||||
if state.action.dir.x == 0 then
|
||||
relxaxis = "x"
|
||||
else
|
||||
relxaxis = "z"
|
||||
end
|
||||
|
||||
local height = 2
|
||||
if state.action.dir.y ~= 0 then
|
||||
if state.action.steps then
|
||||
height = 4
|
||||
else
|
||||
height = 3
|
||||
end
|
||||
end
|
||||
|
||||
-- Make it so we dig from top to bottom when tunnelling downwards, and
|
||||
-- bottom to top otherwise.
|
||||
local yfrom, yto, ydir
|
||||
if state.action.dir.y < 0 then
|
||||
yfrom = height
|
||||
yto = 0
|
||||
ydir = -1
|
||||
else
|
||||
yfrom = 0
|
||||
yto = height
|
||||
ydir = 1
|
||||
end
|
||||
|
||||
-- "Special" positions are those where supports and lighting are placed
|
||||
local special_sup = (state.action.startdist - state.action.distance + 2) % 8 == 7
|
||||
local special_light = (state.action.startdist - state.action.distance) % 4 == 3
|
||||
|
||||
-- TODO - the following is all a bit ineffecient, because we look at the
|
||||
-- whole cross-section every time through. We could keep track of
|
||||
-- where we've got to during a run and skip some.
|
||||
|
||||
for y = yfrom, yto, ydir do
|
||||
for x = -1, 1 do
|
||||
local thisoff = {x=0, y=y, z=0}
|
||||
thisoff[relxaxis] = x
|
||||
local thispos = vector.add(digpos, thisoff)
|
||||
local dignode = minetest.get_node(thispos)
|
||||
|
||||
-- Steps at the bottom row if needed.
|
||||
if y == 0 and state.action.steps and state.action.dir.y ~= 0 then
|
||||
|
||||
if dignode.name == "air" then
|
||||
state.action = {"place", pos=thispos, item=state.action.steps, successaction=state.action,
|
||||
param2=minetest.dir_to_facedir({x=-state.action.dir.x,y=0,z=-state.action.dir.z}, false)}
|
||||
return false
|
||||
elseif dignode.name ~= state.action.steps then
|
||||
state.action = {"dig", pos=thispos, successaction=state.action}
|
||||
return false
|
||||
end
|
||||
|
||||
elseif y == 2 and x ~= 0 and state.action.lighting and special_light then
|
||||
|
||||
-- We don't actually place lighting (e.g. torches) here,
|
||||
-- because we do walls later and that would disturb them.
|
||||
-- But we need to make sure we don't remove existing ones.
|
||||
if dignode.name ~= "air" and
|
||||
dignode.name ~= state.action.lighting then
|
||||
state.action = {"dig", pos=thispos, successaction=state.action}
|
||||
return false
|
||||
end
|
||||
|
||||
elseif y == height and state.action.support_top and special_sup then
|
||||
|
||||
if dignode.name == "air" then
|
||||
state.action = {"place", pos=thispos, item=state.action.support_top, successaction=state.action}
|
||||
return false
|
||||
elseif dignode.name ~= state.action.support_top then
|
||||
state.action = {"dig", pos=thispos, successaction=state.action}
|
||||
return false
|
||||
end
|
||||
|
||||
elseif x ~= 0 and state.action.support_side and special_sup then
|
||||
|
||||
if dignode.name == "air" then
|
||||
local param2
|
||||
if state.action.support_side_facein then
|
||||
local facevec = rotate({x=-x, y=0, z=0},
|
||||
state.action.dir)
|
||||
if facevec.x > 0 then
|
||||
param2 = 4 * 4
|
||||
elseif facevec.x < 0 then
|
||||
param2 = 4 * 3
|
||||
elseif facevec.z > 0 then
|
||||
param2 = 4 * 2
|
||||
else
|
||||
param2 = 4 * 1
|
||||
end
|
||||
end
|
||||
state.action = {"place", pos=thispos,
|
||||
item=state.action.support_side,
|
||||
successaction=state.action,
|
||||
param2=param2}
|
||||
return false
|
||||
elseif dignode.name ~= state.action.support_side then
|
||||
state.action = {"dig", pos=thispos, successaction=state.action}
|
||||
return false
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
if dignode.name ~= "air" then
|
||||
state.action = {"dig", pos=thispos, successaction=state.action}
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
if state.action.floor and state.action.dir.y == 0 then
|
||||
for x = -1, 1 do
|
||||
local thisoff = {x=0, y=-1, z=0}
|
||||
thisoff[relxaxis] = x
|
||||
local thispos = vector.add(digpos, thisoff)
|
||||
local dignode = minetest.get_node(thispos)
|
||||
if dignode.name == "air" then
|
||||
state.action = {"place", pos=thispos, item=state.action.floor, successaction=state.action}
|
||||
return false
|
||||
elseif dignode.name ~= state.action.floor then
|
||||
state.action = {"dig", pos=thispos, successaction=state.action}
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local wall = state.action.wall
|
||||
if special_sup and state.action.support_wall then
|
||||
wall = state.action.support_wall
|
||||
end
|
||||
|
||||
if wall then
|
||||
for y = 0, height + 1 do
|
||||
local thisoff = {x=0, y=y, z=0}
|
||||
for x = -2, 2, 4 do
|
||||
thisoff[relxaxis] = x
|
||||
local thispos = vector.add(digpos, thisoff)
|
||||
local dignode = minetest.get_node(thispos)
|
||||
if dignode.name == "air" then
|
||||
state.action = {"place", pos=thispos, item=wall, successaction=state.action}
|
||||
return false
|
||||
elseif dignode.name ~= wall then
|
||||
state.action = {"dig", pos=thispos, successaction=state.action}
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if state.action.lighting and special_light then
|
||||
local thisoff = {x=0, y=2, z=0}
|
||||
for x = -1, 1, 2 do
|
||||
thisoff[relxaxis] = x
|
||||
local thispos = vector.add(digpos, thisoff)
|
||||
local dignode = minetest.get_node(thispos)
|
||||
if dignode.name ~= state.action.lighting then
|
||||
local againstdir = {x=0, y=0, z=0}
|
||||
againstdir[relxaxis] = x
|
||||
state.action = {"place", pos=thispos, item=state.action.lighting, successaction=state.action,
|
||||
againstdir=againstdir}
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local ceiling = state.action.ceiling
|
||||
if special_sup and state.action.support_ceiling then
|
||||
ceiling = state.action.support_ceiling
|
||||
end
|
||||
|
||||
if ceiling then
|
||||
-- We need to place the ceiling nodes against something - we use
|
||||
-- the walls.
|
||||
local againstdir = {x=0, y=0, z=0}
|
||||
againstdir[relxaxis] = -1
|
||||
for x = -1, 1 do
|
||||
local thisoff = {x=0, y=height+1, z=0}
|
||||
thisoff[relxaxis] = x
|
||||
local thispos = vector.add(digpos, thisoff)
|
||||
local dignode = minetest.get_node(thispos)
|
||||
if dignode.name == "air" then
|
||||
state.action = {"place", pos=thispos, item=ceiling, successaction=state.action,
|
||||
againstdir=againstdir}
|
||||
return false
|
||||
elseif dignode.name ~= ceiling then
|
||||
state.action = {"dig", pos=thispos, successaction=state.action}
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- We've cleared the cross-section at the next position, so we can move
|
||||
-- forward a step...
|
||||
state.action.distance = state.action.distance - 1
|
||||
state.action = {"go", pos=digpos, successaction=state.action}
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
|
42
commands.lua
42
commands.lua
|
@ -11,6 +11,7 @@ local get_person = function(args)
|
|||
|
||||
if not args then return nil, nil, nil end
|
||||
|
||||
local person_name
|
||||
person_name, args = string.match(args, "^([^ ]+)(.*)")
|
||||
|
||||
if person_name and not people.is_valid_name(person_name) then
|
||||
|
@ -174,6 +175,47 @@ subcmd.where = {
|
|||
end
|
||||
}
|
||||
|
||||
subcmd.attach = {
|
||||
params = "[<name>]",
|
||||
desc = "Attach to a person (or remove, with no parameter)",
|
||||
exec = function(playername, args)
|
||||
|
||||
if not minetest.check_player_privs(playername, {server=true}) then
|
||||
return false, "Only admins can attach to people"
|
||||
end
|
||||
|
||||
local function removecur(playername)
|
||||
if not people.attach_by_player[playername] then return end
|
||||
local player = minetest.get_player_by_name(playername)
|
||||
player:set_detach()
|
||||
end
|
||||
|
||||
local person, person_name
|
||||
person_name, person, args = get_person(args)
|
||||
if not person then
|
||||
if args then
|
||||
return false, "No such person as "..person_name
|
||||
end
|
||||
if not people.attach_by_player[playername] then
|
||||
return false, "Not attached to a person"
|
||||
end
|
||||
removecur(playername)
|
||||
local n = people.attach_by_player[playername].name
|
||||
people.attach_by_player[playername] = nil
|
||||
return true, "Detached from "..n
|
||||
end
|
||||
removecur(playername)
|
||||
people.attach_by_player[playername] = {name=person_name}
|
||||
local player = minetest.get_player_by_name(playername)
|
||||
local ent = person.entity
|
||||
if not ent then
|
||||
return false, nil, true
|
||||
end
|
||||
player:set_attach(ent.object, "", {x=0,y=0,z=0}, {x=0,y=0,z=0})
|
||||
return true, "Attached to "..person_name
|
||||
end
|
||||
}
|
||||
|
||||
subcmd.track = {
|
||||
params = "[<name>]",
|
||||
desc = "Track a person on the HUD (or remove, with no parameter)",
|
||||
|
|
34
form.lua
34
form.lua
|
@ -25,6 +25,9 @@ minetest.register_on_player_receive_fields(function(sender, formname, fields)
|
|||
"list[current_player;main;0,5;8,4;]"
|
||||
minetest.show_formspec(playername, "people:invform", formspec)
|
||||
|
||||
elseif fields.skin then
|
||||
minetest.show_formspec(playername, "people:skinform", skins.formspec.main(playername))
|
||||
|
||||
elseif fields.program then
|
||||
if string.sub(entity.fcode, 1, 1) ~= "@" then
|
||||
entity.code = fields.code
|
||||
|
@ -33,7 +36,10 @@ minetest.register_on_player_receive_fields(function(sender, formname, fields)
|
|||
end
|
||||
|
||||
-- Some things get reset when programming...
|
||||
entity.gather = {items={}, nodes={}, topnodes={}, plant=nil}
|
||||
entity.gather = {items={}, nodes={}, topnodes={}, plant=nil,
|
||||
animal = nil, -- name of animal to gather from
|
||||
animal_wield = nil, -- when animal set, the item to wield
|
||||
}
|
||||
entity.action = nil
|
||||
entity.wait = 0
|
||||
|
||||
|
@ -64,6 +70,27 @@ minetest.register_on_player_receive_fields(function(sender, formname, fields)
|
|||
|
||||
-- Just a placeholder - doesn't need any handling currently
|
||||
|
||||
elseif formname == "people:skinform" then
|
||||
local playername = sender:get_player_name()
|
||||
local entity = lastformbyplayer[playername]
|
||||
if not entity then return end
|
||||
if playername ~= entity.owner then return end
|
||||
if fields.main then
|
||||
people.show_form(entity, playername)
|
||||
return
|
||||
end
|
||||
for field, _ in pairs(fields) do
|
||||
if string.sub(field,0,string.len("skins_set_")) == "skins_set_" then
|
||||
local req = skins.list[tonumber(string.sub(field,string.len("skins_set_")+1))]
|
||||
entity.props.textures = {req..".png"}
|
||||
entity:update_props()
|
||||
end
|
||||
if string.sub(field,0,string.len("skins_page_")) == "skins_page_" then
|
||||
skins.pages[playername] = tonumber(string.sub(field,string.len("skins_page_")+1))
|
||||
minetest.show_formspec(playername, "people:skinform", skins.formspec.main(playername))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end)
|
||||
|
@ -105,8 +132,9 @@ people.show_form = function(entity, playername)
|
|||
presetnum = 1
|
||||
entity.fcode = "@Example"
|
||||
end
|
||||
formspec = formspec.."button[2.5,6;2.5,1;program;Program]"..
|
||||
"button[5.5,6;2.5,1;inventory;Inventory]"..
|
||||
formspec = formspec.."button[1.5,5;2.5,1;program;Program]"..
|
||||
"button[4,5;2.5,1;inventory;Inventory]"..
|
||||
"button[6.5,5;2.5,1;skin;Skin]"..
|
||||
"label[0,7;Preset]"..
|
||||
"dropdown[2,7;3;preset;"..prelist..";"..presetnum + 1 .."]"
|
||||
else
|
||||
|
|
30
init.lua
30
init.lua
|
@ -4,6 +4,7 @@ if moddebug then dbg=moddebug.dbg("people") else dbg={v1=function() end,v2=funct
|
|||
people = {}
|
||||
|
||||
people.hud_show_by_player = {}
|
||||
people.attach_by_player = {}
|
||||
|
||||
local people_modpath = minetest.get_modpath("people")
|
||||
dofile(people_modpath .. "/commands.lua")
|
||||
|
@ -27,10 +28,15 @@ dofile(people_modpath .. "/actions/place.lua")
|
|||
dofile(people_modpath .. "/actions/gather.lua")
|
||||
dofile(people_modpath .. "/actions/stash_and_retrieve.lua")
|
||||
dofile(people_modpath .. "/actions/buy_and_sell.lua")
|
||||
dofile(people_modpath .. "/actions/obtain.lua")
|
||||
dofile(people_modpath .. "/actions/craft.lua")
|
||||
dofile(people_modpath .. "/actions/attackplayer.lua")
|
||||
dofile(people_modpath .. "/actions/pickup.lua")
|
||||
dofile(people_modpath .. "/actions/rightclicknode.lua")
|
||||
dofile(people_modpath .. "/actions/harvest.lua")
|
||||
dofile(people_modpath .. "/actions/tunnel.lua")
|
||||
dofile(people_modpath .. "/actions/building.lua")
|
||||
dofile(people_modpath .. "/actions/claimplot.lua")
|
||||
|
||||
people.presets = {}
|
||||
for p, priv in pairs({FollowOwner=false,
|
||||
|
@ -38,6 +44,7 @@ for p, priv in pairs({FollowOwner=false,
|
|||
RouteWalker=false,
|
||||
FarmHand=true,
|
||||
CowTest=true,
|
||||
Miner=true,
|
||||
TreeFarmer=true}) do
|
||||
local file = io.open(minetest.get_modpath("people").."/presets/"..p..".lua", "r")
|
||||
local code
|
||||
|
@ -554,23 +561,28 @@ minetest.register_entity("people:person" ,{
|
|||
|
||||
if action_done then
|
||||
|
||||
local lastaction = state.action
|
||||
|
||||
if state.action.prevaction then
|
||||
dbg.v3(state.ent.name.." completed action - setting previous action")
|
||||
dbg.v3(state.ent.name.." completed action - setting prevaction")
|
||||
self.action = state.action.prevaction
|
||||
else
|
||||
if(action_success) then
|
||||
if action_success == true then
|
||||
dbg.v3(state.ent.name.." completed action")
|
||||
if state.action.successaction then
|
||||
dbg.v3(state.ent.name.." completed action - setting successaction")
|
||||
self.action = state.action.successaction
|
||||
else
|
||||
self.action = nil
|
||||
end
|
||||
else
|
||||
dbg.v3(state.ent.name.." failed action")
|
||||
end
|
||||
|
||||
if not action_success then
|
||||
local event = {type="actfail"}
|
||||
dbg.v3(state.ent.name.." failed action: "..minetest.serialize(action_success))
|
||||
self.action = nil
|
||||
local event = {type="actfail", failedaction=lastaction, failcode=action_success}
|
||||
local err = people.exec_event(self, event)
|
||||
if err then dbg.v1("Lua error "..err) end
|
||||
end
|
||||
|
||||
self.action = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -716,6 +728,7 @@ people.exec_event = function(ent, event)
|
|||
|
||||
local env = ent.env
|
||||
env.action = ent.action
|
||||
env.name = ent.name
|
||||
env.gather = ent.gather
|
||||
env.mem = ent.memory
|
||||
env.carrying = function(item)
|
||||
|
@ -733,6 +746,7 @@ people.exec_event = function(ent, event)
|
|||
local inv = ent.inventory
|
||||
return currency.count_money(inv, "main")
|
||||
end
|
||||
env.vector = vector
|
||||
|
||||
env.event = event
|
||||
|
||||
|
|
|
@ -132,16 +132,17 @@ if event.type == "program" then
|
|||
{"go", pos={x=174, y=11.5, z=320}},
|
||||
|
||||
{"go", pos={x=174, y=11.5, z=341}},
|
||||
{"stash", dest="default:chest", items={"*farming:weed", "*farming:cotton",
|
||||
"*farming:wheat", "*farming_plus:carrot_item", "*farming:seed_wheat",
|
||||
"*farming_plus:rhubarb_item",
|
||||
"*farming_plus:carrot_seed", "*farming:seed_cotton",
|
||||
"*farming_plus:tomato_seed", "*farming_plus:tomato_item",
|
||||
"*farming_plus:rhubarb_seed", "*farming_plus:orange_seed",
|
||||
"*farming_plus:potato_seed", "*farming_plus:potato_item",
|
||||
"*farming_plus:orange_item",
|
||||
"*farming_plus:strawberry_item", "*farming_plus:strawberry_seed",
|
||||
"*farming_plus:cocoa", "default:tree"}},
|
||||
{"stash", dest="default:chest", items={"farming:weed", "farming:cotton",
|
||||
"farming:wheat", "farming_plus:carrot_item", "farming:seed_wheat",
|
||||
"farming_plus:rhubarb_item",
|
||||
"farming_plus:carrot_seed", "farming:seed_cotton",
|
||||
"farming_plus:tomato_seed", "farming_plus:tomato_item",
|
||||
"farming_plus:rhubarb_seed", "farming_plus:orange_seed",
|
||||
"farming_plus:potato_seed", "farming_plus:potato_item",
|
||||
"farming_plus:orange_item",
|
||||
"farming:pumpkin",
|
||||
"farming_plus:strawberry_item", "farming_plus:strawberry_seed",
|
||||
"farming_plus:cocoa", "default:tree"}},
|
||||
|
||||
{"go", pos={x=174, y=11.5, z=320}},
|
||||
|
||||
|
@ -165,14 +166,13 @@ if event.type == "program" then
|
|||
|
||||
-- Chuck all harvested stuff in the recycle bin. It will end up
|
||||
-- at the factory.
|
||||
{"go", name="path_Jeiffel Tower"},
|
||||
{"go", name="Jeiffel Recycle Bin"},
|
||||
{"wait", time=5},
|
||||
{"go", pos={x=-221,y=1.5,z=-187}},
|
||||
{"stash", dest="default:chest",
|
||||
items={"*default:tree",
|
||||
"*default:leaves",
|
||||
"*default:apple",
|
||||
"*default:sapling"}},
|
||||
items={"default:tree",
|
||||
"default:leaves",
|
||||
"default:apple",
|
||||
"default:sapling"}},
|
||||
|
||||
-- Turn off gathering now
|
||||
{"gather"},
|
||||
|
@ -181,19 +181,18 @@ if event.type == "program" then
|
|||
-- ********************
|
||||
-- Head f0r the cactus farm, but get some flowers on the way
|
||||
--
|
||||
{"go", name="path_Jeiffel Station"},
|
||||
{"gather", nodes={"flowers:geranium",
|
||||
"flowers:rose",
|
||||
"flowers:dandelion_white",
|
||||
"flowers:dandelion_yellow",
|
||||
"flowers:viola",
|
||||
"flowers:tulip"}},
|
||||
{"go", name="path_Cactus Approach"},
|
||||
{"go", name="Near Cactusville"},
|
||||
{"gather"},
|
||||
|
||||
-- ********************
|
||||
-- Cactus Farm
|
||||
{"go", name="path_Cactus Farm"},
|
||||
{"go", name="Cactus Farm"},
|
||||
{"wait", time=10},
|
||||
{"gather", topnodes={"default:cactus"}},
|
||||
{"go", pos={x=-34, y=11.5, z=-462}},
|
||||
|
@ -203,14 +202,14 @@ if event.type == "program" then
|
|||
{"go", pos={x=-33, y=11.5, z=-465}},
|
||||
{"go", pos={x=-34, y=11.5, z=-462}},
|
||||
{"gather"},
|
||||
{"go", name="path_Cactusville Square"},
|
||||
{"stash", items={"*default:cactus",
|
||||
"*flowers:geranium",
|
||||
"*flowers:rose",
|
||||
"*flowers:dandelion_white",
|
||||
"*flowers:dandelion_yellow",
|
||||
"*flowers:viola",
|
||||
"*flowers:tulip",
|
||||
{"go", name="Cactusville Square"},
|
||||
{"stash", items={"default:cactus",
|
||||
"flowers:geranium",
|
||||
"flowers:rose",
|
||||
"flowers:dandelion_white",
|
||||
"flowers:dandelion_yellow",
|
||||
"flowers:viola",
|
||||
"flowers:tulip",
|
||||
}, dest="default:chest"},
|
||||
|
||||
|
||||
|
@ -223,15 +222,13 @@ if event.type == "program" then
|
|||
{"go", pos={x=153, y=4.5, z=203}},
|
||||
{"go", pos={x=156, y=4.5, z=202}},
|
||||
{"go", pos={x=156, y=4.5, z=199}},
|
||||
{"stash", items={"*default:papyrus"}, dest="default:chest"},
|
||||
{"stash", items={"default:papyrus"}, dest="default:chest"},
|
||||
{"go", pos={x=156, y=4.5, z=202}},
|
||||
{"go", pos={x=153, y=4.5, z=203}},
|
||||
{"go", name="path_Industrial Estate"},
|
||||
|
||||
-- *****************
|
||||
-- A bit of random wandering f0r test purposes
|
||||
{"go", name="path_Building Supplies Shop"},
|
||||
{"wait", time=10},
|
||||
{"go", name="path_Mia's Shop"},
|
||||
{"wait", time=10},
|
||||
{"go", name="path_Adventure Shop"},
|
||||
|
|
|
@ -0,0 +1,231 @@
|
|||
|
||||
local MODE_selling = 1 -- Sell stuff
|
||||
local MODE_inventory = 2 -- Manage our inventory
|
||||
local MODE_mining = 3 -- Do mining
|
||||
local MODE_exitmine = 4 -- Get out of the mine
|
||||
local MODE_minebuilding = 5 -- Build the mine building
|
||||
local MODE_homebuilding = 6 -- Build a home
|
||||
local MODE_panic = 7 -- Don't know what to do
|
||||
|
||||
local inventory_actions = {
|
||||
|
||||
-- All these have a prevaction on to prevent them raising errors.
|
||||
-- We still (probably) want to try and carry on mining if we're
|
||||
-- missing some materials - maybe we'll be able to get them later.
|
||||
{"obtain", item="stairs:stair_cobble", num=40, prevaction={"wait", time=1}},
|
||||
{"obtain", item="default:stone", num=40, prevaction={"wait", time=1}},
|
||||
{"obtain", item="default:wood", num=40, prevaction={"wait", time=1}},
|
||||
{"obtain", item="stairs:slab_wood", num=20, prevaction={"wait", time=1}},
|
||||
{"obtain", item="default:stick", num=40, prevaction={"wait", time=1}},
|
||||
{"obtain", item="default:torch", num=20, prevaction={"wait", time=1}},
|
||||
|
||||
{"go", name="Jeiffel Recycle Bin", successaction={"stash",
|
||||
dest="default:chest",
|
||||
items={{"default:dirt", keep=50},
|
||||
{"default:cobble", keep=50},
|
||||
"default:snow",
|
||||
"default:gravel"
|
||||
}
|
||||
}},
|
||||
|
||||
{"go", name="Miner Willy's"}
|
||||
|
||||
}
|
||||
|
||||
if event.type == "program" then
|
||||
mem.mode = MODE_selling
|
||||
mem.cur = 1
|
||||
mem.lastxmode = MODE_mining
|
||||
mem.needed = {}
|
||||
|
||||
elseif event.type == "actfail" then
|
||||
|
||||
if mem.mode == MODE_inventory or mem.mode == MODE_selling or
|
||||
mem.mode == MODE_minebuilding or mem.mode == MODE_homebuilding then
|
||||
|
||||
if type(event.failcode) == "table" and event.failcode[1] == "need" then
|
||||
table.insert(mem.needed, event.failcode.item)
|
||||
end
|
||||
|
||||
action = {"wait", time=5}
|
||||
mem.mode = MODE_selling
|
||||
mem.cur = 1
|
||||
elseif mem.mode == MODE_mining then
|
||||
mem.mode = MODE_exitmine
|
||||
mem.cur = #mem.exitmine
|
||||
elseif mem.mode == MODE_exitmine then
|
||||
-- If something goes wrong when exiting the mine, just keep
|
||||
-- trying
|
||||
action = {"wait", time=5}
|
||||
mem.cur = mem.cur + 1
|
||||
else
|
||||
mem.mode = MODE_panic
|
||||
end
|
||||
|
||||
elseif event.type == "act" then
|
||||
|
||||
if mem.mode == MODE_selling then
|
||||
|
||||
if carrying("default:iron_lump") > 0 then
|
||||
action = {"go", name="Mineral Shop", successaction={"sell", item="default:iron_lump"}}
|
||||
return
|
||||
end
|
||||
-- TODO - need to sell excess coal here, but the sell action currently
|
||||
-- doesn't allow an amount to be specified, so we'd sell it all!
|
||||
mem.mode = MODE_inventory
|
||||
mem.cur = 1
|
||||
action = {"wait", time=1}
|
||||
|
||||
elseif mem.mode == MODE_inventory then
|
||||
|
||||
if #mem.needed > 0 then
|
||||
action={"obtain", item=mem.needed[1], num=1, prevaction={"wait", time=1}}
|
||||
table.remove(mem.needed, 1)
|
||||
return
|
||||
end
|
||||
|
||||
action = inventory_actions[mem.cur]
|
||||
mem.cur = mem.cur + 1
|
||||
if mem.cur > #inventory_actions then
|
||||
|
||||
if mem.lastxmode == MODE_minebuilding then
|
||||
mem.mode = MODE_mining
|
||||
elseif mem.lastxmode == MODE_mining then
|
||||
mem.mode = MODE_homebuilding
|
||||
elseif mem.lastxmode == MODE_homebuilding then
|
||||
mem.mode = MODE_mining
|
||||
end
|
||||
mem.lastxmode = mem.mode
|
||||
mem.cur = 1
|
||||
end
|
||||
|
||||
elseif mem.mode == MODE_mining then
|
||||
|
||||
if mem.cur == 1 then
|
||||
action = {"go", name="Miner Willy's",
|
||||
successaction={"gather", items={"default:torch"}}}
|
||||
mem.exitmine = {}
|
||||
mem.cur = 2
|
||||
elseif mem.cur == 2 then
|
||||
|
||||
-- Select some materials to fancy up the tunnel, if we're carrying
|
||||
-- them. If not, we'll do it without them and they'll get done
|
||||
-- another time.
|
||||
local steps = nil
|
||||
local wall_and_floor = nil
|
||||
local support_c = nil
|
||||
local support_s = nil
|
||||
local lighting = nil
|
||||
if carrying("stairs:stair_cobble") > 3 then
|
||||
steps = "stairs:stair_cobble"
|
||||
if carrying("default:wood") > 3 then
|
||||
support_c = "default:wood"
|
||||
end
|
||||
if carrying("stairs:slab_wood") > 3 then
|
||||
support_s = "stairs:slab_wood"
|
||||
end
|
||||
if carrying("default:stone") > 10 then
|
||||
wall_and_floor = "default:stone"
|
||||
end
|
||||
end
|
||||
if carrying("default:torch") > 1 then
|
||||
lighting = "default:torch"
|
||||
end
|
||||
|
||||
action = {"tunnel", distance=40, dir={x=0,y=-1,z=-1}, steps=steps,
|
||||
lighting=lighting, support_ceiling=support_c,
|
||||
support_side=support_s,
|
||||
support_side_facein=true,
|
||||
wall=wall_and_floor, floor=wall_and_floor}
|
||||
action.successaction= {"tunnel", distance=8, dir={x=0,y=0,z=-1},
|
||||
lighting=lighting, floor=wall_and_floor,
|
||||
ceiling=wall_and_floor}
|
||||
action.successaction.successaction={"go", rel={x=1,y=0,z=2}}
|
||||
table.insert(mem.exitmine, {"go", name="Miner Willy's"})
|
||||
mem.cur = 3
|
||||
|
||||
elseif mem.cur == 3 then
|
||||
|
||||
action = {"tunnel", distance=20, dir={x=1,y=-1,z=0}, steps="stairs:stair_cobble",
|
||||
lighting="default:torch", wall="default:stone", floor="default:stone"}
|
||||
action.successaction=
|
||||
{"tunnel", distance=8, dir={x=1,y=0,z=0}, lighting="default:torch", successaction=
|
||||
{"go", rel={x=-1,y=0,z=1}} }
|
||||
table.insert(mem.exitmine, {"go", pos=vector.subtract(pos, {x=1,y=0,z=0})})
|
||||
mem.cur = 4
|
||||
|
||||
elseif mem.cur == 4 then
|
||||
mem.mode = MODE_exitmine
|
||||
mem.cur = #mem.exitmine
|
||||
action = {"wait", time=1}
|
||||
end
|
||||
|
||||
elseif mem.mode == MODE_exitmine then
|
||||
if mem.cur == 0 or not mem.exitmine then
|
||||
mem.exitmine = nil
|
||||
mem.mode = MODE_selling
|
||||
mem.cur = 1
|
||||
action = {"gather"}
|
||||
else
|
||||
action = mem.exitmine[mem.cur]
|
||||
mem.cur = mem.cur - 1
|
||||
end
|
||||
|
||||
elseif mem.mode == MODE_minebuilding then
|
||||
|
||||
if mem.cur == 1 then
|
||||
action = {"go", name="Miner Willy's"}
|
||||
mem.cur = 2
|
||||
elseif mem.cur == 2 then
|
||||
action = {"building", dir={x=0,y=-1,z=-1},
|
||||
width=5, depth=7, height=5,
|
||||
wall="default:stone",
|
||||
ceiling="default:wood",
|
||||
outside_floor={"default:dirt", "default:dirt_with_grass"},
|
||||
door="doors:door_wood"
|
||||
}
|
||||
mem.cur = 3
|
||||
else
|
||||
mem.mode = MODE_selling
|
||||
mem.cur = 1
|
||||
action = {"wait", time=5}
|
||||
end
|
||||
|
||||
elseif mem.mode == MODE_homebuilding then
|
||||
|
||||
local home_jctname = "people_"..name.."_home"
|
||||
|
||||
if mem.cur == 1 then
|
||||
-- Attempt to claim our plot. If we already have it, this will fail
|
||||
-- and we'll just do the wait.
|
||||
action = {"claimplot", name=home_jctname, prevaction={"wait", time=1}}
|
||||
mem.cur = 2
|
||||
elseif mem.cur == 2 then
|
||||
action = {"go", name=home_jctname, faceexit="@build"}
|
||||
mem.cur = 3
|
||||
elseif mem.cur == 3 then
|
||||
|
||||
-- We'd better be facing the right way!!
|
||||
local bdir = vector.round(vector.from_speed_yaw(1, yaw))
|
||||
|
||||
action = {"building", dir=bdir,
|
||||
width=5, depth=5, height=4,
|
||||
wall="default:stone",
|
||||
ceiling="default:wood",
|
||||
outside_floor={"default:dirt", "default:dirt_with_grass"},
|
||||
door="doors:door_wood"
|
||||
}
|
||||
mem.cur = 4
|
||||
else
|
||||
mem.mode = MODE_selling
|
||||
mem.cur = 1
|
||||
action = {"wait", time=5}
|
||||
end
|
||||
|
||||
else
|
||||
action = {"wait", time=600}
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -25,10 +25,10 @@ if event.type == "program" then
|
|||
{"wait", time=5},
|
||||
{"go", pos={x=-221,y=1.5,z=-187}},
|
||||
{"stash", dest="default:chest",
|
||||
items={"*default:tree",
|
||||
"*default:leaves",
|
||||
"*default:apple",
|
||||
"*default:sapling"}}
|
||||
items={"default:tree",
|
||||
"default:leaves",
|
||||
"default:apple",
|
||||
"default:sapling"}}
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue