210 lines
7.6 KiB
Lua
210 lines
7.6 KiB
Lua
|
|
-- helper function for get_path_from_pos_to_plot
|
|
mg_villages.next_step_on_road_path = function( p, this_road_xdir, following_road )
|
|
if( this_road_xdir == true ) then
|
|
if( p.x < following_road.x ) then
|
|
p.x = following_road.x;
|
|
else
|
|
p.x = following_road.x + following_road.bsizex -1;
|
|
end
|
|
else
|
|
if( p.z < following_road.z ) then
|
|
p.z = following_road.z;
|
|
else
|
|
p.z = following_road.z + following_road.bsizez -1;
|
|
end
|
|
end
|
|
return p;
|
|
end
|
|
|
|
|
|
-- pos needs to be a position either on a road or at max 1 node away from a road
|
|
mg_villages.get_path_from_pos_to_plot_via_roads = function( village_id, pos, target_plot_nr )
|
|
if( not( mg_villages.all_villages[ village_id ] )
|
|
or not( target_plot_nr )
|
|
or not( mg_villages.all_villages[ village_id ].to_add_data.bpos[ target_plot_nr ])
|
|
or not( mg_villages.all_villages[ village_id ].to_add_data.bpos[ target_plot_nr ].road_nr)) then
|
|
return {};
|
|
end
|
|
local bpos_list = mg_villages.all_villages[ village_id ].to_add_data.bpos;
|
|
|
|
-- find out which road is the one next to pos
|
|
local standing_on_road = nil;
|
|
local roads = mg_villages.get_road_list( village_id, false );
|
|
for i,road in ipairs( roads ) do
|
|
local r = bpos_list[ road ]; -- road data
|
|
-- if this is really a road, and if a parent road exists (or is 0)
|
|
if( r and r.btype == "road" and r.parent_road_plot
|
|
-- ..and pos is in the area of the road or next to it
|
|
and pos.x >= r.x-1 and pos.x <= r.x + r.bsizex + 1
|
|
and pos.z >= r.z-1 and pos.z <= r.z + r.bsizez + 1
|
|
and pos.y >= r.y-4 and pos.y <= r.y + 4 ) then
|
|
standing_on_road = i;
|
|
end
|
|
end
|
|
-- nothing found
|
|
if( not( standing_on_road )) then
|
|
return;
|
|
end
|
|
|
|
-- walk from pos up to the main road
|
|
local start_to_main_road = {};
|
|
local next_road_plot = roads[ standing_on_road ];
|
|
while( next_road_plot and bpos_list[ next_road_plot ] and bpos_list[ next_road_plot ].btype=="road" ) do
|
|
table.insert( start_to_main_road, next_road_plot );
|
|
next_road_plot = bpos_list[ next_road_plot ].parent_road_plot;
|
|
end
|
|
|
|
-- walk from the target road up to the main road - until we find a road that is
|
|
-- already part of the path from pos to the main road
|
|
local target_to_main_road = {};
|
|
local next_road_plot = roads[ bpos_list[ target_plot_nr ].road_nr ];
|
|
local match_found = -1;
|
|
while( next_road_plot and bpos_list[ next_road_plot ] and bpos_list[ next_road_plot ].btype=="road" and match_found==-1) do
|
|
-- it may not be necessary to go all the way back to the main road
|
|
for i,r in ipairs( start_to_main_road ) do
|
|
if( r == next_road_plot ) then
|
|
match_found = i;
|
|
end
|
|
end
|
|
if( match_found == -1) then
|
|
table.insert( target_to_main_road, next_road_plot );
|
|
end
|
|
next_road_plot = bpos_list[ next_road_plot ].parent_road_plot;
|
|
end
|
|
|
|
if( match_found == -1 ) then
|
|
match_found = #start_to_main_road;
|
|
end
|
|
-- we may have gone too far up and can take a turn much earlier
|
|
local start_to_target = {};
|
|
for i=1,match_found do
|
|
table.insert( start_to_target, start_to_main_road[i] );
|
|
end
|
|
|
|
-- combine the full walk through the tree-like road structure into one list of roads
|
|
for i=#target_to_main_road,1,-1 do
|
|
table.insert( start_to_target, target_to_main_road[i] );
|
|
end
|
|
|
|
-- generate a path for travelling on these roads
|
|
local path = {};
|
|
|
|
-- let the mob take the first step onto the road
|
|
local first_road = bpos_list[ start_to_target[1] ];
|
|
local p = {x=pos.x, y=first_road.y+1, z=pos.z};
|
|
p = mg_villages.next_step_on_road_path( p, not(first_road.xdir), first_road );
|
|
table.insert( path, {x=p.x, y=p.y, z=p.z} );
|
|
|
|
-- travel using all the given roads
|
|
for i=1,#start_to_target-1 do
|
|
local this_road = bpos_list[ start_to_target[i] ];
|
|
local following_road = bpos_list[ start_to_target[i+1]];
|
|
-- walk on the inside in curves instead of taking longer paths
|
|
p = mg_villages.next_step_on_road_path( p, this_road.xdir, following_road );
|
|
table.insert( path, {x=p.x, y=p.y, z=p.z} );
|
|
end
|
|
|
|
-- walk on the last road to the target plot
|
|
local last_road = bpos_list[ start_to_target[ #start_to_target ] ];
|
|
local target = {x=bpos_list[ target_plot_nr ].x + math.floor(bpos_list[ target_plot_nr ].bsizex/2),
|
|
y = p.y,
|
|
z=bpos_list[ target_plot_nr ].z + math.floor(bpos_list[ target_plot_nr ].bsizez/2),
|
|
bsizex = 2, bsizez = 2};
|
|
p = mg_villages.next_step_on_road_path( p, last_road.xdir, target);
|
|
table.insert( path, {x=p.x, y=p.y, z=p.z} );
|
|
|
|
-- take the very last step and leave the road
|
|
p = mg_villages.next_step_on_road_path( p, not(last_road.xdir), target);
|
|
-- make sure we do not walk further than one step into the plot
|
|
if( p.x < last_road.x ) then
|
|
p.x = last_road.x - 1;
|
|
elseif( p.x >= last_road.x + last_road.bsizex ) then
|
|
p.x = last_road.x + last_road.bsizex + 1;
|
|
elseif( p.z < last_road.z ) then
|
|
p.z = last_road.z - 1;
|
|
elseif( p.z >= last_road.z + last_road.bsizez ) then
|
|
p.z = last_road.z + last_road.bsizez + 1;
|
|
end
|
|
table.insert( path, {x=p.x, y=p.y, z=p.z} );
|
|
|
|
--[[
|
|
-- if you want to visualize the path with yellow wool blocks for debugging, uncomment this
|
|
local str = " path: ";
|
|
for i,p in ipairs( path ) do
|
|
minetest.set_node( p, {name="wool:yellow"});
|
|
str = str.." "..minetest.pos_to_string( p );
|
|
end
|
|
minetest.chat_send_player("singleplayer","roads to walk on: "..minetest.serialize( start_to_target)..str);
|
|
--]]
|
|
return path;
|
|
end
|
|
|
|
-- try to reconstruct the tree-like road network structure (the data was
|
|
-- not saved completely from the beginning)
|
|
mg_villages.get_road_list = function( village_id, force_check )
|
|
if( not( mg_villages.all_villages[ village_id ] )) then
|
|
return {};
|
|
end
|
|
local bpos_list = mg_villages.all_villages[ village_id ].to_add_data.bpos;
|
|
local roads = {};
|
|
for i,pos in ipairs( bpos_list ) do
|
|
if( pos.btype and pos.btype=="road" ) then
|
|
-- store the plot nr for each road nr
|
|
roads[ pos.road_nr ] = i;
|
|
-- store weather the road streches in x- or z-direction
|
|
if( pos.bsizex >= pos.bsizez) then
|
|
pos.xdir = true;
|
|
else
|
|
pos.xdir = false;
|
|
end
|
|
end
|
|
end
|
|
-- a village without roads (i.e. a single house)
|
|
if( not( roads[1])) then
|
|
return {};
|
|
end
|
|
-- the parent roads have already been identified
|
|
if( not( force_check ) and bpos_list[ roads[ 1 ]].parent_road_plot == 0 ) then
|
|
return roads;
|
|
end
|
|
|
|
-- assume that road nr. 1 is the main road (which it is due to the way villages are constructed)
|
|
bpos_list[ roads[ 1 ]].parent_road_plot = 0;
|
|
|
|
-- identify all parent roads
|
|
for i=1,#roads do
|
|
if( bpos_list[ roads[i] ].parent_road_plot ) then
|
|
mg_villages.mark_roads_that_branch_off( bpos_list, roads, roads[i] );
|
|
end
|
|
end
|
|
|
|
return roads;
|
|
end
|
|
|
|
|
|
-- changes bpos_list and sets bpos_list[ road ].parent_road_plot = plot_nr for those roads where
|
|
-- plot_nr contains the road from which road branches off
|
|
mg_villages.mark_roads_that_branch_off = function( bpos_list, roads, plot_nr )
|
|
-- see which roads branch off from this parent road
|
|
local parent_road = bpos_list[ plot_nr ];
|
|
for i,road in ipairs( roads ) do
|
|
local r = bpos_list[ road ]; -- road data
|
|
-- if the road is not yet connected to another one
|
|
if( r.parent_road_plot == nil
|
|
-- and if it is 90 degree rotated compared to the potential parent road
|
|
and( r.xdir ~= parent_road.xdir )
|
|
-- and if one end lies inside the parent road
|
|
and( (r.x >= parent_road.x and r.x <= parent_road.x + parent_road.bsizex)
|
|
or(r.x+r.bsizex >= parent_road.x and r.x+r.bsizex <= parent_road.x + parent_road.bsizex))
|
|
and( (r.z >= parent_road.z and r.z <= parent_road.z + parent_road.bsizez)
|
|
or(r.z+r.bsizez >= parent_road.z and r.z+r.bsizez <= parent_road.z + parent_road.bsizez))) then
|
|
|
|
-- store plot_nr instead of road_nr as that is more useful
|
|
bpos_list[ road ].parent_road_plot = plot_nr;
|
|
end
|
|
end
|
|
end
|
|
|
|
|