From 3caca9b8819a2669db51aab65b10b43e4d10ac3b Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 9 Jul 2016 14:57:39 -0500 Subject: [PATCH] Update mg_villages and handle_schematics, update wood door textures --- mods/default/functions.lua | 2 +- mods/doors/init.lua | 37 ++-- mods/handle_schematics/build_chest.lua | 143 ++++++++++--- .../build_chest_add_schems_by_directory.lua | 57 ++--- .../build_chest_handle_replacements.lua | 107 +++++++--- .../build_chest_preview_image.lua | 10 +- mods/handle_schematics/init.lua | 1 + mods/handle_schematics/place_buildings.lua | 139 +++++++++--- .../replacements_discontinued_nodes.lua | 42 ++++ mods/handle_schematics/replacements_wood.lua | 5 +- mods/mg_villages/config.lua | 16 +- mods/mg_villages/mapgen.lua | 47 +++- mods/mg_villages/protection.lua | 200 +++++++++++++++++- mods/mg_villages/replacements.lua | 13 ++ mods/mobs/api.lua | 16 +- mods/mobs/step.lua | 3 +- 16 files changed, 658 insertions(+), 180 deletions(-) create mode 100644 mods/handle_schematics/replacements_discontinued_nodes.lua diff --git a/mods/default/functions.lua b/mods/default/functions.lua index 2e2dda7..5286dad 100644 --- a/mods/default/functions.lua +++ b/mods/default/functions.lua @@ -461,7 +461,7 @@ end function randomChance (percent) math.randomseed( os.clock() ) - return percent >= math.random(1, 100) + return percent >= ( math.random(1000, 100000) / 1000 ) end function default.tprint (tbl, indent) diff --git a/mods/doors/init.lua b/mods/doors/init.lua index 343a777..2562730 100644 --- a/mods/doors/init.lua +++ b/mods/doors/init.lua @@ -416,15 +416,10 @@ function doors.register(name, def) end doors.register("door_wood", { - tiles = {{ name = "doors_door_wood.png", backface_culling = true }}, + tiles = {{ name = "[combine:32x38:0,0=default_wood.png:0,16=default_wood.png:0,32=default_wood.png:16,0=default_wood.png:16,16=default_wood.png:16,32=default_wood.png^[transformR270^[colorize:#fff:30^ts_doors_base.png^[noalpha^[makealpha:0,255,0", backface_culling = true }}, + inventory_image = "[combine:32x38:0,0=default_wood.png:0,16=default_wood.png:16,0=default_wood.png:16,16=default_wood.png^[transformR270^[colorize:#fff:30^ts_doors_base_inv.png^[noalpha^[makealpha:0,255,0", description = "Wooden Door", - inventory_image = "doors_item_wood.png", - groups = { snappy = 1, choppy = 2, oddly_breakable_by_hand = 2, flammable = 2 }, - recipe = { - {"group:wood", "group:wood"}, - {"group:wood", "group:wood"}, - {"group:wood", "group:wood"}, - } + groups = { snappy = 1, choppy = 2, flammable = 2 }, }) doors.register("door_steel", { @@ -724,33 +719,27 @@ doors.register_fencegate("doors:gate_wood", { description = "Wooden Fence Gate", texture = "default_wood.png", material = "default:wood", - groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2} + groups = {choppy = 2, flammable = 2} }) -doors.register_fencegate("doors:gate_acacia_wood", { - description = "Acacia Fence Gate", - texture = "default_acacia_wood.png", - material = "default:acacia_wood", - groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2} +doors.register_fencegate("doors:gate_savanna_wood", { + description = "Savana Fence Gate", + texture = "mg_dry_wood.png", + material = "mg:savannawood", + groups = {choppy = 2, flammable = 2} }) doors.register_fencegate("doors:gate_junglewood", { description = "Junglewood Fence Gate", texture = "default_junglewood.png", material = "default:junglewood", - groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2} + groups = {choppy = 2, flammable = 2} }) doors.register_fencegate("doors:gate_pine_wood", { description = "Pine Fence Gate", - texture = "default_pine_wood.png", - material = "default:pine_wood", - groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2} + texture = "mg_pine_wood.png", + material = "mg:pinewood", + groups = {choppy = 2, flammable = 2} }) -doors.register_fencegate("doors:gate_aspen_wood", { - description = "Aspen Fence Gate", - texture = "default_aspen_wood.png", - material = "default:aspen_wood", - groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2} -}) diff --git a/mods/handle_schematics/build_chest.lua b/mods/handle_schematics/build_chest.lua index 93b7f2f..4e647fd 100644 --- a/mods/handle_schematics/build_chest.lua +++ b/mods/handle_schematics/build_chest.lua @@ -277,6 +277,38 @@ end +-- offer diffrent replacement groups +handle_schematics.get_formspec_group_replacement = function( pos, fields, formspec ) + + if( fields.set_wood and fields.set_wood ~= "" ) then + return formspec.. + "label[1,2.2;Select replacement for "..tostring( fields.set_wood )..".]".. + "label[1,2.5;Trees, saplings and other blocks will be replaced accordingly as well.]".. + -- invisible field that encodes the value given here + "field[-20,-20;0.1,0.1;set_wood;;"..minetest.formspec_escape( fields.set_wood ).."]".. + build_chest.replacements_get_group_list_formspec( pos, 'wood', 'wood_selection' ); + end + + if( fields.set_farming and fields.set_farming ~= "" ) then + return formspec.. + "label[1,2.5;Select the fruit the farm is going to grow:]".. + -- invisible field that encodes the value given here + "field[-20,-20;0.1,0.1;set_farming;;"..minetest.formspec_escape( fields.set_farming ).."]".. + build_chest.replacements_get_group_list_formspec( pos, 'farming', 'farming_selection' ); + end + + if( fields.set_roof and fields.set_roof ~= "" ) then + return formspec.. + "label[1,2.5;Select a roof type for the house:]".. + -- invisible field that encodes the value given here + "field[-20,-20;0.1,0.1;set_roof;;"..minetest.formspec_escape( fields.set_roof ).."]".. + build_chest.replacements_get_group_list_formspec( pos, 'roof', 'roof_selection' ); + end + return nil; +end + + + build_chest.update_formspec = function( pos, page, player, fields ) -- information about the village the build chest may belong to and about the owner @@ -286,10 +318,45 @@ build_chest.update_formspec = function( pos, page, player, fields ) local owner_name = meta:get_string( 'owner' ); local building_name = meta:get_string('building_name' ); + -- are we dealing with a plotmarker inside a village? + local village_id = meta:get_string( 'village_id' ); + local plot_nr = meta:get_int( 'plot_nr' ); + if( village_id + and village_id~="" + and plot_nr + and plot_nr>0 + and mg_villages.all_villages + and mg_villages.all_villages[ village_id ] + and mg_villages.all_villages[ village_id ].to_add_data.bpos + and mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ]) then + + local v = mg_villages.all_villages[ village_id ]; + village_name = v.name; + -- the center of the village + village_pos = { x = v.vx, y = v.vh, z = v.vz }; + -- who has bought the plot? + owner_name = v.to_add_data.bpos[ plot_nr ].owner; + building_name = v.to_add_data.bpos[ plot_nr ].btype; + -- get the name of the blueprint the building was created from + if( mg_villages.BUILDINGS[ building_name ] ) then + building_name = tostring( mg_villages.BUILDINGS[ building_name ].scm ); + end + -- we also know where the building will start and end + + -- TODO: these may need to be set + --local start_pos = meta:get_string('start_pos'); + --local end_pos = minetest.deserialize( meta:get_string('end_pos')); + --local rotate = meta:get_string('rotate'); + --local mirror = meta:get_string('mirror'); + else + village_id = ""; + plot_nr = -1; + end + -- distance from village center local distance = math.floor( math.sqrt( (village_pos.x - pos.x ) * (village_pos.x - pos.x ) - + (village_pos.y - pos.y ) * (village_pos.x - pos.y ) - + (village_pos.z - pos.z ) * (village_pos.x - pos.z ) )); + + (village_pos.y - pos.y ) * (village_pos.y - pos.y ) + + (village_pos.z - pos.z ) * (village_pos.z - pos.z ) )); -- the statistic is needed for all the replacements later on as it also contains the list of nodenames if( building_name and building_name~=""and not( build_chest.building[ building_name ].size )) then @@ -321,6 +388,28 @@ build_chest.update_formspec = function( pos, page, player, fields ) "label[3.3,1.6;Click on a menu entry to select it:]".. build_chest.show_size_data( building_name ); + if( fields.show_materials and fields.show_materials ~= "" ) then + -- do not allow any changes; just show the materials and their replacements + return formspec..build_chest.replacements_get_list_formspec( pos, nil, 0, meta, village_id, building_name, -1 ); + end + + -- are we dealing with a plotmarker? if so, we are finished here + -- (we mostly wanted the header and the option to see the replacements) + if( village_id and village_id ~= "" ) then + -- TODO: actually implement the villages_* functions + return formspec.."button[3,3;3,0.5;villages_create_backup;Create backup of current stage]".. + "button[3,4;3,0.5;show_materials;Show materials used]".. + "button[3,5;3,0.5;villages_reset_building;Reset building]".. + "button[3,3;3,0.5;villages_remove_building;Remove building]"; + end + + -- the building has been placed; offer to restore a backup + local backup_file = meta:get_string('backup'); + if( backup_file and backup_file ~= "" ) then + return formspec.."button[3,3;3,0.5;restore_backup;Restore original landscape]".. + "button[3,4;3,0.5;show_materials;Show materials used]"; + end + local current_path = minetest.deserialize( meta:get_string( 'current_path' ) or 'return {}' ); if( #current_path > 0 ) then formspec = formspec.."button[9.9,0.4;2,0.5;back;Back]"; @@ -340,46 +429,27 @@ build_chest.update_formspec = function( pos, page, player, fields ) end -- offer diffrent replacement groups - if( fields.set_wood and fields.set_wood ~= "" ) then - return formspec.. - "label[1,2.2;Select replacement for "..tostring( fields.set_wood )..".]".. - "label[1,2.5;Trees, saplings and other blocks will be replaced accordingly as well.]".. - -- invisible field that encodes the value given here - "field[-20,-20;0.1,0.1;set_wood;;"..minetest.formspec_escape( fields.set_wood ).."]".. - build_chest.replacements_get_group_list_formspec( pos, 'wood', 'wood_selection' ); - end - - if( fields.set_farming and fields.set_farming ~= "" ) then - return formspec.. - "label[1,2.5;Select the fruit the farm is going to grow:]".. - -- invisible field that encodes the value given here - "field[-20,-20;0.1,0.1;set_farming;;"..minetest.formspec_escape( fields.set_farming ).."]".. - build_chest.replacements_get_group_list_formspec( pos, 'farming', 'farming_selection' ); - end - - if( fields.set_roof and fields.set_roof ~= "" ) then - return formspec.. - "label[1,2.5;Select a roof type for the house:]".. - -- invisible field that encodes the value given here - "field[-20,-20;0.1,0.1;set_roof;;"..minetest.formspec_escape( fields.set_roof ).."]".. - build_chest.replacements_get_group_list_formspec( pos, 'roof', 'roof_selection' ); + local formspec_group_replacement = handle_schematics.get_formspec_group_replacement( pos, fields, formspec ); + if( formspec_group_replacement ) then + return formspec_group_replacement; end if( fields.preview and building_name ) then return formspec..build_chest.preview_image_formspec( building_name, - minetest.deserialize( meta:get_string( 'replacements' )), fields.preview); + build_chest.replacements_get_current( meta, village_id ), fields.preview); end -- show list of all node names used local start_pos = meta:get_string('start_pos'); if( building_name and building_name ~= '' and start_pos and start_pos ~= '' and meta:get_string('replacements')) then - return formspec..build_chest.replacements_get_list_formspec( pos ); + -- allow changes to the replacement list + return formspec..build_chest.replacements_get_list_formspec( pos, nil, 1, meta, village_id, building_name, -1 ); end -- find out where we currently are in the menu tree local menu = build_chest.menu; - for i,v in pairs( current_path ) do + for i,v in ipairs( current_path ) do if( menu and menu[ v ] ) then menu = menu[ v ]; end @@ -408,9 +478,12 @@ build_chest.update_formspec = function( pos, page, player, fields ) -- do replacements for realtest where necessary (this needs to be done only once) local replacements = {}; replacements_group['realtest'].replace( replacements ); + -- do replacements for nodes that no longer exist + replacements_group['discontinued_nodes'].replace( replacements ); meta:set_string( 'replacements', minetest.serialize( replacements )); - return formspec..build_chest.replacements_get_list_formspec( pos ); + -- allow changes to be made + return formspec..build_chest.replacements_get_list_formspec( pos, nil, 1, meta, village_id, building_name, -1 ); elseif( type(start_pos)=='string' ) then return formspec.."label[3,3;Error reading building data:]".. "label[3.5,3.5;"..start_pos.."]"; @@ -560,21 +633,21 @@ build_chest.on_receive_fields = function(pos, formname, fields, player) 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 ); + build_chest.replacements_apply( pos, meta, fields.replace_row_material, fields.replace_row_with, nil ); elseif( fields.replace_rest_with_air ) then build_chest.replacements_replace_rest_with_air( pos, meta ); elseif( fields.wood_selection ) then - build_chest.replacements_apply_for_group( pos, meta, 'wood', fields.wood_selection, fields.set_wood ); + build_chest.replacements_apply_for_group( pos, meta, 'wood', fields.wood_selection, fields.set_wood, nil ); fields.set_wood = nil; elseif( fields.farming_selection ) then - build_chest.replacements_apply_for_group( pos, meta, 'farming', fields.farming_selection, fields.set_farming ); + build_chest.replacements_apply_for_group( pos, meta, 'farming', fields.farming_selection, fields.set_farming, nil ); fields.set_farming = nil; elseif( fields.roof_selection ) then - build_chest.replacements_apply_for_group( pos, meta, 'roof', fields.roof_selection, fields.set_roof ); + build_chest.replacements_apply_for_group( pos, meta, 'roof', fields.roof_selection, fields.set_roof, nil ); fields.set_roof = nil; @@ -600,7 +673,7 @@ build_chest.on_receive_fields = function(pos, formname, fields, player) end -- TODO: use scaffolding here (exchange some replacements) - local replacement_list = minetest.deserialize( meta:get_string( 'replacements' )); + local replacement_list = build_chest.replacements_get_current( meta, village_id ); local rotate = meta:get_string('rotate'); local mirror = meta:get_string('mirror'); local axis = build_chest.building[ building_name ].axis; @@ -608,7 +681,7 @@ build_chest.on_receive_fields = function(pos, formname, fields, player) -- actually place the building --minetest.place_schematic( start_pos, building_name..'.mts', rotate, replacement_list, true ); mirror = nil; - fields.error_msg = handle_schematics.place_building_from_file( start_pos, end_pos, building_name, replacement_list, rotate, axis, mirror, no_plotmarker ); + fields.error_msg = handle_schematics.place_building_from_file( start_pos, end_pos, building_name, replacement_list, rotate, axis, mirror, no_plotmarker, false ); if( fields.error_msg ) then fields.error_msg = 'Error: '..tostring( fields.error_msg ); end diff --git a/mods/handle_schematics/build_chest_add_schems_by_directory.lua b/mods/handle_schematics/build_chest_add_schems_by_directory.lua index 9086d41..e383d05 100644 --- a/mods/handle_schematics/build_chest_add_schems_by_directory.lua +++ b/mods/handle_schematics/build_chest_add_schems_by_directory.lua @@ -41,12 +41,12 @@ end -- search for mods and modpacks containing schematics in any form local build_chest_check_all_directories_mods_and_modpacks = function( path, menu_title, gamename ) local d2 = minetest.get_dir_list( path..'/mods', true ); - for _,modname in pairs( d2 ) do + for _,modname in ipairs( d2 ) do local d3 = minetest.get_dir_list( path..'/mods/'..modname, true ); - for _,subdir in pairs( d3 ) do + for _,subdir in ipairs( d3 ) do if( subdir ~= 'textures' and subdir ~= 'sounds' and subdir ~= 'models' and subdir ~= '.git' and subdir ~= 'locale') then local d4 = minetest.get_dir_list( path..'/mods/'..modname..'/'..subdir, false ); - for _,filename in pairs( d4 ) do + for _,filename in ipairs( d4 ) do build_chest_add_files_to_menu_from_directory( filename, path..'/mods/'..modname..'/'..subdir..'/', @@ -56,10 +56,10 @@ local build_chest_check_all_directories_mods_and_modpacks = function( path, menu end -- it might be a modpack d4 = minetest.get_dir_list( path..'/mods/'..modname..'/'..subdir, true ); - for _,subsubdir in pairs( d4 ) do + for _,subsubdir in ipairs( d4 ) do if( subsubdir ~= 'textures' and subsubdir ~= 'sounds' and subsubdir ~= 'models' and subsubdir ~= '.git' and subsubdir ~= 'locale') then local d5 = minetest.get_dir_list( path..'/mods/'..modname..'/'..subdir..'/'..subsubdir, false ); - for _,filename in pairs( d5 ) do + for _,filename in ipairs( d5 ) do build_chest_add_files_to_menu_from_directory( filename, path..'/mods/'..modname..'/'..subdir..'/'..subsubdir..'/', @@ -75,6 +75,28 @@ local build_chest_check_all_directories_mods_and_modpacks = function( path, menu end end +build_chest.add_files_from_path = function( worldpath, worldname ) + -- get list of subdirectories + local path = worldpath..'/'..worldname; + local subdir_list = minetest.get_dir_list( path, true ); + if( not( subdir_list )) then + return; + end + for _,subdir in ipairs( subdir_list ) do + if( subdir=='schems' ) then + local file_list = minetest.get_dir_list( path..'/schems', false ); + for _,filename in ipairs( file_list ) do + build_chest_add_files_to_menu_from_directory( + filename, + path..'/schems/', + 'import from world', + 'landscape backups', + {'OVERWRITE THIS', worldname }); + end + end + end +end + local build_chest_check_all_directories = function() -- find the name of the directory directly above the current worldpath @@ -106,27 +128,12 @@ local build_chest_check_all_directories = function() end end --]] - worldpath = string.sub( worldpath, 1, string.len( worldpath )-p ); - +-- worldpath = string.sub( worldpath, 1, string.len( worldpath )-p ); -- locate .mts, .wem and .we files in the worlds/WORLDNAME/schems/* folders local d1 = minetest.get_dir_list( worldpath, true ); - for _,worldname in pairs( d1 ) do - -- get list of subdirectories - local d2 = minetest.get_dir_list( worldpath..'/'..worldname, true ); - for _,subdir in pairs( d2 ) do - if( subdir=='schems' ) then - local d3 = minetest.get_dir_list( worldpath..'/'..worldname..'/schems', false ); - for _,filename in pairs( d3 ) do - build_chest_add_files_to_menu_from_directory( - filename, - worldpath..'/'..worldname..'/schems/', - 'import from world', - 'landscape backups', - {'OVERWRITE THIS', worldname }); - end - end - end + for _,worldname in ipairs( d1 ) do + build_chest.add_files_from_path( worldpath, worldname ); end local main_path = string.sub( worldpath, 1, string.len(worldpath)-string.len('/worlds')); @@ -137,7 +144,7 @@ local build_chest_check_all_directories = function() -- search in all GAMES/* folders for mods containing schematics local game_path = main_path..'/games'; d1 = minetest.get_dir_list( game_path, true ); - for _,gamename in pairs( d1 ) do + for _,gamename in ipairs( d1 ) do build_chest_check_all_directories_mods_and_modpacks( game_path..'/'..gamename, 'import from game', gamename ); end end @@ -149,7 +156,7 @@ if( minetest.setting_getbool( 'secure.enable_security' )) then local worldpath = minetest.get_worldpath(); local d3 = minetest.get_dir_list( worldpath..'/schems', false ); if( d3 ) then - for _,filename in pairs( d3 ) do + for _,filename in ipairs( d3 ) do build_chest_add_files_to_menu_from_directory( filename, worldpath..'/schems/', diff --git a/mods/handle_schematics/build_chest_handle_replacements.lua b/mods/handle_schematics/build_chest_handle_replacements.lua index 4d596dc..099a8da 100644 --- a/mods/handle_schematics/build_chest_handle_replacements.lua +++ b/mods/handle_schematics/build_chest_handle_replacements.lua @@ -2,17 +2,52 @@ --- contains the handling of replacements for the build chest ------------------------------------------------------------- +build_chest.replacements_get_current = function( meta, village_id ) + + -- villages have their own replacement list for the entire village + if( village_id~="" + and mg_villages.all_villages + and mg_villages.all_villages[ village_id ] + and mg_villages.all_villages[ village_id ].to_add_data + and mg_villages.all_villages[ village_id ].to_add_data.replacements) then + + return mg_villages.all_villages[ village_id ].to_add_data.replacements; + end + + -- but usually, we store the replacement list in the build chest itself + return minetest.deserialize( meta:get_string( 'replacements' )); +end + + +-- store the new set of replacements +build_chest.replacements_set_current = function( meta, village_id, replacements ) + + -- villages have their own replacement list for the entire village + if( village_id~="" + and mg_villages.all_villages + and mg_villages.all_villages[ village_id ] + and mg_villages.all_villages[ village_id ].to_add_data + and mg_villages.all_villages[ village_id ].to_add_data.replacements) then + + mg_villages.all_villages[ village_id ].to_add_data.replacements = replacements; + end + + -- but usually, we store the replacement list in the build chest itself + meta:set_string( 'replacements', minetest.serialize( replacements )); +end + + -- internal function build_chest.replacements_get_extra_buttons = function( group, name, types_found_list, button_name, extra_buttons ) -- find out if there are any nodes that may need a group replacement local found_type = ""; - for k,w in pairs( replacements_group[ group ].all ) do + for k,w in ipairs( replacements_group[ group ].all ) do -- we have found the full block of that group type if( name == w ) then found_type = w; -- no primary node found; there may still be subordinate types else - for nr,t in pairs( replacements_group[ group ].data[ w ] ) do + for nr,t in ipairs( replacements_group[ group ].data[ w ] ) do if( name==t and not( types_found_list[ w ])) then found_type = w; end @@ -33,17 +68,18 @@ end -build_chest.replacements_get_list_formspec = function( pos, selected_row ) +build_chest.replacements_get_list_formspec = function( pos, selected_row, allow_changes, meta, village_id, building_name, replace_row ) if( not( pos )) then return ""; end - local meta = minetest.env:get_meta( pos ); - local replacements = minetest.deserialize( meta:get_string( 'replacements' )); - local building_name = meta:get_string( 'building_name' ); + local replacements = build_chest.replacements_get_current( meta, village_id ); + if( replace_row == -1 and meta and (not( building_name ) or building_name =="" )) then + building_name = meta:get_string( 'building_name' ); + replace_row = meta:get_int('replace_row'); + end if( not( building_name ) or not( build_chest.building[ building_name ])) then return ""; end - local replace_row = meta:get_int('replace_row'); local formspec = "tableoptions[" .. "color=#ff8000;" .. @@ -85,14 +121,14 @@ build_chest.replacements_get_list_formspec = function( pos, selected_row ) local types_found_list_roof = {}; local not_the_first_entry = false; - for i,v in pairs( build_chest.building[ building_name ].statistic ) do + for i,v in ipairs( build_chest.building[ building_name ].statistic ) do local name = build_chest.building[ building_name ].nodenames[ v[1]]; -- nodes that are to be ignored do not need to be replaced if( name ~= 'air' and name ~= 'ignore' and name ~= 'mg:ignore' and v[2] and v[2]>0) then local anz = v[2]; -- find out if this node name gets replaced local repl = name; - for j,r in pairs( replacements ) do + for j,r in ipairs( replacements ) do if( r and r[1]==name ) then repl = r[2]; end @@ -129,9 +165,11 @@ build_chest.replacements_get_list_formspec = function( pos, selected_row ) end end - extra_buttons = build_chest.replacements_get_extra_buttons( 'wood', name, types_found_list_wood, 'set_wood', extra_buttons ); - extra_buttons = build_chest.replacements_get_extra_buttons( 'farming', name, types_found_list_farming, 'set_farming', extra_buttons ); - extra_buttons = build_chest.replacements_get_extra_buttons( 'roof', name, types_found_list_farming, 'set_roof', extra_buttons ); + if( allow_changes==1 ) then + extra_buttons = build_chest.replacements_get_extra_buttons( 'wood', name, types_found_list_wood, 'set_wood', extra_buttons ); + extra_buttons = build_chest.replacements_get_extra_buttons( 'farming', name, types_found_list_farming, 'set_farming', extra_buttons ); + extra_buttons = build_chest.replacements_get_extra_buttons( 'roof', name, types_found_list_farming, 'set_roof', extra_buttons ); + end j=j+1; @@ -139,13 +177,20 @@ build_chest.replacements_get_list_formspec = function( pos, selected_row ) end end formspec = formspec.."]"; - -- add the proceed-button as soon as all unkown materials have been replaced - if( may_proceed ) then - formspec = formspec.."button[9.9,9.0;2.0,0.5;proceed_with_scaffolding;Proceed]"; - else - formspec = formspec.."button[9.9,9.0;3.2,0.5;replace_rest_with_air;Suggest air for unknown]"; + if( allow_changes==0) then + return formspec.."label[0.5,2.1;Materials and replacements used:]".. + -- the back button returns a diffrent (unimportant) value here so that we don't accidently go too far back + "button[9.9,0.4;2,0.5;back_from_show_materials;Back]"; + end + if( meta ) then + -- add the proceed-button as soon as all unkown materials have been replaced + if( may_proceed ) then + formspec = formspec.."button[9.9,9.0;2.0,0.5;proceed_with_scaffolding;Proceed]"; + else + formspec = formspec.."button[9.9,9.0;3.2,0.5;replace_rest_with_air;Suggest air for unknown]"; + end + formspec = formspec.."button[9.9,1.0;2.0,0.5;preview;Preview]"; end - formspec = formspec.."button[9.9,1.0;2.0,0.5;preview;Preview]"; if( extra_buttons.text and extra_buttons.text ~= "" ) then formspec = formspec..extra_buttons.text.. "label[9.9,2.8;Replace by type:]"; @@ -172,13 +217,13 @@ build_chest.replacements_replace_rest_with_air = function( pos, meta ) return; end local replacements_orig = minetest.deserialize( meta:get_string( 'replacements' )); - for i,v in pairs( build_chest.building[ building_name ].statistic ) do + for i,v in ipairs( build_chest.building[ building_name ].statistic ) do local name = build_chest.building[ building_name ].nodenames[ v[1]]; -- nodes that are to be ignored do not need to be replaced if( name ~= 'air' and name ~= 'ignore' and name ~= 'mg:ignore' and v[2] and v[2]>0) then -- find out if this node name gets replaced local repl = name; - for j,r in pairs( replacements_orig ) do + for j,r in ipairs( replacements_orig ) do if( r and r[1]==name ) then repl = r[2]; -- set replacements for inexisting nodes to air @@ -200,14 +245,14 @@ end -build_chest.replacements_apply = function( pos, meta, old_material, new_material ) +build_chest.replacements_apply = function( pos, meta, old_material, new_material, village_id ) -- a new value has been entered - we do not need to remember the row any longer meta:set_int('replace_row', 0 ); local found = false; -- only accept replacements which can actually be placed if( new_material=='air' or minetest.registered_nodes[ new_material ] ) then - local replacements_orig = minetest.deserialize( meta:get_string( 'replacements' )); - for i,v in pairs(replacements_orig) do + local replacements_orig = build_chest.replacements_get_current( meta, village_id ); + for i,v in ipairs(replacements_orig) do if( v and v[1]==old_material ) then v[2] = new_material; found = true; @@ -217,14 +262,14 @@ build_chest.replacements_apply = function( pos, meta, old_material, new_material table.insert( replacements_orig, { old_material, new_material }); end -- store the new set of replacements - meta:set_string( 'replacements', minetest.serialize( replacements_orig )); + build_chest.replacements_set_current( meta, village_id, replacements_orig ); end end build_chest.replacements_get_group_list_formspec = function( pos, group, button_name ) local formspec = ""; - for i,v in pairs( replacements_group[ group ].found ) do + for i,v in ipairs( replacements_group[ group ].found ) do formspec = formspec.."item_image_button["..tostring(((i-1)%8)+1)..",".. tostring(3+math.floor((i-1)/8))..";1,1;".. tostring( v )..";"..tostring( button_name )..";"..tostring(i).."]"; @@ -233,24 +278,24 @@ build_chest.replacements_get_group_list_formspec = function( pos, group, button_ end -build_chest.replacements_apply_for_group = function( pos, meta, group, selected, old_material ) +build_chest.replacements_apply_for_group = function( pos, meta, group, selected, old_material, village_id ) local nr = tonumber( selected ); if( not(nr) or nr <= 0 or nr > #replacements_group[ group ].found ) then return; end local new_material = replacements_group[ group ].found[ nr ]; - if( old_material and old_material == new_material ) then - return; - end +-- if( old_material and old_material == new_material ) then +-- return; +-- end - local replacements = minetest.deserialize( meta:get_string( 'replacements' )); + local replacements = build_chest.replacements_get_current( meta, village_id ); if( not( replacements )) then replacements = {}; end replacements_group[ group ].replace_material( replacements, old_material, new_material ); -- store the new set of replacements - meta:set_string( 'replacements', minetest.serialize( replacements )); + build_chest.replacements_set_current( meta, village_id, replacements ); end diff --git a/mods/handle_schematics/build_chest_preview_image.lua b/mods/handle_schematics/build_chest_preview_image.lua index 44cae9c..82eae3e 100644 --- a/mods/handle_schematics/build_chest_preview_image.lua +++ b/mods/handle_schematics/build_chest_preview_image.lua @@ -134,7 +134,7 @@ build_chest.preview_image_formspec = function( building_name, replacements, side local side_names = {"front","right","back","left","top"}; local side = 1; - for i,v in pairs( side_names ) do + for i,v in ipairs( side_names ) do if( side_name and side_name==v ) then side = i; end @@ -154,9 +154,9 @@ build_chest.preview_image_formspec = function( building_name, replacements, side -- the draw_tile function is based on content_id local content_ids = {}; - for i,v in pairs( data.nodenames ) do + for i,v in ipairs( data.nodenames ) do local found = false; - for j,w in pairs( replacements ) do + for j,w in ipairs( replacements ) do if( w and w[1] and w[1]==v) then found = true; if( minetest.registered_nodes[ w[2]] ) then @@ -203,8 +203,8 @@ build_chest.preview_image_formspec = function( building_name, replacements, side formspec = formspec.."label[3,3;Sorry, this schematic is too big for a preview image.]"; return formspec; end - for y,y_values in pairs( preview ) do - for l,v in pairs( y_values ) do + for y,y_values in ipairs( preview ) do + for l,v in ipairs( y_values ) do -- air, ignore and mg:ignore are not stored if( v and content_ids[ v ]==-1 ) then formspec = formspec..build_chest.preview_image_draw_tile( nil, "unknown_node.png", (l*scale), 9-(y*scale), scale*1.3, scale*1.2, tile_nr); diff --git a/mods/handle_schematics/init.lua b/mods/handle_schematics/init.lua index a314eb0..a3b043a 100644 --- a/mods/handle_schematics/init.lua +++ b/mods/handle_schematics/init.lua @@ -30,6 +30,7 @@ dofile(handle_schematics.modpath.."/handle_schematics_meta.lua"); replacements_group = {}; -- the replacement groups do add some non-ground nodes; needed by mg_villages replacements_group.node_is_ground = {} +dofile(handle_schematics.modpath.."/replacements_discontinued_nodes.lua") dofile(handle_schematics.modpath.."/replacements_wood.lua") dofile(handle_schematics.modpath.."/replacements_realtest.lua") dofile(handle_schematics.modpath.."/replacements_farming.lua") diff --git a/mods/handle_schematics/place_buildings.lua b/mods/handle_schematics/place_buildings.lua index 0cd133c..1b31a10 100644 --- a/mods/handle_schematics/place_buildings.lua +++ b/mods/handle_schematics/place_buildings.lua @@ -1,11 +1,7 @@ -- TODO: this function also occours in replacements.lua handle_schematics.get_content_id_replaced = function( node_name, replacements ) - if( not( replacements ) or not(replacements.table )) then - if not( node_name ) then - return minetest.get_content_id( 'ignore' ); - else - return minetest.get_content_id( node_name ); - end + 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 ] ); @@ -113,7 +109,10 @@ local function generate_building_plotmarker( pos, minp, maxp, data, param2_data, end -- actually position the marker if( p.x >= minp.x and p.x <= maxp.x and p.z >= minp.z and p.z <= maxp.z and p.y >= minp.y and p.y <= maxp.y) then - if( data[ a:index(p.x, p.y, p.z)] == cid.c_snow and p.y place dirt nodes instead of trying to keep the ground nodes - generate_building(pos, minp, maxp, data, param2_data, a, extranodes, replacements, cid, extra_calls, pos.building_nr, pos.village_id, binfo, cid.c_gravel, false); + generate_building(pos, minp, maxp, data, param2_data, a, extranodes, replacements, cid, extra_calls, pos.building_nr, pos.village_id, binfo, cid.c_gravel, keep_ground); -- store the changed map data vm:set_data(data); @@ -702,7 +718,7 @@ end -- places a building read from file "building_name" on the map between start_pos and end_pos using luavoxelmanip -- returns error message on failure and nil on success -handle_schematics.place_building_from_file = function( start_pos, end_pos, building_name, replacement_list, rotate, axis, mirror, no_plotmarker ) +handle_schematics.place_building_from_file = function( start_pos, end_pos, building_name, replacement_list, rotate, axis, mirror, no_plotmarker, keep_ground ) if( not( building_name )) then return "No file name given. Cannot find the schematic."; end @@ -752,7 +768,7 @@ handle_schematics.place_building_from_file = function( start_pos, end_pos, build start_pos.no_plotmarker = no_plotmarker; -- all those calls to on_construct need to be done now - local res = handle_schematics.place_building_using_voxelmanip( start_pos, binfo, replacement_list); + local res = handle_schematics.place_building_using_voxelmanip( start_pos, binfo, replacement_list, keep_ground); if( not(res) or not( res.extra_calls )) then return; end @@ -768,6 +784,24 @@ handle_schematics.place_building_from_file = function( start_pos, end_pos, build end end + for k, v in pairs( res.extra_calls.door_b ) do + local meta = minetest.get_meta( v ); + + local l = 2 -- b + local h = meta:get_int("right") + 1 + + local replace = { + { { type = "a", state = 0 }, { type = "a", state = 3 } }, + { { type = "b", state = 1 }, { type = "b", state = 2 } } + } + local new = replace[l][h] +-- minetest.swap_node(v, {name = name .. "_" .. new.type, param2 = v.p2}) + meta:set_int("state", new.state) + -- wipe meta on top node as it's unused + minetest.set_node({x = v.x, y = v.y + 1, z = v.z}, { name = "doors:hidden" }) + end + + if( binfo.metadata ) then -- if it is a .we/.wem file, metadata was included directly handle_schematics.restore_meta( nil, binfo.metadata, start_pos, end_pos, start_pos.brotate, mirror); @@ -830,6 +864,51 @@ handle_schematics.place_road = function(minp, maxp, data, param2_data, a, c_road end + +-- the node layer at height "ground_level" is not touched; thus +-- dirt/sand/whatever can remain there (=biome dependant); this +-- also means that the foundations for the ex-building's walls +-- will keep standing +handle_schematics.clear_area = function( start_pos, end_pos, ground_level) + + local vm = minetest.get_voxel_manip() + local minp, maxp = vm:read_from_map( + {x = start_pos.x, y = start_pos.y, z = start_pos.z}, + {x = end_pos.x, y = end_pos.y, z = end_pos.z} + ) + local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp}) + local data = vm:get_data() + + if( ground_level < start_pos.y or ground_level > end_pos.y ) then + ground_level = start_pos.y; + end + + local cid_air = minetest.get_content_id("air"); + for y=ground_level+1, end_pos.y do + for x=start_pos.x, end_pos.x do + for z=start_pos.z, end_pos.z do + data[ a:index( x, y, z ) ] = cid_air; + end + end + end + + local cid_dirt = minetest.get_content_id("default:dirt"); + for y=start_pos.y, ground_level-1 do + for x=start_pos.x, end_pos.x do + for z=start_pos.z, end_pos.z do + data[ a:index( x, y, z ) ] = cid_dirt; + end + end + end + + -- store the changed map data + vm:set_data(data); + vm:write_to_map(); + vm:update_liquids(); + vm:update_map(); +end + + if( minetest.get_modpath('moresnow' )) then handle_schematics.moresnow_installed = true; end diff --git a/mods/handle_schematics/replacements_discontinued_nodes.lua b/mods/handle_schematics/replacements_discontinued_nodes.lua new file mode 100644 index 0000000..c1e33c3 --- /dev/null +++ b/mods/handle_schematics/replacements_discontinued_nodes.lua @@ -0,0 +1,42 @@ +replacements_group['discontinued_nodes'] = {} + +replacements_group['discontinued_nodes'].doors = function( repl, door_type) + if( not( door_type )) then + return repl; + end + -- the upper part is no longer a seperate part + table.insert( repl, {'doors:door_'..door_type..'_t_1', 'doors:hidden'}); + table.insert( repl, {'doors:door_'..door_type..'_t_2', 'doors:hidden'}); + -- the lower part is now two nodes high + table.insert( repl, {'doors:door_'..door_type..'_b_1', 'doors:door_'..door_type..'_a'}); + table.insert( repl, {'doors:door_'..door_type..'_b_2', 'doors:door_'..door_type..'_b'}); + return repl; +end + +replacements_group['discontinued_nodes'].replace = function( replacements ) + + local repl = {}; + + -- doors changed from two nodes for a door to one two-node-high mesh + replacements_group['discontinued_nodes'].doors( repl, 'wood' ); + replacements_group['discontinued_nodes'].doors( repl, 'steel' ); + replacements_group['discontinued_nodes'].doors( repl, 'glass' ); + replacements_group['discontinued_nodes'].doors( repl, 'obsidian_glass'); + + for i,v in ipairs( repl ) do + if( v and v[2] and minetest.registered_nodes[ v[2]] ) then + local found = false; + for j,w in ipairs( replacements ) do + if( w and w[1] and w[1]==v[1] ) then + w[2] = v[2]; + found = true; + end + end + if( not( found )) then + table.insert( replacements, {v[1],v[2]} ); + end + end + end + return replacements; +end + diff --git a/mods/handle_schematics/replacements_wood.lua b/mods/handle_schematics/replacements_wood.lua index 4a2dc9b..06cd0a6 100644 --- a/mods/handle_schematics/replacements_wood.lua +++ b/mods/handle_schematics/replacements_wood.lua @@ -165,10 +165,7 @@ replacements_group['wood'].construct_wood_type_list = function() -- default tree and jungletree; no gates available replacements_group['wood'].add_material( {'', 'jungle' }, 'default:', '','wood','', 'tree', '','leaves', '','sapling', 'stairs:stair_', 'wood', 'stairs:slab_', 'wood', 'default:fence_','wood', 'NONE', '' ); - -- default:pine_needles instead of leaves; no gates available - replacements_group['wood'].add_material( {'pine' }, 'default:', '','wood','', 'tree', '','_needles','','_sapling', - 'stairs:stair_', 'wood', 'stairs:slab_', 'wood', 'default:fence_','wood', 'NONE','' ); - + -- https://github.com/Novatux/mg -- trees from nores mapgen replacements_group['wood'].add_material( {'savanna', 'pine' },'mg:', '','wood','', 'tree', '','leaves', '','sapling', diff --git a/mods/mg_villages/config.lua b/mods/mg_villages/config.lua index 04151ef..ce21791 100644 --- a/mods/mg_villages/config.lua +++ b/mods/mg_villages/config.lua @@ -20,7 +20,7 @@ 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; +mg_villages.VILLAGE_DETECT_RANGE = 50; -- if set to true, only players which have the mg_villages priv can use the "/visit " -- command which allows teleporting to the village with the given number @@ -68,12 +68,12 @@ mg_villages.medieval_subtype = false; -- 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; +mg_villages.sapling_probability[ minetest.get_content_id( 'default:sapling' ) ] = 15; -- suitable for a relatively dense forrest of normal trees +mg_villages.sapling_probability[ minetest.get_content_id( 'default:junglesapling' ) ] = 30; -- jungletrees are a bit bigger and need more space +mg_villages.sapling_probability[ minetest.get_content_id( 'default:pinesapling' ) ] = 20; 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; + mg_villages.sapling_probability[ minetest.get_content_id( 'mg:savannasapling' ) ] = 20; + mg_villages.sapling_probability[ minetest.get_content_id( 'mg:pinesapling' ) ] = 25; end mg_villages.moretrees_treelist = nil; if( minetest.get_modpath( 'moretrees' )) then @@ -159,9 +159,9 @@ mg_villages.prices = { -- 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; +mg_villages.ENABLE_TERRAIN_BLEND = false; -- 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; +mg_villages.UNDO_CAVEGEN_AND_MUDFLOW = false; -- internal variables for village generation diff --git a/mods/mg_villages/mapgen.lua b/mods/mg_villages/mapgen.lua index 322012d..40702cd 100644 --- a/mods/mg_villages/mapgen.lua +++ b/mods/mg_villages/mapgen.lua @@ -12,7 +12,7 @@ mg_villages.new_village_spawned = function( village_id ) if mg_villages.anz_villages < 2 then mg_villages.all_villages[ village_id ].barbarians = false else - if rptype <= 3 then + if rptype <= 3 then mg_villages.all_villages[ village_id ].barbarians = true else mg_villages.all_villages[ village_id ].barbarians = false @@ -94,11 +94,8 @@ end -- TODO: determine water level from mapgens? -local MG_VILLAGES_WATER_LEVEL = 1; -if( minetest.get_modpath( 'mg' )) then - MG_VILLAGES_WATER_LEVEL = 0; -end - +local mg_params = minetest.get_mapgen_params() +local MG_VILLAGES_WATER_LEVEL = mg_params.water_level; --replacements_group.node_is_ground = {}; -- store nodes which have previously been identified as ground mg_villages.check_if_ground = function( ci ) @@ -106,7 +103,7 @@ mg_villages.check_if_ground = function( ci ) -- pre-generate a list of no-ground-nodes for caching if( replacements_group.node_is_ground[ minetest.get_content_id('air')]==nil) then local no_ground_nodes = {'air','ignore','default:sandstonebrick','default:cactus','default:wood','default:junglewood', - 'default:pine_wood','default:pine_tree','default:acacia_wood','default:acacia_tree', + 'mg:pinewood','mg:pinetree','mg:savannawood','mg:savannatree', 'ethereal:mushroom_pore','ethereal:mushroom_trunk','ethereal:bamboo', 'ethereal:mushroom'}; -- TODO: add all those other tree and leaf nodes that might be added by mapgen for _,name in pairs( no_ground_nodes ) do @@ -155,6 +152,7 @@ mg_villages.lower_or_raise_terrain_at_point = function( x, z, target_height, min local jtree = false; local ptree = false; local atree = false; + local asptree = false; local old_height = maxp.y; local y = maxp.y; @@ -198,6 +196,9 @@ mg_villages.lower_or_raise_terrain_at_point = function( x, z, target_height, min -- acacia elseif( ci == cid.c_atree and data[a:index( x, y-1, z)]==cid.c_atree) then atree = true; + -- aspen + elseif( ci == cid.c_asptree and data[a:index( x, y-1, z)]==cid.c_asptree) then + asptree = true; elseif( not( surface_node) and ci ~= cid.c_air and ci ~= cid.c_ignore and mg_villages.check_if_ground( ci ) == true) then -- we have found a surface of some kind surface_node = ci; @@ -291,6 +292,9 @@ mg_villages.lower_or_raise_terrain_at_point = function( x, z, target_height, min elseif( atree and not( mg_villages.ethereal_trees ) and treepos) then data[ a:index( x, target_height+1, z)] = cid.c_asapling table.insert( treepos, {x=x, y=target_height+1, z=z, typ=3, snow=has_artificial_snow}); + elseif( asptree and not( mg_villages.ethereal_trees ) and treepos) then + data[ a:index( x, target_height+1, z)] = cid.c_aspsapling + table.insert( treepos, {x=x, y=target_height+1, z=z, typ=3, snow=has_artificial_snow}); elseif( has_snow ) then data[ a:index( x, target_height+1, z)] = cid.c_snow; end @@ -737,6 +741,10 @@ mg_villages.grow_a_tree = function( pos, plant_id, minp, maxp, data, a, cid, pr, elseif( plant_id == cid.c_asapling and minetest.registered_nodes[ 'default:acacia_tree']) then data[ a:index( pos.x, pos.y, pos.z )] = cid.c_asapling; return true; + -- aspen tree from newer minetest game + elseif( plant_id == cid.c_aspsapling and minetest.registered_nodes[ 'default:aspen_tree']) then + data[ a:index( pos.x, pos.y, pos.z )] = cid.c_aspsapling; + return true; -- a savannatree from the mg mod elseif( plant_id == cid.c_savannasapling and mg_villages.add_savannatree) then mg_villages.add_savannatree( data, a, pos.x, pos.y, pos.z, minp, maxp, pr) -- TODO: snow @@ -907,6 +915,8 @@ mg_villages.place_villages_via_voxelmanip = function( villages, minp, maxp, vm, cid.c_psapling = minetest.get_content_id( 'default:pine_sapling'); cid.c_atree = minetest.get_content_id( 'default:acacia_tree'); cid.c_asapling = minetest.get_content_id( 'default:acacia_sapling'); + cid.c_asptree = minetest.get_content_id( 'default:aspen_tree'); + cid.c_aspsapling = minetest.get_content_id( 'default:aspen_sapling'); cid.c_water = minetest.get_content_id( 'default:water_source'); -- PM ^ cid.c_stone_with_coal = minetest.get_content_id( 'default:stone_with_coal'); cid.c_sandstone = minetest.get_content_id( 'default:sandstone'); @@ -1104,6 +1114,29 @@ mg_villages.place_villages_via_voxelmanip = function( villages, minp, maxp, vm, end end + -- the doors need to be adjusted as well + for _, village in ipairs(villages) do + if( village.to_add_data.extra_calls.door_b ) then + for k, v in pairs( village.to_add_data.extra_calls.door_b ) do + local meta = minetest.get_meta( v ); + + local l = 2 -- b + local h = meta:get_int("right") + 1 + + local replace = { + { { type = "a", state = 0 }, { type = "a", state = 3 } }, + { { type = "b", state = 1 }, { type = "b", state = 2 } } + } + local new = replace[l][h] +-- minetest.swap_node(v, {name = name .. "_" .. new.type, param2 = v.p2}) + meta:set_int("state", new.state) + -- wipe meta on top node as it's unused + minetest.set_node({x = v.x, y = v.y + 1, z = v.z}, { name = "doors:hidden" }) + end + end + end + + local pr = PseudoRandom(mg_villages.get_bseed(minp)); for _, village in pairs(villages) do for _,v in pairs( village.to_add_data.extra_calls.chests ) do diff --git a/mods/mg_villages/protection.lua b/mods/mg_villages/protection.lua index c8bdc47..6563a2c 100644 --- a/mods/mg_villages/protection.lua +++ b/mods/mg_villages/protection.lua @@ -129,6 +129,8 @@ mg_villages.plotmarker_formspec = function( pos, formname, fields, player ) 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; @@ -137,8 +139,204 @@ mg_villages.plotmarker_formspec = function( pos, formname, fields, player ) local owner = mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].owner; local btype = mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].btype; - --minetest.chat_send_player( player:get_player_name(),'DATA FOR '..tostring(plot_nr)..': '..minetest.serialize( 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 + + 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 ) )); + + -- 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 ); + + if( plot and plot.traders ) then + 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; + 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 + end + + + 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: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: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: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: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: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: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]".. "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 ).."]".. diff --git a/mods/mg_villages/replacements.lua b/mods/mg_villages/replacements.lua index 47719be..49d3b77 100644 --- a/mods/mg_villages/replacements.lua +++ b/mods/mg_villages/replacements.lua @@ -172,6 +172,8 @@ mg_villages.replace_tree_trunk = function( replacements, wood_type ) 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 @@ -272,6 +274,8 @@ mg_villages.replace_saplings = function( replacements, wood_type ) 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 @@ -309,6 +313,7 @@ mg_villages.replace_saplings = function( replacements, wood_type ) 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 @@ -349,6 +354,14 @@ mg_villages.get_replacement_list = function( housetype, pr ) 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 diff --git a/mods/mobs/api.lua b/mods/mobs/api.lua index 4d1244c..f399aee 100644 --- a/mods/mobs/api.lua +++ b/mods/mobs/api.lua @@ -146,26 +146,28 @@ function mobs:register_mob(name, def) end, do_avoidance = function(self) + if self.avoid_nodes ~= nil then local avoid_range = self.avoid_range local avoid_nodes = self.avoid_nodes local pos = self.object:getpos() - local minx = pos.x - math.ceil( avoid_range / 2 ) - local maxx = pos.x + math.ceil( avoid_range / 2 ) + local minx = pos.x - avoid_range + local maxx = pos.x + avoid_range - local minz = pos.z - math.ceil( avoid_range / 2 ) - local maxz = pos.z + math.ceil( avoid_range / 2 ) + local minz = pos.z - avoid_range + local maxz = pos.z + avoid_range - local npos = minetest.find_nodes_in_area({x=minx,y=(pos.y-1),z=minz},{x=maxx,y=(pos.y+1),z=maxz}, avoid_nodes) + local npos = minetest.find_nodes_in_area({x=minx,y=(pos.y-2),z=minz},{x=maxx,y=(pos.y+2),z=maxz}, avoid_nodes) if #npos > 0 then local fpos = { x=(npos[1].x * -1),y=npos[1].y,z=(npos[1].z*-1) } mobs:face_pos(self,fpos) self.state="walk" self:set_animation("walk") - self:set_velocity(4) + self.set_velocity(self, self.walk_velocity) + self.pause_timer = 3 end end end, @@ -337,7 +339,7 @@ function mobs:register_mob(name, def) tflp = 1 end process_weapon(hitter,tflp,tool_capabilities) - + self.pause_timer = 0 local hpos = hitter:getpos() local pos = self.object:getpos() if self.object:get_hp() <= 0 then diff --git a/mods/mobs/step.lua b/mods/mobs/step.lua index 2c0e38a..25c6821 100644 --- a/mods/mobs/step.lua +++ b/mods/mobs/step.lua @@ -48,8 +48,7 @@ function mobs.on_step(self,dtime) end end - -- if pause state then this is where the loop ends - -- pause is only set after a monster is hit + -- if pause state then this is where the loop ends if self.pause_timer > 0 then self.pause_timer = self.pause_timer - dtime if self.pause_timer <= 0 then