diff --git a/README.md b/README.md index 4089048..2d2e5ef 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # [witches] Witches (Mobs Redo addon) [mod] for Minetest -Witches is copyright 2020 Francisco Athens, Ramona Athens, Damon Athens and Simone Athens +Witches is copyright 2022 Francisco Athens, Ramona Athens, Damon Athens and Simone Athens The MIT License (MIT) * code/issue tracking :https://gitlab.com/freelikegnu/witches @@ -13,16 +13,12 @@ Witches inhabit the land! They are currently in development but, can already: * Witches have magic! They will defend themselves and each other against aggressive players and mobs! -* If you are repeatedly helpful to a witch... +* If you are repeatedly helpful to a witch something good is likely to happen! -* Witch cottages adapted from Sokomine's basic_houses: - (https://github.com/Sokomine/basic_houses) mod under under MIT license - with permission from author. - Option requires Sokomine's handle_schematics mod (also GPLv3) - https://github.com/Sokomine/handle_schematics - - Settings provided from settings menu! +* New Witch cottage code with no additional mod requirements! +* If protector (or similar) mod is available and enabled, Witches will no build in these areas! + * Some cottages will spawn over a dungeon if they are near the surface * Have a name and origin location which they will tell player. @@ -43,8 +39,7 @@ Witches inhabit the land! They are currently in development but, can already: * Mobs Redo git repository: https://notabug.org/TenPlus1/mobs_redo ## Optional Mods: -* For Witches Cottages: Sokomine's handle_schematics mod (GPLv3) - * git repository: https://github.com/Sokomine/handle_schematics +* protector (or similar) - to prevent Witches from placing cottages in protected areas! * Any mobs from any mobs mod attacking Witches may be turned into a sheep! @@ -72,10 +67,6 @@ Witches inhabit the land! They are currently in development but, can already: * sheep.lua code adapted from mobs_animals by TenPlus1 and authors credited in sheep.lua -* Witch houses code adapted from Sokomine's basic_houses - (https://github.com/Sokomine/basic_houses) mod under MIT license - with permission from author. - * Sound files: witches_magic01.ogg MATRIXXX_ December 28th, 2018 CC-BY 3.0 https://freesound.org/people/MATRIXXX_/sounds/455205/ diff --git a/basic_houses.lua b/basic_houses.lua deleted file mode 100644 index 416bec7..0000000 --- a/basic_houses.lua +++ /dev/null @@ -1,1327 +0,0 @@ - - ---[[ -* Witch houses adapted from Sokomine's basic_houses - (https://github.com/Sokomine/basic_houses) mod under MIT - with permission from author. - -* Optional Depends: - Sokomine's handle_schematics mod (also GPLv3) - https://github.com/Sokomine/handle_schematics ---]] - --- Features: --- * each house has a door and one mese lamp per floor --- * houses can have multiple floors --- * each house comes with a ladder for access to all floors --- * normal saddle roofs and flat roofs supported --- * trees, plants and snow inside the house are not cleared --- -> the houses look abandoned (ready for players to move in) --- * houses look acceptable but leave a lot of room for improvement --- through their future inhabitants --- (no windows in gable, no decoration, no cellar, no furniture, --- no mini-house for elevator/ladder on top of skyscrapers, ...) --- * if the saddle roof does not fit into the height volume that is --- reserved for the house, the top of the roof is made flat --- * some random houses receive a chest with further building material --- for the house the chest spawned in --- * houses made out of plasterwork nodes may receive a machine from --- plasterwork instead of a chest --- * can be used with the RealTest game as well --- Technical stuff: --- * used function from handle_schematics to mark parts of the heightmap as used --- * glass panes, glass and obisidan glass are more common than bars --- * windows are no longer "filled" (param2 now set to 0) --- * doors are sourrounded by wall node and not glass panes or bars --- (would look strange and leave gaps otherwise) --- Known issues: --- * cavegen may eat holes into the ground below the house --- * houses may very seldom overlap - -local witches_dungeon_cellar_chance = tonumber(minetest.settings:get("witches_dungeon_cellar_chance")) or .50 -local witches_dungeon_cellar_depth = tonumber(minetest.settings:get("witches_dungeon_cellar_depth")) or -5 - -witches.bh = {}; - --- generate at max this many houses per mapchunk; --- Note: This amount will likely only spawn if your mapgen is very flat. --- Else you will see far less houses. -witches.bh.max_per_mapchunk = tonumber(minetest.settings:get("witches_house_max_per_mapchunk")) or 2; - --- how many houses shall be generated on average per mapchunk? -witches.bh.houses_wanted_per_mapchunk = tonumber(minetest.settings:get("witches_houses_wanted_per_mapchunk")) or .05; - --- even if there would not be any house here due to amount of houses --- generated beeing equal or larger than the amount of houses expected, --- there is still this additional chance (in percent) that the mapchunk --- will receive a house anyway (more randomness is good!) -witches.bh.additional_chance = 1; - --- how many mapchunks have been generated since the server was started? -witches.bh.mapchunks_processed = 0; --- how many houses have been generated in these mapchunks? -witches.bh.houses_generated = 0; - --- materials the houses can be made out of --- allows to reach upper floors -witches.bh.ladder = "default:ladder_wood"; --- gets placed over the door -witches.bh.lamp = "default:torch_wall"; --- floor at the entrance level of the house -witches.bh.floor = "default:cobble"; --- placed randomly in some houses -witches.bh.chest = "default:chest_locked"; -witches.bh.bookshelf ="default:bookshelf" -witches.bh.bed = "beds:bed" --- glass can be glass panes, iron bars or solid glass -witches.bh.glass = {"default:fence_junglewood","default:fence_wood"}; --- some walls are tree logs, some wooden planks, some colored plasterwork (if installed) --- - and some nodes are made out of these materials here -witches.bh.walls = {"default:cobble","default:mossycobble"}; --- doors -witches.bh.door_bottom = "doors:door_wood_witch_a"; -witches.bh.door_top = "doors:hidden"; --- make sure the place in front of the door will not get griefed by mapgen -witches.bh.around_house = {"default:mossycobble","default:tree","default:jungletree","default:acacia_tree","default:cobble"}; - ---check for mods (found in MTG but not default) -if minetest.get_modpath("fireflies") then - witches.bh.lamp = "fireflies:firefly"; -end - --- if the realtest game is choosen: adjust materials -if( minetest.get_modpath("core") and minetest.get_modpath("trees")) then - witches.bh.ladder = "trees:pine_ladder"; - witches.bh.lamp = "light:streetlight"; - witches.bh.glass = {"xpanes:pane_5","xpanes:pane_5","xpanes:pane_5", - "default:glass","default:glass"}; - witches.bh.walls = {"default:clay", "default:stone", "default:stone_bricks", "default:stone_flat", - "default:stone_macadam", "default:desert_stone", "default:desert_stone_bricks", - "default:desert_stone_flat", "default:desert_stone_macadam", "decorations:malachite_block", - "decorations:cinnabar_block", "decorations:gypsum_block", "decorations:jet_block", - "decorations:lazurite_block", "decorations:olivine_block", "decorations:petrified_wood_block", - "decorations:satinspar_block", "decorations:selenite_block", "decorations:serpentine_block"}; - witches.bh.door_bottom = "doors:door_pine_b_1"; - witches.bh.door_top = "doors:door_pine_t_1"; - witches.bh.around_house = witches.bh.walls; --- if the MineClone2 game is choosen: adjust materials -elseif( minetest.get_modpath("mcl_core")) then - local colors = {"red", "green", "blue", "light_blue", "black", "white", - "yellow", "brown", "orange"; "pink", "grey", "lime", "silver", - "magenta", "purple", "cyan"}; - witches.bh.ladder = "mcl_core:ladder"; - witches.bh.lamp = "mcl_ocean:sea_lantern"; - witches.bh.floor = "mcl_core:brick_block"; - witches.bh.chest = "mcl_chests:chest"; - witches.bh.glass = {"mcl_core:glass", "mcl_core:glass", "mcl_core:glass", - "xpanes:bar_flat"}; - for i,k in ipairs( colors ) do - table.insert( witches.bh.glass, "mcl_core:glass_"..k ); - table.insert( witches.bh.glass, "xpanes:pane_"..k.."_flat" ); - end - - witches.bh.walls = {"mcl_core:brick_block", - "mcl_core:stonebrick", "mcl_core:stonebrickcarved", "mcl_core:stonebrickcracked", - "mcl_core:stonebrickmossy","mcl_core:sandstonecarved", "mcl_core:sandstonesmooth2", - "mcl_core:redsandstonecarved"}; - for i,k in ipairs( colors ) do - table.insert( witches.bh.walls, "mcl_colorblocks:glazed_terracotta_"..k ); - table.insert( witches.bh.walls, "mcl_colorblocks:hardened_clay_"..k ); - end - witches.bh.around_house = { "mcl_core:stone_smooth", "mcl_core:granite_smooth", - "mcl_core:andesite_smooth", "mcl_core:diorite_smooth", "mcl_core:sandstonesmooth", - "mcl_core:sandstonecarved", "mcl_core:sandstonesmooth2", - "mcl_core:redsandstonesmooth", "mcl_core:redsandstonesmooth2"}; - witches.bh.door_bottom = "mcl_doors:wooden_door_b_1"; - witches.bh.door_top = "mcl_doors:wooden_door_t_1"; -end - ---lets see if any dungeons are near -minetest.set_gen_notify("dungeon") -local dungeon_cellar = { - chance = tonumber(witches_dungeon_cellar_chance), -- chance to try putting cottage over dungeon instead of anywhere else - max_depth = tonumber(witches_dungeon_cellar_depth) -- deepest dungeon depth to check -} - -local dungeon_list ={} - -minetest.register_on_generated(function(minp, maxp, blockseed) - local dg = minetest.get_mapgen_object("gennotify") - if dg and dg.dungeon and #dg.dungeon > 2 then - for i=1,#dg.dungeon do - if dg.dungeon[i].y >= dungeon_cellar.max_depth then - --print("dungeon found: "..minetest.pos_to_string(dg.dungeon[i])) - - table.insert(dungeon_list, dg.dungeon[i]) - end - end - end -end) - --- build either the two walls of the box that forms the house in x or z direction; --- windows are added randomly --- parameters: --- p starting point of these walls --- sizex length of the entire building in x direction --- sizez same for z direction --- in_x_direction do we have to build the two walls in x direction or the two in z direction? --- materials needs to contain at least the fields --- walls node name of wall material --- glass node name of glass material --- color optional; param2-color-value for wall node --- rotation_1 param2 for materials.wall nodes for the first wall --- rotation_2 param2 for materials.wall nodes for the second wall --- vm voxel manipulator - -witches.bh.build_two_walls = function( p, sizex, sizez, in_x_direction, materials, vm, pr) - - local v = 0; - if( not( in_x_direction )) then - v = 2; - end - -- param2 (orientation or color) for the first two walls; - -- tree logs need to be orientated correctly, colored nodes have to keep their color; - local node_wall_1 = {name=materials.walls, param2 = materials.wall_orients[1+v]}; - local node_wall_2 = {name=materials.walls, param2 = materials.wall_orients[2+v]}; - -- glass panes and metal bars need the correct rotation and no color value - local node_glass_1 = {name=materials.glass, param2 = materials.glass_orients[1+v]}; - local node_glass_2 = {name=materials.glass, param2 = materials.glass_orients[2+v]}; - -- solid glass needs a rotation of 0 (else it would be interpreted as level) - if( minetest.registered_nodes[ materials.glass ] - and minetest.registered_nodes[ materials.glass ].paramtype2 == "glasslikeliquidlevel") then - node_glass_1.param2 = 0; - node_glass_2.param2 = 0; - end - - local w1_x; - local w2_x; - local w1_z; - local w2_z; - local size; - if( in_x_direction ) then - w1_x = p.x; - w2_x = p.x; - w1_z = p.z; - w2_z = p.z+sizez; - size = sizex+1; - else - w1_x = p.x; - w2_x = p.x+sizex; - w1_z = p.z; - w2_z = p.z; - size = sizez+1; - end - - -- place windows at even or odd rows? -> create some variety - local window_at_odd_row = false; - if( pr:next(1,2)==1 ) then - window_at_odd_row = true; - end - - -- place where a door or ladder might be added (no window there); - -- we need to avid adding ladders directly in front of windows or - -- placing doors right next to glass panes because that would look ugly - local special_wall_1 = pr:next(3,math.max(2,size-2)); - local special_wall_2 = pr:next(3,math.max(2,size-2)); - if( special_wall_2 == special_wall_1 ) then - special_wall_2 = special_wall_2 - 1; - if( special_wall_2 < 3 ) then - special_wall_2 = 3; - end - end - - local wall_height = #materials.window_at_height; - for lauf = 1, size do - local wall_1_has_window = false; - local wall_2_has_window = false; - -- the corners never get glass - if( lauf>1 and lauf1) then - i = i-1; - else - i = i+1; - end - end - -- ladders need to be placed on the right side so that people can climb up - if( use_this_one and places[use_this_one]) then - i = use_this_one; - end - local at_odd_row = (places[i]%2==1); - if( (i==1 or i==2) and (places[5]==at_odd_row)) then - return {x=p.x+places[i], y=p.y, z=p.z+1+offset, p2=5, used=i}; - elseif( (i==1 or i==2) and (places[5]~=at_odd_row)) then - return {x=p.x+places[i], y=p.y, z=p.z-1-offset+sizez, p2=4, used=i}; - elseif( (i==3 or i==4) and (places[6]==at_odd_row)) then - return {x=p.x+1+offset, y=p.y, z=p.z+places[i], p2=3, used=i}; - elseif( (i==3 or i==4) and (places[6]~=at_odd_row)) then - return {x=p.x-1-offset+sizex, y=p.y, z=p.z+places[i], p2=2, used=i}; - else - return {x=p.x, y=p.y, z=p.z, used=0}; - end -end - --- add a ladder from bottom to top (staircases would be nicer but are too difficult to do well) --- if flat_roof is false, the ladder needs to be placed on the smaller side so that people can --- actually climb it; --- ladder_places are the special places witches.bh.build_two_walls(..) has reserved -witches.bh.place_ladder = function( p, sizex, sizez, ladder_places, ladder_height, flat_roof, vm, pr, d1) - -- place the ladder at the galbe side in houses with a real roof (else - -- climbing the ladder up to the roof would fail due to lack of room) - local use_place = nil; - if( not( flat_roof) and (sizex < sizez )) then - use_place = pr:next(1,2); - elseif( not( flat_roof) and (sizex >= sizez )) then - use_place = pr:next(3,4); - end - -- select one of the four reserved places - local res = witches.bh.get_random_place( p, sizex, sizez, ladder_places, use_place, -1, 1, pr ); - local ladder_node = {name=witches.bh.ladder, param2 = res.p2}; - -- actually place the ladders - for height=p.y+1, p.y + ladder_height do - vm:set_node_at( {x=res.x, y=height, z=res.z}, ladder_node ); - end - if d1 and d1.y and d1.y < p.y-1 then - for height=d1.y-2,p.y do - - vm:set_node_at( {x=res.x, y=height, z=res.z}, {name = "air"} ); - vm:set_node_at( {x=res.x, y=height, z=res.z}, ladder_node ); - - end - vm:set_node_at( {x=res.x, y=p.y+1, z=res.z}, {name = "doors:trapdoor"}) - end - return res.used; - -end - --- place the door into one of the reserved places -witches.bh.place_door = function( p, sizex, sizez, door_places, wall_with_ladder, floor_height, vm, pr ) - - local res = witches.bh.get_random_place( p, sizex, sizez, door_places, -1, wall_with_ladder, 0, pr ); - vm:set_node_at( {x=res.x, y=p.y+1, z=res.z}, {name=witches.bh.door_bottom, param2 = 0 }); - vm:set_node_at( {x=res.x, y=p.y+2, z=res.z}, {name=witches.bh.door_top, param2 = 0}); - -- light so that the door can be found - vm:set_node_at( {x=res.x+1, y=p.y+3, z=res.z+1}, {name=witches.bh.lamp}); - vm:set_node_at( {x=res.x-1, y=p.y+3, z=res.z-1}, {name=witches.bh.lamp}); - -- add some light to the upper floors as well - for i,height in ipairs( floor_height ) do - if( i>2) then - vm:set_node_at( {x=res.x,y=height-1,z=res.z},{name=witches.bh.lamp}); - end - end - return res.used; -end - --- the chest is placed on one of the upper floors; it contains --- additional building material -witches.bh.place_chest = function( p, sizex, sizez, chest_places, wall_with_ladder, floor_height, vm, materials, pr ) - -- not each building needs a chest - --[[yes it does! - if( pr:next(1,2)>1 ) then - return; - end ---]] - local res = witches.bh.get_random_place( p, sizex, sizez, chest_places, -1, wall_with_ladder, 1, pr ); - local height = floor_height[ pr:next(2,math.max(2,#floor_height))]; - local height_bk = floor_height[ 1 ]; - -- translate wallmounted (for ladder) to facedir for chest - res.p2 = res.p2; - if( res.p2 == 5 ) then - res.p2n = 2; - elseif( res.p2 == 4 ) then - res.p2n = 0; - elseif( res.p2 == 3 ) then - res.p2n = 3; - elseif( res.p2 == 2 ) then - res.p2n = 1; - end - -- determine target position - local pos = {x=res.x, y=height+1, z=res.z}; - - - local pos_bk = {x=res.x, y=height_bk+1, z=res.z}; - - -- if plasterwork is installed: place a machine - if( materials.color and minetest.global_exists("plasterwork")) then -- and pr:next(1,10)==1) then - vm:set_node_at( pos, {name=materials.walls, param2 = materials.color}); - local pos2 = {x=res.x, y=height+2, z=res.z}; - vm:set_node_at( pos2, {name="plasterwork:machine", param2 = res.p2n}); - -- if we are operating inside handle_schematics, pos2 will not relate to the real world; - -- it will just be a data structure. Therefore, we can't change the world at those coordinates. - if( not( vm.is_fake_vm )) then - minetest.registered_nodes[ "plasterwork:machine" ].after_place_node(pos2, nil, nil); - local meta = minetest.get_meta( pos2); - meta:set_string( "target_node", materials.walls ); - meta:set_int( "target_color", materials.color ); - end - return; - end - -- place the chest - --set place bookshelf on first floor - vm:set_node_at( pos, {name=witches.bh.chest, param2 = res.p2n}); - --placed_nodes.pos_bk = {name=witches.bh.bookshelf, param2 = res.p2n}; - - --if math.random()< 0.50 and not minetest.find_node_near(pos_bk, 2, {witches.bh.door_bottom,witches.bh.ladder}) then - -- vm:set_node_at( pos_bk, {name=witches.bh.bookshelf, param2 = res.p2n}); - --end - - -- if we are operating inside handle_schematics, positions do not directly correspond - -- to real map positions; we can't change the map directly at this time. Therefore, - -- we're finished for now. - - if( vm.is_fake_vm ) then - return; - end - -- fill chest with building material - minetest.registered_nodes[ witches.bh.chest ].on_construct( pos ); - local secret_name = witches.generate_text(witches.name_parts_female) - local meta = minetest.get_meta(pos); - local inv = meta:get_inventory(); - - if witches.bh.chest == "default:chest_locked" then - meta:set_string("secret_type", "witches_chest") - meta:set_string("secret_name", secret_name) - meta:set_string("owner",secret_name) - meta:set_string("infotext", "Sealed chest of "..secret_name) - if minetest.get_modpath("fireflies") then - inv:add_item( "main", {name = "fireflies:bug_net"}) - end - inv:add_item( "main", {name = "default:meselamp"}) - if math.random() < 0.50 then - for i=1,math.random(3) do - inv:add_item( "main", {name = "default:diamond"}) - end - end - end - local c = pr:next(1,4); - for i=1,c do - local stack_name = materials.walls.." "..pr:next(1,99); - if( materials.color ) then - stack_name = minetest.itemstring_with_palette( stack_name, materials.color ); - end - inv:add_item( "main", stack_name ); - end - inv:add_item( "main", materials.first_floor.." "..pr:next(1,49) ); - c = pr:next(1,2); - for i=1,c do - inv:add_item( "main", materials.ceiling.." "..pr:next(1,99) ); - end - inv:add_item( "main", materials.glass.." "..pr:next(1,20) ); - if( not( materials.roof_flat )) then - inv:add_item( "main", materials.roof.." "..pr:next(1,99) ); - inv:add_item( "main", materials.roof_middle.." "..pr:next(1,49) ); - end - inv:add_item( "main", {name = witches.bh.bookshelf}); - if minetest.get_modpath("beds") then - inv:add_item( "main", {name = witches.bh.bed} ); - end - if minetest.get_modpath("fireflies") then - inv:add_item( "main", {name = "fireflies:firefly_bottle"} ); - end - if minetest.get_modpath("bucket") then - inv:add_item( "main", {name = "bucket:bucket_empty"} ); - end - if minetest.get_modpath("dye") then - local dname = dye.dyes[math.random(1,#dye.dyes)][1] - inv:add_item( "main", {name = "dye:"..dname }) - end -end - - --- locate a place for the "hut" -witches.bh.simple_hut_find_place = function( heightmap, minp, maxp, sizex, sizez, minheight, maxheight ) - - local res = handle_schematics.find_flat_land_get_candidates_fast( heightmap, minp, maxp, - sizex, sizez, minheight, maxheight ); - ---print( "Places found of size "..tostring( sizex ).."x"..tostring(sizez)..": "..tostring( #res.places_x ).. --- " and "..tostring( sizez ).."x"..tostring(sizex)..": "..tostring( #res.places_z ).. --- "."); - - if( (#res.places_x + #res.places_z )< 1 ) then --- print( " Aborting. No place found."); - return nil; - end - - -- select a random place - either sizex x sizez or sizez x sizex - --first find a place over a dungeon - local near_dungeon = {}; - - --if not near_dungeon.x then near_dungeon.x = {} end - if #dungeon_list >=1 then - for i=1,#dungeon_list do - --print("dungeon list:"..minetest.pos_to_string(dungeon_list[i])) - end - else - --print("no dungeon list!") - end - - local chunksize = maxp.x - minp.x + 1; - local c = math.random( 1, #res.places_x + #res.places_z ); - --local i = 1; - --local d = 1; - - if #dungeon_list >=1 then - --print("there is a list!") - local nearest_dungeon = 10000 - --make a list from either of the res - if math.random() <= 0.5 then - - for dc=1,#res.places_z do - if res.places_x[dc] and res.places_z[dc] then - for d=1,#dungeon_list do - - --local check = {x = res.places_x[dc], y = dungeon_list[d].y, z = res.places_z[dc]} - local check = {x = minp.x+(dc%chunksize)-1, y = dungeon_list[d].y, z=minp.z+math.floor(dc/chunksize)} - local dist = vector.distance(dungeon_list[d], check) - --print("checking for z: "..minetest.pos_to_string(check)) - if dist < nearest_dungeon then nearest_dungeon = math.floor(dist) end - if dist <= 2 then - --print("found for z! "..dump(dist)) - dungeon_list[d].i = dc - dungeon_list[d].sizex = sizez - dungeon_list[d].sizez = sizex - table.insert(near_dungeon,dungeon_list[d]) - end - - end - end - end - - - else - - for dc=1,#res.places_x do - if res.places_x[dc] and res.places_z[dc] then - for d=1,#dungeon_list do - --{x=minp.x+(i%chunksize)-1, y=heightmap[ i ], z=minp.z+math.floor(i/chunksize), i=i}; - local check = {x = minp.x+(dc%chunksize)-1, y = dungeon_list[d].y, z=minp.z+math.floor(dc/chunksize)} - local dist = vector.distance(dungeon_list[d], check) - --print("checking for x: "..minetest.pos_to_string(check)) - if dist < nearest_dungeon then nearest_dungeon = math.floor(dist) end - if dist <= 2 then - --print("found for x! "..dump(dist)) - dungeon_list[d].i = dc - dungeon_list[d].sizex = sizex - dungeon_list[d].sizez = sizez - table.insert(near_dungeon,dungeon_list[d]) - end - end - end - end - - end - print("\n nearest dungeon was "..nearest_dungeon.."\n") - end - - if #near_dungeon < 1 and math.random() < (1-dungeon_cellar.chance) then - --print("standard placement") - --print("failed dungeon_list count: " ..#dungeon_list) - --for f=1,#dungeon_list do - -- print("dungeon list:"..minetest.pos_to_string(dungeon_list[f])) - --end - local i = 1 - if( c > #res.places_x ) then - i = res.places_z[ c-#res.places_x ]; - -- swap x and z due to rotation of 90 or 270 degree - local tmp = sizex; - sizex = sizez; - sizez = tmp; - tmp = nil; - else - i = res.places_x[ c ]; - end - - -- translate index back into coordinates - local p = {x=minp.x+(i%chunksize)-1, y=heightmap[ i ], z=minp.z+math.floor(i/chunksize), i=i}; - --print("standard placement of cottage: "..minetest.pos_to_string(p)) - return {p1={x=p.x - sizex, y=p.y, z=p.z - sizez }, p2=p, sizex=sizex, sizez=sizez}; - - else - - -- translate index back into coordinates - --local p = {x=minp.x+(i%chunksize)-1, y=heightmap[ i ], z=minp.z+math.floor(i/chunksize), i=i}; - - if #near_dungeon >= 1 then - - --print("near dungeon count: "..#near_dungeon) - local choice = math.random(1,#near_dungeon) - --print("dungeon found: "..minetest.pos_to_string(near_dungeon[choice])) - local t = minetest.find_node_near(near_dungeon[choice],3,"air") - --local p = {x=minp.x+(i%chunksize)-1, y=heightmap[ t.y ], z=minp.z+math.floor(i/chunksize), i=t.i}; - local i = near_dungeon[choice].i - --print("i = "..i) - local p = { - x = math.floor(t.x + (near_dungeon[choice].sizex / 2)), - y = heightmap[ i ], - z = math.floor(t.z + (near_dungeon[choice].sizez / 2)), - i = i, - } - --print(dump(p)) - return {p1={x=p.x - sizex, y=p.y, z=p.z - sizez }, p2=p, sizex=sizex, sizez=sizez, d1=near_dungeon[choice]}; - else - -- print("dungeon chance: ".. dungeon_cellar.chance.." dungeon_list: "..#dungeon_list) - --for i=1,#dungeon_list do - -- print("dungeon list:"..minetest.pos_to_string(dungeon_list[i])) - -- end - - end - - - end - dungeon_list = {} -end - -local build_type = "default" - --- chooses random materials, amount of floors etc.; --- sets data.materials and data.p2.ymax -witches.bh.simple_hut_get_materials = function( data, amount_in_this_mapchunk, chunk_ends_at_height, pr ) - -- select some random materials, height etc. - -- wood is always useful - local wood_types = replacements_group['wood'].found; - local wood = wood_types[ pr:next(1,math.max(1,#wood_types))]; - local wood_roof = wood_types[ pr:next(1,math.max(1,#wood_types))]; - -- choose random materials - local materials = { - walls = nil, - color = nil, - gable = nil, - glass = witches.bh.glass[ pr:next( 1,math.max(1,#witches.bh.glass ))], - roof = replacements_group['wood'].data[ wood_roof ][7], -- stair - roof_middle = replacements_group['wood'].data[ wood_roof ][8], -- slab - first_floor = witches.bh.floor, - ceiling = wood_types[ pr:next(1,math.max(1,#wood_types))], - wall_orients = {0,1,2,3}, - glass_orients = {12,18,9,7}, - }; - - -- windows 3 nodes high, 2 high, or just 1? - local r = pr:next(1,6); --- if( r==1 or r==2) then materials.window_at_height = {0,1,1,1,0}; - if( r==1 or r==3 or r==5) then - materials.window_at_height = {0,0,1,1,0}; - else - materials.window_at_height = {0,0,1,0,0}; - end - - -- how many floors will the house have? - local max_floors_possible = math.floor((chunk_ends_at_height-1-data.p2.y)/#materials.window_at_height); - if( pr:next(1,5)==1) then - materials.floors = pr:next(1,math.min(2,math.max(1,max_floors_possible-1))); - else - materials.floors = pr:next(1,math.min(2,math.max(1,max_floors_possible-1))); - end - - -- some houses may have a flat roof instead of a saddle roof - materials.flat_roof = false; - --[[ yeah,nah... - if( pr:next(1,2)==1) then - materials.flat_roof = true; - end - --]] - -- path around the house so that the door is accessible - materials.around_house = witches.bh.around_house[ pr:next(1, #witches.bh.around_house )]; - -- which wall material shall be used? - if( minetest.global_exists("plasterwork") and pr:next(1,2)==1 ) then - -- colored plasterwork - materials.walls = plasterwork.node_list[ pr:next(1, #plasterwork.node_list)]; - materials.color = pr:next(0,255); - else - local r = pr:next(1,1); - --[[ wooden house unused for now - if( r==1 ) then - - materials.walls = wood; - -- wooden houses with more than 3 floors would be strange - materials.floors = pr:next(1, math.min( 2, math.max(2,max_floors_possible-1 ))); - -- flat roofs do not look good on them either - materials.flat_roof = false; - -- vertical wood is also pretty decorative - if( pr:next(1,2)==1 ) then - materials.wall_orients = {12,18,9,7}; - end - - -- tree logs - --]] - if( r==1 ) then - - build_type = "log_cabin" --sets the corner orientation and extention - - materials.walls = replacements_group['wood'].data[ wood ][4]; -- tree trunk - -- log cabins with more than 2 floors are unlikely - materials.floors = pr:next(1, math.min( 2, math.max(2,max_floors_possible-1 ))); - -- log cabins do not have a flat roof either - materials.flat_roof = false; - materials.wall_orients = {12,18,9,7}; - - --else - --materials.walls = witches.bh.walls[ pr:next(1,#witches.bh.walls)]; - end - end - -- if there are less than three houses in a mapchunk: do not place skyscrapers - if( amount_in_this_mapchunk < 100 ) then - -- use saddle roof instead of flat one - materials.roof_flat = false; - -- at max two floors - materials.floors = math.min( 2, materials.floors ); - end - - materials.gable = materials.walls; - if( pr:next(1,3)==1 ) then - materials.gable = wood_types[ pr:next(1,#wood_types)]; - end - - local height = materials.floors * #materials.window_at_height +1; - if( materials.flat_roof ) then - data.p2.ymax = math.min( chunk_ends_at_height, data.p2.y + height + math.ceil( math.min( data.sizex, data.sizez )/2 )); - else - data.p2.ymax = math.min( chunk_ends_at_height, data.p2.y + height + 4); - end - data.p2.ymax = math.min( chunk_ends_at_height, data.p2.ymax ); - data.materials = materials; - - - -- place windows at even or odd rows? -> create some variety - local window_at_odd_row = false; - if( pr:next(1,2)==1 ) then - window_at_odd_row = true; - end - - -- place where a door or ladder might be added (no window there); - -- we need to avid adding ladders directly in front of windows or - -- placing doors right next to glass panes because that would look ugly - local special_wall_1 = pr:next(3,math.max(3,math.min(data.sizex,data.sizez)-3)); - local special_wall_2 = pr:next(3,math.max(3,math.min(data.sizex,data.sizez)-3)); - if( special_wall_2 == special_wall_1 ) then - special_wall_2 = special_wall_2 - 1; - if( special_wall_2 < 3 ) then - special_wall_2 = 4; - end - end - ---[[ - local wall_height = #materials.window_at_height; --- TODO: size (1x x, 1x z) - for lauf = 1, size do - local wall_1_has_window = false; - local wall_2_has_window = false; - -- the corners never get glass - if( lauf>1 and lauf64 or sizez>64) then - return nil; - end - --adjust height for foundation - p.y = p.y+1 - -- replaicate the pattern of windows for the other floors - - local first_floor_height = #materials.window_at_height; - local floor_height = {p.y}; - local floor_materials = {{name=materials.first_floor}}; - for i=1,materials.floors-1 do - for k=2,first_floor_height do - table.insert( materials.window_at_height, materials.window_at_height[k]); - end - table.insert( floor_height, floor_height[ #floor_height] + first_floor_height-1); - table.insert( floor_materials, {name=materials.ceiling}); - end - table.insert( floor_height, floor_height[ #floor_height] + first_floor_height-1); - if( materials.flat_roof ) then - -- the upper floor will form the roof of the house and is made out of - -- its wall material - table.insert( floor_materials, {name=materials.walls, param2 = (materials.color or 12)}); - table.insert( materials.window_at_height, 0 ); - else - -- the house uses a saddle roof; the ceiling will use wood - table.insert( floor_materials, {name=materials.ceiling, param2 = (materials.color or 12)}); - end - - local p_start = {x=p.x-sizex+1, y=p.y-1, z=p.z-sizez+1}; - -- build the two walls in x direction - local s1 = witches.bh.build_two_walls(p_start, sizex-2, sizez-2, true, materials, vm, pr ); --12, 18, vm ); - -- build the two walls in z direction - local s2 = witches.bh.build_two_walls(p_start, sizex-2, sizez-2, false, materials, vm, pr ); -- 9, 7, vm ); - - if build_type == "log_cabin" then - --alternating log cabin ends (thanks again, Sokomine!) - - local wall1 = {name=materials.walls, param2 = (materials.color or materials.wall_orients[4])} - local wall2 = {name=materials.walls, param2 = (materials.color or materials.wall_orients[2])} - for h=1,#materials.window_at_height do - if(h%2~=0) then - - --vm:set_node_at({x=p_start.x, z=p_start.z, y=p_start.y+h}, wall1) - vm:set_node_at({x=p_start.x, z=p_start.z-1, y=p_start.y+h}, wall1) - - --vm:set_node_at({x=p_start.x+sizex-2, z=p_start.z, y=p_start.y+h}, wall1) - vm:set_node_at({x=p_start.x+sizex-2, z=p_start.z-1, y=p_start.y+h}, wall1) - - --vm:set_node_at({x=p_start.x, z=p_start.z+sizez-2, y=p_start.y+h}, wall1) - vm:set_node_at({x=p_start.x, z=p_start.z+sizez-1, y=p_start.y+h}, wall1) - - --vm:set_node_at({x=p_start.x+sizex-2, z=p_start.z+sizez-2, y=p_start.y+h}, wall2) - vm:set_node_at({x=p_start.x+sizex-2, z=p_start.z+sizez-1, y=p_start.y+h}, wall1) - end - end - for h=1,#materials.window_at_height do - if(h%2==0) then - - vm:set_node_at({x=p_start.x, z=p_start.z, y=p_start.y+h}, wall2) - vm:set_node_at({x=p_start.x-1, z=p_start.z, y=p_start.y+h}, wall2) - - vm:set_node_at({x=p_start.x+sizex-2, z=p_start.z, y=p_start.y+h}, wall2) - vm:set_node_at({x=p_start.x+sizex-1, z=p_start.z, y=p_start.y+h}, wall2) - - vm:set_node_at({x=p_start.x, z=p_start.z+sizez-2, y=p_start.y+h}, wall2) - vm:set_node_at({x=p_start.x-1, z=p_start.z+sizez-2, y=p_start.y+h}, wall2) - - vm:set_node_at({x=p_start.x+sizex-2, z=p_start.z+sizez-2, y=p_start.y+h}, wall2) - vm:set_node_at({x=p_start.x+sizex-1, z=p_start.z+sizez-2, y=p_start.y+h}, wall2) - end - end - end - -- each floor is 3 blocks heigh - local roof_starts_at = p.y + (3*materials.floors); - p_start = {x=p.x-sizex, y=roof_starts_at, z=p.z-sizez, ymax = p.ymax}; - -- make the roof one higher - so that players/mobs can stay upright on - -- each roof floor node - this makes it easier to build staircases - p_start.y = p_start.y+2; - -- build the roof - if( materials.flat_roof ) then - -- build a flat roof - p_start.y = p_start.y-1; -- no need to make that higher - elseif( sizex < sizez ) then - witches.bh.build_roof_and_gable(p_start, sizex, sizez, true, materials, 1, 3, vm ); - else - witches.bh.build_roof_and_gable(p_start, sizex, sizez, false, materials, 0, 2, vm ); - end - - local do_ceiling = ( math.min( sizex, sizez )>4 ); - -- floor and ceiling - for dx = p.x-sizex+2, p.x-2 do - for dz = p.z-sizez+2, p.z-2 do - for i,height in ipairs( floor_height ) do - vm:set_node_at( {x=dx,y=height,z=dz},floor_materials[i]); - end - end - end - --foundation - for dx = p.x-sizex, p.x do - for dz = p.z-sizez, p.z do - vm:set_node_at( {x=dx,y=p.y-1,z=dz},floor_materials[1]); - end - end - - local fstyle = math.random(2) - local max_trees = 2 - local around_house_node = {name=materials.around_house, param2=0}; - local air_node = {name="air"}; - for dx = p.x-sizex, p.x do - -- path around the house - flower_pos[#flower_pos+1] = {x=dx-math.random(1,12), y=p.y-1, z=p.z-(sizez+math.random(4,12))} - - if math.random(1,sizex) and max_trees >= 1 then - tree_pos[1] = {x=dx-math.random(1,12), y=p.y-1, z=p.z-(sizez+math.random(8,12))} - max_trees = max_trees - 1 - - end - - flower_pos[#flower_pos+1] = {x=dx+math.random(1,12), y=p.y-1, z=p.z+math.random(4,12)} - - if math.random(1,sizex) and max_trees >= 1 then - tree_pos[2] = {x=dx+math.random(1,12), y=p.y-1, z=p.z+math.random(8,12)} - max_trees = max_trees - 1 - - end - - if fstyle == 1 then - - vm:set_node_at( {x=dx, y=p.y, z=p.z-sizez}, around_house_node ); - vm:set_node_at( {x=dx, y=p.y, z=p.z }, around_house_node ); - - elseif fstyle == 2 then - - vm:set_node_at( {x=dx, y=p.y, z=p.z-sizez}, around_house_node ); - vm:set_node_at( {x=dx, y=p.y-1, z=p.z-(sizez+1)}, around_house_node ); - - vm:set_node_at( {x=dx, y=p.y, z=p.z }, around_house_node ); - vm:set_node_at( {x=dx, y=p.y-1, z=p.z+1 }, around_house_node ); - - end - - -- make sure there is no snow blocking entrance - vm:set_node_at( {x=dx, y=p.y+1, z=p.z-sizez}, air_node ); - vm:set_node_at( {x=dx, y=p.y+1, z=p.z }, air_node ); - end - max_trees = 2 - - for dz = p.z-sizez, p.z do - -- path around the house - - flower_pos[#flower_pos+1] = {x=p.x-(sizex+math.random(4,12)), y=p.y-1, z=dz+math.random(1,12)} - - if math.random(1,sizez) and max_trees >= 1 then - tree_pos[3] = {x=p.x-(sizex+math.random(8,12)), y=p.y-1, z=dz+math.random(1,12)} - max_trees = max_trees - 1 - end - - - flower_pos[#flower_pos+1] = {x=p.x+math.random(4,12), y=p.y-1, z=dz-math.random(1,12)} - - if math.random(1,sizez) and max_trees >= 1 then - tree_pos[4] = {x=p.x+math.random(8,12), y=p.y-1, z=dz-math.random(1,12)} - max_trees = max_trees - 1 - end - - if fstyle == 1 then - - vm:set_node_at( {x=p.x-sizex, y=p.y, z=dz}, around_house_node ); - vm:set_node_at( {x=p.x, y=p.y, z=dz}, around_house_node ); - - elseif fstyle == 2 then - - vm:set_node_at( {x=p.x-sizex, y=p.y, z=dz}, around_house_node ); - vm:set_node_at( {x=p.x-(sizex+1), y=p.y-1, z=dz}, around_house_node ); - - vm:set_node_at( {x=p.x, y=p.y, z=dz}, around_house_node ); - vm:set_node_at( {x=p.x+1, y=p.y-1, z=dz}, around_house_node ); - - end - -- make sure there is no snow blocking entrance - vm:set_node_at( {x=p.x-sizex, y=p.y+1, z=dz}, air_node ); - vm:set_node_at( {x=p.x, y=p.y+1, z=dz}, air_node ); - end - - - -- index 1 and 2 are offsets in any of the walls; index 3 indicates if the - -- windows start at odd indices or not - local reserved_places = {s1[1], s1[2], s2[1], s2[2], s1[3], s2[3]}; - p_start = {x=p.x-sizex, y=p.y, z=p.z-sizez}; - local wall_with_ladder = witches.bh.place_ladder( p_start, sizex, sizez, - reserved_places, #materials.window_at_height-1, materials.flat_roof, vm, pr, d1 ); - - witches.bh.place_door( p_start, sizex, sizez, reserved_places, wall_with_ladder, floor_height, vm, pr ); - witches.bh.place_chest( p_start, sizex, sizez, reserved_places, wall_with_ladder, floor_height, vm, materials, pr ); - - ---this is for more furniture later --- local wp = window_pos[math.random(#window_pos)] - - - -- return where the hut has been placed - - return {p1={x=p.x - sizex, y=p.y, z=p.z - sizez }, p2=p}; -end - - --- get the voxelmanip object and place the house in there -witches.bh.simple_hut_place_hut = function( data, materials, pr ) - local p = data.p2; - local sizex = data.sizex-1; - local sizez = data.sizez-1; - -- house too small or too large - if( sizex < 3 or sizez < 3 or sizex>64 or sizez>64) then - return nil; - end - print( " Placing house at "..minetest.pos_to_string( p )); - - local vm = minetest.get_voxel_manip(); - vm:read_from_map( - - {x=p.x - sizex, y=p.y-1, z=p.z - sizez }, - {x=p.x, y=p.ymax, z=p.z}); - witches.bh.simple_hut_place_hut_using_vm( data, materials, vm, pr ) - vm:write_to_map(true); - - if tree_pos then - local biome_name = "" - for _,v in pairs(tree_pos) do - - local check = minetest.get_node(v) - --print(dump(check.name)) - - if check.name == "air" then - v = nil - elseif check.name == "ignore" then - v = nil - elseif minetest.get_decoration_id(check.name) then - v = nil - else - - local biome_id = minetest.get_biome_data(v) - --print(dump(biome_id)) - biome_name = minetest.get_biome_name(biome_id.biome) - --print(dump(biome_name)) - - end - if v then - if string.find(biome_name,"desert") then - --print(dump(v)) - if math.random() <.20 then - minetest.spawn_tree(v,witches.acacia_tree) - else - local v2 = {x = v.x, y = v.y +1, z = v.z} - default.grow_large_cactus(v2) - end - elseif string.find(biome_name,"jungle") then - if math.random() <.40 then - minetest.spawn_tree(v,witches.apple_tree) - elseif math.random() <.50 then - default.grow_new_emergent_jungle_tree(v) - else - default.grow_new_jungle_tree(v) - end - elseif math.random() < .2 then - minetest.set_node(v,{name = "default:acacia_tree"}) - minetest.spawn_tree(v,witches.acacia_tree) - --print("growing tree at "..minetest.pos_to_string(vector.round(v))) - - else - minetest.set_node(v,{name = "default:tree"}) - minetest.spawn_tree(v,witches.apple_tree) - --print("growing tree at "..minetest.pos_to_string(vector.round(v))) - - end - end - end - end - - if flower_pos then - for _,v in pairs(flower_pos) do - if math.random(1,#flower_pos) then - witches.flower_patch(v) - - --print("flowers planted at: "..minetest.pos_to_string(v)) - end - end - end - -end - - -witches.bh.simple_hut_get_size_and_place = function( heightmap, minp, maxp) - if( minp.y < -64 or minp.y > 500 or not(heightmap)) then - return; - end - -- halfway reasonable house sizes - local maxsize = 9; - --[[ - if( math.random(1,5)==1) then - maxsize = 17; - end - --]] --- TODO: if more than 2-3 houses are placed, get voxelmanip for entire area instead of for each house --- TODO: avoid overlapping with mg_villages if that one is installed - local sizex = math.random(8,maxsize); - local sizez = math.max( 8, math.min( maxsize, math.random( math.floor(sizex/4), sizex*2 ))); - -- chooses random materials and a random place without destroying the landscape - -- minheight 2: one above water level; avoid below water level and places on ice - return witches.bh.simple_hut_find_place( heightmap, minp, maxp, sizex, sizez, 2, 1000 ); -end - - --- mg_villages takes precedence; however, both mods can work together; it's just that mg_villages --- has to take care of all the things at mapgen time -if(not(minetest.get_modpath("mg_villages"))) then - minetest.register_on_generated(function(minp, maxp, seed) - if( minp.y < -64 or minp.y > 500) then - return; - end - witches.bh.mapchunks_processed = witches.bh.mapchunks_processed + 1; - -- with each map chunk generated, there's more room where houses could be - local missing = math.floor(witches.bh.mapchunks_processed * witches.bh.houses_wanted_per_mapchunk) - - witches.bh.houses_generated; - -- some randomness to make it more intresting - -- also place a house in the first mapchunk possible in order to "greet" the player - -- with it and assure the player that the mod is installed - if( (witches.bh.houses_generated>1) - and missing < witches.bh.max_per_mapchunk and math.random(1,100)>witches.bh.additional_chance) then - return; - end - local heightmap = minetest.get_mapgen_object('heightmap'); - local houses_placed = 0; - local house_data = {}; - local anz_houses = math.random( math.min( missing, math.floor(witches.bh.max_per_mapchunk/2 )), - witches.bh.max_per_mapchunk ); - - for i=1,anz_houses do - local res = witches.bh.simple_hut_get_size_and_place( heightmap, minp, maxp); - if( res and res.p1 and res.p2 - and res.p2.x>=minp.x and res.p2.z>=minp.z - and res.p2.x<=maxp.x and res.p2.z<=maxp.z) then - - handle_schematics.mark_flat_land_as_used(heightmap, minp, maxp, - res.p2.i, - (res.p2.x-res.p1.x), - (res.p2.z-res.p1.z)); - table.insert( house_data, res ); - houses_placed = houses_placed + 1; - - if res.d1 then - -- print("res.d1 "..minetest.pos_to_string(res.d1)) - end - - end - end - -- use the same material around the houses in the entire mapchunk - local around_house_material = nil; - for i,data in ipairs( house_data ) do - -- initialize pseudorandom number generator - local pr = PseudoRandom( data.p2.x + data.p2.z ); - local res = witches.bh.simple_hut_get_materials( data, #house_data, maxp.y+16, pr ); - if( not( around_house_material )) then - around_house_material = res.materials.around_house; - else - res.materials.around_house = around_house_material; - end - witches.bh.simple_hut_place_hut( data, res.materials, pr ); - end - - if( houses_placed > 0 ) then - witches.bh.houses_generated = witches.bh.houses_generated + houses_placed; --- print("Count: "..tostring( witches.bh.mapchunks_processed ).. --- " Houses: "..tostring( witches.bh.houses_generated )); - end - end); -end - - --- interface for handle_schematics for manual generation of houses -witches.bh.get_parameter = function( pos, sizex, sizez, sizey, pr ) - local data = { p2={x=pos.x+sizex, y=pos.y, z=pos.z+sizez}, sizex=sizex, sizez=sizez, sizey=sizey}; - -- it needs at least 3 houses in this mapchunk in order to generate a flat roof - local amount_in_this_mapchunk = 100; - -- how heigh can the building become at max? - local chunk_ends_at_height = data.p2.y+1+sizey; - -- suggest random materials and other values - local res = witches.bh.simple_hut_get_materials( data, amount_in_this_mapchunk, chunk_ends_at_height, pr ) - -- these parameters are needed as well - res.p2 = data.p2; - res.sizex = data.sizex; - res.sizez = data.sizez; - res.sizey = data.sizey; - return res; -end - - --- for manual placement with handle_schematics and/or mg_villages; --- vm may be a fake VoxelManip data structure --- returns a value != nil (actually the start and end position) if successful -witches.bh.generate_random_hut_at_pos = function( pos, sizex, sizez, sizey, seed, vm ) - -- prepare the data structure containing position and size - local data = { p2 = {x=pos.x+sizex, y=pos.y, z=pos.z+sizez}, sizex = sizex, sizez = sizez }; - -- initialize pseudorandom number generator for reproducability - local pr = PseudoRandom( seed ); - -- if the second parameter is greater than 3, houses with a flat roof can be generated - local res = witches.bh.simple_hut_get_materials( data, 4, pos.y+sizey+1, pr ); - -- no need to assure a walkable path to the entrance if we are dealing with mods - -- that ensure that by diffrent means (mg_villages = flat land; build chest from - -- handle_schematics = player places manually); dirt with grass is a general - -- placeholder for the biome surface - res.materials.around_house = "default:dirt_with_grass"; - -- place the house into the vm data structure - local res = witches.bh.simple_hut_place_hut_using_vm( data, data.materials, vm, pr ) - -- the structure is burried one node deep (=floor) - vm.yoff = 0; - -- the fake voxelmanip data structure contains all the data we need - return vm; -end - - -build_chest.add_entry( {'generate building','basic_houses', 'witches.bh.generator'}); -build_chest.add_building( 'witches.bh.generator', - { generator=witches.bh.generate_random_hut_at_pos, - } ); diff --git a/changelog b/changelog index fc006db..d3243be 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,7 @@ + 2022/02/14: Dialog updates + 2022/02/13: Debug output can be enabled from game Settings tab > All Settings > Mods > witches + 2022/02/12: Witches honor protected nodes ("protector" mod support) + 2020/08/10: Testing new cottage building code. 2020/08/06: Fixed witches not registered when handle_schematics is not loaded! D'oh! 2020/08/01: Witches have two new wands from Damon and Simone! 2020/07/31: Witches can turn aggressive mobs into sheep! Witches gain drench spell! diff --git a/cottages.lua b/cottages.lua new file mode 100644 index 0000000..8e85972 --- /dev/null +++ b/cottages.lua @@ -0,0 +1,959 @@ +--this file is copyright (c) 2020 Francisco Athens licensed under the terms of the MIT license + +local witches_dungeon_cellar_chance = tonumber(minetest.settings:get("witches_dungeon_cellar_chance")) or .50 +local witches_dungeon_cellar_depth = tonumber(minetest.settings:get("witches_dungeon_cellar_depth")) or -5 + +local function mts(table) + local output = minetest.serialize(table) + return output +end + +local function mtpts(table) + local output = minetest.pos_to_string(table) + return output +end + +--lets see if any dungeons are near +minetest.set_gen_notify("dungeon") +local dungeon_cellar = { + chance = tonumber(witches_dungeon_cellar_chance), -- chance to try putting cottage over dungeon instead of anywhere else + max_depth = tonumber(witches_dungeon_cellar_depth) -- deepest dungeon depth to check +} + +local dungeon_list ={} + +minetest.register_on_generated(function(minp, maxp, blockseed) + local dg = minetest.get_mapgen_object("gennotify") + if dg and dg.dungeon and #dg.dungeon > 2 then + for i=1,#dg.dungeon do + if dg.dungeon[i].y >= dungeon_cellar.max_depth then + print("dungeon found: "..minetest.pos_to_string(dg.dungeon[i])) + + table.insert(dungeon_list, dg.dungeon[i]) + end + end + end + + +end) + + +--local vol_vec = {x=5,y=5,z=5} +function witches.grounding(self,vol_vec,required_list,exception_list,replacement_node) + local r_tweak = math.random(-1,1) + local area = vol_vec or {x=math.random(5+r_tweak,9),y=1,z=math.random(5-r_tweak,9)} + + local pos = vector.round(self.object:get_pos()) + --drop checks below sea level + if pos.y < 0 then return end + --local yaw = self.object:get_yaw() + --print(mts(self.object:get_yaw())) + + local pos1 = {x= pos.x-(area.x/2),y=pos.y-area.y ,z= pos.z-(area.z/2)} + local pos2 = {x= pos.x+(area.x/2),y=pos.y, z= pos.z+(area.z/2)} + local ck_pos1 = vector.subtract(pos1,4) + local ck_pos2 = vector.add(pos2,4) + + --ck_pos2.y = ck_pos2.y + 12 + + + --print("pos = ".. mtpts(pos)) + --print("pos1 = ".. mtpts(pos1)) + --print("pos2 = ".. mtpts(pos2)) + + --test if area is suitable (no air or water) + local rlist = required_list or {"soil","crumbly"} + local elist = exception_list or {"group:stone","group:cracky","group:wood", "group:tree"} + local exceptions = minetest.find_nodes_in_area_under_air(ck_pos1, ck_pos2,elist) + local protected_area = minetest.is_area_protected(ck_pos1, ck_pos2, "", 2) + + if #exceptions and #exceptions >= 1 then + witches.debug("exceptions count = "..#exceptions) + return + elseif protected_area then + witches.debug("protected area found at "..mtpts(protected_area)) + return + else + witches.debug("SUCCESS!".."pos1 = ".. mtpts(pos1).."pos2 = ".. mtpts(pos2)) + + local volume = {pos1,pos2} + local ck_volume = {ck_pos1,ck_pos2} + + return volume,ck_volume + + end + +end + +local cottage_id = nil +local default_params = { + --plan_size = {x=9, y=7 ,z=9}, --general size not including roof + foundation_nodes = {"default:mossycobble"}, + foundation_depth = 3, + porch_nodes = {"default:tree","default:pine_tree","default:acacia_tree"}, + porch_size = 2, + first_floor_nodes = {"default:cobble","default:wood","default:pine_wood","default:acacia_wood","default:junglewood"}, + second_floor_nodes = {"default:wood","default:pine_wood","default:acacia_wood","default:junglewood"}, + gable_nodes = {"default:wood","default:junglewood"}, + roof_nodes = {"stairs:stair_wood","stairs:stair_junglewood"}, + roof_slabs = {"stairs:slab_wood","stairs:slab_junglewood"}, + wall_nodes = {"default:tree","default:pine_tree","default:acacia_tree"}, + wall_nodes_ftype = {"wall_wdir"}, --wall_dir, wall_fdir, wall_wdir + wall_height = 3, + window_nodes = {"default:fence_wood","default:fence_pine_wood","default:fence_acacia_wood","default:fence_junglewood"}, + window_height = {1,2}, --height min, height max + orient_materials = true, + door_bottom = "doors:door_wood_witch_a"; + door_top = "doors:hidden"; + root_nodes = {"witches:treeroots"}; + builder = "none" +} + +function witches.generate_cottage(secret_name,pos1,pos2,params) + local working_parameters = params or default_params -- if there is nothing then initialize with defs + pos1 = vector.round(pos1) + pos2 = vector.round(pos2) + local wp = working_parameters + + if params then --get defaults for any missing params + for k,v in default_params do + if not params[k] then + wp[k] = table.copy(default_params[k]) + end + end + else wp = table.copy(default_params) + + end + + local ps = wp.porch_size or math.random(2) + local wall_node = wp.wall_nodes[math.random(#wp.wall_nodes)] + local root_node = wp.root_nodes [math.random(#wp.root_nodes)] + local window_node = wp.window_nodes[math.random(#wp.window_nodes)] + local window_height = wp.window_height[math.random(#wp.window_height)] + --start with basement + --local od = vector.subtract(pos2,pos1) + + local lower_corner_nodes = { + {x= pos1.x, y = pos1.y, z = pos1.z}, + {x= pos1.x, y = pos1.y, z = pos2.z}, + {x= pos2.x, y = pos1.y, z = pos2.z}, + {x= pos2.x, y = pos1.y, z = pos1.z}, + } + local upper_corner_nodes = { + + {x= pos1.x, y = pos2.y, z = pos1.z}, + {x= pos1.x, y = pos2.y, z = pos2.z}, + {x= pos2.x, y = pos2.y, z = pos2.z}, + {x= pos2.x, y = pos2.y, z = pos1.z}, + } + + local ucn = upper_corner_nodes + for h=1, wp.foundation_depth do + for i=1, #ucn do + local pos = {x=ucn[i].x, y=ucn[i].y-h+1,z=ucn[i].z} + minetest.set_node(pos,{name=wp.foundation_nodes[math.random(#wp.foundation_nodes)]}) + end + end + + for h=1, wp.foundation_depth do + for i=1, #ucn do + local pos = {x=ucn[i].x, y=ucn[i].y-h+1,z=ucn[i].z} + minetest.set_node(pos,{name=wp.foundation_nodes[math.random(#wp.foundation_nodes)]}) + end + end + + -- clear the area + local cpos1 = {x = pos1.x-ps, y=pos2.y ,z=pos1.z-ps} + local cpos2 = {x = pos2.x+ps, y=pos2.y+13, z=pos2.z+ps} + local carea = vector.subtract(cpos2,cpos1) + for h=1,carea.y+2 do + for i=1, carea.z+1 do + for j=1, carea.x+1 do + + local pos = {x=cpos1.x+j-1, y=cpos1.y+h, z=cpos1.z+i-1} + minetest.set_node(pos,{ + name="air" + }) + + end + end + end + + -- porch + local prnodes = wp.porch_nodes[math.random(#wp.porch_nodes)] + + local ppos1 = {x = pos1.x-ps, y=pos2.y ,z=pos1.z-ps} + local ppos2 = {x = pos2.x+ps, y=pos2.y, z=pos2.z+ps} + local parea = vector.subtract(ppos2,ppos1) + for i=1, parea.z+1 do + for j=1, parea.x+1 do + + local pos = {x=ppos1.x+j-1, y=ppos1.y, z=ppos1.z+i-1} + minetest.set_node(pos,{ + name=prnodes, + paramtype2="facedir", + param2=5 + }) + + end + end + + local pcn = { + + {x= pos1.x-ps, y = pos2.y, z = pos1.z-ps}, + {x= pos1.x-ps, y = pos2.y, z = pos2.z+ps}, + {x= pos2.x+ps, y = pos2.y, z = pos2.z+ps}, + {x= pos2.x+ps, y = pos2.y, z = pos1.z-ps}, + } + local pcn_height = wp.foundation_depth + 1 + + for h=1, pcn_height do + for i=1, #pcn do + local pos = {x=pcn[i].x, y=pcn[i].y+2-h,z=pcn[i].z} + minetest.set_node(pos,{name=wall_node}) + minetest.set_node({x=pos.x, y=pos.y-1, z=pos.z},{name=root_node}) + end + end + + + + local function mr(min,max) + local v = math.random(min,max) + return v + end + + local treecn = { + + {x= pcn[1].x-ps+mr(-1,1), y = pos2.y-1, z = pcn[1].z-ps+mr(-1,1)}, + {x= pcn[2].x-ps+mr(-1,1), y = pos2.y-1, z = pcn[2].z+ps+mr(-1,1)}, + {x= pcn[3].x+ps+mr(-1,1), y = pos2.y-1, z = pcn[3].z+ps+mr(-1,1)}, + {x= pcn[4].x+ps+mr(-1,1), y = pos2.y-1, z = pcn[4].z-ps+mr(-1,1)}, + } + + local tree_pos = treecn[math.random(#treecn)] + local root_pos = vector.new(tree_pos) + root_pos.y = root_pos.y-1 + minetest.spawn_tree(tree_pos,witches.acacia_tree) + minetest.set_node(root_pos,{name =root_node}) + + + --first floor! + local ffnodes = wp.first_floor_nodes[math.random(#wp.first_floor_nodes)] + local ffpos1 = {x = pos1.x, y=pos2.y ,z=pos1.z} + local ffpos2 = {x = pos2.x, y=pos2.y, z=pos2.z} + local area = vector.subtract(pos2,pos1) + + for i=1, area.z+1 do + for j=1, area.x+1 do + + local pos = {x=ffpos1.x+j-1, y=ffpos1.y, z=ffpos1.z+i-1} + minetest.set_node(pos,{ + name=ffnodes, + paramtype2="facedir", + param2=5 + }) + + end + end + + --local wall_node = wp.wall_nodes[math.random(#wp.wall_nodes)] + if math.random() < 0.9 then + --wall corners wood + for h=1, wp.wall_height do + for i=1, #ucn do + if h % 2 == 0 then + local pos = {x=ucn[i].x, y=ucn[i].y+h,z=ucn[i].z} + minetest.set_node(pos,{ + name=wall_node, + paramtype2="facedir", + param2=5 + }) + else + local pos = {x=ucn[i].x, y=ucn[i].y+h,z=ucn[i].z} + minetest.set_node(pos,{ + name=wall_node, + paramtype2="facedir", + param2=13 + }) + end + end + end + else + --wall corners stone + for h=1, wp.wall_height do + for i=1, #ucn do + local pos = {x=ucn[i].x, y=ucn[i].y+h,z=ucn[i].z} + minetest.set_node(pos,{name=wp.foundation_nodes[math.random(#wp.foundation_nodes)]}) + end + end + end + + --create first floor wall plan! + local wall_plan ={} + for i=1,area.z-1 do --west wall + local pos = {x=ffpos1.x, y=ffpos1.y+1, z=ffpos1.z+i} + local fpos = {x=ffpos1.x, y=ffpos1.y+1, z=ffpos1.z-1} + local dir = vector.direction(fpos,pos) -- the raw dir we can manipulate later + local facedir = minetest.dir_to_facedir(dir) --this facedir + --walldir is for placing tree nodes in wall direction + table.insert(wall_plan, { + pos = pos, dir = dir, facedir = facedir, walldir = 5 + }) + + end + + for i=1,area.x-1 do --north wall + local pos = {x=ffpos1.x+i, y=ffpos1.y+1, z=ffpos1.z} + local fpos = {x=ffpos1.x-1, y=ffpos1.y+1, z=ffpos1.z} + local dir = vector.direction(fpos,pos) + local facedir = minetest.dir_to_facedir(dir) + table.insert(wall_plan, { + pos = pos, dir = dir, facedir = facedir, walldir = 13 + }) + end + + for i=1,area.z-1 do --east wall + local pos = {x=ffpos1.x+area.x, y=ffpos1.y+1, z=ffpos1.z+i} + local fpos = {x=ffpos1.x+area.x, y=ffpos1.y+1, z=ffpos1.z-1} + local dir = vector.direction(fpos,pos) + local facedir = minetest.dir_to_facedir(dir) + table.insert(wall_plan, { + pos = pos, dir = dir, facedir = facedir, walldir = 5 + }) + end + + for i=1,area.x-1 do --south wall + local pos = {x=ffpos1.x+i, y=ffpos1.y+1, z=ffpos1.z+area.z} + local fpos = {x=ffpos1.x-1, y=ffpos1.y+1, z=ffpos1.z+area.z} + local dir = vector.direction(fpos,pos) + local facedir = minetest.dir_to_facedir(dir) + table.insert(wall_plan, { + pos = pos, dir = dir, facedir = facedir, walldir = 13 + }) + end + + + + for h=1, wp.wall_height do + for i=1, #wall_plan do + minetest.set_node(wall_plan[i].pos,{ + + name=wall_node, + paramtype2 = "facedir", + param2 = wall_plan[i].walldir + }) + end + for i=1, #wall_plan do + wall_plan[i].pos.y = wall_plan[i].pos.y+1 + end + end + +--possible door locations, extra offset data + local p_door_pos = { + w = {x = ffpos1.x, z = ffpos1.z+math.random(2,area.z-2), y = ffpos1.y+1, p ="z", fp={"x",-1}}, + n = {x = ffpos1.x+math.random(2,area.x-2), z = ffpos2.z, y = ffpos1.y+1, p ="x", fp={"z",1}}, + e = {x = ffpos2.x, z = ffpos1.z+math.random(2,area.z-2), y = ffpos1.y+1, p ="z", fp={"x",1}}, + s = {x = ffpos1.x+math.random(2,area.x-2), z = ffpos1.z, y = ffpos1.y+1, p ="x", fp={"z",-1}} + } + + local door_pos = {} + local test = 4 + for k,v in pairs(p_door_pos) do + if test >= 1 and math.random(test) == 1 then + door_pos[k]=v + test = 0 + else + test = test - 1 + end + + end + +--local door_pos= p_door_pos + + witches.debug("door: "..mts(door_pos)) + for k,v in pairs(door_pos) do + + witches.debug(mts(v)) + local f_pos1 = vector.new(v) + --get the offsets + f_pos1[v.fp[1] ] = f_pos1[v.fp[1] ] + v.fp[2] + + local dir=vector.direction(f_pos1,door_pos[k]) + local f_facedir = minetest.dir_to_facedir(dir) + + minetest.set_node(v,{ + name=wp.door_bottom, + paramtype2 = "facedir", + param2 = f_facedir + }) + + local door_pos_t = vector.new(v) + + door_pos_t.y = door_pos_t.y+1 + minetest.set_node(door_pos_t,{ + name=wp.door_top, + paramtype2 = "facedir", + param2 = f_facedir + }) + + --set some torch-like outside the door + local t_pos1 = vector.new(v) + --use fp to get outside + t_pos1[v.fp[1] ]= t_pos1[v.fp[1] ] + (v.fp[2]) + --get wallmount param2 + local t_dir = vector.direction(t_pos1,v) + local t_wm = minetest.dir_to_wallmounted(t_dir) + + t_pos1.y = t_pos1.y + 1 + --offset from door + local t_pos2 = vector.new(t_pos1) + t_pos1[v.p] = t_pos1[v.p] - 1 + + t_pos2[v.p] = t_pos2[v.p] + 1 + minetest.bulk_set_node({t_pos1, t_pos2},{ + name="default:torch_wall", + --paramtype2 = "facedir", + param2 = t_wm + }) + + end +--set windows + + local window_pos = {w ={},n={},e={},s={}} + local az = math.floor((area.z-2)/2) + local ax = math.floor((area.x-2)/2) + witches.debug("az/ax= "..az.." "..ax) + for i=1, az do + local wz = {x = ffpos1.x, z = ffpos1.z+math.random(2,area.z-2), y = ffpos1.y+2, p= "z", fp = {"x", 1} } + table.insert(window_pos.w,wz) + local ez = {x = ffpos2.x, z = ffpos1.z+math.random(2,area.z-2), y = ffpos1.y+2, p= "z", fp = {"x", -1} } + table.insert(window_pos.e, ez) + end + for i=1, ax do + local nx = {x = ffpos1.x+math.random(2,area.x-2), z = ffpos2.z, y = ffpos1.y+2, p= "x", fp = {"z", -1} } + table.insert(window_pos.n,nx) + local sx = {x = ffpos1.x+math.random(2,area.x-2), z = ffpos1.z, y = ffpos1.y+2, p= "x", fp = {"z", 1} } + table.insert(window_pos.s,sx) + end + witches.debug(mts(window_pos)) + + + for k,v in pairs(door_pos) do + --v is the door pos vector table + for i=v[v.p]+1,v[v.p]-1,-1 do --start with lateral axis (p) pos on either side of door + witches.debug("doorpos "..v.p.." "..i) + for j,_ in ipairs(window_pos[k]) do --we want the vector table value of each + witches.debug("windowpos "..mts(window_pos[k][j]).." vs "..i) + if window_pos[k][j] and i == window_pos[k][j][v.p] then + witches.debug("windowpos "..window_pos[k][j][v.p].." vs "..i) + witches.debug("removing window_pos[k][j][v.p] = ".. mtpts(window_pos[k][j])) + --table.remove(window_pos[k],j) + window_pos[k][j] = nil + end + end + end + + end + + if window_pos then + for k,_ in pairs(window_pos) do + for _,v in pairs(window_pos[k]) do + + for i=1,window_height do + + witches.debug("window set: "..mtpts(v)) + minetest.set_node({x= v.x, y=v.y-1+i, z=v.z},{ + name=window_node + }) + + end + + end + end + end + + --set some torch-like inside near window + if window_pos then + + for k,_ in pairs(window_pos) do + for _,v in ipairs(window_pos[k]) do + local t_pos1 = vector.new(v) + --use fp to get inside + t_pos1[v.fp[1] ]= t_pos1[v.fp[1] ] + (v.fp[2]) + local t_pos2 = vector.new(t_pos1) + + --get wallmount param2 + local t_dir = vector.direction(t_pos1,v) + local t_wm = minetest.dir_to_wallmounted(t_dir) + + t_pos1[v.p] = t_pos1[v.p] - 1 + t_pos2[v.p] = t_pos2[v.p] + 1 + + local ck_pos1 = vector.new(v) + ck_pos1[v.p] = ck_pos1[v.p] - 1 + local ck_pos2 = vector.new(v) + ck_pos2[v.p] = ck_pos1[v.p] + 1 + + + + if math.random() < .5 then + local ck = minetest.get_node(ck_pos1) + witches.debug("ck: "..ck.name) + if ck.name ~= window_node then + minetest.set_node(t_pos1,{ + name="default:torch_wall", + --paramtype2 = "facedir", + param2 = t_wm + + }) + end + else + local ck = minetest.get_node(ck_pos2) + witches.debug("ck: "..ck.name) + if ck.name ~= window_node then + minetest.set_node(t_pos2,{ + name="default:torch_wall", + --paramtype2 = "facedir", + param2 = t_wm + }) + end + end + end + end + end + local furnace_pos = {} --gonna need this later! + --place some furniture + if window_pos then + local furniture = {"default:bookshelf","default:chest_locked","beds:bed","default:furnace"} + local f_pos1 ={} + for j in pairs(window_pos) do + for k,v in ipairs(window_pos[j]) do + if furniture and #furniture >= 1 then + f_pos1 = vector.new(v) + f_pos1[v.fp[1] ] = f_pos1[v.fp[1] ]+v.fp[2] + f_pos1.y = f_pos1.y-1 + + witches.debug("window:"..mtpts(v)) + witches.debug("furniture:"..mtpts(f_pos1)) + local dir1=vector.direction(f_pos1,v) + local dir2=vector.direction(v,f_pos1) + local f_facedir1 = minetest.dir_to_facedir(dir1) + local f_facedir2 = minetest.dir_to_facedir(dir2) + local f_num = math.random(#furniture) + local f_name = furniture[f_num] + + if f_name == "beds:bed" then + local f_pos2 = vector.new(f_pos1) + if math.random()<0.001 then + f_pos2[v.fp[1] ] = f_pos2[v.fp[1] ]+v.fp[2] + else + f_pos2[v.p] = f_pos2[v.p] + v.fp[2] --bed along wall_nodes + dir1=vector.direction(f_pos2,f_pos1) + dir2=vector.direction(f_pos1,f_pos2) + f_facedir1 = minetest.dir_to_facedir(dir1) + f_facedir2 = minetest.dir_to_facedir(dir2) + end + + minetest.set_node(f_pos1,{ + name=f_name, + paramtype2 = "facedir", + param2 = f_facedir2 + }) + witches.debug("bed1:"..mtpts(f_pos1)) + witches.debug("bed2:"..mtpts(f_pos2)) + minetest.set_node(f_pos2,{ + name=f_name, + paramtype2 = "facedir", + param2 = f_facedir1 + }) + + elseif f_name == "default:furnace" then + f_pos1[v.fp[1] ] = f_pos1[v.fp[1] ]-v.fp[2] + minetest.set_node(f_pos1,{ + name=f_name, + paramtype2 = "facedir", + param2 = f_facedir1 + }) + furnace_pos = vector.new(f_pos1) + elseif f_name == "default:chest_locked" then + + minetest.set_node(f_pos1,{ + name=f_name, + paramtype2 = "facedir", + param2 = f_facedir1 + }) + + minetest.registered_nodes[ f_name ].on_construct( f_pos1 ); + local meta = minetest.get_meta(f_pos1); + local inv = meta:get_inventory(); + meta:set_string("secret_type", "witches_chest") + meta:set_string("secret_name", secret_name) + meta:set_string("owner",secret_name) + meta:set_string("infotext", "Sealed chest of "..secret_name) + if minetest.get_modpath("fireflies") then + inv:add_item( "main", {name = "fireflies:bug_net"}) + end + inv:add_item( "main", {name = "default:meselamp"}) + if math.random() < 0.50 then + for i=1,math.random(3) do + inv:add_item( "main", {name = "default:diamond"}) + end + end + + + elseif f_name ~="beds:bed" then + minetest.set_node(f_pos1,{ + name=f_name, + paramtype2 = "facedir", + param2 = f_facedir1 + }) + end + + table.remove(furniture, f_num) + end + end + end + end + + -- second_floor! + local sfnodes = wp.second_floor_nodes[math.random(#wp.second_floor_nodes)] + + local sfpos1 = {x = ffpos1.x, y=ffpos2.y+wp.wall_height,z=ffpos1.z} + local sfpos2 = {x = ffpos2.x, y=ffpos2.y+wp.wall_height, z=ffpos2.z} + local sfarea = vector.subtract(sfpos2,sfpos1) +-- + for i=1, sfarea.z+1 do + for j=1, sfarea.x+1 do + + local pos = {x=sfpos1.x+j-1, y=sfpos1.y+1, z=sfpos1.z+i-1} + minetest.set_node(pos,{ + name=sfnodes, + paramtype2="facedir", + param2=5 + }) + + end + end + -- +--[[ + for h=1, wp.wall_height-1 do + for i=1, #ucn do + local pos = {x=ucn[i].x, y=ucn[i].y+h+1+wp.wall_height,z=ucn[i].z} + minetest.set_node(pos,{name=wp.foundation_nodes[math.random(#wp.foundation_nodes)]}) + end + end +--]] +local stovepipe_pos = {} +--gable and roof + --orientation + local rfnum = math.random(#wp.roof_nodes) + local rfnodes = wp.roof_nodes[rfnum] + local rfslabs = wp.roof_slabs[rfnum] + local gbnodes = wp.gable_nodes[rfnum] + local orientations = {{"x","z"},{"z","x"}} + local o = orientations[math.random(#orientations)] + local gbpos1 = vector.new({x = sfpos1.x, y=sfpos2.y+1, z=sfpos1.z}) + local gbpos2 = vector.new({x = sfpos2.x, y=sfpos2.y+1, z=sfpos2.z}) --this is going to change while building + local rfpos1 = vector.new({x = sfpos1.x-1, y=sfpos2.y, z=sfpos1.z-1}) + local rfpos2 = vector.new({x = sfpos2.x+1, y=sfpos2.y, z=sfpos2.z+1}) --this is going to change while building + + local rfarea = vector.subtract(rfpos2,rfpos1) + local gbarea = vector.subtract(gbpos2,gbpos1) + local l_pos = {} + local rfaz = math.floor(rfarea.z/2) + local rfax = math.floor(rfarea.x/2) + if math.random() < 0.5 then + + local midpoint = (rfarea.z+1)/2 + local gmp = rfarea.z-1 + for i=1, midpoint do + for j=1, rfarea.x+1 do + local pos = {x=rfpos1.x+j-1, y=rfpos2.y+1, z=rfpos1.z+i-1} + minetest.set_node(pos,{ + name=rfnodes, + paramtype2="facedir", + param2=0 + }) + --print("mp "..midpoint) + --both gables are made at the same time + for g=1, gmp do + + local gpos = {x=gbpos1.x, y=rfpos2.y+2, z=gbpos1.z+gmp-g} + local gpos2 = {x=gbpos1.x+gbarea.x, y=rfpos2.y+2, z=gbpos1.z+gmp-g} + minetest.bulk_set_node({gpos,gpos2},{ + name=gbnodes, + paramtype2="facedir", + param2=0 + }) + + end + + end + --transform coords for each step from outer dimension toward midpoint + gmp = gmp -2 + gbpos1.z = gbpos1.z+1 + rfpos2.y = rfpos2.y+1 + end + + rfpos2 = vector.new({x = sfpos2.x+1, y=sfpos2.y, z=sfpos2.z+1})--reset rfpos2 for other side of roof + rfarea = vector.subtract(rfpos2,rfpos1) + + local rfamid = math.floor((rfarea.z+1)/2) + for i=rfarea.z+1,rfamid+1,-1 do + for j=1, rfarea.x+1 do + local pos = {x=rfpos1.x+j-1, y=rfpos2.y+1, z=rfpos1.z+i-1} + minetest.set_node(pos,{ + name=rfnodes, + paramtype2="facedir", + param2=2 + }) + end + + rfpos2.y=rfpos2.y+1 + + end + + if rfarea.z % 2 == 0 then + for j=1, rfarea.x+1 do + local pos = {x=rfpos1.x+j-1, y=rfpos2.y, z=rfpos1.z+(rfarea.z/2)} + minetest.set_node(pos,{ + name=rfslabs + }) + end + -- p is positional axis along which it is made + -- fp is the facing axis and direction inward + + local wpos1 = {x=rfpos1.x+1, y=rfpos2.y-2, z=rfpos1.z+(rfaz), p="z", fp={"x",1}} + table.insert(l_pos,wpos1) + local wpos2 = {x=rfpos1.x+rfarea.x-1, y=rfpos2.y-2, z=rfpos1.z+(rfaz), p="z", fp={"x",-1}} + table.insert(l_pos,wpos2) + minetest.bulk_set_node({wpos1,wpos2},{ + name=wp.window_nodes[1] + }) + else + local wpos1 = {x=rfpos1.x+1, y=rfpos2.y-2, z=rfpos1.z+(rfaz)+1, p="z", fp={"x",1}} + table.insert(l_pos,wpos1) + local wpos2 = {x=rfpos1.x+1, y=rfpos2.y-2, z=rfpos1.z+(rfaz), p="z", fp={"x",1}} + table.insert(l_pos,wpos2) + local wpos3 = {x=rfpos1.x+rfarea.x-1, y=rfpos2.y-2, z=rfpos1.z+(rfaz)+1, p="z", fp={"x",-1}} + table.insert(l_pos,wpos3) + local wpos4 = {x=rfpos1.x+rfarea.x-1, y=rfpos2.y-2, z=rfpos1.z+(rfaz), p="z", fp={"x",-1}} + table.insert(l_pos,wpos4) + minetest.bulk_set_node({wpos1,wpos2,wpos3,wpos4},{ + name=wp.window_nodes[1] + }) + end + + else -------------------------------------------- + + local gmp = rfarea.x-1 + + for j=1, (rfarea.x+1)/2 do + for i=1, rfarea.z+1 do + + local pos = {x=rfpos1.x+j-1, y=rfpos2.y+1, z=rfpos1.z+i-1} + minetest.set_node(pos,{ + name=rfnodes, + paramtype2="facedir", + param2=1 + }) + end + + for g=1, gmp do + + local gpos = {x=gbpos1.x+gmp-g, y=rfpos2.y+2, z=gbpos1.z} + local gpos2 = {x=gbpos1.x+gmp-g, y=rfpos2.y+2, z=gbpos1.z+gbarea.z} + minetest.bulk_set_node({gpos,gpos2},{ + name=gbnodes, + paramtype2="facedir", + param2=0 + }) + + end + gmp = gmp -2 + gbpos1.x = gbpos1.x+1 + rfpos2.y=rfpos2.y+1 + end + + + rfpos2 = vector.new({x = sfpos2.x+1, y=sfpos2.y, z=sfpos2.z+1})--reset rfpos2 for other side of roof + rfarea = vector.subtract(rfpos2,rfpos1) + + local rfamid = math.floor((rfarea.x+1)/2) + for j=rfarea.x+1, rfamid+1,-1 do + for i=1,rfarea.z+1 do + local pos = {x=rfpos1.x+j-1, y=rfpos2.y+1, z=rfpos1.z+i-1} + minetest.set_node(pos,{ + name=rfnodes, + paramtype2="facedir", + param2=3 + }) + end + + rfpos2.y=rfpos2.y+1 + end + + if rfarea.x % 2 == 0 then + for i=1,rfarea.z+1 do + local pos = {x=rfpos1.x+(rfarea.x/2), y=rfpos2.y, z=rfpos1.z+i-1} + minetest.set_node(pos,{ + name=rfslabs + }) + end + local wpos1 = {x=rfpos1.x+(rfax), y=rfpos2.y-2, z=rfpos1.z+1, p="x", fp={"z",1}} + table.insert(l_pos,wpos1) + local wpos2 = {x=rfpos1.x+(rfax), y=rfpos2.y-2, z=rfpos1.z+rfarea.z-1, p="x", fp={"z",-1}} + table.insert(l_pos,wpos2) + minetest.bulk_set_node({wpos1,wpos2},{ + name=wp.window_nodes[1] + }) + else + local wpos1 = {x=rfpos1.x+(rfax), y=rfpos2.y-2, z=rfpos1.z+1, p="x", fp={"z",1}} + table.insert(l_pos,wpos1) + local wpos2 = {x=rfpos1.x+(rfax)+1, y=rfpos2.y-2, z=rfpos1.z+1, p="x", fp={"z",1}} + table.insert(l_pos,wpos2) + local wpos3 = {x=rfpos1.x+(rfax), y=rfpos2.y-2, z=rfpos1.z+rfarea.z-1, p="x", fp={"z",-1}} + table.insert(l_pos,wpos3) + local wpos4 = {x=rfpos1.x+(rfax)+1, y=rfpos2.y-2, z=rfpos1.z+rfarea.z-1, p="x", fp={"z",-1}} + table.insert(l_pos,wpos4) + minetest.bulk_set_node({wpos1,wpos2,wpos3,wpos4},{ + name=wp.window_nodes[1] + }) + end + + end + witches.debug("ladder l_pos: "..mts(l_pos)) + --extend the stovepipe + if furnace_pos and furnace_pos.x then + --print("furnace pos: "..mtpts(furnace_pos)) + local stovepipe = (rfpos2.y - furnace_pos.y) + 1 + --print(rfpos2.y.." "..furnace_pos.y.." "..stovepipe) + stovepipe_pos = vector.new(furnace_pos) + for i=1, stovepipe do + stovepipe_pos.y = stovepipe_pos.y + 1 + minetest.set_node(stovepipe_pos,{ + name="default:cobble" + }) + end + end + + --drop a ladder from the center of the gable, avoiding any doors or windows + witches.debug("door: ".. mts(door_pos)) + if door_pos and l_pos then + for _,d in pairs(door_pos) do + for k,l in pairs(l_pos) do + if l.x == d.x and l.z == d.z then + table.remove(l_pos,k) + end + end + end + end + + if window_pos and l_pos then + for v,_ in pairs(window_pos) do + for _,w in ipairs(window_pos[v]) do + for k,l in pairs(l_pos) do + witches.debug("possible window before check: ".. mtpts(w)) + witches.debug("possible ladder before check: ".. mtpts(l)) + if math.ceil(l.x) == w.x and math.ceil(l.z) == w.z then + witches.debug("removing".. mtpts(l_pos[k])) + table.remove(l_pos,k) + end + end + end + end + end + + witches.debug("possible ladder: ".. mts(l_pos)) + if l_pos and #l_pos >= 1 then + + local lpn = math.random(#l_pos) + local lpc = l_pos[lpn] + local ladder_length = lpc.y - 1 - ffpos1.y + local fpos = vector.new(lpc) + + fpos[ lpc.fp[1] ] = fpos[ lpc.fp[1] ] + lpc.fp[2] + + --print("ladder: "..mtpts(l_pos)) + --print("ladder f: "..mtpts(fpos)) + + local dir1=vector.direction(fpos,lpc) + local dir1_wm = minetest.dir_to_wallmounted(dir1) + witches.debug("ladder chosen: ".. mts(lpc)) + lpc[ lpc.fp[1] ] = lpc[ lpc.fp[1] ] + lpc.fp[2] + --l_pos.y = l_pos.y-1 + + for i=1, ladder_length do + lpc.y = lpc.y-1 + minetest.set_node(lpc,{ + name= "default:ladder_wood", + param2 = dir1_wm + }) + + + end + witches.debug("ladder: "..mtpts(lpc)) + else + local loftpos1 = {x= sfpos1.x+2, y = sfpos1.y+1, z=sfpos1.z+1} + local loftpos2 = {x= sfpos2.x-2, y = sfpos1.y+1, z=sfpos2.z-1} + local loftarea = vector.subtract(loftpos2,loftpos1) + witches.debug(dump(loftpos1)) + witches.debug(dump(loftpos2)) + witches.debug(dump(loftarea)) + for i=1, loftarea.z+1 do + for j=1, loftarea.x+1 do + local pos = {x= loftpos1.x-1 + j, y = loftpos1.y, z = loftpos1.z-1 + i} + witches.debug(mts(pos)) + minetest.set_node(pos, {name = "air"}) + end + end + + + end + + + + +--[[ + for i=1, sfarea.z+1 do + for j=1, sfarea.x+1 do + + local pos = {x=sfpos1.x+j-1, y=sfpos1.y+1, z=sfpos1.z+i-1} + minetest.set_node(pos,{ + name=wp.second_floor_nodes[math.random(#wp.second_floor_nodes)] + }) + + end + end + + for h=1, wp.wall_height-1 do + for i=1, #ucn do + local pos = {x=ucn[i].x, y=ucn[i].y+h+1+wp.wall_height,z=ucn[i].z} + minetest.set_node(pos,{name=wp.foundation_nodes[math.random(#wp.foundation_nodes)]}) + end + end +--]] + + local c_area1 = vector.new(ppos1) + local c_area2 =vector.new(ppos2) + if stovepipe_pos and stovepipe_pos.y then + c_area2.y = stovepipe_pos.y + + else + c_area2.y = c_area2.y + 12 + end + + local cottage_area = {c_area1,c_area2} + local cottage_va = VoxelArea:new{MinEdge = c_area1, MaxEdge = c_area2} + --print(mts(VoxelArea)) + return cottage_area +end + + +--- build the cottage in a defined area +local function place_cottage(cottage_id, pos1,pos2) + if not cottage_id then + return + end + +end \ No newline at end of file diff --git a/depends.txt b/depends.txt index becab14..43784d1 100644 --- a/depends.txt +++ b/depends.txt @@ -1,6 +1,6 @@ default mobs -handle_schematics? +protector? fireflies? mobs_monster? doors? diff --git a/init.lua b/init.lua index a073d9f..d0c8e7e 100644 --- a/init.lua +++ b/init.lua @@ -5,7 +5,7 @@ local path = minetest.get_modpath("witches") witches = {} -witches.version = "20200806" +witches.version = "20220214" print("This is Witches "..witches.version.."!") -- Strips any kind of escape codes (translation, colors) from a string @@ -41,12 +41,20 @@ local function print_s(input) end local S = minetest.get_translator("witches") +local settings = minetest.settings + +function witches.debug(input) + local witches_debug = settings:get_bool("witches_debug") + if witches_debug then + print_s(input) + end +end local witches_version = witches.version if mobs.version then if tonumber(mobs.version) >= tonumber(20200516) then - print_s(S("Mobs Redo 20200516 or greater found!")) + print_s(S("Mobs Redo 20200516 or greater found! ("..mobs.version..")")) else print_s(S("You should find a more recent version of Mobs Redo!")) print_s(S("https://notabug.org/TenPlus1/mobs_redo")) @@ -81,15 +89,9 @@ end dofile(path .. "/magic.lua") -if not minetest.get_modpath("handle_schematics") then - print("optional handle_schematics not found!\n Witch cottages not available!") - --dofile(path .. "/cottages.lua") +dofile(path .. "/cottages.lua") +witches.cottages = true -else - - dofile(path .. "/basic_houses.lua") - print("handle_schematics found! Witch cottages enabled!") -end dofile(path .. "/witches.lua") @@ -111,7 +113,7 @@ function witches.generate(witch_types,witch_template) g_template[x] = g_type[x] end - print_s("Registering the "..g_template.description..": witches:witch_"..k) + witches.debug("Registering the "..g_template.description..": witches:witch_"..k) if g_template.lore then print_s(" "..g_template.lore) end --print_s("resulting template: " ..dump(g_template)) mobs:register_mob("witches:witch_"..k, g_template) diff --git a/items.lua b/items.lua index 10c8e33..64a3600 100644 --- a/items.lua +++ b/items.lua @@ -54,7 +54,7 @@ minetest.register_entity("witches:witch_tool_wand_sp",witch_tool_wand_sp) minetest.register_tool("witches:witch_wand_btb", { - description = "Better Thank Bacon!", + description = "Better Than Bacon!", inventory_image = "witches_wand_better_than_bacon.png", tool_capabilities = { full_punch_interval = 1.2, diff --git a/mod.conf b/mod.conf index e1ca887..b889961 100644 --- a/mod.conf +++ b/mod.conf @@ -1,4 +1,6 @@ name = witches -descriptions = adds witches +descriptions = adds witches and their cottages depends = default, mobs -optional_depends = handle_schematics, animalia, mobs_animal + +optional_depends = protector, animalia, mobs_animal + diff --git a/nodes.lua b/nodes.lua index 53e0086..682f575 100644 --- a/nodes.lua +++ b/nodes.lua @@ -132,4 +132,61 @@ function witches.flower_patch(pos) end -end \ No newline at end of file +end + +minetest.register_node("witches:treeroots", { + description = S("tree roots"), + drawtype = "liquid", + tiles = {{backface_culling = false, name= "default_tree.png"},{backface_culling = false, name= "default_tree.png"}}, + --alpha = 220, + paramtype = "light", + walkable = true, + pointable = true, + diggable = true, + buildable_to = true, + is_ground_content = false, + drop = "", + drowning = 0, + liquidtype = "source", + liquid_alternative_flowing = "witches:treeroots_growing", + liquid_alternative_source = "witches:treeroots", + liquid_viscosity = 9, + -- Not renewable to avoid horizontal spread of water sources in sloping + -- rivers that can cause water to overflow riverbanks and cause floods. + -- River water source is instead made renewable by the 'force renew' + -- option used in the 'bucket' mod by the river water bucket. + liquid_renewable = false, + liquid_range = 1, + post_effect_color = {a = 200, r = 5, g = 5, b = 0}, + groups = {liquid = 3, cools_lava = 1, tree = 1, choppy = 2, oddly_breakable_by_hand = 1, flammable = 2}, + --sounds = default.node_sound_water_defaults(), +}) + +minetest.register_node("witches:treeroots_growing", { + description = S("Tree Roots"), + drawtype = "flowingliquid", + tiles = {{backface_culling = false, name= "default_tree.png"}}, + + special_tiles = {{backface_culling = false, name= "default_tree.png"},{backface_culling = false, name= "default_tree.png"}}, + --alpha = 220, + paramtype = "light", + paramtype2 = "flowingliquid", + walkable = true, + pointable = false, + diggable = true, + buildable_to = true, + is_ground_content = false, + drop = "", + drowning = 0, + liquidtype = "flowing", + liquid_alternative_flowing = "witches:treeroots_growing", + liquid_alternative_source = "witches:treeroots", + liquid_viscosity = 9, + liquid_renewable = false, + liquid_range = 1, + post_effect_color = {a = 200, r = 5, g = 5, b = 0}, + groups = { liquid = 3, not_in_creative_inventory = 1, + cools_lava = 1,tree = 1, choppy = 2, oddly_breakable_by_hand = 1, flammable = 2}, + --sounds = default.node_sound_water_defaults(), + +}) diff --git a/settingtypes.txt b/settingtypes.txt index fbce870..0a75d8a 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -1,4 +1,7 @@ +# debug mode +witches_debug (enable debug) bool false + #maximum number of houses per mapchunk witches_house_max_per_mapchunk (maximum number of houses per mapchunk) int 2 @@ -6,11 +9,12 @@ witches_house_max_per_mapchunk (maximum number of houses per mapchunk) int 2 witches_houses_wanted_per_mapchunk (average number of houses to mapchunks over the world) float .05 -# chance (1-99) of a witch house spawning over a dungeon instead of anywhere else (requires Sokomines handle_schematics mod!) +# chance (1-99) of a witch house spawning over a dungeon instead of anywhere else witches_dungeon_cellar_chance (chance as decimal like .5 of a witch house spawning over a dungeon instead of anywhere else) float .5 -# depth (1-20) maximum depth of a dungeon to spawn a witch house over (requires Sokomines handle_schematics mod!) +# depth (1-20) maximum depth of a dungeon to spawn a witch house over witches_dungeon_cellar_depth (maximum depth 0 to -20 of a dungeon to spawn a witch house over) int -5 + diff --git a/ui.lua b/ui.lua index cb50127..8197038 100644 --- a/ui.lua +++ b/ui.lua @@ -10,13 +10,14 @@ witches.find_item_quest = {} witches.found_item_quest = {} --local item_request = witches.generate_name(witches.quest_dialogs, {"item_request"}) + function witches.find_item_quest.get_formspec(self,name) -- retrieve the thing --local quest_item = witches.looking_for(self) local text = "" if self.item_request.text and type(self.item_request.text) == "table" then local intro = self.item_request.text.intro - local request = self.item_request.text.request + local request = "\n"..self.item_request.text.request text = S("@1 @2",intro,request) --print(text) diff --git a/utilities.lua b/utilities.lua index b9d70f4..5b05e6d 100644 --- a/utilities.lua +++ b/utilities.lua @@ -11,45 +11,60 @@ witches.name_parts_male = { syllablesStart = "Aer, Al, Am, An, Ar, Arm, Arth, B, Bal, Bar, Be, Bel, Ber, Bok, Bor, Bran, Breg, Bren, Brod, Cam, Chal, Cham, Ch, Cuth, Dag, Daim, Dair, Del, Dr, Dur, Duv, Ear, Elen, Er, Erel, Erem, Fal, Ful, Gal, G, Get, Gil, Gor, Grin, Gun, H, Hal, Han, Har, Hath, Hett, Hur, Iss, Khel, K, Kor, Lel, Lor, M, Mal, Man, Mard, N, Ol, Radh, Rag, Relg, Rh, Run, Sam, Tarr, T, Tor, Tul, Tur, Ul, Ulf, Unr, Ur, Urth, Yar, Z, Zan, Zer", syllablesMiddle = "de, do, dra, du, duna, ga, go, hara, kaltho, la, latha, le, ma, nari, ra, re, rego, ro, rodda, romi, rui, sa, to, ya, zila", syllablesEnd = "bar, bers, blek, chak, chik, dan, dar, das, dig, dil, din, dir, dor, dur, fang, fast, gar, gas, gen, gorn, grim, gund, had, hek, hell, hir, hor, kan, kath, khad, kor, lach, lar, ldil, ldir, leg, len, lin, mas, mnir, ndil, ndur, neg, nik, ntir, rab, rach, rain, rak, ran, rand, rath, rek, rig, rim, rin, rion, sin, sta, stir, sus, tar, thad, thel, tir, von, vor, yon, zor", + syllablesTown = "mar, ton, veil, Loch, del, Pass, Hillock, shire, nia, ing", } witches.name_parts_female = { syllablesStart = "Ad, Aer, Ar, Bel, Bet, Beth, Ce'N, Cyr, Eilin, El, Em, Emel, G, Gl, Glor, Is, Isl, Iv, Lay, Lis, May, Ner, Pol, Por, Sal, Sil, Vel, Vor, X, Xan, Xer, Yv, Zub", syllablesMiddle = "bre, da, dhe, ga, lda, le, lra, mi, ra, ri, ria, re, se, ya", syllablesEnd = "ba, beth, da, kira, laith, lle, ma, mina, mira, na, nn, nne, nor, ra, rin, ssra, ta, th, tha, thra, tira, tta, vea, vena, we, wen, wyn", + syllablesTown = "maer, tine, veila, Loch, dael, Pass, Hillock, shire, mia, aeng", } witches.words_desc = { - tool_adj = S("shiny, polished, favorite, beloved, cherished, sharpened"), + tool_adj = S("shiny, polished, favorite, beloved, cherished, sharpened, enhanced"), titles = S("artificer, librarian, logician, sorcerant, thaumaturgist, polymorphist, elementalist, hedge, herbologist, arcanologist, tutor, historian, mendicant, restorationist"), } local function quest_dialogs(self) + local thing = self.item_request.item.desc + local thing_l = string.lower(self.item_request.item.desc) local dialogs = { intro = { S("Hello, @1, I am @2, @3 of @4! ", self.speaking_to,self.secret_name,self.secret_title,self.secret_locale), S("Just one minute, @1! @2, @3 of @4 seeks your assistance! ", self.speaking_to,self.secret_name,self.secret_title,self.secret_locale), S("If you are indeed @1, perhaps you and I, @2, @3 of @4 can help each other! ", self.speaking_to,self.secret_name,self.secret_title,self.secret_locale), + S("Being a long way from @1, can be confusing. I'm known as @2 the @3! ", self.secret_locale,self.secret_name,self.secret_title), + S("You look as though you could be from @1, but I'm sure we have not yet met. I am @2 the @3! ", self.secret_locale,self.secret_name,self.secret_title), + }, + having_met = { + S("Well, @1, I have yet to return to @2. Can you help me? ", self.speaking_to,self.secret_locale), + S("@1, do you have any intention of helping me? ", self.speaking_to), + S("There are some matters that still need my attention, @1. ", self.speaking_to), + S("I have been so busy in my search for materials, @1. ", self.speaking_to), + S("It's just that the @1 is so difficult to procure, @2! ", thing_l, self.speaking_to), + S("Great @1!, Where could that be found, @2?!? ", thing_l, self.speaking_to) }, item_request = { - S("I've been looking all over for the @1! ",self.item_request.item.desc), - S("I seem to have misplaced the @1! ",self.item_request.item.desc), - S("Would you happen to have some number of @1? ",self.item_request.item.desc), - S("Would you kindly retrieve for me the @1? ",self.item_request.item.desc), - S("Might you please return with the @1? ",self.item_request.item.desc), - S("Do you know I seek only the @1? ",self.item_request.item.desc), - S("Have you but some number of @1? ",self.item_request.item.desc), - S("Why must my task require the @1? ",self.item_request.item.desc), - S("Is it so difficult to find the @1? ",self.item_request.item.desc), - S("Wherefor about this land art the @1? ",self.item_request.item.desc), - S("Must there be but a few of the @1 about? ",self.item_request.item.desc), - S("Could I trouble you for some kind of @1? ",self.item_request.item.desc), - S("The @1 would make my collection complete! ",self.item_request.item.desc), - S("I sense the @1 are not far away...",self.item_request.item.desc), - S("Certainly the @1 is not as rare as a blood moon! ",self.item_request.item.desc), - S("You look like you know where to find the @1! ",self.item_request.item.desc) + S("A @1, just one will do! ", thing_l), + S("I've been looking all over for the @1! ",thing_l), + S("I seem to have misplaced the @1! ",thing_l), + S("Would you happen to have some number of @1? ",thing_l), + S("Would you kindly retrieve for me the @1? ",thing_l), + S("Might you please return with the @1? ",thing_l), + S("Do you know I seek only the @1? ",thing_l), + S("Have you but some number of @1? ",thing_l), + S("Why must my task require the @1? ",thing_l), + S("Is it so difficult to find the @1? ",thing_l), + S("Wherefor about this land art the @1? ",thing_l), + S("Must not there be but a few of the @1 about? ",thing_l), + S("Could I trouble you for some kind of @1? ",thing_l), + S("The @1 would make my collection complete! ",thing_l), + S("I sense the @1 are not far away...",thing_l), + S("Certainly the @1 is not as rare as a blood moon! ",thing_l), + S("You look like you know where to find the @1! ",thing_l) } } --print(dump(dialogs)) @@ -234,11 +249,11 @@ end function witches.gift(self, pname, drop_chance_min, drop_chance_max, item_wear ) if not pname then - print("no player defined!") + witches.debug("no player defined!") return end if not self.drops then - print("no droplist defined in this mob!") + witches.debug("no droplist defined in this mob!") return end local list = {} @@ -355,7 +370,7 @@ function witches.claim_witches_chest(self) -- if sn then print(sn) end local o = meta:get_string("owner") if o and sn and sn == o then - print("unbound chest: "..sn) + witches.debug("unbound chest: "..sn) meta:set_string("owner", self.secret_name) meta:set_string("infotext", self.secret_name.."'s sealed chest of ".. sn) @@ -400,8 +415,29 @@ function witches.item_request(self,name) --we need text for the quest! -- print("generating") local dialog_list = quest_dialogs(self) - local dli_num = math.random(1,#dialog_list.intro) - local intro_text = dialog_list.intro[dli_num] + if not self.players then self.players = {} end + if not self.players[name] then + self.players[name] = {} + --if not self.players.met or #self.players.met < 1 or type(self.players.met) == string then + + --table.insert(self.players_met, self.secret_name) + end + local intro_text = "" + + if not self.players[name].met then + --print(dump(self.players[name])) + --print( "We don't know "..name.."!") + local dli_num = math.random(1,#dialog_list.intro) + intro_text = dialog_list.intro[dli_num] + + self.players[name] = {met = math.floor(os.time())} + + else + --print(dump(self.players.met)) + --print( "We first met "..name.." ".. os.time() - self.players[name].met.." seconds ago") + local dli_num = math.random(1,#dialog_list.having_met) + intro_text = dialog_list.having_met[dli_num] + end --print(intro_text) local quest_item = self.item_request.item.desc @@ -523,7 +559,7 @@ function witches.quests(self, clicker) if var1 == var2 then self.dev_mode = pname - print("dev mode active for: "..pname) + witches.debug("dev mode active for: "..pname) end --print("we are holding a "..dump(item:get_name())) diff --git a/witches.lua b/witches.lua index 79c83a8..a362498 100644 --- a/witches.lua +++ b/witches.lua @@ -17,7 +17,7 @@ local spawning = { day_toggle = nil, on_spawn = function(self) local pos = self.object:get_pos() - print(self.secret_name.." spawned at ".. minetest.pos_to_string(vector.round(pos))) + witches.debug(self.secret_name.." spawned at ".. minetest.pos_to_string(vector.round(pos))) end, }, @@ -34,7 +34,7 @@ local spawning = { day_toggle = nil, on_spawn = function(self) local pos = self.object:get_pos() - print(self.secret_name.." spawned at ".. minetest.pos_to_string(vector.round(pos))) + witches.debug(self.secret_name.." spawned at ".. minetest.pos_to_string(vector.round(pos))) end @@ -57,13 +57,14 @@ witches.witch_types = { local pos = self.object:get_pos() if pos then pos.y = pos.y+1 - local pos1 = minetest.find_node_near(pos, 3, "air") - if pos1 then + local pos1 = minetest.find_node_near(pos, 3, "air") + if pos1 then minetest.set_node(pos1, {name = "fireflies:firefly"}) --print("setting firefly"..minetest.pos_to_string(pos1)) end end end + end, on_spawn_addendum = function(self) @@ -82,6 +83,22 @@ witches.witch_types = { "default:blueberries", "default:torch", "default:stick", "flowers:mushroom_brown","flowers:mushroom_red"}, do_custom_addendum = function(self) + if witches.cottages then + if not self.built_house and math.random() < 0.01 then + + local volume = witches.grounding(self) + if volume then + witches.debug("volume passed: "..dump(volume)) + + local pos = self.object:get_pos() + pos.y = pos.y+3 + self.object:set_pos(pos) + self.built_house = pos + witches.generate_cottage(self.secret_name,volume[1],volume[2]) + + end + end + end end, on_spawn_addendum = function(self) witches.claim_witches_chest(self) @@ -90,6 +107,7 @@ witches.witch_types = { spawning = spawning.cottage, } } + witches.witch_template = { --your average witch, description = "Basic Witch", lore = "This witch has a story yet to be...", @@ -113,7 +131,7 @@ witches.witch_template = { --your average witch, "witches_clothes.png" }, --blood_texture = "witches_blood.png", - collisionbox = {-0.25, 0, -.25, 0.25, 2, 0.25}, + collisionbox = {-0.2, 0, -.2, 0.2, 1.9, 0.2}, drawtype = "front", makes_footstep_sound = true, sounds = { @@ -272,13 +290,17 @@ witches.witch_template = { --your average witch, self.secret_title = witches.generate_text(witches.words_desc, {"titles"}) end if not self.secret_locale then - self.secret_locale = witches.generate_text(witches.name_parts_female, {"syllablesStart","syllablesEnd"}) + if math.random(2) == 1 then + self.secret_locale = witches.generate_text(witches.name_parts_female, {"syllablesStart","syllablesEnd","syllablesTown"}) + else + self.secret_locale = witches.generate_text(witches.name_parts_male, {"syllablesStart","syllablesEnd","syllablesTown"}) + end end --self.item_request.text = witches.generate_name(witches.quest_dialogs, {"item_request"}) --print(self.secret_name.." has spawned") --print("self: "..dump(self.follow)) - -- print("self properties "..dump(self.object:get_properties())) + --print("self properties "..dump(self.object:get_properties())) --self.follow = {} if not self.follow or #self.follow < 1 or type(self.follow) == string then self.follow = {}