Add mg_villages dependency
parent
0325ddf021
commit
2a826c2dc4
|
@ -0,0 +1,3 @@
|
|||
This is a continuation of my (Sokomines) fork of Nores mg mapgen.
|
||||
The fork can be found under https://github.com/Sokomine/mg
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
|
||||
-- helper function for mg_villages.analyze_building_for_mobs_update_paths
|
||||
-- "res" is the raw data as provided by analyze_file
|
||||
-- "node_name" is the name of the node we are looking for
|
||||
mg_villages.analyze_building_for_mobs_search_nodes = function( res, node_name, check_place_for_standing )
|
||||
local node_positions = {};
|
||||
-- find out if the building contains any of the nodes we are looking for
|
||||
local found = -1;
|
||||
for i,n in ipairs( res.nodenames ) do
|
||||
if( n == node_name ) then
|
||||
found = i;
|
||||
end
|
||||
end
|
||||
-- that node does not exist in the building
|
||||
if( found == -1 ) then
|
||||
return {};
|
||||
end
|
||||
|
||||
for z = 1, res.size.z do
|
||||
for y = 1, res.size.y do
|
||||
for x = 1, res.size.x do
|
||||
if( res.scm_data_cache[y]
|
||||
and res.scm_data_cache[y][x]
|
||||
and res.scm_data_cache[y][x][z]
|
||||
and res.scm_data_cache[y][x][z][1] == found ) then
|
||||
|
||||
if( (check_place_for_standing==false)
|
||||
) then
|
||||
-- or ( mob_world_interaction.can_stand_in_node_type( TODO )
|
||||
-- and mob_world_interaction.can_stand_in_node_type( TODO ))) then
|
||||
table.insert( node_positions, {x=x, y=y, z=z, p2=res.scm_data_cache[y][x][z][2]});
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return node_positions;
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
-- changes path_info and adds paths from beds and workplaces to front of building
|
||||
-- path_info[ short_file_name ] contains the paths from the beds
|
||||
-- path_info[ short_file_name.."|WORKPLACE" ] contains the paths from the workplaces
|
||||
-- creates building_data.all_entrances
|
||||
-- creates building_data.workplace_list
|
||||
mg_villages.analyze_building_for_mobs_update_paths = function( file_name, building_data, path_info )
|
||||
|
||||
local short_file_name = string.sub(file_name, mg_villages.file_name_offset, 256);
|
||||
building_data.short_file_name = short_file_name;
|
||||
|
||||
if( not( minetest.get_modpath( "mob_world_interaction" ))) then
|
||||
return building_data;
|
||||
end
|
||||
|
||||
-- identify front doors and paths to them from the beds
|
||||
-- TODO: provide a more general list with beds, work places etc.
|
||||
if( building_data.bed_list
|
||||
and #building_data.bed_list > 0 ) then
|
||||
if(not( path_info[ short_file_name ])) then
|
||||
print("BEDS in "..tostring( short_file_name )..":");
|
||||
path_info[ short_file_name ] = mob_world_interaction.find_all_front_doors( building_data, building_data.bed_list );
|
||||
end
|
||||
-- we are looking for the places in front of the front doors; not the front doors themshelves
|
||||
building_data.all_entrances = {};
|
||||
for i,e in ipairs( path_info[ short_file_name ] ) do
|
||||
-- the last entry in the list for the first bed is what we are looking for
|
||||
-- (provided there actually is a path)
|
||||
if( e[1] and #e[1]>0 ) then
|
||||
table.insert( building_data.all_entrances, e[1][ #e[1] ]);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- some buildings (i.e. a tavern, school, shop, church, ...) contain places where a mob working
|
||||
-- there will most likely be standing, awaiting his guests/doing his job. Such places can be
|
||||
-- manually marked by placing mg_villages:mob_workplace_marker
|
||||
|
||||
-- this is diffrent information from the normal bed list
|
||||
local store_as = short_file_name.."|WORKPLACE";
|
||||
if(not( path_info[ store_as ] )) then
|
||||
local workplace_list = mg_villages.analyze_building_for_mobs_search_nodes( building_data, "mg_villages:mob_workplace_marker", false );
|
||||
|
||||
if( workplace_list and #workplace_list>0) then
|
||||
-- store it for later use
|
||||
building_data.workplace_list = workplace_list;
|
||||
|
||||
print("WORKPLACE: "..tostring( building_data.short_file_name )..": "..minetest.serialize( workplace_list ));
|
||||
path_info[ store_as ] = mob_world_interaction.find_all_front_doors( building_data, workplace_list );
|
||||
|
||||
-- if no entrances are known yet, then store them now; the entrances associated with
|
||||
-- beds are considered to be more important. This here is only a fallback if no beds
|
||||
-- exist in the house.
|
||||
if( not( building_data.all_entrances )) then
|
||||
-- we are looking for the places in front of the front doors; not the front doors themshelves
|
||||
building_data.all_entrances = {};
|
||||
for i,e in ipairs( path_info[ store_as ] ) do
|
||||
-- might just be the place outside the house instead of a door
|
||||
if( e[1] and #e[1]>0 ) then
|
||||
table.insert( building_data.all_entrances, e[1][ #e[1] ]);
|
||||
end
|
||||
end
|
||||
end
|
||||
-- else
|
||||
-- print("NO workplace found in "..tostring(building_data.short_file_name ));
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
TODO: check if 2 nodes above the target node are air or walkable;
|
||||
TODO: exceptions to that: bench (only 1 above needs to be walkable)
|
||||
TODO: other exceptions: furnace, chests, washing place: place in front is wanted - not on top
|
||||
TODO: search for:
|
||||
local pos_list = mg_villages.analyze_building_for_mobs_search_nodes( building_data, "farming:soil_wet", true );
|
||||
farming:soil farming:soil_wet
|
||||
cottages:straw_ground
|
||||
default:chest cottages:shelf cottages:chest_storage cottages:chest_private cottages:chest_work
|
||||
cottages:bench (cottages:table?)
|
||||
cottages:washing
|
||||
default:furnace
|
||||
cottages:barrel (and variants); cottages:tub
|
||||
|
||||
default:ladder
|
||||
default:fence_wood cottages:gate_closed cottages:gate_open
|
||||
any door...
|
||||
any hatch...
|
||||
--]]
|
||||
|
||||
-- some debug information
|
||||
if( mg_villages.DEBUG_LEVEL and mg_villages.DEBUG_LEVEL == mg_villages.DEBUG_LEVEL_TIMING ) then
|
||||
local str2 = " in "..short_file_name.." ["..building_data.typ.."]";
|
||||
if( not( path_info[ short_file_name ] )
|
||||
and not( path_info[ store_as ] )) then
|
||||
str2 = "nothing of intrest (no bed, no workplace)"..str2;
|
||||
elseif( path_info[ short_file_name ]
|
||||
and (#path_info[ short_file_name ]<1
|
||||
or #path_info[ short_file_name ][1]<1
|
||||
or #path_info[ short_file_name ][1][1]<1 )) then
|
||||
str2 = "BROKEN paths for beds"..str2;
|
||||
elseif( path_info[ store_as ]
|
||||
and (#path_info[ store_as ]<1
|
||||
or #path_info[ store_as ][1]<1
|
||||
or #path_info[ store_as ][1][1]<1 )) then
|
||||
str2 = "BROKEN paths for workplaces"..str2;
|
||||
else
|
||||
if( path_info[ store_as ] ) then
|
||||
str2 = tostring( #path_info[ store_as ][1]-1 )..
|
||||
" workplaces"..str2;
|
||||
else
|
||||
str2 = "no workplaces"..str2;
|
||||
end
|
||||
if( path_info[ short_file_name ] ) then
|
||||
str2 = tostring( #path_info[ short_file_name ][1]-1 )..
|
||||
" beds and "..str2;
|
||||
else
|
||||
str2 = "no beds and "..str2;
|
||||
end
|
||||
end
|
||||
print( str2 );
|
||||
end
|
||||
return building_data;
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- Calls mg_villages.analyze_building_for_mobs_update_paths and evaluates the output:
|
||||
-- * determines the position of front doors (building_data.front_door_list)
|
||||
-- * position of beds (building_data.bed_list)
|
||||
-- * places where mobs can stand when they got up from their bed or want
|
||||
-- to go to bed (building_data.stand_next_to_bed_list)
|
||||
-- * amount of usable beds in the house (building_data.bed_count)
|
||||
-- * position of workplaces where a currently working mob may want to
|
||||
-- stand (i.e. behind a shop's counter, next to a machine, in front
|
||||
-- of the class/congregation, ..) (building_data.workplace_list)
|
||||
-- Returns: Updated building_data with the values mentionned above set.
|
||||
-- building_data Information about the building as gained from registration
|
||||
-- and from handle_schematics.analze_file(..)
|
||||
-- file_name with complete path to the schematic
|
||||
-- path_info Data structure where path_info (paths from doors to beds etc.)
|
||||
-- is cached.
|
||||
mg_villages.analyze_building_for_mobs = function( building_data, file_name, path_info )
|
||||
|
||||
-- identify front doors, calculate paths from beds/workplaces to front of house
|
||||
building_data = mg_villages.analyze_building_for_mobs_update_paths( file_name, building_data, path_info );
|
||||
|
||||
-- building_data.bed_list and building_data.workspace_list are calculated withhin
|
||||
-- the above function - provided they are not part of path_info yet;
|
||||
-- the information stored in path_info is the relevant one for mob movement/pathfinding
|
||||
|
||||
-- store the front doors in extra list
|
||||
building_data.front_door_list = {};
|
||||
-- gain the list of beds from path_info data
|
||||
building_data.bed_list = {};
|
||||
-- mobs are seldom able to stand directly on or even next to the bed when getting up
|
||||
building_data.stand_next_to_bed_list = {};
|
||||
-- have any beds been found?
|
||||
if( building_data.short_file_name
|
||||
and path_info[ building_data.short_file_name ] ) then
|
||||
local paths = path_info[ building_data.short_file_name];
|
||||
if( paths and paths[1] ) then
|
||||
-- iterate over all bed-to-first-front-door-paths (we want to identify beds)
|
||||
for i,p in ipairs( paths[1] ) do
|
||||
-- the last entry has a diffrent meaning
|
||||
if( p and p[1] and i<#paths[1]) then
|
||||
-- param2 is the 5th parameter
|
||||
building_data.bed_list[i] = {p[1][1],p[1][2],p[1][3],p[1][5]};
|
||||
-- also store where the mob may stand
|
||||
if( p[2] ) then
|
||||
building_data.stand_next_to_bed_list[i] = p[2];
|
||||
end
|
||||
end
|
||||
end
|
||||
-- iterate over all paths and take a look at the first bed only (we want to
|
||||
-- get the doors now, not the beds)
|
||||
for i,p in ipairs( paths ) do
|
||||
-- paths[i]: paths from all beds to front door i
|
||||
-- paths[i][1]: path from first bed to front door i
|
||||
if( p and p[1] ) then
|
||||
-- the place in front of the door is the last entry
|
||||
local d = p[1][ #p[1] ];
|
||||
building_data.front_door_list[i] = {d[1],d[2],d[3]};
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- make sure this refers to the same data as building_data.bed_list
|
||||
building_data.bed_count = #building_data.bed_list;
|
||||
|
||||
-- gain the list of workplaces from the path_info data
|
||||
building_data.workplace_list = {};
|
||||
-- have any workplaces been found?
|
||||
if( building_data.short_file_name
|
||||
and path_info[ building_data.short_file_name.."|WORKPLACE" ] ) then
|
||||
local paths = path_info[ building_data.short_file_name.."|WORKPLACE"];
|
||||
if( paths and paths[1] ) then
|
||||
for i,p in ipairs( paths[1] ) do
|
||||
if( p and p[1] and i<#paths[1]) then
|
||||
building_data.workplace_list[i] = {p[1][1],p[1][2],p[1][3],p[1][4]};
|
||||
end
|
||||
end
|
||||
-- no front doors found through beds? then take a look if the workplaces found doors
|
||||
if( #building_data.front_door_list < 1 ) then
|
||||
for i,p in ipairs( paths ) do
|
||||
if( p and p[1] ) then
|
||||
local d = p[1][ #p[1] ];
|
||||
building_data.front_door_list[i] = {d[1],d[2],d[3]};
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return building_data;
|
||||
end
|
|
@ -0,0 +1,425 @@
|
|||
-- scm="bla" Name of the file that holds the buildings' schematic. Supported types: .we and .mts (omit the extension!)
|
||||
-- sizex, sizez, ysize: obsolete
|
||||
-- yoff=0 how deep is the building burried?
|
||||
-- pervillage=1 Never generate more than this amount of this building and this type (if set) of building per village.
|
||||
-- axis=1 Building needs to be mirrored along the x-axis instead of the z-axis because it is initially rotated
|
||||
-- inh=2 maximum amount of inhabitants the building may hold (usually amount of beds present)
|
||||
-- if set to i.e. -1, this indicates that a mob is WORKING, but not LIVING here
|
||||
-- we_origin Only needed for very old .we files (savefile format version 3) which do not start at 0,0,0 but have an offset.
|
||||
-- price Stack that has to be paid in order to become owner of the plot the building stands on and the building;
|
||||
-- overrides mg_villages.prices[ building_typ ].
|
||||
-- guests Negative value, i.e. -2: 2 of the beds will belong to the family working here; the rest will be guests.
|
||||
-- For building type "chateau", guest names the number of servants/housemaids instead of guests.
|
||||
|
||||
mg_villages.all_buildings_list = {}
|
||||
|
||||
local buildings = {
|
||||
|
||||
-- the houses the mod came with
|
||||
{yoff= 0, scm="house_1_0", typ='house', weight={nore=1, single=2 }, inh=4},
|
||||
{yoff= 0, scm="wheat_field", typ='field', weight={nore=1 }, inh=-1},
|
||||
{yoff= 0, scm="cotton_field", typ='field', weight={nore=1 }, inh=-1},
|
||||
{yoff= 1, scm="lamp", no_rotate=true, typ='lamp', weight={nore=1/5 }},
|
||||
{yoff=-5, scm="well", no_rotate=true, pervillage=1, typ='well', weight={nore=1 }},
|
||||
{yoff= 0, scm="fountain", pervillage=3, typ='fountain', weight={nore=1/4 }, axis=1},
|
||||
{yoff= 0, scm="small_house_1_0", typ='house', weight={nore=1, single=2 }, inh=2},
|
||||
{yoff= 0, scm="house_with_garden_1_0", typ='house', weight={nore=1, single=2 }, inh=3},
|
||||
{yoff= 0, scm="church_1_0", pervillage=1, typ='church', weight={nore=1 }, inh=-1},
|
||||
{yoff= 0, scm="tower_1_0", typ='tower', weight={nore=1/7, single=1 }, inh=-1},
|
||||
{yoff= 0, scm="forge_1_0", pervillage=2, typ='forge', weight={nore=1, single=1/3 }, inh=-1},
|
||||
{yoff= 0, scm="library_1_0", pervillage=2, typ='library', weight={nore=1 }, inh=-1},
|
||||
{yoff= 0, scm="inn_1_0", pervillage=4, typ='inn', weight={nore=1/2, single=1/3 }, inh=-1, guests=-2}, -- has room for 4 guests
|
||||
{yoff= 0, scm="pub_1_0", pervillage=2, typ='tavern', weight={nore=1/3, single=1/3 }, inh=-1},
|
||||
|
||||
|
||||
-- log cabins by Sokomine (requiring cottages, glasspanes)
|
||||
{yoff= 0, scm="logcabin1", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=2, typ='hut'},
|
||||
{yoff= 0, scm="logcabin2", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=2, typ='hut'},
|
||||
{yoff= 0, scm="logcabin3", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=3, typ='hut'},
|
||||
{yoff= 0, scm="logcabin4", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=3, typ='hut'},
|
||||
{yoff= 0, scm="logcabin5", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=1, typ='hut'},
|
||||
{yoff= 0, scm="logcabin6", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=1, typ='hut'},
|
||||
{yoff= 0, scm="logcabin7", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=2, typ='hut'},
|
||||
{yoff= 0, scm="logcabin8", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=2, typ='hut'},
|
||||
{yoff= 0, scm="logcabin9", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=1, typ='hut'},
|
||||
{yoff= 0, scm="logcabin10", orients={2}, weight={logcabin=1, single=1}, inh=3, typ='hut'},
|
||||
{yoff= 0, scm="logcabin11", orients={1}, weight={logcabin=1, single=1}, inh=6, typ='hut'},
|
||||
{yoff= 0, scm="logcabinpub1", orients={1}, weight={logcabin=1/6, single=1}, pervillage=1, typ='tavern', axis=1, inh=1, guests=-2}, -- +5 guests
|
||||
{yoff= 0, scm="logcabinpub2", orients={1}, weight={logcabin=1/6, single=1}, pervillage=1, typ='tavern', axis=1, inh=2, guests=-3}, -- +8 guests
|
||||
{yoff= 0, scm="logcabinpub3", orients={1}, weight={logcabin=1/6, single=1}, pervillage=1, typ='tavern', axis=1, inh=2, guests=-4}, -- +12 guest
|
||||
|
||||
-- grass huts (requiring cottages, dryplants, cavestuff/undergrowth, plantlife)
|
||||
{yoff= 0, scm="grasshut1_1_90", weight={grasshut=1, single=1}, nomirror=1, typ='hut'},
|
||||
{yoff= 0, scm="grasshut2_1_90", weight={grasshut=1, single=1}, nomirror=1, typ='townhall'}, -- community hut for meetings
|
||||
{yoff= 0, scm="grasshut3_1_90", weight={grasshut=1, single=1}, nomirror=1, typ='hut'},
|
||||
{yoff= 0, scm="grasshut4_1_90", weight={grasshut=1, single=1}, nomirror=1, typ='hut'},
|
||||
{yoff= 0, scm="grasshut5_1_90", weight={grasshut=1, single=1}, nomirror=1, typ='hut'},
|
||||
{yoff= 0, scm="grasshut6_1_90", weight={ single=1}, nomirror=1, typ='hut'},
|
||||
{yoff= 0, scm="grasshutcenter_1_90", pervillage=1, weight={grasshut=2}, nomirror=1, typ = 'tavern'}, -- open meeting place
|
||||
|
||||
-- for the buildings below, sizex, sizez and ysize are read from the file directly;
|
||||
|
||||
-- schematics from Sokomines villages mod (requires cottages)
|
||||
{scm="church_1", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='church', weight={medieval=4 }, pervillage=1, inh=-1},
|
||||
-- {scm="church_2_twoelk", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='church', weight={medieval=4}, pervillage=1},
|
||||
{scm="forge_1", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='forge', weight={medieval=2, single=1/2}, pervillage=1, inh=-1},
|
||||
{scm="mill_1", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='mill', weight={medieval=2 }, pervillage=1, inh=-1},
|
||||
{scm="watermill_1", yoff=-3, orients={1}, farming_plus=0, avoid='', typ='mill', weight={medieval=2 }, pervillage=1, inh=-2},
|
||||
{scm="hut_1", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='hut', weight={medieval=1, single=1 }, inh=1},
|
||||
{scm="hut_2", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='hut', weight={medieval=1, single=1 }, inh=2},
|
||||
{scm="farm_full_1", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='farm_full', weight={medieval=1/4, single=1 }, inh=2},
|
||||
{scm="farm_full_2", yoff= 0, orients={1}, farming_plus=0, avoid='', typ='farm_full', weight={medieval=1/4, single=1 }, inh=5},
|
||||
{scm="farm_full_3", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='farm_full', weight={medieval=1/4, single=1 }, inh=5},
|
||||
{scm="farm_full_4", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='farm_full', weight={medieval=1/4, single=1 }, inh=8},
|
||||
{scm="farm_full_5", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='farm_full', weight={medieval=1/4, single=1 }, inh=5},
|
||||
{scm="farm_full_6", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='farm_full', weight={medieval=1/4, single=1 }, inh=5},
|
||||
{scm="farm_tiny_1", yoff= 0, orients={0}, farming_plus=1, avoid='', typ='farm_tiny', weight={medieval=1, single=1 }, inh=2},
|
||||
{scm="farm_tiny_2", yoff= 0, orients={0}, farming_plus=1, avoid='', typ='farm_tiny', weight={medieval=1, single=1 }, inh=6},
|
||||
{scm="farm_tiny_3", yoff= 0, orients={0}, farming_plus=1, avoid='', typ='farm_tiny', weight={medieval=1, single=1 }, inh=4},
|
||||
{scm="farm_tiny_4", yoff= 0, orients={0}, farming_plus=1, avoid='', typ='farm_tiny', weight={medieval=1, single=1 }, inh=4},
|
||||
{scm="farm_tiny_5", yoff= 0, orients={0}, farming_plus=1, avoid='', typ='farm_tiny', weight={medieval=1, single=1 }, inh=4},
|
||||
{scm="farm_tiny_6", yoff= 0, orients={0}, farming_plus=1, avoid='', typ='farm_tiny', weight={medieval=1, single=1 }, inh=4},
|
||||
{scm="farm_tiny_7", yoff= 0, orients={3}, farming_plus=1, avoid='', typ='farm_tiny', weight={medieval=1, single=1 }, inh=7},
|
||||
{scm="taverne_1", yoff= 0, orients={0}, farming_plus=1, avoid='', typ='tavern', weight={medieval=1/2, single=1 }, pervillage=1, inh=6, guests=-3}, -- 19 beds: 10 guest, 3 worker, 6 family
|
||||
{scm="taverne_2", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='tavern', weight={medieval=1/2, single=1/3}, pervillage=1, inh=2}, -- no guests
|
||||
{scm="taverne_3", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='tavern', weight={medieval=1/2, single=1/3}, pervillage=1, inh=2}, -- no guests
|
||||
{scm="taverne_4", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='tavern', weight={medieval=1/2, single=1/3}, pervillage=1, inh=1}, -- no guests
|
||||
|
||||
{scm="well_1", yoff= 0, orients={0}, farming_plus=0, avoid='well', typ='well', weight={medieval=1/12, single=1/2}, pervillage=4},
|
||||
{scm="well_2", yoff= 0, orients={0}, farming_plus=0, avoid='well', typ='well', weight={medieval=1/12, single=1/2}, pervillage=4},
|
||||
{scm="well_3", yoff= 0, orients={0}, farming_plus=0, avoid='well', typ='well', weight={medieval=1/12, single=1/2}, pervillage=4},
|
||||
{scm="well_4", yoff= 0, orients={0}, farming_plus=0, avoid='well', typ='well', weight={medieval=1/12, single=1/2}, pervillage=4},
|
||||
{scm="well_5", yoff= 0, orients={0}, farming_plus=0, avoid='well', typ='well', weight={medieval=1/12, single=1/2}, pervillage=4},
|
||||
{scm="well_6", yoff= 0, orients={0}, farming_plus=0, avoid='well', typ='well', weight={medieval=1/12, single=1/2}, pervillage=4},
|
||||
{scm="well_7", yoff= -1, orients={0}, farming_plus=0, avoid='well', typ='well', weight={medieval=1/12, single=1/2}, pervillage=4},
|
||||
{scm="well_8", yoff= 0, orients={0}, farming_plus=0, avoid='well', typ='well', weight={medieval=1/12, single=1/2}, pervillage=4},
|
||||
|
||||
{scm="allmende_3_90", yoff=-2, orients={0}, farming_plus=0, avoid='', typ='allmende', weight={medieval=3,taoki=3,nore=3,logcabin=1,grasshut=1}, pervillage=1},
|
||||
|
||||
{scm="tree_place_1", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||
{scm="tree_place_2", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||
{scm="tree_place_3", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||
{scm="tree_place_4", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||
{scm="tree_place_5", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||
{scm="tree_place_6", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||
{scm="tree_place_7", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||
{scm="tree_place_8", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||
{scm="tree_place_9", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||
{scm="tree_place_10", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||
|
||||
{scm="wagon_1", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||
{scm="wagon_2", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||
{scm="wagon_3", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||
{scm="wagon_4", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||
{scm="wagon_5", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||
{scm="wagon_6", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||
{scm="wagon_7", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||
{scm="wagon_8", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||
{scm="wagon_9", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||
{scm="wagon_10", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||
{scm="wagon_11", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||
{scm="wagon_12", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||
|
||||
{scm="bench_1", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='bench', weight={medieval=1/12}, nomirror=1},
|
||||
{scm="bench_2", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='bench', weight={medieval=1/12}, nomirror=1},
|
||||
{scm="bench_3", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='bench', weight={medieval=1/12}, nomirror=1},
|
||||
{scm="bench_4", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='bench', weight={medieval=1/12}, nomirror=1},
|
||||
|
||||
{scm="shed_1", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||
{scm="shed_2", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||
{scm="shed_3", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||
{scm="shed_5", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||
{scm="shed_6", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||
{scm="shed_7", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||
{scm="shed_8", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||
{scm="shed_9", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||
{scm="shed_10", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||
{scm="shed_11", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||
{scm="shed_12", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='stable', weight={medieval=1/10}},
|
||||
|
||||
{scm="weide_1", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='pasture', typ='pasture', weight={medieval=1/6}, pervillage=8},
|
||||
{scm="weide_2", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='pasture', typ='pasture', weight={medieval=1/6}, pervillage=8},
|
||||
{scm="weide_3", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='pasture', typ='pasture', weight={medieval=1/6}, pervillage=8},
|
||||
{scm="weide_4", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='pasture', typ='pasture', weight={medieval=1/6}, pervillage=8},
|
||||
{scm="weide_5", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='pasture', typ='pasture', weight={medieval=1/6}, pervillage=8},
|
||||
{scm="weide_6", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='pasture', typ='pasture', weight={medieval=1/6}, pervillage=8},
|
||||
|
||||
{scm="field_1", yoff=-2, orients={0,1,2,3}, farming_plus=0, avoid='field', typ='field', weight={medieval=1/6}, pervillage=8},
|
||||
{scm="field_2", yoff=-2, orients={0,1,2,3}, farming_plus=0, avoid='field', typ='field', weight={medieval=1/6}, pervillage=8},
|
||||
{scm="field_3", yoff=-2, orients={0,1,2,3}, farming_plus=0, avoid='field', typ='field', weight={medieval=1/6}, pervillage=8},
|
||||
{scm="field_4", yoff=-2, orients={0,1,2,3}, farming_plus=0, avoid='field', typ='field', weight={medieval=1/6}, pervillage=8},
|
||||
|
||||
-- hut and hills for charachoal burners; perhaps they could live together with lumberjacks?
|
||||
{scm="charachoal_hut", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='hut', weight={charachoal=1, single=5}, inh=2, nomirror=1},
|
||||
{scm="charachoal_hill", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='hut', weight={charachoal=2 }, inh=-1, nomirror=1},
|
||||
|
||||
-- lumberjacks; they require the cottages mod
|
||||
{scm="lumberjack_1", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=3},
|
||||
{scm="lumberjack_2", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=4},
|
||||
{scm="lumberjack_3", yoff= 1, orients={1,2,3}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, inh=3},
|
||||
{scm="lumberjack_4", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=4},
|
||||
{scm="lumberjack_5", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=9},
|
||||
{scm="lumberjack_6", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=5},
|
||||
{scm="lumberjack_7", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=5},
|
||||
{scm="lumberjack_8", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=9},
|
||||
{scm="lumberjack_9", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=5},
|
||||
{scm="lumberjack_10", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=2},
|
||||
{scm="lumberjack_11", yoff= 0, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=2},
|
||||
{scm="lumberjack_12", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=3},
|
||||
{scm="lumberjack_13", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=3},
|
||||
{scm="lumberjack_14", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=2},
|
||||
{scm="lumberjack_15", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=2},
|
||||
{scm="lumberjack_16", yoff= 0, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=2},
|
||||
{scm="lumberjack_school", yoff= 1, orients={1}, avoid='', typ='school', weight={lumberjack=2 }, axis=1, inh=1},
|
||||
{scm="lumberjack_stable", yoff= 0, orients={3}, avoid='', typ='horsestable', weight={lumberjack=1, single=3}, axis=1, inh=-1},
|
||||
{scm="lumberjack_pub_1", yoff= 1, orients={1}, avoid='', typ='tavern', weight={lumberjack=3, single=1}, pervillage=1, axis=1, inh=-1},
|
||||
{scm="lumberjack_church_1", yoff= 1, orients={1}, avoid='', typ='church', weight={lumberjack=3}, pervillage=1, axis=1, inh=-1},
|
||||
{scm="lumberjack_hotel_1", yoff= 1, orients={0}, avoid='', typ='inn', weight={lumberjack=1, single=1}, axis=1, inh=16, guests=-1}, -- all but one of the 16 are guests
|
||||
{scm="lumberjack_shop_1", yoff= 1, orients={1}, avoid='', typ='shop', weight={lumberjack=1}, pervillage=1, axis=1, inh=-1},
|
||||
{scm="lumberjack_sawmill_1",yoff=-7, orients={1}, avoid='', typ='sawmill', weight={lumberjack=2, single=1}, pervillage=1, axis=1, inh=-1},
|
||||
|
||||
|
||||
-- {scm="cow_trader_1", yoff= 0, orients={4}, avoid='', typ='trader', weight={lumberjack=1}},
|
||||
|
||||
-- clay traders depend on cottages as well
|
||||
{scm="trader_clay_1", yoff= 1, orients={1}, avoid='', typ='trader', weight={claytrader=3, single=3}, axis=1, inh=1}, -- poor guy who has to live in that small thing
|
||||
{scm="trader_clay_2", yoff= 1, orients={1}, avoid='', typ='trader', weight={claytrader=3, single=3}, axis=1, inh=1}, -- not that he'll live very comftable there...
|
||||
{scm="trader_clay_3", yoff= 1, orients={1}, avoid='', typ='trader', weight={claytrader=3, single=3}, inh=2},
|
||||
{scm="trader_clay_4", yoff= 1, orients={1}, avoid='', typ='trader', weight={claytrader=3, single=3}, inh=2},
|
||||
{scm="trader_clay_5", yoff= 1, orients={1}, avoid='', typ='trader', weight={claytrader=3, single=3}, axis=1, inh=2},
|
||||
|
||||
{scm="clay_pit_1", yoff=-3, orients={0,1,2,3}, avoid='', typ='pit', weight={claytrader=1}},
|
||||
{scm="clay_pit_2", yoff=-1, orients={0,1,2,3}, avoid='', typ='pit', weight={claytrader=1}},
|
||||
{scm="clay_pit_3", yoff=-6, orients={0,1,2,3}, avoid='', typ='pit', weight={claytrader=1}},
|
||||
{scm="clay_pit_4", yoff= 0, orients={0,1,2,3}, avoid='', typ='pit', weight={claytrader=1}},
|
||||
{scm="clay_pit_5", yoff= 1, orients={0,1,2,3}, avoid='', typ='pit', weight={claytrader=1}},
|
||||
|
||||
|
||||
-- Houses from Taokis Structure I/O Mod (see https://forum.minetest.net/viewtopic.php?id=5524)
|
||||
{scm="default_town_farm", yoff= -1, orients={1}, farming_plus=0, avoid='', typ='field', weight={taoki=1, single=1}, axis=1},
|
||||
{scm="default_town_house_large_1", yoff= -4, orients={1}, farming_plus=0, avoid='', typ='house', weight={taoki=1/4, single=1}, axis=1, inh=10},
|
||||
{scm="default_town_house_large_2", yoff= -4, orients={1}, farming_plus=0, avoid='', typ='house', weight={taoki=1/4, single=1}, axis=1, inh=8},
|
||||
{scm="default_town_house_medium", yoff= -4, orients={1}, farming_plus=0, avoid='', typ='house', weight={taoki=1/2, single=1}, axis=1, inh=6},
|
||||
{scm="default_town_house_small", yoff= -4, orients={1}, farming_plus=0, avoid='', typ='house', weight={taoki=1, single=1}, axis=1, inh=4},
|
||||
{scm="default_town_house_tiny_1", yoff= 1, orients={1}, farming_plus=0, avoid='', typ='house', weight={taoki=1, single=1}, axis=1, inh=3},
|
||||
{scm="default_town_house_tiny_2", yoff= 1, orients={1}, farming_plus=0, avoid='', typ='house', weight={taoki=1, single=1}, axis=1, inh=3},
|
||||
{scm="default_town_house_tiny_3", yoff= 1, orients={1}, farming_plus=0, avoid='', typ='house', weight={taoki=1, single=1}, axis=1, inh=2},
|
||||
{scm="default_town_park", yoff= 1, orients={1}, farming_plus=0, avoid='', typ='park', weight={taoki=1 }, axis=1},
|
||||
{scm="default_town_tower", yoff= 1, orients={1}, farming_plus=0, avoid='', typ='tower', weight={taoki=1/6, single=1}, axis=1, inh=-1},
|
||||
{scm="default_town_well", yoff= -6, orients={1}, farming_plus=0, avoid='', typ='well', weight={taoki=1/4 }, axis=1},
|
||||
{scm="default_town_fountain", yoff= 1, orients={1}, farming_plus=0, avoid='', typ='fountain',weight={taoki=1/4 }, axis=1},
|
||||
-- the hotel seems to be only the middle section of the building; it's build for another spawning algorithm
|
||||
-- {scm="default_town_hotel", yoff= -1, orients={1}, farming_plus=0, avoid='', typ='house', weight={taoki=1/5}},
|
||||
|
||||
{scm="tent_tiny_1", yoff=0, orients={3}, farming_plus=0, avoid='', typ='tent', weight={tent=1, single=1}, inh=1},
|
||||
{scm="tent_tiny_2", yoff=0, orients={3}, farming_plus=0, avoid='', typ='tent', weight={tent=1, single=1}, inh=1},
|
||||
{scm="tent_big_1", yoff=0, orients={1}, farming_plus=0, avoid='', typ='shop', weight={tent=1, single=1}}, -- no sleeping place
|
||||
{scm="tent_big_2", yoff=0, orients={3}, farming_plus=0, avoid='', typ='tent', weight={tent=1, single=1}, inh=2},
|
||||
{scm="tent_medium_1", yoff=0, orients={1}, farming_plus=0, avoid='', typ='tent', weight={tent=1/2, single=1}, inh=3},
|
||||
{scm="tent_medium_2", yoff=0, orients={3}, farming_plus=0, avoid='', typ='shed', weight={tent=1/2, single=1}, inh=3},
|
||||
{scm="tent_medium_3", yoff=0, orients={1}, farming_plus=0, avoid='', typ='tent', weight={tent=1/2, single=1}, inh=3},
|
||||
{scm="tent_medium_4", yoff=0, orients={1}, farming_plus=0, avoid='', typ='tent', weight={tent=1/2, single=1}, inh=3},
|
||||
{scm="tent_open_1", yoff=0, orients={3}, farming_plus=0, avoid='', typ='pub', weight={tent=1/5}},
|
||||
{scm="tent_open_2", yoff=0, orients={3}, farming_plus=0, avoid='', typ='shed', weight={tent=1/5}},
|
||||
{scm="tent_open_3", yoff=0, orients={3}, farming_plus=0, avoid='', typ='shop', weight={tent=1/5}},
|
||||
{scm="tent_open_big_1", yoff=0, orients={3}, farming_plus=0, avoid='', typ='pub', weight={tent=1/5}},
|
||||
{scm="tent_open_big_2", yoff=0, orients={3}, farming_plus=0, avoid='', typ='church', weight={tent=1/5}},
|
||||
{scm="tent_open_big_3", yoff=0, orients={3}, farming_plus=0, avoid='', typ='townhall', weight={tent=5}, pervillage=1},
|
||||
|
||||
{scm="hochsitz_1", yoff=0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='tower', weight={tower=1, single=1/3}, nomirror=1},
|
||||
{scm="hochsitz_2", yoff=0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='tower', weight={tower=1, single=1/3}, nomirror=1},
|
||||
{scm="hochsitz_3", yoff=0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='tower', weight={tower=1, single=1/3}, nomirror=1},
|
||||
{scm="hochsitz_4", yoff=0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='tower', weight={tower=1, single=1/3}, nomirror=1},
|
||||
|
||||
{scm="chateau_without_garden", yoff=-1,orients={0,1,2,3}, farming_plus=0, avoid='', typ='chateau', weight={chateau=1,single=8}, pervillage=1, inh=8, guests=-6}, -- 6 family members of the landlord's family; rest are servants
|
||||
|
||||
{scm="baking_house_1", yoff=0, orients={0}, farming_plus=0, avoid='', typ='bakery', weight={medieval=1/4}, pervillage=1, inh=-1},
|
||||
{scm="baking_house_2", yoff=0, orients={0}, farming_plus=0, avoid='', typ='bakery', weight={medieval=1/4}, pervillage=1, inh=-1},
|
||||
{scm="baking_house_3", yoff=0, orients={0}, farming_plus=0, avoid='', typ='bakery', weight={medieval=1/4}, pervillage=1, inh=-1},
|
||||
{scm="baking_house_4", yoff=0, orients={0}, farming_plus=0, avoid='', typ='bakery', weight={medieval=1/4}, pervillage=1, inh=-1},
|
||||
|
||||
{scm="empty_1", yoff=0, typ='empty', inh=0, pervillage=4,
|
||||
weight={nore=1,taoki=1,medieval=1,charachoal=1,lumberjack=1,claytrader=1,logcabin=1,canadian=1,grasshut=1,tent=1}},
|
||||
{scm="empty_2", yoff=0, typ='empty', inh=1, pervillage=4,
|
||||
weight={nore=1,taoki=1,medieval=1,charachoal=1,lumberjack=1,claytrader=1,logcabin=1,canadian=1,grasshut=1,tent=1}},
|
||||
{scm="empty_3", yoff=0, typ='empty', inh=1, pervillage=4,
|
||||
weight={nore=1,taoki=1,medieval=1,charachoal=1,lumberjack=1,claytrader=1,logcabin=1,canadian=1,grasshut=1,tent=1}},
|
||||
{scm="empty_4", yoff=0, typ='empty', inh=1, pervillage=4,
|
||||
weight={nore=1,taoki=1,medieval=1,charachoal=1,lumberjack=1,claytrader=1,logcabin=1,canadian=1,grasshut=1,tent=1}},
|
||||
{scm="empty_5", yoff=0, typ='empty', inh=1, pervillage=4,
|
||||
weight={nore=1,taoki=1,medieval=1,charachoal=1,lumberjack=1,claytrader=1,logcabin=1,canadian=1,grasshut=1,tent=1}},
|
||||
|
||||
{scm="house_medieval_fancy_1_90", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='farm_full', weight={medieval=1/4, single=1 }, inh=6},
|
||||
{scm="cow_shed_1_270", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='stable', weight={medieval=1/4, single=1 }, inh=-1},
|
||||
{scm="shed_with_forge_v2_1_0", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='forge', weight={medieval=1,single=1/2}, inh=1},
|
||||
|
||||
{scm="empty_16x32_2_90", typ='empty', inh=1, pervillage=4,
|
||||
weight={nore=2,taoki=2,medieval=2,charachoal=2,lumberjack=2,claytrader=2,logcabin=2,canadian=2,grasshut=2,tent=2}},
|
||||
{scm="empty_32x32_2_90", typ='empty', inh=1, pervillage=4,
|
||||
weight={nore=2,taoki=2,medieval=2,charachoal=2,lumberjack=2,claytrader=2,logcabin=2,canadian=2,grasshut=2,tent=2}},
|
||||
|
||||
-- some new grasshut variants
|
||||
{scm="grasshut7_1_90", weight={grasshut=1, single=1}, nomirror=1, typ='hut'},
|
||||
{scm="grasshut8_1_90", weight={grasshut=1, single=1}, nomirror=1, typ='hut'},
|
||||
{scm="grasshut9_1_90", weight={grasshut=1, single=1}, nomirror=1, typ='hut'},
|
||||
{scm="grasshut_pub_1_90", weight={grasshut=1/4, single=1}, nomirror=1, typ='pub'},
|
||||
{scm="grasshut_hotel_1_90", weight={grasshut=1/4, single=1}, nomirror=1, typ='inn'},
|
||||
{scm="grasshut_shop_1_90", weight={grasshut=1, single=1}, nomirror=1, typ='shop'},
|
||||
{scm="grasshutwell_8_90", weight={grasshut=1, single=1}, nomirror=1, typ='well'},
|
||||
}
|
||||
|
||||
|
||||
-- read the data files and fill in information like size and nodes that need on_construct to be called after placing;
|
||||
-- skip buildings that cannot be used due to missing mods
|
||||
mg_villages.add_building = function( building_data )
|
||||
|
||||
local file_name = building_data.mts_path .. building_data.scm;
|
||||
-- a building will only be used if it is used by at least one supported village type (=mods required for that village type are installed)
|
||||
local is_used = false;
|
||||
for typ,weight in pairs( building_data.weight ) do
|
||||
if( typ and weight and typ ~= 'single' and mg_villages.village_type_data[ typ ] and mg_villages.village_type_data[ typ ].supported ) then
|
||||
is_used = true;
|
||||
end
|
||||
-- add the building to the menu list for the build chest ("single" would be too many houses)
|
||||
-- the empty plots are added to each village and of no intrest here
|
||||
if( build_chest and build_chest.add_entry and typ and typ ~= 'single' and (not( building_data.typ ) or building_data.typ ~= 'empty')) then
|
||||
build_chest.add_entry( {'main','mg_villages', typ, building_data.scm, file_name });
|
||||
end
|
||||
end
|
||||
-- buildings as such may have a type as well
|
||||
if( build_chest and build_chest.add_entry and building_data.typ ) then
|
||||
build_chest.add_entry( {'main','mg_villages', building_data.typ, building_data.scm, file_name });
|
||||
end
|
||||
|
||||
|
||||
if( not( is_used )) then
|
||||
-- do nothing; skip this file
|
||||
mg_villages.print(mg_villages.DEBUG_LEVEL_INFO, 'SKIPPING '..tostring( building_data.scm )..' due to village type not supported.');
|
||||
-- building cannot be used
|
||||
building_data.not_available = 1;
|
||||
return false;
|
||||
end
|
||||
|
||||
|
||||
-- read the size of the building;
|
||||
-- convert to .mts for later usage if necessary
|
||||
-- true: no entry in the build_chest (we did that manually already)
|
||||
local res = handle_schematics.analyze_file( file_name, building_data.we_origin, building_data.mts_path .. building_data.scm, building_data, true );
|
||||
|
||||
if( not( res )) then
|
||||
mg_villages.print(mg_villages.DEBUG_LEVEL_WARNING, 'SKIPPING '..tostring( building_data.scm )..' due to import failure.');
|
||||
building_data.not_available = 1;
|
||||
return false;
|
||||
-- provided the file could be analyzed successfully (now covers both .mts and .we files)
|
||||
elseif( res and res.size and res.size.x ) then
|
||||
|
||||
building_data = res;
|
||||
-- identify front doors, calculate paths from beds/workplaces to front of house
|
||||
building_data = mg_villages.analyze_building_for_mobs( building_data, file_name, mg_villages.path_info);
|
||||
|
||||
-- missing data regarding building size - do not use this building for anything
|
||||
elseif( not( building_data.sizex ) or not( building_data.sizez )
|
||||
or building_data.sizex == 0 or building_data.sizez==0) then
|
||||
|
||||
-- no village will use it
|
||||
mg_villages.print( mg_villages.DEBUG_LEVEL_INFO, 'No schematic found for building \''..tostring( building_data.scm )..'\'. Will not use that building.');
|
||||
building_data.weight = {};
|
||||
building_data.not_available = 1;
|
||||
return false;
|
||||
|
||||
else
|
||||
-- the file has to be handled by worldedit; it is no .mts file
|
||||
building_data.is_mts = 0;
|
||||
end
|
||||
|
||||
|
||||
if( not( building_data.weight ) or type( building_data.weight ) ~= 'table' ) then
|
||||
mg_villages.print( mg_villages.DEBUG_LEVEL_WARNING, 'SKIPPING '..tostring( building_data.scm )..' due to missing weight information.');
|
||||
building_data.not_available = 1;
|
||||
return false;
|
||||
end
|
||||
|
||||
|
||||
-- handle duplicates; make sure buildings always get the same number;
|
||||
-- check if the building has been used in previous runs and got an ID there
|
||||
|
||||
-- create a not very unique, but for this case sufficient "id";
|
||||
-- (buildings with the same size and name are considered to be drop-in-replacements
|
||||
local building_id = building_data.sizex..'x'..building_data.sizez..'_'..building_data.scm;
|
||||
-- if the building is new, it will get the next free id
|
||||
local building_nr = #mg_villages.all_buildings_list + 1;
|
||||
for i,v in ipairs( mg_villages.all_buildings_list ) do
|
||||
if( v==building_id ) then
|
||||
-- we found the building
|
||||
building_nr = i;
|
||||
end
|
||||
end
|
||||
|
||||
-- if it is a new building, then save the list
|
||||
if( building_nr == #mg_villages.all_buildings_list+1 ) then
|
||||
mg_villages.all_buildings_list[ building_nr ] = building_id;
|
||||
-- save information about previously imported buildings
|
||||
save_restore.save_data( 'mg_villages_all_buildings_list.data', mg_villages.all_buildings_list );
|
||||
end
|
||||
|
||||
-- determine the internal number for the building; this number is used as a key and can be found in the mg_all_villages.data file
|
||||
if( not( mg_villages.BUILDINGS )) then
|
||||
mg_villages.BUILDINGS = {};
|
||||
end
|
||||
-- actually store the building data
|
||||
mg_villages.BUILDINGS[ building_nr ] = minetest.deserialize( minetest.serialize( building_data ));
|
||||
|
||||
|
||||
-- create lists for all village types containing the buildings which may be used for that village
|
||||
for typ, data in pairs( mg_villages.village_type_data ) do
|
||||
local total_weight = 0;
|
||||
if( not( data.building_list ) or not( data.max_weight_list )) then
|
||||
data.building_list = {};
|
||||
data.max_weight_list = {};
|
||||
elseif( #data.max_weight_list > 0 ) then
|
||||
-- get the last entry - that one will determine the current total_weight
|
||||
total_weight = data.max_weight_list[ #data.max_weight_list ];
|
||||
end
|
||||
|
||||
if( building_data.weight[ typ ] and building_data.weight[ typ ] > 0 ) then
|
||||
local index = #data.building_list+1;
|
||||
data.building_list[ index ] = building_nr;
|
||||
data.max_weight_list[ index ] = total_weight + building_data.weight[ typ ];
|
||||
end
|
||||
end
|
||||
|
||||
-- print it for debugging usage
|
||||
--print( building_data.scm .. ': '..tostring(building_data.sizex)..' x '..tostring(building_data.sizez)..' x '..tostring(building_data.ysize)..' h');
|
||||
return true;
|
||||
end
|
||||
|
||||
|
||||
-- this list contains some information about previously imported buildings so that they will get the same id
|
||||
mg_villages.all_buildings_list = save_restore.restore_data( 'mg_villages_all_buildings_list.data' );
|
||||
|
||||
-- information about beds, positions to stand next to the beds, paths to the doors, and doors
|
||||
--mg_villages.path_info = {};
|
||||
--mg_villages.path_info = save_restore.restore_data( 'mg_villages_path_info.data' );
|
||||
|
||||
mg_villages.file_name_offset = string.len( minetest.get_modpath( "mg_villages" ))-11+1;
|
||||
|
||||
-- import all the buildings
|
||||
mg_villages.BUILDINGS = {};
|
||||
local mts_path = mg_villages.modpath.."/schems/";
|
||||
-- determine the size of the given houses and other necessary values
|
||||
for i,v in ipairs( buildings ) do
|
||||
v.mts_path = mts_path;
|
||||
mg_villages.add_building( v, i );
|
||||
end
|
||||
buildings = nil;
|
||||
|
||||
-- roads are built in a diffrent way
|
||||
mg_villages.BUILDINGS["road"] = {yoff = 0, ysize = 2, scm = {}}
|
||||
|
||||
-- save the path data; wait a bit so that all mods may have registered their buildings
|
||||
-- Note: uncomment the following line if you have added a larger amount of new buildings; then, after
|
||||
-- WORLDNAME/mg_villages_path_info.data has been written, copy that file over to your
|
||||
-- mods/mg_villages/ folder and replace the old one. Add
|
||||
-- mg_villages.path_info = ..
|
||||
-- at the start of the table so that a dofile can execute it.
|
||||
--minetest.after( 10, save_restore.save_data, 'mg_villages_path_info.data', mg_villages.path_info );
|
|
@ -0,0 +1,279 @@
|
|||
|
||||
minetest.register_privilege("mg_villages", { description = "Allows to teleport to villages via /vist <nr>", give_to_singleplayer = false});
|
||||
|
||||
-- store per player which list of villages was offered
|
||||
mg_villages.tmp_player_village_list = {};
|
||||
|
||||
-- list all plots of a village:
|
||||
-- plot_nr, type of building, #inhabitants, occupation, name
|
||||
mg_villages.list_plots_formspec = function( player, formname, fields )
|
||||
|
||||
if( not( player ) or fields.quit or not( fields.village_id) or not( mg_villages.all_villages[ fields.village_id ])) then
|
||||
return
|
||||
end
|
||||
local pname = player:get_player_name();
|
||||
|
||||
-- analyze the road network (this has not been done from the beginning..)
|
||||
mg_villages.get_road_list( fields.village_id, false );
|
||||
|
||||
-- allow to click through the villages using prev/next buttons
|
||||
local liste = mg_villages.tmp_player_village_list[ pname ];
|
||||
local prev_next_button = "button[8.5,11.6;1,0.5;back_to_villagelist;Back]";
|
||||
if( liste and #liste>1 and liste[1]~=fields.village_id ) then
|
||||
prev_next_button = prev_next_button..'button[9.5,11.6;1,0.5;prev;Prev]';
|
||||
end
|
||||
if( liste and #liste>1 and liste[#liste]~=fields.village_id ) then
|
||||
prev_next_button = prev_next_button..'button[10.5,11.6;1,0.5;next;Next]';
|
||||
end
|
||||
|
||||
local formspec = 'size[12,12]'..
|
||||
'field[20,20;0.1,0.1;village_id;VillageID;'..minetest.formspec_escape( fields.village_id ).."]"..
|
||||
'button_exit[4.0,1.0;2,0.5;quit;Exit]'..
|
||||
'button[9.5,1.0;3,0.5;back_to_villagelist;Back to village list]'..
|
||||
prev_next_button..
|
||||
'tablecolumns[' ..
|
||||
'text,align=right;'.. -- plot nr
|
||||
'text,align=center;'.. -- type of building
|
||||
'text,align=center;'.. -- amount of inhabitants
|
||||
'text,align=center;'.. -- occupation of first inhabitant
|
||||
'text,align=center;'.. -- name of first inhabitat
|
||||
'text,align=center]'.. -- comment
|
||||
'table[0.1,2.0;11.4,8.8;'..formname..';'..
|
||||
'PlotNr,Type of building,'..minetest.formspec_escape('#Inhab.')..
|
||||
',Job,Owner,Comment,';
|
||||
|
||||
local bpos_list = mg_villages.all_villages[ fields.village_id ].to_add_data.bpos;
|
||||
for plot_nr,bpos in ipairs( bpos_list ) do
|
||||
|
||||
formspec = formspec..plot_nr..',';
|
||||
if( bpos.btype and bpos.btype ~= "road" and mg_villages.BUILDINGS[ bpos.btype ]) then
|
||||
formspec = formspec..mg_villages.BUILDINGS[ bpos.btype ].typ..',';
|
||||
else
|
||||
formspec = formspec..tostring( bpos.btype )..',';
|
||||
end
|
||||
if( not( bpos.beds ) or #bpos.beds<1 ) then
|
||||
if( bpos.worker and bpos.worker.lives_at and bpos_list[ bpos.worker.lives_at ]
|
||||
and bpos_list[ bpos.worker.lives_at ].beds
|
||||
and bpos_list[ bpos.worker.lives_at ].beds[1]) then
|
||||
local btype2 = mg_villages.BUILDINGS[ bpos_list[ bpos.worker.lives_at ].btype];
|
||||
local worker_plot = bpos_list[ bpos.worker.lives_at ];
|
||||
formspec = formspec..'-,'..
|
||||
( worker_plot.beds[1].title or '-')..','..
|
||||
( worker_plot.beds[1].first_name or '-')..','..
|
||||
"lives in the "..tostring( btype2.typ ).." on plot "..tostring( bpos.worker.lives_at )..',';
|
||||
elseif( bpos.belongs_to and bpos_list[ bpos.belongs_to ]) then
|
||||
formspec = formspec..'-,-,-,';
|
||||
local owner_plot = bpos_list[ bpos.belongs_to ];
|
||||
if( owner_plot and owner_plot.beds and owner_plot.beds[1] ) then
|
||||
formspec = formspec.."owned by "..
|
||||
( owner_plot.beds[1].title or '?')..' '..
|
||||
( owner_plot.beds[1].first_name or '?')..
|
||||
minetest.formspec_escape(" [plot "..tostring( bpos.belongs_to )..']')..',';
|
||||
else
|
||||
formspec = formspec.."owned by "..minetest.formspec_escape(" [plot "..tostring( bpos.belongs_to )..']')..',';
|
||||
end
|
||||
elseif( bpos.btype == "road" ) then
|
||||
if( not( bpos.parent_road_plot )) then
|
||||
formspec = formspec..'-,-,-,road stump,';
|
||||
elseif( bpos.parent_road_plot==0 ) then
|
||||
formspec = formspec..'-,-,-,main road,';
|
||||
else
|
||||
formspec = formspec..'-,-,-,road nr. '..tostring( bpos.road_nr)..
|
||||
minetest.formspec_escape(', sideroad of ');
|
||||
if( bpos_list[ bpos.parent_road_plot ].parent_road_plot == 0 ) then
|
||||
formspec = formspec..'the main road,';
|
||||
else
|
||||
formspec = formspec..'road nr. '..
|
||||
tostring( bpos_list[ bpos.parent_road_plot ].road_nr)..',';
|
||||
end
|
||||
end
|
||||
else
|
||||
formspec = formspec..'-,-,-,-,';
|
||||
end
|
||||
else
|
||||
formspec = formspec..tostring( #bpos.beds )..','..
|
||||
( bpos.beds[1].title or '-')..','..
|
||||
( bpos.beds[1].first_name or '-')..',';
|
||||
if( bpos.beds[1].works_at
|
||||
and bpos.beds[1].works_at ~= plot_nr
|
||||
and bpos_list[ bpos.beds[1].works_at ]) then
|
||||
local btype2 = mg_villages.BUILDINGS[ bpos_list[ bpos.beds[1].works_at].btype];
|
||||
formspec = formspec.."works at the "..tostring( btype2.typ ).." on plot "..tostring(bpos.beds[1].works_at)..",";
|
||||
else
|
||||
formspec = formspec.."-,";
|
||||
end
|
||||
end
|
||||
end
|
||||
formspec = formspec..';1]';
|
||||
minetest.show_formspec( pname, formname, formspec );
|
||||
end
|
||||
|
||||
|
||||
-- list all villages withhin a certain range of the player's position:
|
||||
-- village_nr, distance from player, name of village, population,
|
||||
-- type (i.e. "medieval"), x, y, z, diameter, #buildings, village/single house
|
||||
-- this function is only used for the chat command "/villages" currently
|
||||
mg_villages.list_villages_formspec = function( player, formname, fields )
|
||||
|
||||
if( not( player ) or fields.quit) then
|
||||
return
|
||||
end
|
||||
local pname = player:get_player_name();
|
||||
local ppos = player:getpos();
|
||||
|
||||
local radius = 1000000;
|
||||
-- without the special priv, players can only obtain informatoin about villages which are very close by
|
||||
if( not( minetest.check_player_privs( pname, {mg_villages=true}))) then
|
||||
radius = mg_villages.VILLAGE_DETECT_RANGE;
|
||||
end
|
||||
|
||||
local formspec = 'size[12,12]'..
|
||||
'button_exit[4.0,1.0;2,0.5;quit;Exit]'..
|
||||
'tablecolumns[' ..
|
||||
'text,align=right;'.. -- village number
|
||||
'text,align=right;'.. -- distance from player
|
||||
'text,align=center;'.. -- name of village
|
||||
'text,align=center;'.. -- inhabitants
|
||||
'text,align=center;'.. -- typ of village
|
||||
'text,align=right;'.. -- x
|
||||
'text,align=right;'.. -- y
|
||||
'text,align=right;'.. -- z
|
||||
'text,align=right;'.. -- size
|
||||
'text,align=center;'.. -- #houses where inhabitants may live or work
|
||||
'text,align=right]'..
|
||||
'table[0.1,2.0;11.4,8.8;'..formname..';'..
|
||||
'Nr,Dist,Name of village,Population,Type of village,_X_,_H_,_Z_,Size,'..minetest.formspec_escape('#Buildings')..',,';
|
||||
|
||||
mg_villages.tmp_player_village_list[ pname ] = {};
|
||||
for k,v in pairs( mg_villages.all_villages ) do
|
||||
|
||||
local dx = math.abs( v.vx - ppos.x );
|
||||
local dz = math.abs( v.vz - ppos.z );
|
||||
-- distance in y direction is less relevant here and may be ignored
|
||||
if( dx + dz < radius ) then
|
||||
local dist = math.sqrt( dx * dx + dz * dz );
|
||||
local is_full_village = 'village';
|
||||
if( v.is_single_house ) then
|
||||
is_full_village = '';
|
||||
end
|
||||
-- count the inhabitants
|
||||
if( not( v.population )) then
|
||||
v.population = 0;
|
||||
for _,pos in ipairs( v.to_add_data.bpos ) do
|
||||
if( pos and pos.beds ) then
|
||||
v.population = v.population + #pos.beds;
|
||||
end
|
||||
end
|
||||
end
|
||||
local show_population = v.population;
|
||||
if( show_population == 0 ) then
|
||||
show_population = "-";
|
||||
end
|
||||
formspec = formspec..
|
||||
v.nr..','..
|
||||
tostring( math.floor( dist ))..','..
|
||||
tostring( v.name or 'unknown' )..','..
|
||||
show_population..','..
|
||||
v.village_type..','..
|
||||
tostring( v.vx )..','..
|
||||
tostring( v.vh )..','..
|
||||
tostring( v.vz )..','..
|
||||
tostring( v.vs )..','..
|
||||
tostring( v.anz_buildings )..','..
|
||||
tostring( is_full_village )..',';
|
||||
|
||||
-- store which list we have shown to this particular player
|
||||
table.insert( mg_villages.tmp_player_village_list[ pname ], k );
|
||||
end
|
||||
end
|
||||
formspec = formspec..';1]';
|
||||
-- 'tabheader[0.1,2.6;spalte;Nr,Dist,Name of village,Population,Type of village,_X_,_H_,_Z_,Size,'..minetest.formspec_escape('#Buildings')..';;true;true]';
|
||||
|
||||
minetest.show_formspec( pname, formname, formspec );
|
||||
end
|
||||
|
||||
|
||||
minetest.register_chatcommand( 'villages', {
|
||||
description = "Shows a list of all known villages.",
|
||||
privs = {},
|
||||
func = function(name, param)
|
||||
mg_villages.list_villages_formspec( minetest.get_player_by_name( name ), "mg_villages:formspec_list_villages", {});
|
||||
end
|
||||
});
|
||||
|
||||
|
||||
minetest.register_chatcommand( 'visit', {
|
||||
description = "Teleports you to a known village.",
|
||||
params = "<village number>",
|
||||
privs = {},
|
||||
func = function(name, param)
|
||||
|
||||
|
||||
if( mg_villages.REQUIRE_PRIV_FOR_TELEPORT and not( minetest.check_player_privs( name, {mg_villages=true}))) then
|
||||
minetest.chat_send_player( name, "You need the 'mg_villages' priv in order to teleport to villages using this command.");
|
||||
return;
|
||||
end
|
||||
|
||||
if( not( param ) or param == "" ) then
|
||||
minetest.chat_send_player( name, "Which village do you want to visit? Please provide the village number!");
|
||||
return;
|
||||
end
|
||||
|
||||
local nr = tonumber( param );
|
||||
for id, v in pairs( mg_villages.all_villages ) do
|
||||
-- we have found the village
|
||||
if( v and v.nr == nr ) then
|
||||
|
||||
minetest.chat_send_player( name, "Initiating transfer to village no. "..tostring( v.nr )..", called "..( tostring( v.name or 'unknown'))..".");
|
||||
local player = minetest.get_player_by_name( name );
|
||||
player:moveto( { x=v.vx, y=(v.vh+1), z=v.vz }, false);
|
||||
return;
|
||||
end
|
||||
end
|
||||
-- no village found
|
||||
minetest.chat_send_player( name, "There is no village with the number "..tostring( param ).." (yet?).");
|
||||
end
|
||||
});
|
||||
|
||||
minetest.register_chatcommand( 'village_mob_repopulate', {
|
||||
description = "Discards old mob data and assigns beds and workplaces anew. Mobs get new names.",
|
||||
params = "<village number>",
|
||||
privs = {},
|
||||
func = function(name, param)
|
||||
|
||||
|
||||
if( not( minetest.check_player_privs( name, {protection_bypass=true}))) then
|
||||
minetest.chat_send_player( name, "You need the 'protection_bypass' priv in order to delete all the old mob data of a village and to recalculate it anew.");
|
||||
return;
|
||||
end
|
||||
|
||||
if( not( param ) or param == "" ) then
|
||||
minetest.chat_send_player( name, "Which village do you want to repopulate? Please provide the village number!");
|
||||
return;
|
||||
end
|
||||
|
||||
local nr = tonumber( param );
|
||||
for id, v in pairs( mg_villages.all_villages ) do
|
||||
-- we have found the village
|
||||
if( v and v.nr == nr ) then
|
||||
|
||||
minetest.chat_send_player( name, "Deleting information about workplaces and beds. Recalculating. Assigning new data for village no. "..tostring( v.nr )..", called "..( tostring( v.name or 'unknown'))..".");
|
||||
-- move the player to the center of the village he just changed
|
||||
local player = minetest.get_player_by_name( name );
|
||||
player:moveto( { x=v.vx, y=(v.vh+1), z=v.vz }, false);
|
||||
|
||||
local village_id = tostring( v.vx )..':'..tostring( v.vz );
|
||||
-- actually do the reassigning
|
||||
mg_villages.inhabitants.assign_mobs( v, village_id, true);
|
||||
-- save the modified data
|
||||
save_restore.save_data( 'mg_all_villages.data', mg_villages.all_villages );
|
||||
|
||||
-- adjust beds and workplaces
|
||||
mg_villages.inhabitants.prepare_metadata( v, village_id, nil, nil );
|
||||
return;
|
||||
end
|
||||
end
|
||||
-- no village found
|
||||
minetest.chat_send_player( name, "There is no village with the number "..tostring( param ).." (yet?).");
|
||||
end
|
||||
});
|
|
@ -0,0 +1,206 @@
|
|||
-----------------------------------------------------------------------------
|
||||
-- configuration values which you can adjust according to your liking
|
||||
-----------------------------------------------------------------------------
|
||||
-- set to false if you do not want to have any villages spawning
|
||||
mg_villages.ENABLE_VILLAGES = true;
|
||||
|
||||
-- generate one random building for each mg_villages.INVERSE_HOUSE_DENSITY th mapchunk;
|
||||
-- set to 0 in order to disable spawning of these lone buildings outside villages
|
||||
mg_villages.INVERSE_HOUSE_DENSITY = 4;
|
||||
|
||||
-- cover some villages with artificial snow; probability: 1/mg_villages.artificial_snow_probability
|
||||
mg_villages.artificial_snow_probability = 10;
|
||||
|
||||
-- if set to true, soil around villaes will get special soil-snow instead of plant + snow cover
|
||||
mg_villages.use_soil_snow = false;
|
||||
|
||||
-- only place roads if there are at least that many buildings in the village
|
||||
mg_villages.MINIMAL_BUILDUNGS_FOR_ROAD_PLACEMENT = 4;
|
||||
|
||||
|
||||
-- players without the mg_villages priv can only see villages which are less than that many blocks away
|
||||
-- from them when using the /vmap command
|
||||
mg_villages.VILLAGE_DETECT_RANGE = 400;
|
||||
|
||||
-- if set to true, only players which have the mg_villages priv can use the "/visit <village nr>"
|
||||
-- command which allows teleporting to the village with the given number
|
||||
mg_villages.REQUIRE_PRIV_FOR_TELEPORT = false;
|
||||
|
||||
-- if set to true, players cannot modify spawned villages without buying the house from the village first
|
||||
mg_villages.ENABLE_PROTECTION = true;
|
||||
|
||||
-- the first village - the one the player spawns in - will be of this type
|
||||
mg_villages.FIRST_VILLAGE_TYPE = 'medieval';
|
||||
|
||||
-- the mapgen will disregard mapchunks where min.y > mg_villages.MAX_HEIGHT_TREATED;
|
||||
-- you can set this value to 64 if you have a slow machine and a mapgen which does not create extreme mountains
|
||||
-- (or if you don't care if extreme mountains may create burried villages occasionally)
|
||||
mg_villages.MAX_HEIGHT_TREATED = 200;
|
||||
|
||||
-- choose the debug level you want
|
||||
mg_villages.DEBUG_LEVEL = mg_villages.DEBUG_LEVEL_TIMING
|
||||
|
||||
-- if set to true, a water source will be added all 2-3 blocks on a field for farming;
|
||||
-- as long as you do not plan to dig up all fields, hoe them and use them manually,
|
||||
-- better keep this to "false" as that is much faster
|
||||
mg_villages.PLACE_WATER_FOR_FARMING = false
|
||||
|
||||
-- if set to true (or anything else but nil or false), highlandpools by paramat (see
|
||||
-- https://forum.minetest.net/viewtopic.php?t=8400) will be created
|
||||
mg_villages.CREATE_HIGHLANDPOOLS = true
|
||||
|
||||
-- Torches are replaced by mg_villages:torch - which does not melt snow. If you want to use the normal
|
||||
-- torches from minetest_game, set this to true.:w!
|
||||
mg_villages.USE_DEFAULT_3D_TORCHES = true;
|
||||
|
||||
-- background image for the /vmap command
|
||||
-- RealTest comes with a diffrent texture
|
||||
if( minetest.get_modpath('grounds') and minetest.get_modpath('joiner_table')) then
|
||||
mg_villages.MAP_BACKGROUND_IMAGE = "default_dirt_grass.png";
|
||||
elseif( minetest.registered_nodes[ 'default:dirt_with_grass'] ) then
|
||||
mg_villages.MAP_BACKGROUND_IMAGE = "default_grass.png";
|
||||
else
|
||||
mg_villages.MAP_BACKGROUND_IMAGE = "";
|
||||
end
|
||||
|
||||
-- if set to true, the outer buildings in medieval villages will be fields; this is not very convincing yet
|
||||
-- currently not really used; does not look as good as expected
|
||||
mg_villages.medieval_subtype = false;
|
||||
|
||||
-- set this to true if you want to use normal lava - but beware: charachoal villages may cause bushfires!
|
||||
--mg_villages.use_normal_unsafe_lava = false;
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- decrese these values slightly if you want MORE trees around your villages;
|
||||
-- increase it if you want to DECREASE the amount of trees around villages
|
||||
-----------------------------------------------------------------------------
|
||||
-- on average, every n.th node inside a village area may be one of these trees - and it will be a relatively dense packed forrest
|
||||
mg_villages.sapling_probability = {};
|
||||
|
||||
mg_villages.sapling_probability[ minetest.get_content_id( 'default:sapling' ) ] = 25; -- suitable for a relatively dense forrest of normal trees
|
||||
mg_villages.sapling_probability[ minetest.get_content_id( 'default:junglesapling' ) ] = 40; -- jungletrees are a bit bigger and need more space
|
||||
mg_villages.sapling_probability[ minetest.get_content_id( 'default:pinesapling' ) ] = 30;
|
||||
if( minetest.get_modpath( 'mg' )) then
|
||||
mg_villages.sapling_probability[ minetest.get_content_id( 'mg:savannasapling' ) ] = 30;
|
||||
mg_villages.sapling_probability[ minetest.get_content_id( 'mg:pinesapling' ) ] = 35;
|
||||
end
|
||||
mg_villages.moretrees_treelist = nil;
|
||||
if( minetest.get_modpath( 'moretrees' )) then
|
||||
mg_villages.moretrees_treelist = moretrees.treelist;
|
||||
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:birch_sapling_ongen' ) ] = 200;
|
||||
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:spruce_sapling_ongen' ) ] = 200;
|
||||
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:fir_sapling_ongen' ) ] = 90;
|
||||
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:jungletree_sapling_ongen' ) ] = 200;
|
||||
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:beech_sapling_ongen' ) ] = 30;
|
||||
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:apple_sapling_ongen' ) ] = 380;
|
||||
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:oak_sapling_ongen' ) ] = 380; -- ca 20x20; height: 10
|
||||
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:sequoia_sapling_ongen' ) ] = 90; -- ca 10x10
|
||||
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:palm_sapling_ongen' ) ] = 90;
|
||||
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:pine_sapling_ongen' ) ] = 200;
|
||||
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:willow_sapling_ongen' ) ] = 380;
|
||||
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:rubber_tree_sapling_ongen' ) ] = 380;
|
||||
end
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- no need to change this, unless you add new farming_plus fruits
|
||||
-----------------------------------------------------------------------------
|
||||
-- the schematics for buildings of type 'farm_tiny' grow cotton; the farming_plus fruits would be far more fitting
|
||||
mg_villages.fruit_list = {'carrot','potatoe','orange','rhubarb','strawberry','tomato','cotton'};
|
||||
-- is farming_plus available? If not, we can't use this
|
||||
if( not( minetest.get_modpath("farming_plus"))) then
|
||||
mg_villages.fruit_list = nil;
|
||||
end
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- players can buy plots in villages with houses on for this price;
|
||||
-- set according to your liking
|
||||
-----------------------------------------------------------------------------
|
||||
-- how much does the player have to pay for a plot with a building?
|
||||
mg_villages.prices = {
|
||||
empty = "default:copper_ingot 1", -- plot to build on
|
||||
|
||||
-- building types which usually have inhabitants (and thus allow the player
|
||||
-- who bought the building to modifiy the entire village area minus other
|
||||
-- buildings)
|
||||
tent = "default:copper_ingot 1",
|
||||
hut = "default:copper_ingot 1",
|
||||
farm_full = "default:gold_ingot 4",
|
||||
farm_tiny = "default:gold_ingot 2",
|
||||
lumberjack = "default:gold_ingot 2",
|
||||
house = "default:gold_ingot 2",
|
||||
house_large = "default:gold_ingot 4",
|
||||
tavern = "default:gold_ingot 12",
|
||||
trader = "default:gold_ingot 2",
|
||||
|
||||
-- more or less community buildings
|
||||
well = "default:gold_ingot 1",
|
||||
village_square = "default:goldblock 1",
|
||||
secular = "default:goldblock 2", -- secular buildings, such as libraries ec.
|
||||
church = "default:goldblock 10",
|
||||
|
||||
-- places for mobs to work at; usually without inhabitants
|
||||
tower = "default:copper_ingot 1",
|
||||
shed = "default:copper_ingot 2",
|
||||
pit = "default:copper_ingot 3", -- claytrader pit
|
||||
mill = "default:gold_ingot 10",
|
||||
forge = "default:gold_ingot 10",
|
||||
bakery = "default:gold_ingot 10",
|
||||
shop = "default:gold_ingot 20",
|
||||
sawmill = "default:gold_ingot 30",
|
||||
|
||||
-- decoration
|
||||
wagon = "default:tree 10",
|
||||
bench = "default:tree 4",
|
||||
|
||||
-- seperate fields
|
||||
pasture = "default:copper_ingot 2",
|
||||
field = "default:copper_ingot 2",
|
||||
|
||||
-- chateaus are expensive
|
||||
chateau = "default:diamondblock 5",
|
||||
|
||||
-- one mese crystal per square meter in the spawn town :-)
|
||||
empty6x12 = "default:mese_crystal 72",
|
||||
empty8x8 = "default:mese_crystal 64",
|
||||
-- a large plot costs mese blocks
|
||||
empty16x16 = "default:mese 56",
|
||||
-- this is just enough space to grow a tree
|
||||
empty5x5 = "default:mese_crystal 12",
|
||||
-- nobody is supposed to buy the spawn building...except for the admin
|
||||
spawn = "nyancat:nyancat 99",
|
||||
}
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- The values below seldom need adjustment; don't change them unless you
|
||||
-- know exactly what you are doing.
|
||||
-----------------------------------------------------------------------------
|
||||
-- if set to false, villages will not be integrated into the terrain - which looks very bad
|
||||
mg_villages.ENABLE_TERRAIN_BLEND = true;
|
||||
-- if set to false, holes digged by cavegen and mudflow inside the village will not be repaired; houses will be destroyed
|
||||
mg_villages.UNDO_CAVEGEN_AND_MUDFLOW = true;
|
||||
|
||||
-- internal variables for village generation
|
||||
|
||||
mg_villages.VILLAGE_CHECK_RADIUS = 2
|
||||
mg_villages.VILLAGE_CHECK_COUNT = 1
|
||||
--mg_villages.VILLAGE_CHANCE = 28
|
||||
--mg_villages.VILLAGE_MIN_SIZE = 20
|
||||
--mg_villages.VILLAGE_MAX_SIZE = 40
|
||||
mg_villages.VILLAGE_CHANCE = 28
|
||||
-- min and max size are only used in case of them beeing not provided by the village type (see buildings.lua)
|
||||
mg_villages.VILLAGE_MIN_SIZE = 25
|
||||
mg_villages.VILLAGE_MAX_SIZE = 90 --55
|
||||
mg_villages.FIRST_ROADSIZE = 3
|
||||
mg_villages.BIG_ROAD_CHANCE = 0
|
||||
|
||||
-- Enable that for really big villages (there are also really slow to generate)
|
||||
--[[mg_villages.VILLAGE_CHECK_RADIUS = 3
|
||||
mg_villages.VILLAGE_CHECK_COUNT = 3
|
||||
mg_villages.VILLAGE_CHANCE = 28
|
||||
mg_villages.VILLAGE_MIN_SIZE = 100
|
||||
mg_villages.VILLAGE_MAX_SIZE = 150
|
||||
mg_villages.FIRST_ROADSIZE = 5
|
||||
mg_villages.BIG_ROAD_CHANCE = 50]]
|
|
@ -0,0 +1,24 @@
|
|||
handle_schematics
|
||||
default
|
||||
doors?
|
||||
farming?
|
||||
wool?
|
||||
stairs?
|
||||
cottages?
|
||||
moretrees?
|
||||
trees?
|
||||
forest?
|
||||
dryplants?
|
||||
cavestuff?
|
||||
snow?
|
||||
moresnow?
|
||||
darkage?
|
||||
ethereal?
|
||||
deco?
|
||||
metals?
|
||||
grounds?
|
||||
moreblocks?
|
||||
bell?
|
||||
mg?
|
||||
mob_world_interaction?
|
||||
cavestuff?
|
|
@ -0,0 +1,203 @@
|
|||
|
||||
|
||||
|
||||
-- provide a list of roads; function mg_villages.identify_parent_roads got lost somehow
|
||||
mg_villages.extra_show_road_list = function( village_id )
|
||||
if( not( village_id ) or not( mg_villages.all_villages[ village_id ] )) then
|
||||
return;
|
||||
end
|
||||
local str = "List of roads:\n";
|
||||
local bpos_list = mg_villages.all_villages[ village_id ].village.to_add_data.bpos;
|
||||
-- find out which road branches off from which other road
|
||||
mg_villages.identify_parent_roads( bpos_list );
|
||||
for i,pos in ipairs( bpos_list ) do
|
||||
if( pos.btype and pos.btype=="road" ) then
|
||||
str = str.." Plot "..tostring(i)..": road nr. "..tostring(pos.road_nr)..
|
||||
" branching off from road on plot nr "..tostring(pos.parent_road)..
|
||||
"\n data: "..minetest.serialize( pos ).."\n";
|
||||
end
|
||||
end
|
||||
minetest.chat_send_player(pname, str );
|
||||
end
|
||||
|
||||
-- DEPRECATED
|
||||
-- search the trader (who is supposed to be at the given position) and
|
||||
-- spawn a new one in case he went missing
|
||||
mg_villages.plotmarker_search_trader = function( trader, height )
|
||||
|
||||
local obj_list = minetest.get_objects_inside_radius({x=trader.x, y=height, z=trader.z}, 10 );
|
||||
for i,obj in ipairs( obj_list ) do
|
||||
local e = obj:get_luaentity();
|
||||
if( e and e.object ) then
|
||||
local p = e.object:getpos();
|
||||
if( p and p.x and math.abs(p.x-trader.x)<1.5
|
||||
and p.z and math.abs(p.z-trader.z)<1.5
|
||||
and e.name and e.name=="mobf_trader:trader"
|
||||
and e.trader_typ and e.trader_typ==trader.typ) then
|
||||
-- minetest.chat_send_player( "singleplayer", "FOUND trader "..tostring( e.trader_typ)); --TODO
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- TODO: deprecated; but may be useful in a new form for mobs that live in the house
|
||||
mg_villages.plotmarker_list_traders = function( plot, formspec )
|
||||
if( not( plot ) or not( plot.traders )) then
|
||||
return formspec;
|
||||
end
|
||||
|
||||
if( #plot.traders > 1 ) then
|
||||
formspec = formspec.."label[0.3,7.0;Some traders live here. One works as a "..tostring(plot.traders[1].typ)..".]";
|
||||
for i=2,#plot.traders do
|
||||
formspec = formspec.."label[0.3,"..(6.0+i)..";Another trader works as a "..tostring(plot.traders[i].typ)..".]";
|
||||
end
|
||||
elseif( plot.traders[1] and plot.traders[1].typ) then
|
||||
formspec = formspec..
|
||||
"label[0.3,7.0;A trader lives here. He works as a "..tostring( plot.traders[1].typ )..".]";
|
||||
else
|
||||
formspec = formspec..
|
||||
"label[0.3,7.0;No trader currently works at this place.]";
|
||||
end
|
||||
-- add buttons for visiting (teleport to trader), calling (teleporting trader to plot) and firing the trader
|
||||
for i,trader in ipairs(plot.traders) do
|
||||
local trader_entity = mg_villages.plotmarker_search_trader( trader, village.vh );
|
||||
|
||||
formspec = formspec..
|
||||
"button[6.0,"..(6.0+i)..";1.2,0.5;visit_trader_"..i..";visit]"..
|
||||
"button[7.4,"..(6.0+i)..";1.2,0.5;call_trader_"..i..";call]"..
|
||||
"button[8.8,"..(6.0+i)..";1.2,0.5;fire_trader_"..i..";fire]";
|
||||
|
||||
if( fields[ "visit_trader_"..i ] ) then
|
||||
|
||||
player:moveto( {x=trader.x, y=(village.vh+1), z=trader.z} );
|
||||
minetest.chat_send_player( pname, "You are visiting the "..tostring( trader.typ )..
|
||||
" trader, who is supposed to be somewhere here. He might also be on a floor above you.");
|
||||
return formspec;
|
||||
end
|
||||
if( fields[ "visit_call_"..i ] ) then
|
||||
-- TODO: spawning: mob_basics.spawn_mob( {x=v.x, y=v.y, z=v.z}, v.typ, nil, nil, nil, nil, true );
|
||||
end
|
||||
-- TODO: fire mob
|
||||
end
|
||||
formspec = formspec.."button[3.75,"..(7.0+math.max(1,#plot.traders))..";3.5,0.5;hire_trader;Hire a new random trader]";
|
||||
-- TODO: hire mob
|
||||
return formspec;
|
||||
end
|
||||
|
||||
|
||||
-- provide debug information about mobs, let mobf_traders work around to some degree etc
|
||||
mg_villages.mob_spanwer_on_rightclick = function( pos, node, clicker, itemstack, pointed_thing)
|
||||
if( not( clicker )) then
|
||||
return;
|
||||
end
|
||||
local meta = minetest.get_meta( pos );
|
||||
if( not( meta )) then
|
||||
return;
|
||||
end
|
||||
local village_id = meta:get_string( "village_id" );
|
||||
local plot_nr = meta:get_int( "plot_nr" );
|
||||
local bed_nr = meta:get_int( "bed_nr" );
|
||||
-- direction for the mob to look at
|
||||
local yaw = meta:get_int( "yaw" );
|
||||
|
||||
local mob_info = mg_villages.inhabitants.get_mob_data( village_id, plot_nr, bed_nr );
|
||||
|
||||
local str = "Found: ";
|
||||
local mob_pos = nil;
|
||||
local mob = nil;
|
||||
if( mob_info.mob_id and mob_basics) then
|
||||
mob = mob_basics.find_mob_by_id( mob_info.mob_id, "trader" );
|
||||
if( mob ) then
|
||||
mob_pos = mob.object:getpos();
|
||||
if( mob_pos and mob_pos.x == pos.x and mob_pos.z == pos.z ) then
|
||||
str = str.." yes, waiting right here. ";
|
||||
mob.trader_does = "stand";
|
||||
-- TODO: detect "in his bed"
|
||||
elseif( mob.trader_does == "sleep" and mob.trader_uses and mob.trader_uses.x ) then
|
||||
str = str.." yes, sleeping in bed at "..minetest.pos_to_string( mob.trader_uses )..". ";
|
||||
else
|
||||
str = str.." yes, at "..minetest.pos_to_string( mob_pos)..". Teleporting here.";
|
||||
mob.trader_does = "stand";
|
||||
mob_world_interaction.stand_at( mob, pos, yaw );
|
||||
end
|
||||
else
|
||||
str = str.." - not found -. ";
|
||||
end
|
||||
end
|
||||
|
||||
local res = mg_villages.get_plot_and_building_data( village_id, plot_nr );
|
||||
if( not( res ) or not( res.bpos ) or not( mob_info.mob_id ) or not( mob ) or not( mob_world_interaction) or not( movement)) then
|
||||
minetest.chat_send_player( clicker:get_player_name(), str.."Mob data: "..minetest.serialize(mob_info));
|
||||
return;
|
||||
end
|
||||
-- use door_nr 1;
|
||||
local path = nil;
|
||||
if( mob and mob.trader_does == "sleep" ) then
|
||||
path = mg_villages.get_path_from_bed_to_outside( village_id, plot_nr, bed_nr, 1 );
|
||||
-- get out of the bed, walk to the middle of the front of the house
|
||||
if( path and #path>0 ) then
|
||||
mob_world_interaction.stand_at( mob, path[1], yaw );
|
||||
-- last step: go back to the mob spawner that belongs to the mob
|
||||
table.insert( path, pos );
|
||||
str = str.." The mob plans to get up from his bed and stand in front of his house.\n";
|
||||
else
|
||||
str = str.." FAILED to get a path from bed to outside.\n";
|
||||
end
|
||||
else
|
||||
-- go to bed and sleep
|
||||
path = mg_villages.get_path_from_outside_to_bed( village_id, plot_nr, bed_nr, 1 );
|
||||
str = str.." The mob plans to go to his bed and start sleeping.\n";
|
||||
|
||||
-- local target_plot_nr = 9; -- just for testing..
|
||||
-- path = mg_villages.get_path_from_pos_to_plot_via_roads( village_id, pos, target_plot_nr );
|
||||
-- str = str.." The mob plans to go to plot nr. "..tostring(target_plot_nr).."\n";
|
||||
end
|
||||
local move_obj = movement.getControl(mob);
|
||||
move_obj:walk_path( path, 1, {find_path == true});
|
||||
|
||||
minetest.chat_send_player( clicker:get_player_name(), str.."Mob data: "..minetest.serialize(mob_info));
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- check if all mobs have beds and paths from beds to mob spawners in front of the house can be calculated;
|
||||
-- deprecated since pathfinding is now done in the blueprints
|
||||
mg_villages.debug_inhabitants = function( village, plot_nr)
|
||||
if( not( minetest.get_modpath( "mob_world_interaction"))) then
|
||||
return;
|
||||
end
|
||||
-- TODO: only for testing
|
||||
local bpos = village.to_add_data.bpos[ plot_nr ];
|
||||
if( bpos and bpos.beds ) then
|
||||
for i,bed in ipairs( bpos.beds ) do
|
||||
-- find a place next to the bed where the mob can stand
|
||||
local p_next_to_bed = mob_world_interaction.find_place_next_to( bed, 0, {x=0,y=0,z=0});
|
||||
if( not( p_next_to_bed ) or p_next_to_bed.iteration==99 ) then
|
||||
minetest.chat_send_player("singleplayer", "Bed Nr. "..tostring(i).." at "..minetest.pos_to_string( bed )..": FAILED to find a place to stand.");
|
||||
else
|
||||
-- position in front of the building, with the building stretching equally to the right and left
|
||||
-- get a diffrent one for each mob
|
||||
local p_in_front = handle_schematics.get_pos_in_front_of_house( bpos, i );
|
||||
local path = mob_world_interaction.find_path( p_next_to_bed, p_in_front, { collisionbox = {1,0,3,4,2}});
|
||||
local str = "";
|
||||
if( path ) then
|
||||
str = str.."Bed Nr. "..tostring(i).." at "..minetest.pos_to_string( bed )..", standing at "..minetest.pos_to_string( p_next_to_bed )..": "..tostring( table.getn( path )).." Steps to outside.";
|
||||
local front_door_pos = nil;
|
||||
for j,p in ipairs( path ) do
|
||||
local n = minetest.get_node( p );
|
||||
if( n and n.name and mob_world_interaction.door_type[ n.name ]=="door_a_b") then
|
||||
front_door_pos = p;
|
||||
end
|
||||
end
|
||||
if( front_door_pos ) then
|
||||
str = str.." Front door found at: "..minetest.pos_to_string( front_door_pos );
|
||||
end
|
||||
else
|
||||
str = str.." FAILED to find a path from bed "..minetest.pos_to_string(bed )..", standing at "..minetest.pos_to_string( p_next_to_bed )..", to front of house.";
|
||||
end
|
||||
minetest.chat_send_player("singleplayer", str );
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,88 @@
|
|||
|
||||
-- reserve namespace for the villages
|
||||
mg_villages = {}
|
||||
|
||||
mg_villages.all_villages = {}
|
||||
mg_villages.mg_generated_map = {}
|
||||
mg_villages.anz_villages = 0;
|
||||
|
||||
mg_villages.modpath = minetest.get_modpath( "mg_villages");
|
||||
|
||||
|
||||
mg_villages.DEBUG_LEVEL_NONE = -1 -- -1: disable all printed messages
|
||||
mg_villages.DEBUG_LEVEL_NORMAL = 0 -- 0: print information about which village spawned where plus important errors
|
||||
mg_villages.DEBUG_LEVEL_WARNING = 1 -- 1: warnings/errors which may not be particulary helpful for non-developers
|
||||
mg_villages.DEBUG_LEVEL_INFO = 2 -- 2: print even less important warnings
|
||||
mg_villages.DEBUG_LEVEL_TIMING = 3 -- 3: detailled performance information
|
||||
|
||||
mg_villages.print = function( level, msg )
|
||||
if( level <= mg_villages.DEBUG_LEVEL ) then
|
||||
print( "[mg_villages] "..msg );
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- save_restore is now part of handle_schematics
|
||||
--dofile(mg_villages.modpath.."/save_restore.lua")
|
||||
mg_villages.all_villages = save_restore.restore_data( 'mg_all_villages.data' ); -- read mg_villages.all_villages data saved for this world from previous runs
|
||||
mg_villages.mg_generated_map = save_restore.restore_data( 'mg_generated_map.data' );
|
||||
|
||||
dofile(mg_villages.modpath.."/config.lua")
|
||||
|
||||
-- adds a special gravel node which will neither fall nor be griefed by mapgen
|
||||
dofile(mg_villages.modpath.."/nodes.lua")
|
||||
|
||||
-- the default game no longer provides helpful tree growing code
|
||||
dofile(mg_villages.modpath.."/trees.lua")
|
||||
|
||||
dofile(mg_villages.modpath.."/replacements.lua")
|
||||
|
||||
-- fill mg_villages.all_buildings_list with precalculated paths
|
||||
dofile(mg_villages.modpath.."/mg_villages_path_info.data");
|
||||
|
||||
-- multiple diffrent village types with their own sets of houses are supported
|
||||
-- The function mg_villages.add_village_type( village_type_name, village_type_data )
|
||||
-- allows other mods to add new village types.
|
||||
dofile(mg_villages.modpath.."/village_types.lua")
|
||||
|
||||
-- calls path calculation and stores front doors etc.; only called in mg_villages.add_building
|
||||
dofile(mg_villages.modpath.."/analyze_building_for_mobs.lua")
|
||||
|
||||
-- Note: the "buildings" talbe is not in the mg_villages.* namespace
|
||||
-- The function mg_villages.add_building( building_data ) allows other mods to add buildings.
|
||||
dofile(mg_villages.modpath.."/buildings.lua")
|
||||
|
||||
-- mg_villages.init_weights() has to be called AFTER all village types and buildings have
|
||||
-- been added using the functions above
|
||||
dofile(mg_villages.modpath.."/init_weights.lua")
|
||||
|
||||
-- generate village names
|
||||
dofile(mg_villages.modpath.."/name_gen.lua");
|
||||
|
||||
dofile(mg_villages.modpath.."/villages.lua")
|
||||
|
||||
-- determine type of work, name, age, bed position etc. for villagers (none included!)
|
||||
dofile(mg_villages.modpath.."/inhabitants.lua")
|
||||
|
||||
-- provides some extra functionality for development of mob mods etc.;
|
||||
-- contains some deprecated functions
|
||||
dofile(mg_villages.modpath.."/extras_for_development.lua");
|
||||
-- adds a command that allows to teleport to a known village
|
||||
dofile(mg_villages.modpath.."/chat_commands.lua")
|
||||
-- protect villages from griefing
|
||||
dofile(mg_villages.modpath.."/protection.lua")
|
||||
-- allows to buy/sell/restore/.. plots and their buildings
|
||||
dofile(mg_villages.modpath.."/plotmarker_formspec.lua")
|
||||
-- create and show a map of the world
|
||||
dofile(mg_villages.modpath.."/map_of_world.lua")
|
||||
|
||||
-- terrain blending for individual houses
|
||||
dofile(mg_villages.modpath.."/terrain_blend.lua")
|
||||
-- the interface for the mapgen;
|
||||
-- also takes care of spawning the player
|
||||
dofile(mg_villages.modpath.."/mapgen.lua")
|
||||
|
||||
dofile(mg_villages.modpath.."/spawn_player.lua")
|
||||
|
||||
-- reconstruct the connection of the roads inside a village
|
||||
dofile(mg_villages.modpath.."/roads.lua")
|
|
@ -0,0 +1,43 @@
|
|||
-- this functions needs to be called once after *all* village types and buildings have been added
|
||||
mg_villages.init_weights = function()
|
||||
|
||||
-- create a list of all used village types
|
||||
mg_villages.village_types = {};
|
||||
for k,v in pairs( mg_villages.village_type_data ) do
|
||||
if( not( v.only_single ) and v.supported and v.building_list ) then
|
||||
table.insert( mg_villages.village_types, k );
|
||||
end
|
||||
end
|
||||
mg_villages.print(mg_villages.DEBUG_LEVEL_NORMAL,'Will create villages of the following types: '..minetest.serialize( mg_villages.village_types ));
|
||||
|
||||
|
||||
|
||||
mg_villages.village_types[ #mg_villages.village_types+1 ] = 'single';
|
||||
mg_villages.village_types[ #mg_villages.village_types+1 ] = 'fields';
|
||||
mg_villages.village_types[ #mg_villages.village_types+1 ] = 'tower';
|
||||
for j,v in ipairs( mg_villages.village_types ) do
|
||||
|
||||
local total_weight = 0
|
||||
for _, i in ipairs(mg_villages.BUILDINGS) do
|
||||
if( not( i.max_weight )) then
|
||||
i.max_weight = {};
|
||||
end
|
||||
if( i.weight and i.weight[ v ] and i.weight[ v ]>0 ) then
|
||||
total_weight = total_weight+i.weight[ v ]
|
||||
i.max_weight[v] = total_weight
|
||||
end
|
||||
end
|
||||
local multiplier = 3000/total_weight
|
||||
for _,i in ipairs(mg_villages.BUILDINGS) do
|
||||
if( i.weight and i.weight[ v ] and i.weight[ v ]>0 ) then
|
||||
i.max_weight[v] = i.max_weight[ v ]*multiplier
|
||||
end
|
||||
end
|
||||
end
|
||||
-- the fields do not exist as an independent type
|
||||
mg_villages.village_types[ #mg_villages.village_types ] = nil;
|
||||
-- neither does the tower type
|
||||
mg_villages.village_types[ #mg_villages.village_types ] = nil;
|
||||
-- and neither does the "single" type (==lone houses outside villages)
|
||||
mg_villages.village_types[ #mg_villages.village_types ] = nil;
|
||||
end
|
|
@ -0,0 +1,193 @@
|
|||
|
||||
|
||||
-- villages up to this many nodes in each direction are shown on the map
|
||||
mg_villages.MAP_RANGE = 1000;
|
||||
|
||||
|
||||
mg_villages.draw_tile = function( content_id, image, x, z, dx, dz, tile_nr )
|
||||
if( not( image )) then
|
||||
local node_name = minetest.get_name_from_content_id( content_id );
|
||||
if( not( node_name )) then
|
||||
return '';
|
||||
end
|
||||
local node_def = minetest.registered_nodes[ node_name ];
|
||||
if( not( node_def )) then
|
||||
return '';
|
||||
end
|
||||
local tiles = node_def.tiles;
|
||||
local tile = nil;
|
||||
if( tiles ~= nil ) then
|
||||
if( not(tile_nr) or tile_nr > #tiles or tile_nr < 1 ) then
|
||||
tile_nr = 1;
|
||||
end
|
||||
tile = tiles[tile_nr];
|
||||
end
|
||||
if type(tile)=="table" then
|
||||
tile=tile["name"]
|
||||
end
|
||||
image = tile;
|
||||
if( not( image )) then
|
||||
image = "unknown_object.png";
|
||||
end
|
||||
end
|
||||
return "image["..tostring(x)..",".. tostring(z) ..";"..dx..','..dz..";" .. image .."]";
|
||||
end
|
||||
|
||||
|
||||
mg_villages.map_of_world = function( pname )
|
||||
|
||||
local player = minetest.get_player_by_name( pname );
|
||||
if( not( player )) then
|
||||
return '';
|
||||
end
|
||||
local ppos = player:getpos();
|
||||
|
||||
-- also usable: diamond_block, sand, water
|
||||
local formspec = "size[14.4,10]"..
|
||||
"background[0,0;10,10;"..mg_villages.MAP_BACKGROUND_IMAGE.."]"..
|
||||
"label[10,10;x axis]"..
|
||||
"label[0,0;z axis]"..
|
||||
"label[0,10;|]"..
|
||||
"label[0.2,10;->]";
|
||||
|
||||
|
||||
local r = mg_villages.MAP_RANGE;
|
||||
local f1 = 10/(2*r);
|
||||
|
||||
local map_tiles_shown = math.floor( mg_villages.MAP_RANGE/80 );
|
||||
local center_x = math.floor( ppos.x/80 );
|
||||
local center_z = math.floor( ppos.z/80 );
|
||||
for x = center_x - map_tiles_shown, center_x + map_tiles_shown do
|
||||
for z = center_z - map_tiles_shown, center_z + map_tiles_shown do
|
||||
if( mg_villages.mg_generated_map[ x ] and mg_villages.mg_generated_map[ x ][ z ] ) then
|
||||
local surface_types = mg_villages.mg_generated_map[ x ][ z ];
|
||||
local content_id = 0;
|
||||
if( type( surface_types )=='table' ) then
|
||||
content_id = surface_types[ 26 ];
|
||||
else
|
||||
content_id = surface_types;
|
||||
end
|
||||
|
||||
local x1 = f1 * ((x*80) - ppos.x +r);
|
||||
local z1 = f1 * ( (2*r) - ((z*80) - ppos.z + r));
|
||||
local dx = f1 * 80;
|
||||
local dz = f1 * 80;
|
||||
|
||||
formspec = formspec..mg_villages.draw_tile( content_id, nil, x1+0.5, z1-0.5, dx*1.25, dz*1.25, 1 );
|
||||
|
||||
-- if more detailed information is available, draw those tiles that differ from the most common tile
|
||||
if( type( surface_types )=='table' and false) then -- TODO: disabled for now
|
||||
dx = dx/5;
|
||||
dz = dz/5;
|
||||
for i,v in ipairs( surface_types ) do
|
||||
if( v ~= content_id ) then
|
||||
local x2 = x1+( math.floor( (i-1)/5 )*dx);
|
||||
local z2 = z1+( math.floor( (i-1)%5 )*dz);
|
||||
formspec = formspec..mg_villages.draw_tile( v, nil, x2+0.5, z2-0.5, dx*1.3, dz*1.3, 1);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local shown_villages = {};
|
||||
|
||||
r = mg_villages.MAP_RANGE;
|
||||
f1 = 10/(2*r);
|
||||
for name,v in pairs( mg_villages.all_villages ) do
|
||||
|
||||
local data = v; --minetest.deserialize( v );
|
||||
local x = data.vx - ppos.x;
|
||||
local z = data.vz - ppos.z;
|
||||
|
||||
-- show only villages which are at max mg_villages.MAP_RANGE away from player
|
||||
if( x and z
|
||||
and mg_villages.village_type_data[ data.village_type ]
|
||||
and mg_villages.village_type_data[ data.village_type ].texture
|
||||
and math.abs( x ) < r
|
||||
and math.abs( z ) < r ) then
|
||||
|
||||
-- the village size determines the texture size
|
||||
local dx = f1 * (data.vs*2) *1.25;
|
||||
local dz = f1 * (data.vs*2) *1.0;
|
||||
|
||||
-- center the village texture
|
||||
x = x - (data.vs/2);
|
||||
z = z + (data.vs/2);
|
||||
|
||||
-- calculate the position for the village texture
|
||||
x = f1 * (x+r);
|
||||
z = f1 * ( (2*r) -(z+r));
|
||||
|
||||
formspec = formspec..
|
||||
"label["..x..",".. z ..";"..tostring( data.nr ).."]"..mg_villages.draw_tile( nil, mg_villages.village_type_data[ data.village_type ].texture, x, z, dx, dz, 1 );
|
||||
|
||||
shown_villages[ #shown_villages+1 ] = tostring( data.nr )..". "..tostring( v.name or 'unknown' ).."]";
|
||||
end
|
||||
end
|
||||
|
||||
-- code and arrows taken from mapp mod
|
||||
local yaw = player:get_look_yaw()
|
||||
local rotate = 0;
|
||||
if yaw ~= nil then
|
||||
-- Find rotation and texture based on yaw.
|
||||
yaw = math.deg(yaw)
|
||||
yaw = math.fmod (yaw, 360)
|
||||
if yaw<0 then yaw = 360 + yaw end
|
||||
if yaw>360 then yaw = yaw - 360 end
|
||||
if yaw < 90 then
|
||||
rotate = 90
|
||||
elseif yaw < 180 then
|
||||
rotate = 180
|
||||
elseif yaw < 270 then
|
||||
rotate = 270
|
||||
else
|
||||
rotate = 0
|
||||
end
|
||||
yaw = math.fmod(yaw, 90)
|
||||
yaw = math.floor(yaw / 10) * 10
|
||||
|
||||
end
|
||||
|
||||
-- show the players yaw
|
||||
if rotate ~= 0 then
|
||||
formspec = formspec.."image[".. 4.95 ..",".. 4.85 ..";0.4,0.4;d" .. yaw .. ".png^[transformFYR".. rotate .."]"
|
||||
else
|
||||
formspec = formspec.."image[".. 4.95 ..",".. 4.85 ..";0.4,0.4;d" .. yaw .. ".png^[transformFY]"
|
||||
end
|
||||
|
||||
local i = 0.05;
|
||||
formspec = formspec.."label[10,-0.4;Village types:]";
|
||||
-- explain the meaning of the textures
|
||||
if mg_villages.village_types ~= nil then
|
||||
for _,typ in ipairs(mg_villages.village_types) do
|
||||
formspec = formspec.."label[10.5,"..tostring(i)..";"..tostring( typ ).."]"..
|
||||
"image[10.0,"..tostring(i+0.1)..";0.4,0.4;"..tostring( mg_villages.village_type_data[ typ ].texture ).."]";
|
||||
i = i+0.45;
|
||||
end
|
||||
end
|
||||
|
||||
i = i+0.45;
|
||||
formspec = formspec.."label[10.0,"..tostring(i)..";Villages shown on this map:]";
|
||||
i = i+0.45;
|
||||
local j = 1;
|
||||
while (i<10.5 and j<=#shown_villages) do
|
||||
|
||||
formspec = formspec.."label[10.0,"..tostring(i)..";"..tostring( shown_villages[ j ] ).."]";
|
||||
i = i+0.45;
|
||||
j = j+1;
|
||||
end
|
||||
|
||||
return formspec;
|
||||
end
|
||||
|
||||
|
||||
minetest.register_chatcommand( 'vmap', {
|
||||
description = "Shows a map of all known villages withhin "..tostring( mg_villages.MAP_RANGE ).." blocks.",
|
||||
privs = {},
|
||||
func = function(name, param)
|
||||
minetest.show_formspec( name, 'mg:world_map', mg_villages.map_of_world( name ));
|
||||
end
|
||||
});
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,90 @@
|
|||
|
||||
namegen = {};
|
||||
|
||||
namegen.prefixes = {'ac','ast','lang','pen','shep','ship'}
|
||||
namegen.suffixes = {'beck','ey','ay','bury','burgh','brough','by','by','caster',
|
||||
'cester','cum','den','don','field','firth','ford','ham','ham','ham',
|
||||
'hope','ing','kirk','hill','law','leigh','mouth','ness','pool','shaw',
|
||||
'stead','ster','tun','ton','ton','ton','ton','wold','worth','worthy',
|
||||
'ville','river','forrest','lake'}
|
||||
|
||||
-- people/environmental features
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namegen.silben = { 'a', 'an', 'ab', 'ac', 'am',
|
||||
'be', 'ba', 'bi', 'bl', 'bm', 'bn', 'bo', 'br', 'bst', 'bu',
|
||||
'ca', 'ce', 'ch', 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'cv',
|
||||
'da', 'de', 'df', 'di', 'dl', 'dm', 'dn', 'do', 'dr', 'ds', 'dt', 'du', 'dv',
|
||||
'do','ren','nav','ben','ada','min','org','san','pa','re','ne','en','er','ich',
|
||||
'the','and','tha','ent','ing','ion','tio','for','nde',
|
||||
'has','nce','edt','tis','oft','sth','mem',
|
||||
'ich','ein','und','der','nde','sch','die','den','end','cht',
|
||||
'the','and','tha','ent','ing','ion','for','de',
|
||||
'has','ce','ed','is','ft','sth','mem',
|
||||
'ch','ei','un','der','ie','den','end',
|
||||
'do','ren','nav','ben','ada','min','org','san','pa','re','ne','en','er','ich',
|
||||
'ta','bek','nik','le','lan','nem',
|
||||
'bal','cir','da','en','fan','fir','fern','fa','oak','nut','gen','ga','hu','hi','hal',
|
||||
'in','ig','ir','im','ja','je','jo','kla','kon','ker','log','lag','leg','lil',
|
||||
'lon','las','leve','lere','mes','mir','mon','mm','mer','mig',
|
||||
'na','nn','nerv','neu','oto','on','opt','oll','ome','ott',
|
||||
'pen','par','pi','pa','po','pel','pig','qu','ren','rig','raf','res','ring',
|
||||
'rib','rast','rost','ru','rum','rem','sem','sim','su','spring',
|
||||
'cotton','cot','wood','palm',
|
||||
'do','na','ik','ke','gen','bra','bn','lla','lle','st','aa','kir',
|
||||
'nn','en','fo','fn','gi','ja','jn','ke','kr','kon','lis','on','ok','or','op',
|
||||
'pp','p','qu','re','ra','rn','ri','so','sn','se','ti','tu',
|
||||
'a','e','i','o','u',
|
||||
're','ro','pe','pn','ci','co','cl',
|
||||
'no','en','wi','we','er','en','ba','ki','nn','va','wu','x','tel','or',
|
||||
'so','me','mi','em','en','eg','ge','kn'};
|
||||
|
||||
|
||||
namegen.generate_village_name = function( pr )
|
||||
local anz_silben = pr:next(2,5);
|
||||
local name = '';
|
||||
local prefix = '';
|
||||
local postfix = '';
|
||||
if( pr:next(1,8)==1) then
|
||||
prefix = namegen.prefixes[ #namegen.prefixes ];
|
||||
anz_silben = anz_silben -1;
|
||||
end
|
||||
if( pr:next(1,4)==1) then
|
||||
postfix = name..namegen.suffixes[ #namegen.suffixes ];
|
||||
anz_silben = anz_silben -2;
|
||||
end
|
||||
if( anz_silben < 2 ) then
|
||||
anz_silben = 2;
|
||||
end
|
||||
for i = 1, anz_silben do
|
||||
name = name..namegen.silben[ pr:next( 1, #namegen.silben )];
|
||||
end
|
||||
name = prefix..name..postfix;
|
||||
name = string.upper( string.sub( name, 1, 1 ) )..string.sub( name, 2 );
|
||||
return name;
|
||||
end
|
||||
|
||||
|
||||
namegen.generate_village_name_with_prefix = function( pr, village )
|
||||
|
||||
local name = namegen.generate_village_name( pr );
|
||||
|
||||
-- if a village consists of a single house, it gets a prefix depending on the house type
|
||||
if( village.is_single_house and village.to_add_data and village.to_add_data.bpos ) then
|
||||
-- the building got removed from mg_villages.BUILDINGS in the meantime
|
||||
if( not( mg_villages.BUILDINGS[ village.to_add_data.bpos[1].btype] )) then
|
||||
return 'Abandomed building';
|
||||
end
|
||||
local btyp = mg_villages.BUILDINGS[ village.to_add_data.bpos[1].btype].typ;
|
||||
local bdata = mg_villages.village_type_data[ btyp ];
|
||||
if( bdata and (bdata.name_prefix or bdata.name_postfix )) then
|
||||
name = (bdata.name_prefix or '')..name..(bdata.name_postfix or '');
|
||||
else
|
||||
name = 'House '..name;
|
||||
end
|
||||
end
|
||||
return name;
|
||||
end
|
|
@ -0,0 +1,184 @@
|
|||
|
||||
-- slightly lower than a normal nodes for better look
|
||||
minetest.register_node("mg_villages:road", {
|
||||
description = "village road",
|
||||
tiles = {"default_gravel.png", "default_dirt.png"},
|
||||
is_ground_content = false, -- will not be removed by the cave generator
|
||||
groups = {crumbly=2}, -- does not fall
|
||||
sounds = default.node_sound_gravel_defaults,
|
||||
-- sounds = default.node_sound_dirt_defaults({
|
||||
-- footstep = {name="default_gravel_footstep", gain=0.5},
|
||||
-- dug = {name="default_gravel_footstep", gain=1.0},
|
||||
-- }),
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = { { -0.5, -0.5, -0.5, 0.5, 0.5-2/16, 0.5}, },
|
||||
},
|
||||
})
|
||||
|
||||
mg_villages.road_node = minetest.get_content_id( 'mg_villages:road' );
|
||||
-- do not drop snow on roads
|
||||
if( minetest.get_modpath("moresnow")) then
|
||||
moresnow.snow_cover[ mg_villages.road_node ] = moresnow.c_air;
|
||||
end
|
||||
|
||||
|
||||
-- special soil that does not need abms/lbms or water
|
||||
minetest.register_node("mg_villages:soil", {
|
||||
description = "Soil found on a field",
|
||||
tiles = {"default_dirt.png^farming_soil_wet.png", "default_dirt.png"},
|
||||
drop = "default:dirt",
|
||||
is_ground_content = true,
|
||||
groups = {crumbly=3, not_in_creative_inventory=1, grassland = 1, soil=3, wet=1},
|
||||
sounds = default.node_sound_dirt_defaults,
|
||||
})
|
||||
|
||||
minetest.register_node("mg_villages:desert_sand_soil", {
|
||||
description = "Desert Sand",
|
||||
tiles = {"default_desert_sand.png^farming_soil_wet.png", "default_desert_sand.png"},
|
||||
is_ground_content = true,
|
||||
drop = "default:desert_sand",
|
||||
groups = {crumbly=3, not_in_creative_inventory = 1, sand=1, desert = 1, soil=3, wet=1},
|
||||
sounds = default.node_sound_sand_defaults,
|
||||
})
|
||||
|
||||
|
||||
-- this non-snow-melting-torch is only needed if you use the old snow mod
|
||||
if( mg_villages.USE_DEFAULT_3D_TORCHES == false ) then
|
||||
-- This torch is not hot. It will not melt snow and cause no floodings in villages.
|
||||
minetest.register_node("mg_villages:torch", {
|
||||
description = "Torch",
|
||||
drawtype = "torchlike",
|
||||
--tiles = {"default_torch_on_floor.png", "default_torch_on_ceiling.png", "default_torch.png"},
|
||||
tiles = {
|
||||
{name="default_torch_on_floor_animated.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=3.0}},
|
||||
{name="default_torch_on_ceiling_animated.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=3.0}},
|
||||
{name="default_torch_animated.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=3.0}}
|
||||
},
|
||||
inventory_image = "default_torch_on_floor.png",
|
||||
wield_image = "default_torch_on_floor.png",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
light_source = LIGHT_MAX-1,
|
||||
selection_box = {
|
||||
type = "wallmounted",
|
||||
wall_top = {-0.1, 0.5-0.6, -0.1, 0.1, 0.5, 0.1},
|
||||
wall_bottom = {-0.1, -0.5, -0.1, 0.1, -0.5+0.6, 0.1},
|
||||
wall_side = {-0.5, -0.3, -0.1, -0.5+0.3, 0.3, 0.1},
|
||||
},
|
||||
groups = {choppy=2,dig_immediate=3,flammable=1,attached_node=1},
|
||||
legacy_wallmounted = true,
|
||||
sounds = default.node_sound_defaults,
|
||||
drop = "default:torch",
|
||||
is_ground_content = false,
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
-- get information about a plot, the building, its inhabitants; allow to buy the plot etc.
|
||||
minetest.register_node("mg_villages:plotmarker", {
|
||||
description = "Plot marker",
|
||||
drawtype = "nodebox",
|
||||
tiles = {"default_stone_brick.png"},
|
||||
is_ground_content = false,
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5+2/16, -0.5, -0.5+2/16, 0.5-2/16, -0.5+3/16, 0.5-2/16},
|
||||
},
|
||||
},
|
||||
groups = {cracky=3,stone=2},
|
||||
|
||||
on_rightclick = function( pos, node, clicker, itemstack, pointed_thing)
|
||||
return mg_villages.plotmarker_formspec( pos, nil, {}, clicker )
|
||||
end,
|
||||
|
||||
on_receive_fields = function(pos, formname, fields, sender)
|
||||
return mg_villages.plotmarker_formspec( pos, formname, fields, sender );
|
||||
end,
|
||||
|
||||
-- protect against digging
|
||||
can_dig = function( pos, player )
|
||||
local meta = minetest.get_meta( pos );
|
||||
if( meta and meta:get_string( 'village_id' )~='' and meta:get_int( 'plot_nr' ) and meta:get_int( 'plot_nr' )>0) then
|
||||
return false;
|
||||
end
|
||||
return true;
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
-- place this node where a mob that works in your building ought to stand
|
||||
minetest.register_node("mg_villages:mob_workplace_marker", {
|
||||
description = "Place where a mob ought to work",
|
||||
drawtype = "nodebox",
|
||||
tiles = {"character.png"},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
walkable = false,
|
||||
is_ground_content = false,
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5, -0.5, -0.5, 0.5, -0.5+1/16, 0.5},
|
||||
},
|
||||
},
|
||||
groups = {crumbly=3},
|
||||
})
|
||||
|
||||
-- helper node for villager/mob mods that want to spawn npc
|
||||
minetest.register_node("mg_villages:mob_spawner", {
|
||||
description = "Mob spawner",
|
||||
tiles = {"wool_cyan.png^beds_bed_fancy.png","wool_blue.png^doors_door_wood.png"},
|
||||
is_ground_content = false,
|
||||
groups = {not_in_creative_inventory = 1 }, -- cannot be digged by players
|
||||
on_rightclick = function( pos, node, clicker, itemstack, pointed_thing)
|
||||
return mg_villages.mob_spanwer_on_rightclick( pos, node, clicker, itemstack, pointed_thing);
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
-- default to safe lava - prevent fire
|
||||
if( not( mg_villages.use_normal_unsafe_lava )) then
|
||||
local lava = minetest.registered_nodes[ "default:lava_source"];
|
||||
if( lava ) then
|
||||
-- a deep copy for the table would be more helpful...but, well, ...
|
||||
local new_def = minetest.deserialize( minetest.serialize( lava ));
|
||||
-- this lava does not cause fire to spread
|
||||
new_def.name = nil;
|
||||
new_def.groups.lava = nil;
|
||||
new_def.groups.hot = nil;
|
||||
new_def.groups.igniter = nil;
|
||||
new_def.groups.lava_tamed = 3;
|
||||
new_def.description = "Lava Source (tame)";
|
||||
new_def.liquid_alternative_flowing = "mg_villages:lava_flowing_tamed";
|
||||
new_def.liquid_alternative_source = "mg_villages:lava_source_tamed";
|
||||
-- we create a NEW type of lava for this
|
||||
minetest.register_node( "mg_villages:lava_source_tamed", new_def );
|
||||
end
|
||||
|
||||
-- take care of the flowing variant as well
|
||||
lava = minetest.registered_nodes[ "default:lava_flowing"];
|
||||
if( lava ) then
|
||||
-- a deep copy for the table would be more helpful...but, well, ...
|
||||
local new_def = minetest.deserialize( minetest.serialize( lava ));
|
||||
-- this lava does not cause fire to spread
|
||||
new_def.name = nil;
|
||||
new_def.groups.lava = nil;
|
||||
new_def.groups.hot = nil;
|
||||
new_def.groups.igniter = nil;
|
||||
new_def.groups.lava_tamed = 3;
|
||||
new_def.description = "Flowing Lava (tame)";
|
||||
new_def.liquid_alternative_flowing = "mg_villages:lava_flowing_tamed";
|
||||
new_def.liquid_alternative_source = "mg_villages:lava_source_tamed";
|
||||
-- and a NEW type of flowing lava...
|
||||
minetest.register_node( "mg_villages:lava_flowing_tamed", new_def );
|
||||
end
|
||||
end
|
|
@ -0,0 +1,545 @@
|
|||
|
||||
-- used for buying plots, restoring buildings, getting information about mobs etc.
|
||||
mg_villages.plotmarker_formspec = function( pos, formname, fields, player )
|
||||
|
||||
-- if( not( mg_villages.ENABLE_PROTECTION )) then
|
||||
-- return;
|
||||
-- end
|
||||
if( not( pos )) then
|
||||
return;
|
||||
end
|
||||
local meta = minetest.get_meta( pos );
|
||||
if( not( meta )) then
|
||||
return;
|
||||
end
|
||||
local village_id = meta:get_string('village_id');
|
||||
local plot_nr = meta:get_int( 'plot_nr');
|
||||
local pname = player:get_player_name();
|
||||
|
||||
if( not( village_id )
|
||||
or not( mg_villages.all_villages )
|
||||
or not( mg_villages.all_villages[ village_id ] )
|
||||
or not( plot_nr )
|
||||
or not( mg_villages.all_villages[ village_id ].to_add_data )
|
||||
or not( mg_villages.all_villages[ village_id ].to_add_data.bpos )
|
||||
or not( mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ] )) then
|
||||
minetest.chat_send_player( pname, 'Error. This plot marker is not configured correctly.'..minetest.serialize({village_id,plot_nr }));
|
||||
return;
|
||||
end
|
||||
|
||||
local village = mg_villages.all_villages[ village_id ];
|
||||
local plot = mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ];
|
||||
|
||||
local owner_name = plot.owner;
|
||||
if( not( owner_name ) or owner_name == "" ) then
|
||||
if( plot.btype=="road" ) then
|
||||
owner_name = "- the village community -";
|
||||
else
|
||||
owner_name = "- for sale -";
|
||||
end
|
||||
end
|
||||
|
||||
-- missing data
|
||||
if( not( plot.btype ) or not( mg_villages.BUILDINGS[ plot.btype ] )
|
||||
or not( mg_villages.BUILDINGS[ plot.btype ].mts_path )
|
||||
or not( mg_villages.BUILDINGS[ plot.btype ].scm )) then
|
||||
minetest.chat_send_player( pname, 'Error. Unknown building. btype: '..tostring( plot.btype ));
|
||||
return;
|
||||
end
|
||||
local building_name = mg_villages.BUILDINGS[ plot.btype ].mts_path..mg_villages.BUILDINGS[ plot.btype ].scm;
|
||||
|
||||
-- show coordinates of the village center to the player
|
||||
local village_pos = minetest.pos_to_string( {x=village.vx, y=village.vh, z=village.vz});
|
||||
-- distance from village center
|
||||
local distance = math.floor( math.sqrt( (village.vx - pos.x ) * (village.vx - pos.x )
|
||||
+ (village.vh - pos.y ) * (village.vh - pos.y )
|
||||
+ (village.vz - pos.z ) * (village.vz - pos.z ) ));
|
||||
|
||||
-- show a list of who lives (or works) here at this plot
|
||||
if( fields and fields.inhabitants ) then
|
||||
minetest.show_formspec( pname, "mg_villages:plot_mob_list",
|
||||
mg_villages.inhabitants.print_house_info( village.to_add_data.bpos, plot_nr, village_id, pname ));
|
||||
--mg_villages.debug_inhabitants( village, plot_nr);
|
||||
return;
|
||||
end
|
||||
|
||||
local mirror_str = "";
|
||||
if( plot.mirror ) then
|
||||
mirror_str = minetest.formspec_escape(" (mirrored)");
|
||||
end
|
||||
-- create the header
|
||||
local formspec = "size[13,10]"..
|
||||
"label[3.3,0.0;Plot No.: "..tostring( plot_nr )..", with "..tostring( mg_villages.BUILDINGS[ plot.btype ].scm ).."]"..
|
||||
"label[0.3,0.4;Located at:]" .."label[3.3,0.4;"..(minetest.pos_to_string( pos ) or '?')..", which is "..tostring( distance ).." m away]"
|
||||
.."label[7.3,0.4;from the village center]"..
|
||||
"label[0.3,0.8;Part of village:]" .."label[3.3,0.8;"..(village.name or "- name unknown -").."]"
|
||||
.."label[7.3,0.8;located at "..(village_pos).."]"..
|
||||
"label[0.3,1.2;Owned by:]" .."label[3.3,1.2;"..(owner_name).."]"..
|
||||
"label[3.3,1.6;Click on a menu entry to select it:]"..
|
||||
"field[20,20;0.1,0.1;pos2str;Pos;"..minetest.pos_to_string( pos ).."]";
|
||||
build_chest.show_size_data( building_name );
|
||||
|
||||
-- deprecated; adds buttons for registered mobf_traders
|
||||
--formspec = mg_villages.plotmarker_list_traders( plot, formspec );
|
||||
|
||||
local replace_row = -1;
|
||||
-- the player selected a material which ought to be replaced
|
||||
if( fields.build_chest_replacements ) then
|
||||
local event = minetest.explode_table_event( fields.build_chest_replacements );
|
||||
if( event and event.row and event.row > 0 ) then
|
||||
replace_row = event.row;
|
||||
fields.show_materials = "show_materials";
|
||||
end
|
||||
|
||||
-- the player provided the name of the material for the replacement of the currently selected
|
||||
elseif( fields.store_replacement and fields.store_repalcement ~= ""
|
||||
and fields.replace_row_with and fields.replace_row_with ~= ""
|
||||
and fields.replace_row_material and fields.replace_row_material ~= "") then
|
||||
|
||||
build_chest.replacements_apply( pos, meta, fields.replace_row_material, fields.replace_row_with, village_id );
|
||||
fields.show_materials = "show_materials";
|
||||
|
||||
|
||||
-- group selections for easily changing several nodes at once
|
||||
elseif( fields.wood_selection ) then
|
||||
build_chest.replacements_apply_for_group( pos, meta, 'wood', fields.wood_selection, fields.set_wood, village_id );
|
||||
fields.set_wood = nil;
|
||||
fields.show_materials = "show_materials";
|
||||
|
||||
elseif( fields.farming_selection ) then
|
||||
build_chest.replacements_apply_for_group( pos, meta, 'farming', fields.farming_selection, fields.set_farming, village_id );
|
||||
fields.set_farming = nil;
|
||||
fields.show_materials = "show_materials";
|
||||
|
||||
elseif( fields.roof_selection ) then
|
||||
build_chest.replacements_apply_for_group( pos, meta, 'roof', fields.roof_selection, fields.set_roof, village_id );
|
||||
fields.set_roof = nil;
|
||||
fields.show_materials = "show_materials";
|
||||
|
||||
|
||||
-- actually store the new group replacement
|
||||
elseif( (fields.set_wood and fields.set_wood ~= "")
|
||||
or (fields.set_farming and fields.set_farming ~= "" )
|
||||
or (fields.set_roof and fields.set_roof ~= "" )) then
|
||||
minetest.show_formspec( pname, "mg_villages:formspec_plotmarker",
|
||||
handle_schematics.get_formspec_group_replacement( pos, fields, formspec ));
|
||||
return;
|
||||
end
|
||||
|
||||
-- show which materials (and replacements!) where used for the building
|
||||
if( (fields.show_materials and fields.show_materials ~= "" )
|
||||
or (fields.replace_row_with and fields.replace_row_with ~= "")
|
||||
or (fields.replace_row_material and fields.replace_row_material ~= "")) then
|
||||
|
||||
formspec = formspec.."button[9.9,0.4;2,0.5;info;Back]";
|
||||
if( not( minetest.check_player_privs( pname, {protection_bypass=true}))) then
|
||||
-- do not allow any changes; just show the materials and their replacements
|
||||
minetest.show_formspec( pname, "mg_villages:formspec_plotmarker",
|
||||
formspec..build_chest.replacements_get_list_formspec( pos, nil, 0, meta, village_id, building_name, replace_row ));
|
||||
else
|
||||
minetest.show_formspec( pname, "mg_villages:formspec_plotmarker",
|
||||
formspec..build_chest.replacements_get_list_formspec( pos, nil, 1, nil, village_id, building_name, replace_row ));
|
||||
end
|
||||
return;
|
||||
|
||||
-- place the building again
|
||||
elseif( (fields.reset_building and fields.reset_building ~= "")
|
||||
or (fields.remove_building and fields.remove_building ~= "")) then
|
||||
|
||||
formspec = formspec.."button[9.9,0.4;2,0.5;back;Back]";
|
||||
|
||||
if( not( minetest.check_player_privs( pname, {protection_bypass=true}))) then
|
||||
minetest.show_formspec( pname, "mg_villages:formspec_plotmarker", formspec..
|
||||
"label[3,3;You need the protection_bypass priv in order to use this functin.]" );
|
||||
return;
|
||||
end
|
||||
|
||||
local selected_building = build_chest.building[ building_name ];
|
||||
local start_pos = {x=plot.x, y=plot.y, z=plot.z, brotate=plot.brotate};
|
||||
if( selected_building.yoff ) then
|
||||
start_pos.y = start_pos.y + selected_building.yoff;
|
||||
end
|
||||
local end_pos = {x=plot.x+plot.bsizex-1,
|
||||
y=plot.y+selected_building.yoff-1+selected_building.ysize,
|
||||
z=plot.z+plot.bsizez-1};
|
||||
|
||||
local replacements = build_chest.replacements_get_current( meta, village_id );
|
||||
|
||||
if( fields.remove_building and fields.remove_building ~= "" ) then
|
||||
-- clear the space above ground, put dirt below ground, but keep the
|
||||
-- surface intact
|
||||
handle_schematics.clear_area( start_pos, end_pos, pos.y-1);
|
||||
-- also clear the meta data to avoid strange effects
|
||||
handle_schematics.clear_meta( start_pos, end_pos );
|
||||
formspec = formspec.."label[3,3;The plot has been cleared.]";
|
||||
else
|
||||
-- actually place it (disregarding mirroring)
|
||||
local error_msg = handle_schematics.place_building_from_file(
|
||||
start_pos,
|
||||
end_pos,
|
||||
building_name,
|
||||
replacements,
|
||||
plot.o,
|
||||
build_chest.building[ building_name ].axis, plot.mirror, 1, true );
|
||||
formspec = formspec.."label[3,3;The building has been reset.]";
|
||||
if( error_msg ) then
|
||||
formspec = formspec..'label[4,3;Error: '..tostring( fields.error_msg ).."]";
|
||||
end
|
||||
end
|
||||
minetest.show_formspec( pname, "mg_villages:formspec_plotmarker", formspec );
|
||||
return;
|
||||
|
||||
elseif( fields.info and fields.info ~= "" ) then
|
||||
local show_material_text = "Change materials used";
|
||||
if( not( minetest.check_player_privs( pname, {protection_bypass=true}))) then
|
||||
show_material_text = "Show materials used";
|
||||
end
|
||||
|
||||
minetest.show_formspec( pname, "mg_villages:formspec_plotmarker",
|
||||
formspec..
|
||||
"button[9.9,0.4;2,0.5;back;Back]"..
|
||||
"button[3,3;5,0.5;create_backup;Create backup of current stage]"..
|
||||
"button[4,4;3,0.5;show_materials;"..show_material_text.."]"..
|
||||
"button[4,5;3,0.5;reset_building;Reset building]"..
|
||||
"button[4,6;3,0.5;remove_building;Remove building]");
|
||||
return;
|
||||
end
|
||||
|
||||
local owner = plot.owner;
|
||||
local btype = plot.btype;
|
||||
|
||||
|
||||
local original_formspec = "size[8,3]"..
|
||||
"button[7.0,0.0;1.0,0.5;info;Info]"..
|
||||
"button[6.0,1.0;2.0,0.5;inhabitants;Who lives here]"..
|
||||
"label[1.0,0.5;Plot No.: "..tostring( plot_nr ).."]"..
|
||||
"label[2.5,0.5;Building:]"..
|
||||
"label[3.5,0.5;"..tostring( mg_villages.BUILDINGS[btype].scm )..mirror_str.."]"..
|
||||
"field[20,20;0.1,0.1;pos2str;Pos;"..minetest.pos_to_string( pos ).."]";
|
||||
local formspec = "";
|
||||
local ifinhabit = "";
|
||||
|
||||
-- Get Price
|
||||
local price = "default:gold_ingot 2";
|
||||
|
||||
if (btype ~= 'road' and mg_villages.BUILDINGS[btype]) then
|
||||
local plot_descr = 'Plot No. '..tostring( plot_nr ).. ' with '..tostring( mg_villages.BUILDINGS[btype].scm)
|
||||
|
||||
if (mg_villages.BUILDINGS[btype].price) then
|
||||
price = mg_villages.BUILDINGS[btype].price;
|
||||
elseif (mg_villages.BUILDINGS[btype].typ and mg_villages.prices[ mg_villages.BUILDINGS[btype].typ ]) then
|
||||
price = mg_villages.prices[ mg_villages.BUILDINGS[btype].typ ];
|
||||
end
|
||||
-- Get if is inhabitant house
|
||||
if (mg_villages.BUILDINGS[btype].inh and mg_villages.BUILDINGS[btype].inh > 0 ) then
|
||||
ifinhabit = "label[1,1.5;Owners of this plot count as village inhabitants.]";
|
||||
end
|
||||
end
|
||||
-- Determine price depending on building type
|
||||
local price_stack= ItemStack( price );
|
||||
|
||||
|
||||
-- If nobody owns the plot
|
||||
if (not(owner) or owner=='') then
|
||||
|
||||
formspec = original_formspec ..
|
||||
"label[1,1;You can buy this plot for]"..
|
||||
"label[3.8,1;"..tostring( price_stack:get_count() ).." x ]"..
|
||||
"item_image[4.3,0.8;1,1;"..( price_stack:get_name() ).."]"..
|
||||
ifinhabit..
|
||||
"button[2,2.5;1.5,0.5;buy;Buy plot]"..
|
||||
"button_exit[4,2.5;1.5,0.5;abort;Exit]";
|
||||
|
||||
-- On Press buy button
|
||||
if (fields['buy']) then
|
||||
local inv = player:get_inventory();
|
||||
|
||||
if not mg_villages.all_villages[village_id].ownerlist then
|
||||
mg_villages.all_villages[village_id].ownerlist = {}
|
||||
end
|
||||
|
||||
-- Check if player already has a house in the village
|
||||
if mg_villages.all_villages[village_id].ownerlist[pname] then
|
||||
formspec = formspec.."label[1,1.9;Sorry. You already have a plot in this village.]";
|
||||
|
||||
-- Check if the price can be paid
|
||||
elseif( inv and inv:contains_item( 'main', price_stack )) then
|
||||
formspec = original_formspec..
|
||||
"label[1,1;Congratulations! You have bought this plot.]"..
|
||||
"button_exit[5.75,2.5;1.5,0.5;abort;Exit]";
|
||||
mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].owner = pname;
|
||||
if mg_villages.all_villages[village_id].ownerlist then
|
||||
mg_villages.all_villages[village_id].ownerlist[pname] = true;
|
||||
else
|
||||
mg_villages.all_villages[village_id].ownerlist[pname] = true;
|
||||
end
|
||||
meta:set_string('infotext', 'Plot No. '..tostring( plot_nr ).. ' with '..tostring( mg_villages.BUILDINGS[btype].scm)..' (owned by '..tostring( pname )..')');
|
||||
-- save the data so that it survives server restart
|
||||
mg_villages.save_data();
|
||||
-- substract the price from the players inventory
|
||||
inv:remove_item( 'main', price_stack );
|
||||
else
|
||||
formspec = formspec.."label[1,1.9;Sorry. You are not able to pay the price.]";
|
||||
end
|
||||
end
|
||||
|
||||
-- If player is the owner of the plot
|
||||
elseif (owner==pname) then
|
||||
|
||||
-- Check if inhabitant house
|
||||
if(btype ~= 'road'
|
||||
and mg_villages.BUILDINGS[btype]
|
||||
and mg_villages.BUILDINGS[btype].inh
|
||||
and mg_villages.BUILDINGS[btype].inh > 0 ) then
|
||||
|
||||
ifinhabit = "label[1,1.5;You are allowed to modify the common village area.]";
|
||||
end
|
||||
|
||||
formspec = original_formspec.."size[8,3]"..
|
||||
"label[1,1;This is your plot. You have bought it.]"..
|
||||
"button[0.75,2.5;3,0.5;add_remove;Add/Remove Players]"..
|
||||
ifinhabit..
|
||||
"button_exit[3.75,2.5;2.0,0.5;abandon;Abandon plot]"..
|
||||
"button_exit[5.75,2.5;1.5,0.5;abort;Exit]";
|
||||
|
||||
-- If Player wants to abandon plot
|
||||
if(fields['abandon'] ) then
|
||||
formspec = original_formspec..
|
||||
"label[1,1;You have abandoned this plot.]"..
|
||||
"button_exit[5.75,2.5;1.5,0.5;abort;Exit]";
|
||||
mg_villages.all_villages[village_id].ownerlist[pname] = nil;
|
||||
mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].can_edit = {}
|
||||
mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].owner = nil;
|
||||
-- Return price to player
|
||||
local inv = player:get_inventory();
|
||||
inv:add_item( 'main', price_stack );
|
||||
meta:set_string('infotext', 'Plot No. '..tostring( plot_nr ).. ' with '..tostring( mg_villages.BUILDINGS[btype].scm) );
|
||||
mg_villages.save_data();
|
||||
end
|
||||
|
||||
-- If Player wants to add/remove trusted players
|
||||
if (fields['add_remove']) then
|
||||
local previousTrustees = mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].can_edit
|
||||
local output = "";
|
||||
if previousTrustees == nil then
|
||||
previousTrustees = {}
|
||||
else
|
||||
for _, player in ipairs(previousTrustees) do
|
||||
output = output..player.."\n"
|
||||
end
|
||||
end
|
||||
formspec = "size[8,3]"..
|
||||
"field[20,20;0.1,0.1;pos2str;Pos;"..minetest.pos_to_string( pos ).."]"..
|
||||
"textarea[0.3,0.2;8,2.5;ownerplayers;Trusted Players;"..output.."]"..
|
||||
"button[3.25,2.5;1.5,0.5;savetrustees;Save]";
|
||||
|
||||
mg_villages.save_data()
|
||||
end
|
||||
|
||||
-- Save trusted players
|
||||
if (fields["savetrustees"] == "Save") then
|
||||
|
||||
if not mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].can_edit then
|
||||
mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].can_edit = {}
|
||||
end
|
||||
|
||||
local x = 1;
|
||||
for _, player in ipairs(fields.ownerplayers:split("\n")) do
|
||||
mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].can_edit[x] = player
|
||||
x = x + 1
|
||||
end
|
||||
|
||||
mg_villages.save_data();
|
||||
end
|
||||
|
||||
-- If A different Player owns plot
|
||||
else
|
||||
formspec = original_formspec.."label[1,1;"..tostring( owner ).." owns this plot.]"..
|
||||
"button_exit[3,2.5;1.5,0.5;abort;Exit]";
|
||||
end
|
||||
|
||||
minetest.show_formspec( pname, "mg_villages:formspec_plotmarker", formspec );
|
||||
end
|
||||
|
||||
|
||||
|
||||
mg_villages.form_input_handler = function( player, formname, fields)
|
||||
-- mg_villages.print(mg_villages.DEBUG_LEVEL_NORMAL,minetest.serialize(fields));
|
||||
if( not( mg_villages.ENABLE_PROTECTION )) then
|
||||
return false;
|
||||
end
|
||||
|
||||
-- teleport to a plot or mob
|
||||
if( fields[ 'teleport_to' ]
|
||||
and fields[ 'pos2str' ]
|
||||
and player ) then
|
||||
local pname = player:get_player_name();
|
||||
if( minetest.check_player_privs( pname, {teleport=true})) then
|
||||
local pos = minetest.string_to_pos( fields.pos2str );
|
||||
-- teleport the player to the target position
|
||||
player:moveto( { x=pos.x, y=(pos.y+1), z=pos.z }, false);
|
||||
else
|
||||
minetest.chat_sned_player( pname, "Sorry. You do not have the teleport privilege.");
|
||||
end
|
||||
-- do not abort; continue with showing the formspec
|
||||
end
|
||||
|
||||
|
||||
-- are we supposed to show information about a particular mob?
|
||||
local mob_selected = nil;
|
||||
-- show previous mob that lives on the plot
|
||||
if( formname=="mg_villages:formspec_list_one_mob" and fields["prev"] and fields["bed_nr"]) then
|
||||
mob_selected = tonumber(fields.bed_nr) - 1;
|
||||
-- show next mob that lives on the mob
|
||||
elseif( formname=="mg_villages:formspec_list_one_mob" and fields["next"] and fields["bed_nr"]) then
|
||||
mob_selected = tonumber(fields.bed_nr) + 1;
|
||||
-- show informaton about mob selected from list of inhabitants
|
||||
elseif( not( fields['back_to_houselist'])
|
||||
and fields['mg_villages:formspec_list_inhabitants']
|
||||
and fields['mg_villages:formspec_list_inhabitants']~=""
|
||||
and fields['village_id']
|
||||
and fields['plot_nr']) then
|
||||
local selection = minetest.explode_table_event( fields['mg_villages:formspec_list_inhabitants'] );
|
||||
mob_selected = selection.row;
|
||||
end
|
||||
|
||||
-- this index has to be a number and not a string
|
||||
fields.plot_nr = tonumber( fields.plot_nr or "0");
|
||||
local pname = player:get_player_name();
|
||||
|
||||
-- provide information about a particular mob
|
||||
if( mob_selected
|
||||
and fields.village_id
|
||||
and fields.plot_nr
|
||||
and mg_villages.all_villages[ fields.village_id ]
|
||||
and mg_villages.all_villages[ fields.village_id ].to_add_data
|
||||
and mg_villages.all_villages[ fields.village_id ].to_add_data.bpos
|
||||
and mg_villages.all_villages[ fields.village_id ].to_add_data.bpos[ fields.plot_nr ])then
|
||||
-- and mg_villages.all_villages[ fields.village_id ].to_add_data.bpos[ fields.plot_nr ].beds[mob_selected]) then
|
||||
if( not( mg_villages.all_villages[ fields.village_id ].to_add_data.bpos[ fields.plot_nr ].beds)
|
||||
or not( mg_villages.all_villages[ fields.village_id ].to_add_data.bpos[ fields.plot_nr ].beds[ mob_selected] )) then
|
||||
-- allow to click at the worker
|
||||
local bpos = mg_villages.all_villages[ fields.village_id ].to_add_data.bpos;
|
||||
if( bpos[ fields.plot_nr ].worker
|
||||
and bpos[ fields.plot_nr ].worker.lives_at
|
||||
and bpos[ bpos[ fields.plot_nr ].worker.lives_at ]
|
||||
and bpos[ bpos[ fields.plot_nr ].worker.lives_at ].beds
|
||||
and bpos[ bpos[ fields.plot_nr ].worker.lives_at ].beds[1] ) then
|
||||
fields.plot_nr = tonumber(bpos[ fields.plot_nr ].worker.lives_at);
|
||||
mob_selected = 1;
|
||||
-- allow to click at the owner
|
||||
elseif( bpos[ fields.plot_nr ].belongs_to
|
||||
and bpos[ bpos[ fields.plot_nr ].belongs_to ]
|
||||
and bpos[ bpos[ fields.plot_nr ].belongs_to ].beds
|
||||
and bpos[ bpos[ fields.plot_nr ].belongs_to ].beds[1] ) then
|
||||
fields.plot_nr = tonumber(bpos[ fields.plot_nr ].belongs_to);
|
||||
mob_selected = 1;
|
||||
-- this is not a mob
|
||||
else
|
||||
mob_selected = nil;
|
||||
end
|
||||
end
|
||||
if( mob_selected ) then
|
||||
local village = mg_villages.all_villages[ fields.village_id ];
|
||||
minetest.show_formspec( pname, "mg_villages:formspec_list_one_mob",
|
||||
mg_villages.inhabitants.print_mob_info( village.to_add_data.bpos, fields.plot_nr, fields.village_id, mob_selected, pname ));
|
||||
return true;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- are we supposed to show information about a particular plot?
|
||||
local plot_selected = nil;
|
||||
-- show previous plot of that village
|
||||
if( formname=="mg_villages:formspec_list_inhabitants" and fields["prev"] and fields["plot_nr"]) then
|
||||
plot_selected = fields.plot_nr - 1;
|
||||
-- show next plot of that village
|
||||
elseif( formname=="mg_villages:formspec_list_inhabitants" and fields["next"] and fields["plot_nr"]) then
|
||||
plot_selected = fields.plot_nr + 1;
|
||||
-- back from the list of details of a mob to the list of inhabitants of the plot where it lives
|
||||
elseif( fields['back_to_houselist'] ) then
|
||||
plot_selected = fields.plot_nr;
|
||||
-- show informaton about plot selected from list of plots in a village
|
||||
elseif( not( fields['back_to_plotlist'])
|
||||
and fields['mg_villages:formspec_list_plots']
|
||||
and fields['mg_villages:formspec_list_plots']~=""
|
||||
and fields['village_id']) then
|
||||
local selection = minetest.explode_table_event( fields['mg_villages:formspec_list_plots'] );
|
||||
plot_selected = selection.row-1;
|
||||
end
|
||||
|
||||
-- provide information about the inhabitants of a particular plot
|
||||
if( plot_selected
|
||||
and fields.village_id
|
||||
and mg_villages.all_villages[ fields.village_id ]
|
||||
and mg_villages.all_villages[ fields.village_id ].to_add_data
|
||||
and mg_villages.all_villages[ fields.village_id ].to_add_data.bpos
|
||||
and mg_villages.all_villages[ fields.village_id ].to_add_data.bpos[ plot_selected ]) then
|
||||
|
||||
local village = mg_villages.all_villages[ fields.village_id ];
|
||||
minetest.show_formspec( pname, "mg_villages:formspec_list_inhabitants",
|
||||
mg_villages.inhabitants.print_house_info( village.to_add_data.bpos, plot_selected, fields.village_id, pname ));
|
||||
return true;
|
||||
end
|
||||
|
||||
|
||||
-- are we supposed to show the plots contained in a particular village?
|
||||
local village_selected = nil;
|
||||
-- where are we currently in the list of villages as shown to that particular player?
|
||||
local liste = mg_villages.tmp_player_village_list[ pname ];
|
||||
local curr_list_pos = -1;
|
||||
if( liste ) then
|
||||
for i,v in ipairs( liste ) do
|
||||
if( fields.village_id and v==fields.village_id ) then
|
||||
curr_list_pos = i;
|
||||
end
|
||||
end
|
||||
end
|
||||
-- show previous village in list
|
||||
if( formname=="mg_villages:formspec_list_plots" and fields["prev"] and curr_list_pos>1) then
|
||||
village_selected = liste[ curr_list_pos - 1 ];
|
||||
-- show next village
|
||||
elseif( formname=="mg_villages:formspec_list_plots" and fields["next"] and curr_list_pos<#liste) then
|
||||
village_selected = liste[ curr_list_pos + 1 ];
|
||||
-- back from the list of inhabitants to the list of plots of a village
|
||||
elseif( fields['back_to_plotlist'] and fields.village_id) then
|
||||
village_selected = fields.village_id;
|
||||
-- show informaton about all plots in the selected village
|
||||
elseif( not( fields['back_to_villagelist'])
|
||||
and fields['mg_villages:formspec_list_villages']
|
||||
and fields['mg_villages:formspec_list_villages']~="" ) then
|
||||
local selection = minetest.explode_table_event( fields['mg_villages:formspec_list_villages'] );
|
||||
-- this is the village the player is intrested in
|
||||
village_selected = mg_villages.tmp_player_village_list[ pname ][ selection.row-1 ];
|
||||
end
|
||||
|
||||
-- the player has selected a village in the village list
|
||||
if( village_selected
|
||||
and mg_villages.all_villages[ village_selected ]
|
||||
and mg_villages.all_villages[ village_selected ].to_add_data
|
||||
and mg_villages.all_villages[ village_selected ].to_add_data.bpos ) then
|
||||
|
||||
fields.village_id = village_selected;
|
||||
-- show the player a list of plots of the selected village
|
||||
mg_villages.list_plots_formspec( player, 'mg_villages:formspec_list_plots', fields );
|
||||
return true;
|
||||
end
|
||||
|
||||
-- back from plotlist of a village to the list of nearby villages
|
||||
-- mg_villages.list_villages_formspec can be found in chat_commands.lua
|
||||
if( fields['back_to_villagelist']) then
|
||||
mg_villages.list_villages_formspec( player, "mg_villages:formspec_list_villages", {});
|
||||
|
||||
return true;
|
||||
end
|
||||
|
||||
if( (formname == "mg_villages:formspec_plotmarker") and fields.pos2str and not( fields.abort )) then
|
||||
local pos = minetest.string_to_pos( fields.pos2str );
|
||||
mg_villages.plotmarker_formspec( pos, formname, fields, player );
|
||||
return true;
|
||||
end
|
||||
return false;
|
||||
end
|
||||
|
||||
|
||||
minetest.register_on_player_receive_fields( mg_villages.form_input_handler )
|
|
@ -0,0 +1,163 @@
|
|||
-- get the id of the village pos lies in (or nil if outside of villages)
|
||||
mg_villages.get_town_id_at_pos = function( pos )
|
||||
for id, v in pairs( mg_villages.all_villages ) do
|
||||
local height_diff = pos.y - v.vh;
|
||||
if( height_diff < 40 and height_diff > -10 ) then
|
||||
|
||||
local size = v.vs * 3;
|
||||
if( ( math.abs( pos.x - v.vx ) < size )
|
||||
and ( math.abs( pos.z - v.vz ) < size )) then
|
||||
local village_noise = minetest.get_perlin(7635, 3, 0.5, 16);
|
||||
if( mg_villages.inside_village_area( pos.x, pos.z, v, village_noise)) then
|
||||
|
||||
local node = minetest.get_node( pos );
|
||||
-- leaves can be digged in villages
|
||||
if( node and node.name ) then
|
||||
if( minetest.registered_nodes[ node.name ]
|
||||
and minetest.registered_nodes[ node.name ].groups
|
||||
and minetest.registered_nodes[ node.name ].groups.leaves ) then
|
||||
return nil;
|
||||
elseif( node.name=='default:snow' ) then
|
||||
return nil;
|
||||
-- bones can be digged in villages
|
||||
elseif( node.name == 'bones:bones' ) then
|
||||
return nil;
|
||||
else
|
||||
return id;
|
||||
end
|
||||
else
|
||||
return id;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil;
|
||||
end
|
||||
|
||||
|
||||
-- checks if the plot marker is still present; places a new one if needed
|
||||
-- p: plot data (position, size, orientation, owner, ..)
|
||||
mg_villages.check_plot_marker = function( p, plot_nr, village_id )
|
||||
-- roads cannot be bought
|
||||
if( p.btype and p.btype=="road" ) then
|
||||
return;
|
||||
end
|
||||
local plot_pos = { x=p.x, y=p.y, z=p.z };
|
||||
if( p.o==3 ) then
|
||||
plot_pos = { x=p.x, y=p.y+1, z=p.z-1 };
|
||||
elseif( p.o==1 ) then
|
||||
plot_pos = { x=p.x+p.bsizex-1, y=p.y+1, z=p.z+p.bsizez };
|
||||
elseif ( p.o==2 ) then
|
||||
plot_pos = { x=p.x+p.bsizex, y=p.y+1, z=p.z };
|
||||
elseif ( p.o==0 ) then
|
||||
plot_pos = { x=p.x-1, y=p.y+1, z=p.z+p.bsizez-1 };
|
||||
end
|
||||
-- is the plotmarker still present?
|
||||
local node = minetest.get_node( plot_pos );
|
||||
if( not(node) or not(node.name) or node.name ~= "mg_villages:plotmarker" ) then
|
||||
-- place a new one if needed
|
||||
minetest.set_node( plot_pos, {name="mg_villages:plotmarker", param2=p.o});
|
||||
local meta = minetest.get_meta( plot_pos );
|
||||
-- strange error happend; maybe we're more lucky next time...
|
||||
if( not( meta )) then
|
||||
return;
|
||||
end
|
||||
meta:set_string('village_id', village_id );
|
||||
meta:set_int( 'plot_nr', plot_nr );
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
local old_is_protected = minetest.is_protected
|
||||
minetest.is_protected = function(pos, name)
|
||||
|
||||
if( not( mg_villages.ENABLE_PROTECTION )) then
|
||||
return old_is_protected( pos, name );
|
||||
end
|
||||
|
||||
-- allow players with protection_bypass to build anyway
|
||||
if( minetest.check_player_privs( name, {protection_bypass=true})) then
|
||||
return false;
|
||||
end
|
||||
|
||||
local village_id = mg_villages.get_town_id_at_pos( pos );
|
||||
if( village_id ) then
|
||||
local is_houseowner = false;
|
||||
for nr, p in ipairs( mg_villages.all_villages[ village_id ].to_add_data.bpos ) do
|
||||
|
||||
local trustedusers = p.can_edit
|
||||
local trustedUser = false
|
||||
if trustedusers ~= nil then
|
||||
for _,trusted in ipairs(trustedusers) do
|
||||
if trusted == name then
|
||||
trustedUser = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- we have located the right plot; the player can build here if he owns this particular plot
|
||||
if( p.x <= pos.x and (p.x + p.bsizex) >= pos.x
|
||||
and p.z <= pos.z and (p.z + p.bsizez) >= pos.z) then
|
||||
|
||||
-- place a new plot marker if necessary
|
||||
mg_villages.check_plot_marker( p, nr, village_id );
|
||||
|
||||
-- If player has been trusted by owner, can build
|
||||
if (trustedUser) then
|
||||
return false;
|
||||
-- If player is owner, can build
|
||||
elseif( p.owner and p.owner == name ) then
|
||||
return false;
|
||||
-- the allmende can be used by all
|
||||
elseif( mg_villages.BUILDINGS[p.btype] and mg_villages.BUILDINGS[p.btype].typ=="allmende" ) then
|
||||
return false;
|
||||
-- the player cannot modify other plots, even though he may be house owner of another house and be allowed to modify common ground
|
||||
else
|
||||
return true;
|
||||
end
|
||||
-- if the player just owns another plot in the village, check if it's one where villagers may live
|
||||
elseif( p.owner and p.owner == name or trustedUser) then
|
||||
local btype = mg_villages.all_villages[ village_id ].to_add_data.bpos[ nr ].btype;
|
||||
if( btype ~= 'road'
|
||||
and mg_villages.BUILDINGS[btype]
|
||||
and mg_villages.BUILDINGS[btype].inh
|
||||
and mg_villages.BUILDINGS[btype].inh > 0 ) then
|
||||
is_houseowner = true;
|
||||
-- check the node below
|
||||
local node = minetest.get_node( {x=pos.x, y=pos.y-1, z=pos.z});
|
||||
-- replace the fake, inaktive village soil with real farming soil if a player diggs the plant above
|
||||
if( node and node.name and node.name=="mg_villages:soil" ) then
|
||||
minetest.swap_node( {x=pos.x, y=pos.y-1, z=pos.z}, {name="farming:soil_wet"});
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- players who own a house in town where villagers may live (not only work!)
|
||||
-- are allowed to modify common ground
|
||||
if( is_houseowner ) then
|
||||
return false;
|
||||
end
|
||||
return true;
|
||||
end
|
||||
return old_is_protected(pos, name);
|
||||
end
|
||||
|
||||
|
||||
minetest.register_on_protection_violation( function(pos, name)
|
||||
|
||||
if( not( mg_villages.ENABLE_PROTECTION )) then
|
||||
return;
|
||||
end
|
||||
|
||||
local found = mg_villages.get_town_id_at_pos( pos );
|
||||
if( not( found ) or not( mg_villages.all_villages[ found ])) then
|
||||
minetest.chat_send_player( name, 'Error: This area does not belong to a village.');
|
||||
return;
|
||||
end
|
||||
|
||||
minetest.chat_send_player( name, "You are inside of the area of the village "..
|
||||
tostring( mg_villages.all_villages[ found ].name )..
|
||||
". The inhabitants do not allow you any modifications.");
|
||||
end );
|
|
@ -0,0 +1,996 @@
|
|||
|
||||
-- fountains and lakes have river water, not salt water
|
||||
handle_schematics.global_replacement_table[ 'default:water_source' ] = 'default:river_water_source';
|
||||
handle_schematics.global_replacement_table[ 'default:water_flowing' ] = 'default:river_water_flowing';
|
||||
-- always use the cheaper simulated soil that has no problem with water beeing 4 nodes away
|
||||
handle_schematics.global_replacement_table[ 'farming:soil_wet' ] = 'mg_villages:soil';
|
||||
handle_schematics.global_replacement_table[ 'farming:soil' ] = 'mg_villages:soil';
|
||||
handle_schematics.global_replacement_table[ 'farming:desert_sand_soil_wet' ] = 'mg_villages:desert_sand_soil';
|
||||
handle_schematics.global_replacement_table[ 'farming:desert_sand_soil' ] = 'mg_villages:desert_sand_soil';
|
||||
|
||||
-- if cottages is not installed, place "normal" beds in the chateau and wherever else needed
|
||||
if( not( minetest.get_modpath( 'cottages' ))) then
|
||||
handle_schematics.global_replacement_table[ 'cottages:bed_head' ] = 'beds:fancy_bed_top';
|
||||
handle_schematics.global_replacement_table[ 'cottages:bed_foot' ] = 'beds:fancy_bed_bottom';
|
||||
end
|
||||
|
||||
-- ethereal comes with some intresting trees
|
||||
if( minetest.get_modpath( 'ethereal' )) then
|
||||
mg_villages.ethereal_trees = {'acacia','willow','redwood','frost','mushroom','yellow','palm','banana'};
|
||||
end
|
||||
|
||||
if( minetest.get_modpath( 'forest' )) then
|
||||
mg_villages.forest_trees = {'beech','birch','cherry','fir','ginkgo','lavender','mirabelle','oak','plum','willow'};
|
||||
end
|
||||
|
||||
-- we are dealing with the TinyTrees mod from Bas080
|
||||
if( minetest.get_modpath( 'trees' )
|
||||
and minetest.registered_nodes[ 'trees:wood_mangrove' ] ) then
|
||||
mg_villages.tinytrees_trees = {'mangrove','palm','conifer'};
|
||||
end
|
||||
|
||||
-- The trees modname is not unique; there are other mods which bear that name.
|
||||
-- If all the other mods are present as well, it's a strong indication for realtest beeing the game.
|
||||
if( minetest.get_modpath( 'trees' )
|
||||
and minetest.get_modpath( 'anvil')
|
||||
and minetest.get_modpath( 'joiner_table')
|
||||
and minetest.get_modpath( 'scribing_table' )) then
|
||||
mg_villages.realtest_trees = {'ash','aspen','birch','maple','chestnut','pine','spruce'};
|
||||
--print('REALTEST trees will be used.'); else print( 'NO REALTEST trees');
|
||||
|
||||
-- realtest is very special as far as stairs are concerned
|
||||
mg_villages.realtest_stairs = {'default:stone','default:stone_flat','default:stone_bricks',
|
||||
'default:desert_stone_flat','default:desert_stone_bricks'};
|
||||
for i,v in ipairs(metals.list) do
|
||||
table.insert( mg_villages.realtest_stairs, 'metals:'..v..'_block' );
|
||||
end
|
||||
-- the list of minteral names is local; so we can't add "decorations:"..mineral[1].."_block"
|
||||
end
|
||||
|
||||
|
||||
-- only the function mg_villages.get_replacement_table(..) is called from outside this file
|
||||
|
||||
mg_villages.replace_materials = function( replacements, pr, original_materials, prefixes, materials, old_material )
|
||||
|
||||
local postfixes = {};
|
||||
local use_realtest_stairs = false;
|
||||
-- handle realtest stairs/slabs
|
||||
if( mg_villages.realtest_trees
|
||||
and #prefixes==3
|
||||
and prefixes[1]=='stairs:stair_' and prefixes[2]=='stairs:slab_' and prefixes[3]=='default:' ) then
|
||||
|
||||
prefixes = {''};
|
||||
materials = mg_villages.realtest_stairs;
|
||||
postfixes = {''};
|
||||
use_realtest_stairs = true;
|
||||
|
||||
elseif( mg_villages.realtest_trees
|
||||
and #prefixes==1
|
||||
and prefixes[1]=='stairs:stair_') then
|
||||
|
||||
return;
|
||||
else
|
||||
for i,v in ipairs( prefixes ) do
|
||||
postfixes[i] = '';
|
||||
end
|
||||
end
|
||||
|
||||
local known_materials = {};
|
||||
local wood_found = false;
|
||||
-- for all alternate materials
|
||||
for i,m in ipairs( materials ) do
|
||||
-- check if that material exists for each supplied prefix
|
||||
for j,p in ipairs( prefixes ) do
|
||||
-- if wood is present, later on try moretrees wood as well
|
||||
if( 'default:wood' == m ) then
|
||||
wood_found = true;
|
||||
end
|
||||
if( minetest.registered_nodes[ p..m..postfixes[j] ] ) then
|
||||
table.insert( known_materials, m..postfixes[j] );
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- support wooden planks from moretrees
|
||||
if( wood_found and mg_villages.moretrees_treelist ) then
|
||||
for _,v in ipairs( mg_villages.moretrees_treelist ) do
|
||||
if( minetest.registered_nodes[ "moretrees:"..v[1].."_planks"] ) then
|
||||
table.insert( known_materials, "moretrees:"..v[1].."_planks" );
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
-- deco is used by BigFreakingDig; as that one lacks default nodes, it doesn't work out here
|
||||
if( wood_found and minetest.get_modpath('deco')) then
|
||||
local bfd_treelist = {'birch', 'cherry', 'evergreen', 'oak' };
|
||||
for _,v in ipairs( bfd_treelist ) do
|
||||
if( minetest.registered_nodes[ "deco:"..v.."_plank"] ) then
|
||||
table.insert( known_materials, "deco:"..v.."_plank" );
|
||||
end
|
||||
end
|
||||
end
|
||||
--]]
|
||||
|
||||
if( wood_found and mg_villages.ethereal_trees ) then
|
||||
for _,v in ipairs( mg_villages.ethereal_trees ) do
|
||||
-- mushroom in ethereal is a pretty decorative material; increase its probability
|
||||
if( v == 'mushroom' ) then
|
||||
table.insert( known_materials, "ethereal:mushroom_pore" );
|
||||
table.insert( known_materials, "ethereal:mushroom_pore" );
|
||||
table.insert( known_materials, "ethereal:mushroom_pore" );
|
||||
-- also increase probability for the decorative blueish wood
|
||||
table.insert( known_materials, "ethereal:frost_wood" );
|
||||
table.insert( known_materials, "ethereal:frost_wood" );
|
||||
elseif( minetest.registered_nodes[ "ethereal:"..v.."_wood"] ) then
|
||||
table.insert( known_materials, "ethereal:"..v.."_wood" );
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if( wood_found and mg_villages.forest_trees ) then
|
||||
for _,v in ipairs( mg_villages.forest_trees ) do
|
||||
if( minetest.registered_nodes[ 'forest:'..v..'_wood'] ) then
|
||||
table.insert( known_materials, 'forest:'..v..'_wood' );
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if( wood_found and mg_villages.tinytrees_trees ) then
|
||||
for _,v in ipairs( mg_villages.tinytrees_trees ) do
|
||||
if( minetest.registered_nodes[ 'trees:wood_'..v] ) then
|
||||
table.insert( known_materials, 'trees:wood_'..v );
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if( wood_found and mg_villages.realtest_trees ) then
|
||||
for _,v in ipairs( mg_villages.realtest_trees ) do
|
||||
if( minetest.registered_nodes[ 'trees:'..v..'_planks'] ) then
|
||||
table.insert( known_materials, 'trees:'..v..'_planks' );
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- nothing found which could be used
|
||||
if( #known_materials < 1 ) then
|
||||
return;
|
||||
end
|
||||
local new_material = known_materials[ pr:next( 1, #known_materials )];
|
||||
|
||||
if( use_realtest_stairs == true ) then
|
||||
table.insert( replacements, { original_materials[ 1 ], new_material..'_stair' } );
|
||||
table.insert( replacements, { original_materials[ 2 ], new_material..'_slab' } );
|
||||
table.insert( replacements, { original_materials[ 3 ], new_material } );
|
||||
table.insert( replacements, { original_materials[ 1 ]..'upside_down', new_material..'_stair_upside_down' } );
|
||||
table.insert( replacements, { original_materials[ 2 ]..'upside_down', new_material..'_slab_upside_down' } );
|
||||
return new_material;
|
||||
end
|
||||
|
||||
-- no replacement necessary if we did choose the same material as before
|
||||
if( new_material == old_material or old_material == (prefixes[1]..new_material)) then
|
||||
return old_material;
|
||||
end
|
||||
|
||||
for i,v in ipairs( prefixes ) do
|
||||
table.insert( replacements, { original_materials[ i ], v..new_material } );
|
||||
end
|
||||
return new_material;
|
||||
end
|
||||
|
||||
-- replace the tree trunk as well so that it fits to the wood type
|
||||
mg_villages.replace_tree_trunk = function( replacements, wood_type )
|
||||
if( wood_type == 'default:junglewood' ) then
|
||||
table.insert( replacements, {'default:tree', 'default:jungletree'});
|
||||
elseif( wood_type == 'default:pine_wood' ) then
|
||||
table.insert( replacements, {'default:tree', 'default:pine_tree'});
|
||||
elseif( wood_type == 'default:acacia_wood' ) then
|
||||
table.insert( replacements, {'default:tree', 'default:acacia_tree'});
|
||||
elseif( wood_type == 'default:aspen_wood' ) then
|
||||
table.insert( replacements, {'default:tree', 'default:aspen_tree'});
|
||||
elseif( wood_type == 'mg:savannawood' ) then
|
||||
table.insert( replacements, {'default:tree', 'mg:savannatree'});
|
||||
elseif( wood_type == 'mg:pinewood' ) then
|
||||
table.insert( replacements, {'default:tree', 'mg:pinetree'});
|
||||
|
||||
elseif( mg_villages.moretrees_treelist ) then
|
||||
for _,v in ipairs( mg_villages.moretrees_treelist ) do
|
||||
if( wood_type == "moretrees:"..v[1].."_planks" ) then
|
||||
table.insert( replacements, {'default:tree', "moretrees:"..v[1].."_trunk"});
|
||||
table.insert( replacements, {'default:leaves', "moretrees:"..v[1].."_leaves"});
|
||||
end
|
||||
end
|
||||
|
||||
elseif( wood_type == 'deco:birch_plank' ) then
|
||||
table.insert( replacements, {'default:tree', "mapgen:birch_log"});
|
||||
elseif( wood_type == 'deco:cherry_plank' ) then
|
||||
table.insert( replacements, {'default:tree', "mapgen:cherry_log"});
|
||||
elseif( wood_type == 'deco:evergreen_plank' ) then
|
||||
table.insert( replacements, {'default:tree', "mapgen:evergreen_log"});
|
||||
elseif( wood_type == 'deco:oak_plank' ) then
|
||||
table.insert( replacements, {'default:tree', "mapgen:oak_log"});
|
||||
|
||||
elseif( wood_type == 'ethereal:frost_wood' ) then
|
||||
table.insert( replacements, {'default:tree', "ethereal:frost_tree"});
|
||||
|
||||
elseif( wood_type == "ethereal:mushroom_pore" ) then
|
||||
table.insert( replacements, {'default:tree', "ethereal:mushroom_trunk"});
|
||||
|
||||
elseif( mg_villages.ethereal_trees ) then
|
||||
for _,v in ipairs( mg_villages.ethereal_trees ) do
|
||||
if( wood_type == "ethereal:"..v.."_wood" ) then
|
||||
table.insert( replacements, {'default:tree', "ethereal:"..v.."_trunk"});
|
||||
end
|
||||
end
|
||||
|
||||
elseif( mg_villages.forest_trees ) then
|
||||
for _,v in ipairs( mg_villages.forest_trees ) do
|
||||
if( wood_type == "forest:"..v.."_wood" ) then
|
||||
table.insert( replacements, {'default:tree', "forest:"..v.."_tree"});
|
||||
end
|
||||
end
|
||||
|
||||
elseif( mg_villages.tinytrees_trees ) then
|
||||
for _,v in ipairs( mg_villages.tinytrees_trees ) do
|
||||
if( wood_type == "trees:wood_"..v ) then
|
||||
table.insert( replacements, {'default:tree', "trees:tree_"..v});
|
||||
end
|
||||
end
|
||||
|
||||
elseif( mg_villages.realtest_trees ) then
|
||||
for _,v in ipairs( mg_villages.realtest_trees ) do
|
||||
if( wood_type == 'trees:'..v..'_planks' ) then
|
||||
table.insert( replacements, {'default:tree', "trees:"..v..'_log'});
|
||||
-- realtest does not have most of the nodes from default, so we need to replace them as well
|
||||
table.insert( replacements, {'default:wood', 'trees:'..v..'_planks'});
|
||||
table.insert( replacements, {'default:leaves', 'trees:'..v..'_leaves'});
|
||||
table.insert( replacements, {'default:ladder', 'trees:'..v..'_ladder'});
|
||||
table.insert( replacements, {'default:chest', 'trees:'..v..'_chest'});
|
||||
table.insert( replacements, {'default:chest_locked', 'trees:'..v..'_chest_locked'});
|
||||
table.insert( replacements, {'default:fence_wood', 'fences:'..v..'_fence'});
|
||||
table.insert( replacements, {'default:bookshelf', 'decorations:bookshelf_'..v});
|
||||
table.insert( replacements, {'doors:door_wood_t_1', 'doors:door_'..v..'_t_1'});
|
||||
table.insert( replacements, {'doors:door_wood_b_1', 'doors:door_'..v..'_b_1'});
|
||||
table.insert( replacements, {'doors:door_wood_t_2', 'doors:door_'..v..'_t_2'});
|
||||
table.insert( replacements, {'doors:door_wood_b_2', 'doors:door_'..v..'_b_2'});
|
||||
-- not really wood-realted, but needs to be replaced as well
|
||||
table.insert( replacements, {'default:furnace', 'oven:oven'});
|
||||
-- farming is also handled diffrently
|
||||
table.insert( replacements, {'farming:soil_wet', 'farming:soil'});
|
||||
table.insert( replacements, {'farming:cotton_1', 'farming:flax_1'});
|
||||
table.insert( replacements, {'farming:cotton_2', 'farming:flax_1'});
|
||||
table.insert( replacements, {'farming:cotton_3', 'farming:flax_2'});
|
||||
table.insert( replacements, {'farming:cotton_4', 'farming:flax_2'});
|
||||
table.insert( replacements, {'farming:cotton_5', 'farming:flax_3'});
|
||||
table.insert( replacements, {'farming:cotton_6', 'farming:flax_3'});
|
||||
table.insert( replacements, {'farming:cotton_7', 'farming:flax_4'});
|
||||
table.insert( replacements, {'farming:cotton_8', 'farming:flax_4'});
|
||||
-- stairs and slabs made out of default wood
|
||||
table.insert( replacements, {'stairs:stair_wood', 'trees:'..v..'_planks_stair'});
|
||||
table.insert( replacements, {'stairs:slab_wood', 'trees:'..v..'_planks_slab'});
|
||||
table.insert( replacements, {'stairs:stair_woodupside_down','trees:'..v..'_planks_stair_upside_down' } );
|
||||
table.insert( replacements, {'stairs:slab_woodupside_down', 'trees:'..v..'_planks_slab_upside_down' } );
|
||||
end
|
||||
end
|
||||
else
|
||||
return nil;
|
||||
end
|
||||
return wood_type;
|
||||
-- TODO if minetest.get_modpath("moreblocks") and moretrees.enable_stairsplus the
|
||||
end
|
||||
|
||||
|
||||
-- if buildings are made out of a certain wood type, people might expect trees of that type nearby
|
||||
mg_villages.replace_saplings = function( replacements, wood_type )
|
||||
if( wood_type == 'default:junglewood' ) then
|
||||
table.insert( replacements, {'default:sapling', 'default:junglesapling'});
|
||||
elseif( wood_type == 'default:pine_wood' ) then
|
||||
table.insert( replacements, {'default:sapling', 'default:pine_sapling'});
|
||||
elseif( wood_type == 'default:acacia_wood' ) then
|
||||
table.insert( replacements, {'default:sapling', 'default:acacia_sapling'});
|
||||
elseif( wood_type == 'default:aspen_wood' ) then
|
||||
table.insert( replacements, {'default:sapling', 'default:aspen_sapling'});
|
||||
elseif( wood_type == 'mg:savannawood' ) then
|
||||
table.insert( replacements, {'default:sapling', 'mg:savannasapling'});
|
||||
elseif( wood_type == 'mg:pinewood' ) then
|
||||
table.insert( replacements, {'default:sapling', 'mg:pinesapling'});
|
||||
elseif( mg_villages.moretrees_treelist ) then
|
||||
for _,v in ipairs( mg_villages.moretrees_treelist ) do
|
||||
if( wood_type == "moretrees:"..v[1].."_planks" ) then
|
||||
table.insert( replacements, {'default:sapling', "moretrees:"..v[1].."_sapling_ongen"});
|
||||
end
|
||||
end
|
||||
elseif( mg_villages.ethereal_trees ) then
|
||||
for _,v in ipairs( mg_villages.ethereal_trees ) do
|
||||
if( wood_type == "ethereal:"..v.."_wood" ) then
|
||||
table.insert( replacements, {'default:sapling', "ethereal:"..v.."_sapling"});
|
||||
end
|
||||
end
|
||||
|
||||
elseif( mg_villages.forest_trees ) then
|
||||
for _,v in ipairs( mg_villages.forest_trees ) do
|
||||
if( wood_type == "forest:"..v.."_wood" ) then
|
||||
table.insert( replacements, {'default:sapling', "forest:"..v.."_sapling"});
|
||||
end
|
||||
end
|
||||
|
||||
elseif( mg_villages.tinytrees_trees ) then
|
||||
for _,v in ipairs( mg_villages.tinytrees_trees ) do
|
||||
if( wood_type == "trees:wood_"..v ) then
|
||||
table.insert( replacements, {'default:sapling', "trees:sapling_"..v});
|
||||
end
|
||||
|
||||
end
|
||||
elseif( mg_villages.realtest_trees ) then
|
||||
for _,v in ipairs( mg_villages.realtest_trees ) do
|
||||
if( wood_type == 'trees:'..v..'_planks' ) then
|
||||
table.insert( replacements, {'default:sapling', "trees:"..v.."_sapling"});
|
||||
table.insert( replacements, {'default:junglesapling', "trees:"..v.."_sapling"});
|
||||
table.insert( replacements, {'default:pine_sapling', "trees:"..v.."_sapling"});
|
||||
table.insert( replacements, {'default:aspen_sapling', "trees:"..v.."_sapling"});
|
||||
end
|
||||
end
|
||||
|
||||
elseif( wood_type == 'deco:birch_plank' ) then
|
||||
table.insert( replacements, {'default:sapling', "mapgen:birch_sapling"});
|
||||
elseif( wood_type == 'deco:cherry_plank' ) then
|
||||
table.insert( replacements, {'default:sapling', "mapgen:cherry_sapling"});
|
||||
elseif( wood_type == 'deco:evergreen_plank' ) then
|
||||
table.insert( replacements, {'default:sapling', "mapgen:evergreen_sapling"});
|
||||
elseif( wood_type == 'deco:oak_plank' ) then
|
||||
table.insert( replacements, {'default:sapling', "mapgen:oak_sapling"});
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Note: This function is taken from the villages mod (by Sokomine)
|
||||
-- at least the cottages may come in a variety of building materials
|
||||
-- IMPORTANT: don't add any nodes which have on_construct here UNLESS they where in the original file already
|
||||
-- on_construct will only be called for known nodes that need that treatment (see villages.analyze_mts_file and on_constr)
|
||||
mg_villages.get_replacement_list = function( housetype, pr )
|
||||
|
||||
local replacements = {};
|
||||
|
||||
-- else some grass would never (re)grow (if it's below a roof)
|
||||
-- table.insert( replacements, {'default:dirt', dirt_with_grass_replacement });
|
||||
-- table.insert( replacements, {'default:dirt_with_grass', dirt_with_grass_replacement });
|
||||
table.insert( replacements, {'default:dirt', 'default:dirt_with_grass' });
|
||||
|
||||
-- realtest lacks quite a lot from default
|
||||
if( mg_villages.realtest_trees ) then
|
||||
for i=1,8 do
|
||||
table.insert( replacements, {'farming:wheat_'..i, 'farming:spelt_'..tostring( (i+(i%2))/2) });
|
||||
table.insert( replacements, {'farming:cotton_'..i, 'farming:flax_' ..tostring( (i+(i%2))/2) });
|
||||
end
|
||||
for i=1,5 do
|
||||
table.insert( replacements, {'default:grass_'..i, 'air' });
|
||||
end
|
||||
table.insert( replacements, {'default:apple', 'air' });
|
||||
table.insert( replacements, {'default:cobble', 'default:stone_macadam' });
|
||||
table.insert( replacements, {'default:obsidian_glass', 'default:glass' });
|
||||
|
||||
-- the default doors from minetest game have been changed since the schematics where built
|
||||
-- TODO: the door replacement function needs to be more complex; doesn't really work this way
|
||||
else
|
||||
table.insert( replacements, {'doors:door_wood_t_1', 'doors:hidden'});
|
||||
table.insert( replacements, {'doors:door_wood_b_1', 'doors:door_wood_a'});
|
||||
table.insert( replacements, {'doors:door_wood_t_2', 'doors:hidden'});
|
||||
table.insert( replacements, {'doors:door_wood_b_2', 'doors:door_wood_b'});
|
||||
end
|
||||
|
||||
if( housetype and mg_villages.village_type_data[ housetype ] and mg_villages.village_type_data[ housetype ].replacement_function ) then
|
||||
return mg_villages.village_type_data[ housetype ].replacement_function( housetype, pr, replacements );
|
||||
end
|
||||
return replacements;
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- Taokis houses from structure i/o
|
||||
mg_villages.replacements_taoki = function( housetype, pr, replacements )
|
||||
local wood_type = 'default:wood';
|
||||
|
||||
if( mg_villages.realtest_trees ) then
|
||||
wood_type = mg_villages.replace_materials( replacements, pr,
|
||||
{'default:wood'},
|
||||
{''},
|
||||
{'default:wood'},
|
||||
'default:wood');
|
||||
table.insert( replacements, {'stairs:stair_cobble', 'default:stone_bricks_stair' });
|
||||
table.insert( replacements, {'stairs:slab_cobble', 'default:stone_bricks_slab' });
|
||||
table.insert( replacements, {'stairs:stair_stone', 'default:stone_flat_stair' });
|
||||
table.insert( replacements, {'stairs:slab_stone', 'default:stone_flat_slab' });
|
||||
else
|
||||
-- the main body of the houses in the .mts files is made out of wood
|
||||
wood_type = mg_villages.replace_materials( replacements, pr,
|
||||
{'default:wood'},
|
||||
{''},
|
||||
{'default:wood', 'default:junglewood', 'default:pine_wood', 'default:acacia_wood', 'default:aspen_wood', 'mg:pinewood', 'mg:savannawood',
|
||||
'default:clay', 'default:brick', 'default:sandstone',
|
||||
'default:stonebrick', 'default:desert_stonebrick','default:sandstonebrick', 'default:sandstone','default:stone','default:desert_stone',
|
||||
'default:coalblock','default:steelblock','default:goldblock', 'default:bronzeblock', 'default:copperblock', 'wool:white',
|
||||
'default:stone_flat', 'default:desert_stone_flat', -- realtest
|
||||
'darkage:adobe', 'darkage:basalt', 'darkage:basalt_cobble', 'darkage:chalk',
|
||||
'darkage:gneiss', 'darkage:gneiss_cobble', 'darkage:marble', 'darkage:marble_tile',
|
||||
'darkage:mud', 'darkage:ors', 'darkage:ors_cobble',
|
||||
'darkage:schist', 'darkage:serpentine', 'darkage:shale', 'darkage:silt', 'darkage:slate',
|
||||
'mapgen:mese_stone', 'mapgen:soap_stone'},
|
||||
'default:wood');
|
||||
end
|
||||
-- tree trunks are seldom used in these houses; let's change them anyway
|
||||
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||
|
||||
-- all this comes in variants for stairs and slabs as well
|
||||
mg_villages.replace_materials( replacements, pr,
|
||||
{'stairs:stair_stonebrick', 'stairs:slab_stonebrick', 'default:stonebrick'},
|
||||
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||
{ 'stonebrick', 'stone', 'sandstone', 'cobble'},
|
||||
'stonebrick');
|
||||
|
||||
-- decorative slabs above doors etc.
|
||||
mg_villages.replace_materials( replacements, pr,
|
||||
{'stairs:stair_wood'},
|
||||
{'stairs:stair_'},
|
||||
{'stonebrick', 'stone', 'sandstone', 'cobble', 'wood', 'junglewood', 'pine_wood', 'acaica_wood', 'aspen_wood' },
|
||||
'wood');
|
||||
|
||||
-- brick roofs are a bit odd; but then...
|
||||
-- all three shapes of roof parts have to fit together
|
||||
mg_villages.replace_materials( replacements, pr,
|
||||
{'stairs:stair_brick', 'stairs:slab_brick', 'default:brick'},
|
||||
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||
{ 'brick', 'stone', 'cobble', 'stonebrick', 'wood', 'junglewood', 'pine_wood', 'acacia_wood', 'aspen_wood', 'sandstone' },
|
||||
'brick' );
|
||||
|
||||
return replacements;
|
||||
end
|
||||
|
||||
|
||||
mg_villages.replacements_nore = function( housetype, pr, replacements )
|
||||
|
||||
mg_villages.replace_materials( replacements, pr,
|
||||
-- {'default:stonebrick'},
|
||||
-- {'default:'},
|
||||
{'stairs:stair_stonebrick', 'stairs:slab_stonebrick', 'default:stonebrick'},
|
||||
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||
{'stonebrick', 'desert_stonebrick','sandstonebrick', 'sandstone','stone','desert_stone','stone_flat','desert_stone_flat','stone_bricks','desert_strone_bricks'},
|
||||
'stonebrick');
|
||||
|
||||
-- replace the wood as well
|
||||
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||
{'default:wood'},
|
||||
{''},
|
||||
{ 'default:wood', 'default:junglewood', 'default:pine_wood', 'default:acacia_wood', 'default:aspen_wood', 'mg:savannawood', 'mg:pinewood' },
|
||||
'default:wood');
|
||||
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||
mg_villages.replace_saplings( replacements, wood_type );
|
||||
|
||||
if( pr:next(1,3)==1 and not( mg_villages.realtest_trees)) then
|
||||
table.insert( replacements, {'default:glass', 'default:obsidian_glass'});
|
||||
end
|
||||
|
||||
if( mg_villages.realtest_trees ) then
|
||||
table.insert( replacements, {'stairs:stair_cobble', 'default:stone_bricks_stair' });
|
||||
table.insert( replacements, {'stairs:slab_cobble', 'default:stone_bricks_slab' });
|
||||
end
|
||||
return replacements;
|
||||
end
|
||||
|
||||
|
||||
mg_villages.replacements_lumberjack = function( housetype, pr, replacements )
|
||||
-- replace the wood - those are lumberjacks after all
|
||||
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||
{'default:wood'},
|
||||
{''},
|
||||
{ 'default:wood', 'default:junglewood', 'default:pine_wood', 'default:acacia_wood', 'default:aspen_wood', 'mg:savannawood', 'mg:pinewood' },
|
||||
'default:wood');
|
||||
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||
mg_villages.replace_saplings( replacements, wood_type );
|
||||
|
||||
if( not( minetest.get_modpath('bell' ))) then
|
||||
table.insert( replacements, {'bell:bell', 'default:goldblock' });
|
||||
end
|
||||
if( mg_villages.realtest_trees ) then
|
||||
table.insert( replacements, {'stairs:stair_cobble', 'default:stone_bricks_stair' });
|
||||
table.insert( replacements, {'stairs:slab_cobble', 'default:stone_bricks_slab' });
|
||||
end
|
||||
return replacements;
|
||||
end
|
||||
|
||||
|
||||
mg_villages.replacements_logcabin = function( housetype, pr, replacements )
|
||||
|
||||
-- for logcabins, wood is the most likely type of roof material
|
||||
local roof_type = mg_villages.replace_materials( replacements, pr,
|
||||
{'stairs:stair_cobble', 'stairs:slab_cobble' },
|
||||
{'cottages:roof_connector_', 'cottages:roof_flat_' },
|
||||
{'straw', 'wood', 'wood', 'wood', 'reet', 'slate', 'red', 'brown', 'black'},
|
||||
'' );
|
||||
-- some houses have junglewood roofs
|
||||
if( roof_type ) then
|
||||
table.insert( replacements, {'stairs:stair_junglewood', 'cottages:roof_connector_'..roof_type });
|
||||
table.insert( replacements, {'stairs:slab_junglewood', 'cottages:roof_flat_'..roof_type });
|
||||
table.insert( replacements, {'cottages:roof_connector_wood', 'cottages:roof_connector_'..roof_type });
|
||||
table.insert( replacements, {'cottages:roof_flat_wood', 'cottages:roof_flat_'..roof_type });
|
||||
-- realtest does not have normal stairs
|
||||
elseif( mg_villages.realtest_trees ) then
|
||||
table.insert( replacements, {'stairs:stair_junglewood', 'trees:aspen_planks_stair' });
|
||||
table.insert( replacements, {'stairs:slab_junglewood', 'trees:aspen_planks_slab' });
|
||||
end
|
||||
|
||||
if( mg_villages.realtest_trees ) then
|
||||
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||
{'default:wood'},
|
||||
{''},
|
||||
{ 'default:wood' },
|
||||
'default:wood');
|
||||
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||
mg_villages.replace_saplings( replacements, wood_type );
|
||||
table.insert( replacements, {'default:stonebrick', 'default:stone_bricks' }); -- used for chimneys
|
||||
table.insert( replacements, {'stairs:stair_stonebrick', 'default:stone_bricks_stair' });
|
||||
-- table.insert( replacements, {'default:junglewood', wood_type }); -- replace the floor
|
||||
-- replace the floor with another type of wood (looks better than the same type as above)
|
||||
mg_villages.replace_materials( replacements, pr,
|
||||
{'default:junglewood'},
|
||||
{''},
|
||||
{ 'default:wood' },
|
||||
'default:junglewood');
|
||||
end
|
||||
return replacements;
|
||||
end
|
||||
|
||||
|
||||
mg_villages.replacements_chateau = function( housetype, pr, replacements )
|
||||
|
||||
if( minetest.get_modpath( 'cottages' )) then
|
||||
-- straw is the most likely building material for roofs for historical buildings
|
||||
mg_villages.replace_materials( replacements, pr,
|
||||
-- all three shapes of roof parts have to fit together
|
||||
{ 'cottages:roof_straw', 'cottages:roof_connector_straw', 'cottages:roof_flat_straw' },
|
||||
{ 'cottages:roof_', 'cottages:roof_connector_', 'cottages:roof_flat_'},
|
||||
{'straw', 'straw', 'straw', 'straw', 'straw',
|
||||
'reet', 'reet', 'reet',
|
||||
'slate', 'slate',
|
||||
'wood', 'wood',
|
||||
'red',
|
||||
'brown',
|
||||
'black'},
|
||||
'straw');
|
||||
else
|
||||
mg_villages.replace_materials( replacements, pr,
|
||||
-- all three shapes of roof parts have to fit together
|
||||
{ 'cottages:roof_straw', 'cottages:roof_connector_straw', 'cottages:roof_flat_straw' },
|
||||
{ 'stairs:stair_', 'stairs:stair_', 'stairs:slab_'},
|
||||
{'cobble', 'stonebrick', 'desert_cobble', 'desert_stonebrick', 'stone'},
|
||||
'stonebrick');
|
||||
table.insert( replacements, { 'cottages:glass_pane', 'default:glass' });
|
||||
end
|
||||
|
||||
|
||||
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||
{'default:wood'},
|
||||
{''},
|
||||
{ 'default:wood', 'default:junglewood', 'default:pine_wood', 'default:acacia_wood', 'default:aspen_wood', 'mg:savannawood', 'mg:pinewood'}, --, 'default:brick', 'default:sandstone', 'default:desert_cobble' },
|
||||
'default:wood');
|
||||
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||
mg_villages.replace_saplings( replacements, wood_type );
|
||||
|
||||
|
||||
if( mg_villages.realtest_trees ) then
|
||||
-- replace the floor with another type of wood (looks better than the same type as above)
|
||||
mg_villages.replace_materials( replacements, pr,
|
||||
{'stairs:stair_junglewood', 'stairs:slab_junglewood', 'default:junglewood'},
|
||||
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||
{ 'default:wood' },
|
||||
'wood' );
|
||||
end
|
||||
|
||||
|
||||
local mfs2 = mg_villages.replace_materials( replacements, pr,
|
||||
{'stairs:stair_cobble', 'stairs:slab_cobble', 'default:cobble'},
|
||||
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||
{ 'cobble', 'brick', 'clay', 'desert_cobble', 'desert_stone', 'desert_stonebrick', 'sandstone', 'sandstonebrick', 'stonebrick' },
|
||||
'cobble');
|
||||
|
||||
return replacements;
|
||||
end
|
||||
|
||||
|
||||
mg_villages.replacements_tent = function( housetype, pr, replacements )
|
||||
table.insert( replacements, { "glasspanes:wool_pane", "cottages:wool_tent" });
|
||||
table.insert( replacements, { "default:gravel", "default:sand" });
|
||||
-- realtest needs diffrent fence posts and doors
|
||||
if( mg_villages.realtest_trees ) then
|
||||
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||
{'default:wood'},
|
||||
{''},
|
||||
{ 'default:wood' },
|
||||
'default:wood');
|
||||
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||
mg_villages.replace_saplings( replacements, wood_type );
|
||||
end
|
||||
return replacements;
|
||||
end
|
||||
|
||||
|
||||
mg_villages.replacements_grasshut = function( housetype, pr, replacements )
|
||||
table.insert( replacements, {'moreblocks:fence_jungle_wood', 'default:fence' });
|
||||
if( pr:next( 1, 4) == 1 ) then
|
||||
table.insert( replacements, {'dryplants:reed_roof', 'cottages:roof_straw'});
|
||||
table.insert( replacements, {'dryplants:reed_slab', 'cottages:roof_flat_straw' });
|
||||
table.insert( replacements, {'dryplants:wetreed_roof', 'cottages:roof_reet' });
|
||||
table.insert( replacements, {'dryplants:wetreed_slab', 'cottages:roof_flat_reet' });
|
||||
else -- replace the straw and cobble one of the huts uses
|
||||
table.insert( replacements, {'cottages:straw', 'dryplants:wetreed' });
|
||||
table.insert( replacements, {'stairs:slab_cobble', 'dryplants:reed_slab' });
|
||||
end
|
||||
--[[ does not look nice
|
||||
if( pr:next( 1, 4) == 1 ) then
|
||||
table.insert( replacements, {'dryplants:wetreed_roof_corner', 'default:wood' });
|
||||
table.insert( replacements, {'dryplants:wetreed_roof_corner_2', 'default:junglewood' });
|
||||
end
|
||||
--]]
|
||||
if( not( minetest.get_modpath( 'cavestuff' ))) then
|
||||
table.insert( replacements, {'cavestuff:desert_pebble_2', 'default:slab_desert_stone' });
|
||||
end
|
||||
|
||||
table.insert( replacements, {'default:desert_sand', 'default:dirt_with_grass' });
|
||||
return replacements;
|
||||
end
|
||||
|
||||
|
||||
mg_villages.replacements_claytrader = function( housetype, pr, replacements )
|
||||
-- the walls of the clay trader houses are made out of brick
|
||||
mg_villages.replace_materials( replacements, pr,
|
||||
{ 'stairs:stair_brick', 'stairs:slab_brick', 'default:brick' }, -- default_materials
|
||||
{ 'stairs:stair_', 'stairs:slab_', 'default:' }, -- prefixes (for new materials)
|
||||
{ 'brick', 'stone', 'sandstone', 'sandstonebrick', 'desert_stone', 'desert_cobble', 'desert_stonebrick' }, -- new materials
|
||||
'brick' ); -- original material
|
||||
|
||||
-- material for the floor
|
||||
mg_villages.replace_materials( replacements, pr,
|
||||
{'default:stone'},
|
||||
{'default:'},
|
||||
{ 'brick', 'stone', 'sandstone', 'sandstonebrick', 'clay', 'desert_stone', 'desert_cobble', 'desert_stonebrick',
|
||||
'default:stone_flat', 'default:desert_stone_flat', -- realtest
|
||||
},
|
||||
'stone');
|
||||
|
||||
-- the clay trader homes come with stone stair roofs; slabs are used in other places as well (but those replacements here are ok)
|
||||
mg_villages.replace_materials( replacements, pr,
|
||||
{'stairs:stair_stone', 'stairs:slab_stone' },
|
||||
{'cottages:roof_connector_', 'cottages:roof_flat_' },
|
||||
{'straw', 'straw', 'straw', 'straw', 'straw',
|
||||
'reet', 'reet', 'reet',
|
||||
'slate', 'slate',
|
||||
'wood', 'wood',
|
||||
'red',
|
||||
'brown',
|
||||
'black'},
|
||||
'');
|
||||
|
||||
-- hills and pits that contain the materials clay traders dig for
|
||||
mg_villages.replace_materials( replacements, pr,
|
||||
{'default:stone_with_coal'},
|
||||
{'default:'},
|
||||
{'sand', 'sandstone', 'clay'},
|
||||
'');
|
||||
|
||||
if( mg_villages.realtest_trees ) then
|
||||
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||
{'default:wood'},
|
||||
{''},
|
||||
{ 'default:wood' },
|
||||
'default:wood');
|
||||
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||
mg_villages.replace_saplings( replacements, wood_type );
|
||||
table.insert( replacements, {'default:clay', 'default:dirt_with_clay'});
|
||||
local mfs2 = mg_villages.replace_materials( replacements, pr,
|
||||
{'stairs:stair_cobble', 'stairs:slab_cobble', 'default:cobble'},
|
||||
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||
{ 'stone' }, -- will be replaced by mg_villages.realtest_stairs
|
||||
'sandstone');
|
||||
end
|
||||
return replacements;
|
||||
end
|
||||
|
||||
|
||||
mg_villages.replacements_charachoal = function( housetype, pr, replacements )
|
||||
if( mg_villages.realtest_trees ) then
|
||||
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||
{'default:wood'},
|
||||
{''},
|
||||
{ 'default:wood' },
|
||||
'default:wood');
|
||||
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||
mg_villages.replace_saplings( replacements, wood_type );
|
||||
|
||||
table.insert( replacements, {'stairs:slab_loam', 'cottages:loam'});
|
||||
table.insert( replacements, {'stairs:stair_loam', 'cottages:loam'});
|
||||
end
|
||||
return replacements;
|
||||
end
|
||||
|
||||
|
||||
-- wells can get the same replacements as the sourrounding village; they'll get a fitting roof that way
|
||||
mg_villages.replacements_medieval = function( housetype, pr, replacements )
|
||||
|
||||
if( not( minetest.get_modpath('bell' ))) then
|
||||
table.insert( replacements, {'bell:bell', 'default:goldblock' });
|
||||
end
|
||||
|
||||
-- glass that served as a marker got copied accidently; there's usually no glass in cottages
|
||||
table.insert( replacements, {'default:glass', 'air'});
|
||||
-- some plants started growing while the buildings where saved - eliminate them
|
||||
table.insert( replacements, {'junglegrass:medium', 'air'});
|
||||
table.insert( replacements, {'junglegrass:short', 'air'});
|
||||
table.insert( replacements, {'poisonivy:seedling', 'air'});
|
||||
|
||||
-- TODO: sometimes, half_door/half_door_inverted gets rotated wrong
|
||||
-- table.insert( replacements, {'cottages:half_door', 'cottages:half_door_inverted'});
|
||||
-- table.insert( replacements, {'cottages:half_door_inverted', 'cottages:half_door'});
|
||||
|
||||
-- some poor cottage owners cannot afford glass
|
||||
if( pr:next( 1, 2 ) == 2 ) then
|
||||
-- table.insert( replacements, {'cottages:glass_pane', 'default:fence_wood'});
|
||||
local gp = mg_villages.replace_materials( replacements, pr,
|
||||
{'cottages:glass_pane'},
|
||||
{''},
|
||||
{'xpanes:pane', 'default:glass', 'default:obsidian_glass', 'default:fence_wood',
|
||||
'darkage:medieval_glass', 'darkage:iron_bars', 'darkage:iron_grille', 'darkage:wood_bars',
|
||||
'darkage:wood_frame', 'darkage:wood_grille'},
|
||||
'cottages:glass_pane');
|
||||
end
|
||||
|
||||
-- 'glass' is admittedly debatable; yet it may represent modernized old houses where only the tree-part was left standing
|
||||
-- loam and clay are mentioned multiple times because those are the most likely building materials in reality
|
||||
local materials = {'cottages:loam', 'cottages:loam', 'cottages:loam', 'cottages:loam', 'cottages:loam',
|
||||
'default:clay', 'default:clay', 'default:clay', 'default:clay', 'default:clay',
|
||||
'default:wood','default:junglewood', 'default:pine_wood', 'default:acacia_wood', 'default:aspen_wood', 'default:sandstone',
|
||||
'default:desert_stone','default:brick','default:cobble','default:stonebrick',
|
||||
'default:desert_stonebrick','default:sandstonebrick','default:stone',
|
||||
'mg:savannawood', 'mg:savannawood', 'mg:savannawood', 'mg:savannawood',
|
||||
'mg:pinewood', 'mg:pinewood', 'mg:pinewood', 'mg:pinewood',
|
||||
'default:stone_flat', 'default:desert_stone_flat', -- realtest
|
||||
'darkage:adobe', 'darkage:basalt', 'darkage:basalt_cobble', 'darkage:chalk',
|
||||
'darkage:gneiss', 'darkage:gneiss_cobble', 'darkage:marble', 'darkage:marble_tile',
|
||||
'darkage:mud', 'darkage:ors', 'darkage:ors_cobble', 'darkage:reinforced_chalk',
|
||||
'darkage:reinforced_wood', 'darkage:reinforced_wood_left', 'darkage:reinforced_wood_right',
|
||||
'darkage:schist', 'darkage:serpentine', 'darkage:shale', 'darkage:silt', 'darkage:slate',
|
||||
'darkage:slate_cobble', 'darkage:slate_tile', 'darkage:stone_brick',
|
||||
'mapgen:mese_stone', 'mapgen:soap_stone'};
|
||||
|
||||
-- what is sandstone (the floor) may be turned into something else
|
||||
local mfs = mg_villages.replace_materials( replacements, pr,
|
||||
{'default:sandstone'},
|
||||
{''},
|
||||
materials,
|
||||
'default:sandstone');
|
||||
if( mg_villages.realtest_trees ) then
|
||||
table.insert( replacements, {'stairs:slab_sandstone', 'default:stone_slab'});
|
||||
local mfs2 = mg_villages.replace_materials( replacements, pr,
|
||||
{'stairs:stair_sandstone', 'stairs:slab_sandstone', 'default:sandstone'},
|
||||
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||
{ 'stone' }, -- will be replaced by mg_villages.realtest_stairs
|
||||
'sandstone');
|
||||
elseif( mfs and mfs ~= 'default:sandstone' ) then
|
||||
|
||||
if( mfs == 'cottages:loam' or mfs == 'default:clay' or mfs == 'mg:savannawood' or mfs == 'mg:pinewood') then
|
||||
mfs = 'default:wood';
|
||||
elseif( mfs =='default:sandstonebrick' or mfs == 'default:desert_stone' or mfs == 'default:desert_stonebrick'
|
||||
or not( minetest.registered_nodes[ 'stairs:slab_'..string.sub( mfs, 9 )] )) then
|
||||
mfs = '';
|
||||
end
|
||||
|
||||
if( mfs and mfs ~= '' ) then
|
||||
-- realtest needs special treatment
|
||||
table.insert( replacements, {'stairs:slab_sandstone', 'stairs:slab_'..string.sub( mfs, 9 )});
|
||||
end
|
||||
end
|
||||
-- except for the floor, everything else may be glass
|
||||
table.insert( materials, 'default:glass' );
|
||||
|
||||
local uses_wood = false;
|
||||
-- bottom part of the house (usually ground floor from outside)
|
||||
local replace_clay = mg_villages.replace_materials( replacements, pr,
|
||||
{'default:clay'},
|
||||
{''},
|
||||
materials,
|
||||
'default:clay');
|
||||
if( replace_clay and replace_clay ~= 'default:clay' ) then
|
||||
uses_wood = mg_villages.replace_tree_trunk( replacements, replace_clay );
|
||||
mg_villages.replace_saplings( replacements, replace_clay );
|
||||
end
|
||||
|
||||
-- upper part of the house (may be the same as the material for the lower part)
|
||||
local replace_loam = mg_villages.replace_materials( replacements, pr,
|
||||
{'cottages:loam'},
|
||||
{''},
|
||||
materials,
|
||||
'cottages:loam');
|
||||
-- if the bottom was not replaced by wood, perhaps the top is
|
||||
if( not( uses_wood ) and replace_loam ) then
|
||||
mg_villages.replace_tree_trunk( replacements, replace_loam );
|
||||
mg_villages.replace_saplings( replacements, replace_loam );
|
||||
elseif( mg_villages.realtest_trees ) then
|
||||
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||
{'default:wood'},
|
||||
{''},
|
||||
{ 'default:wood' },
|
||||
'default:wood');
|
||||
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||
mg_villages.replace_saplings( replacements, wood_type );
|
||||
end
|
||||
|
||||
|
||||
-- replace cobble; for these nodes, a stony material is needed (used in wells as well)
|
||||
-- mossycobble is fine here as well
|
||||
local mcs = mg_villages.replace_materials( replacements, pr,
|
||||
{'default:cobble'},
|
||||
{'default:'},
|
||||
{'sandstone', 'desert_stone', 'desert_cobble',
|
||||
'cobble', 'cobble',
|
||||
'stonebrick', 'stonebrick', 'stonebrick', -- more common than other materials
|
||||
'mossycobble', 'mossycobble','mossycobble',
|
||||
'stone', 'stone',
|
||||
'desert_stonebrick','sandstonebrick'},
|
||||
'cobble');
|
||||
-- set a fitting material for the slabs; mossycobble uses the default cobble slabs
|
||||
if( mg_villages.realtest_trees ) then
|
||||
local mcs2 = mg_villages.replace_materials( replacements, pr,
|
||||
{'stairs:stair_cobble', 'stairs:slab_cobble', 'default:cobble'},
|
||||
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||
{ 'stone' }, -- will be replaced by mg_villages.realtest_stairs
|
||||
'cobble');
|
||||
table.insert( replacements, {'moreblocks:slab_cobble', 'default:'..mcs..'_slab'});
|
||||
elseif( mcs ~= 'mossycobble' and mcs ~= 'cobble') then
|
||||
|
||||
-- if no slab exists, use sandstone slabs
|
||||
if( not( mcs ) or not( minetest.registered_nodes[ 'stairs:slab_'..mcs ])) then
|
||||
mcs = 'sandstone';
|
||||
end
|
||||
table.insert( replacements, {'stairs:slab_cobble', 'stairs:slab_'..mcs});
|
||||
table.insert( replacements, {'moreblocks:slab_cobble', 'stairs:slab_'..mcs});
|
||||
else
|
||||
table.insert( replacements, {'moreblocks:slab_cobble', 'stairs:slab_'..mcs});
|
||||
end
|
||||
|
||||
|
||||
-- straw is the most likely building material for roofs for historical buildings
|
||||
mg_villages.replace_materials( replacements, pr,
|
||||
-- all three shapes of roof parts have to fit together
|
||||
{ 'cottages:roof_straw', 'cottages:roof_connector_straw', 'cottages:roof_flat_straw' },
|
||||
{ 'cottages:roof_', 'cottages:roof_connector_', 'cottages:roof_flat_'},
|
||||
{'straw', 'straw', 'straw', 'straw', 'straw',
|
||||
'reet', 'reet', 'reet',
|
||||
'slate', 'slate',
|
||||
'wood', 'wood',
|
||||
'red',
|
||||
'brown',
|
||||
'black'},
|
||||
'straw');
|
||||
|
||||
--print('REPLACEMENTS used: '..minetest.serialize( replacements ));
|
||||
return replacements;
|
||||
end
|
||||
|
||||
|
||||
mg_villages.replacements_tower = function( housetype, pr, replacements )
|
||||
-- replace the wood - this is needed in particular for the fences
|
||||
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||
{'default:wood'},
|
||||
{''},
|
||||
{ 'default:wood', 'default:junglewood', 'mg:savannawood', 'mg:pinewood' },
|
||||
'default:wood');
|
||||
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||
mg_villages.replace_saplings( replacements, wood_type );
|
||||
|
||||
mg_villages.replace_materials( replacements, pr,
|
||||
{'stairs:stair_cobble', 'stairs:slab_cobble', 'default:cobble'},
|
||||
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||
{'stonebrick', 'desert_stonebrick','sandstonebrick', 'sandstone','stone','desert_stone','stone_flat','desert_stone_flat','stone_bricks','desert_strone_bricks'},
|
||||
'stonebrick');
|
||||
|
||||
return replacements;
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- Translate replacement function from above (which aims at place_schematic) for the villages in Nores mapgen
|
||||
mg_villages.get_replacement_ids = function( housetype, pr )
|
||||
|
||||
local replace = {};
|
||||
local replacements = mg_villages.get_replacement_list( housetype, pr );
|
||||
for i,v in ipairs( replacements ) do
|
||||
if( v and #v == 2 ) then
|
||||
replace[ minetest.get_content_id( v[1] )] = minetest.get_content_id( v[2] );
|
||||
end
|
||||
end
|
||||
return replace;
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- mapgen based replacements work best using a table, while minetest.place_schematic(..) based spawning needs a list
|
||||
mg_villages.get_replacement_table = function( housetype, pr, replacements )
|
||||
|
||||
local rtable = {};
|
||||
local ids = {};
|
||||
if( not( replacements )) then
|
||||
replacements = mg_villages.get_replacement_list( housetype, pr );
|
||||
end
|
||||
-- it is very problematic if the torches on houses melt snow and cause flooding; thus, we use a torch that is not hot
|
||||
if( mg_villages.USE_DEFAULT_3D_TORCHES == false ) then
|
||||
table.insert( replacements, {'default:torch', 'mg_villages:torch'});
|
||||
end
|
||||
|
||||
-- make charachoal villages safe from spreading fire
|
||||
if( not( mg_villages.use_normal_unsafe_lava )) then
|
||||
table.insert( replacements, {'default:lava_source', 'mg_villages:lava_source_tamed'});
|
||||
table.insert( replacements, {'default:lava_flowing', 'mg_villages:lava_flowing_tamed'});
|
||||
end
|
||||
|
||||
for i,v in ipairs( replacements ) do
|
||||
if( v and #v == 2 ) then
|
||||
rtable[ v[1] ] = v[2];
|
||||
ids[ minetest.get_content_id( v[1] )] = minetest.get_content_id( v[2] );
|
||||
end
|
||||
end
|
||||
return { table = rtable, list = replacements, ids = ids };
|
||||
end
|
||||
|
||||
mg_villages.get_content_id_replaced = function( node_name, replacements )
|
||||
if( not( node_name ) or not( replacements ) or not(replacements.table )) then
|
||||
return minetest.get_content_id( 'ignore' );
|
||||
end
|
||||
if( replacements.table[ node_name ]) then
|
||||
return minetest.get_content_id( replacements.table[ node_name ] );
|
||||
else
|
||||
return minetest.get_content_id( node_name );
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- they don't all grow cotton; farming_plus fruits are far more intresting!
|
||||
-- Note: This function modifies replacements.ids and replacements.table for each building
|
||||
-- as far as fruits are concerned. It needs to be called before placing a building
|
||||
-- which contains fruits.
|
||||
-- The function might as well be a local one.
|
||||
mg_villages.get_fruit_replacements = function( replacements, fruit)
|
||||
|
||||
if( not( fruit )) then
|
||||
return;
|
||||
end
|
||||
|
||||
for i=1,8 do
|
||||
local old_name = '';
|
||||
local new_name = '';
|
||||
-- farming_plus plants sometimes come in 3 or 4 variants, but not in 8 as cotton does
|
||||
if( minetest.registered_nodes[ 'farming_plus:'..fruit..'_'..i ]) then
|
||||
old_name = "farming:cotton_"..i;
|
||||
new_name = 'farming_plus:'..fruit..'_'..i;
|
||||
|
||||
-- "surplus" cotton variants will be replaced with the full grown fruit
|
||||
elseif( minetest.registered_nodes[ 'farming_plus:'..fruit ]) then
|
||||
old_name = "farming:cotton_"..i;
|
||||
new_name = 'farming_plus:'..fruit;
|
||||
|
||||
-- and plants from farming: are supported as well
|
||||
elseif( minetest.registered_nodes[ 'farming:'..fruit..'_'..i ]) then
|
||||
old_name = "farming:cotton_"..i;
|
||||
new_name = 'farming:'..fruit..'_'..i;
|
||||
|
||||
elseif( minetest.registered_nodes[ 'farming:'..fruit ]) then
|
||||
old_name = "farming:cotton_"..i;
|
||||
new_name = 'farming:'..fruit;
|
||||
end
|
||||
|
||||
if( old_name ~= '' and new_name ~= '' ) then
|
||||
-- this is mostly used by the voxelmanip based spawning of .we files
|
||||
replacements.ids[ minetest.get_content_id( old_name )] = minetest.get_content_id( new_name );
|
||||
-- this is used by the place_schematic based spawning
|
||||
replacements.table[ old_name ] = new_name;
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,209 @@
|
|||
|
||||
-- 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
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue