Witches have little houses!
parent
20f19f2a1f
commit
18e0082cdb
|
@ -0,0 +1,923 @@
|
|||
--Adapted from Sokomine's basic_houses mod under GPLv3 requires
|
||||
--Sokomine's handle_schematics mod (also GPLv3)
|
||||
|
||||
-- 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
|
||||
|
||||
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 = 2;
|
||||
|
||||
-- how many houses shall be generated on average per mapchunk?
|
||||
witches.bh.houses_wanted_per_mapchunk = 0.1;
|
||||
|
||||
-- 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";
|
||||
-- floor at the entrance level of the house
|
||||
witches.bh.floor = "default:cobble";
|
||||
-- placed randomly in some houses
|
||||
witches.bh.chest = "default:chest";
|
||||
-- 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:tree","default:jungletree","default:acacia_tree","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"};
|
||||
|
||||
|
||||
-- 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
|
||||
|
||||
-- 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.color or materials.wall_orients[1+v])};
|
||||
local node_wall_2 = {name=materials.walls, param2 = (materials.color or 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 lauf<size ) then
|
||||
-- *one* of the walls may get a window - never both (would look odd to
|
||||
-- be able to see through the house)
|
||||
local not_special = ( (lauf ~= special_wall_1) and (lauf ~= special_wall_2));
|
||||
if( window_at_odd_row == (lauf%2==1)) then
|
||||
wall_1_has_window = (not_special and ( pr:next(1,2)~=2));
|
||||
else
|
||||
wall_2_has_window = (not_special and ( pr:next(1,2)~=2));
|
||||
end
|
||||
end
|
||||
-- actually build the wall from bottom to top
|
||||
for height = 1,wall_height do
|
||||
local node = nil;
|
||||
-- if there is a window in this wall...
|
||||
if( materials.window_at_height[ height ]==1 and wall_1_has_window) then
|
||||
node = node_glass_1;
|
||||
else
|
||||
node = node_wall_1;
|
||||
end
|
||||
vm:set_node_at( {x=w1_x, y=p.y+height, z=w1_z}, node);
|
||||
|
||||
-- ..or in the other wall
|
||||
if( materials.window_at_height[ height ]==1 and (wall_2_has_window)) then
|
||||
node = node_glass_2;
|
||||
else
|
||||
node = node_wall_2;
|
||||
end
|
||||
vm:set_node_at( {x=w2_x, y=p.y+height, z=w2_z}, node);
|
||||
end
|
||||
|
||||
if( in_x_direction ) then
|
||||
w1_x = w1_x + 1;
|
||||
w2_x = w1_x;
|
||||
else
|
||||
w1_z = w1_z + 1;
|
||||
w2_z = w1_z;
|
||||
end
|
||||
end
|
||||
return {special_wall_1, special_wall_2, window_at_odd_row};
|
||||
end
|
||||
|
||||
|
||||
-- roofs may extend in x or z direction
|
||||
local pswap = function( pos, swap )
|
||||
if( not( swap )) then
|
||||
return pos;
|
||||
else
|
||||
return {x=pos.z, y=pos.y, z=pos.x};
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- builds a roof with gable;
|
||||
-- takes the same parameters as witches.bh.build_two_walls (apart from the
|
||||
-- window_at_height parameter which is unnecessary here)
|
||||
witches.bh.build_roof_and_gable = function( p_orig, sizex, sizez, in_x_direction,
|
||||
materials, rotation_1, rotation_2, vm)
|
||||
|
||||
local p = {x=p_orig.x, y=p_orig.y, z=p_orig.z};
|
||||
local node_side_1 = {name=materials.roof, param2=rotation_1};
|
||||
local node_side_2 = {name=materials.roof, param2=rotation_2};
|
||||
local swap = false;
|
||||
local dy = p.y;
|
||||
|
||||
-- do the swapping
|
||||
if( not( in_x_direction )) then
|
||||
local help = sizex;
|
||||
sizex = sizez;
|
||||
sizez = help;
|
||||
p.x = p_orig.z;
|
||||
p.z = p_orig.x;
|
||||
swap = true;
|
||||
end
|
||||
|
||||
local node_slab = {name=materials.roof_middle};
|
||||
|
||||
local xhalf = math.floor( sizex/2 );
|
||||
for dx = 0,xhalf do
|
||||
for dz = p.z, p.z+sizez do
|
||||
-- normal saddle roof
|
||||
if( dy < p_orig.ymax ) then
|
||||
vm:set_node_at( pswap({x=p.x+ dx,y=dy,z=dz}, swap), node_side_1 );
|
||||
vm:set_node_at( pswap({x=p.x+sizex-dx,y=dy,z=dz}, swap), node_side_2 );
|
||||
-- flatten the top of the saddle roof
|
||||
else
|
||||
vm:set_node_at( pswap({x=p.x+ dx,y=p_orig.ymax,z=dz}, swap), node_slab );
|
||||
vm:set_node_at( pswap({x=p.x+sizex-dx,y=p_orig.ymax,z=dz}, swap), node_slab );
|
||||
end
|
||||
end
|
||||
dy = dy+1;
|
||||
end
|
||||
|
||||
-- if sizex is not even, then we need to use slabs at the heighest point
|
||||
if( sizex%2==0 ) then
|
||||
for dz = p.z, p.z+sizez do
|
||||
if( dy <= p_orig.ymax ) then
|
||||
vm:set_node_at( pswap({x=p.x+xhalf,y=p.y+xhalf,z=dz},swap), node_slab );
|
||||
else
|
||||
vm:set_node_at( pswap({x=p.x+xhalf,y=p_orig.ymax,z=dz},swap), node_slab );
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Dachgiebel (=gable)
|
||||
local node_gable = { name = materials.gable,
|
||||
param2 = (materials.color or 0 )}; -- color of the gable
|
||||
for dx = 0,xhalf do
|
||||
for dy = p.y, p.y-1+dx do
|
||||
if( dy < p_orig.ymax ) then
|
||||
vm:set_node_at( pswap({x=p.x+sizex-dx,y=dy,z=p.z+sizez-1}, swap), node_gable );
|
||||
vm:set_node_at( pswap({x=p.x+ dx,y=dy,z=p.z+sizez-1}, swap), node_gable );
|
||||
|
||||
vm:set_node_at( pswap({x=p.x+sizex-dx,y=dy,z=p.z +1}, swap), node_gable );
|
||||
vm:set_node_at( pswap({x=p.x+ dx,y=dy,z=p.z +1}, swap), node_gable );
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- four places have been reserved previously (=no window placed) and
|
||||
-- can be used for ladders, doors etc.
|
||||
witches.bh.get_random_place = function( p, sizex, sizez, places, use_this_one, already_used, offset, pr )
|
||||
local i = pr:next(1,4);
|
||||
if( i==already_used) then
|
||||
if( i>1) 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 )
|
||||
-- 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
|
||||
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, y=p.y+3, z=res.z}, {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))];
|
||||
-- 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};
|
||||
-- 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
|
||||
vm:set_node_at( pos, {name=witches.bh.chest, param2 = res.p2n});
|
||||
-- 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 meta = minetest.get_meta(pos);
|
||||
local inv = meta:get_inventory();
|
||||
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
|
||||
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
|
||||
local c = math.random( 1, #res.places_x + #res.places_z );
|
||||
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
|
||||
|
||||
local chunksize = maxp.x - minp.x + 1;
|
||||
-- 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};
|
||||
return {p1={x=p.x - sizex, y=p.y, z=p.z - sizez }, p2=p, sizex=sizex, sizez=sizez};
|
||||
end
|
||||
|
||||
|
||||
-- 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};
|
||||
elseif( r==3 or r==4 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,3);
|
||||
-- wooden house
|
||||
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
|
||||
elseif( r==2 ) then
|
||||
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 lauf<size ) then
|
||||
-- *one* of the walls may get a window - never both (would look odd to
|
||||
-- be able to see through the house)
|
||||
local not_special = ( (lauf ~= special_wall_1) and (lauf ~= special_wall_2));
|
||||
if( window_at_odd_row == (lauf%2==1)) then
|
||||
wall_1_has_window = (not_special and ( pr:next(1,3)~=3));
|
||||
else
|
||||
wall_2_has_window = (not_special and ( pr:next(1,3)~=3));
|
||||
end
|
||||
end
|
||||
end
|
||||
--]]
|
||||
-- aliases would have no content_id for placement
|
||||
for k, v in pairs(data.materials) do
|
||||
if(v and type(v)=="string") then
|
||||
if(minetest.registered_aliases[v]) then
|
||||
data.materials[k] = minetest.registered_aliases[v]
|
||||
end
|
||||
-- avoid crashes - even if that requires placing air
|
||||
if(not(minetest.registered_nodes[data.materials[k]])) then
|
||||
data.materials[k] = "air"
|
||||
end
|
||||
end
|
||||
end
|
||||
return data;
|
||||
end
|
||||
|
||||
|
||||
-- actually build the "hut"
|
||||
-- parameter:
|
||||
-- data.p2 end point
|
||||
-- data.sizex, data.sizez size in x and z direction
|
||||
-- materials.window_at_height table containing window positions (vertically)
|
||||
-- materials.walls node type of the walls
|
||||
-- materials.color 0-255; color of the walls (if materials.walls uses hardware coloring)
|
||||
-- materials.first_floor node type for the bottommost floor
|
||||
-- materials.ceiling node type for the floors/ceilings
|
||||
-- materials.around_house node type for one node wide path around the house
|
||||
-- materials.floors how many floors does the house have?
|
||||
-- materials.flat_roof if true: add a flat roof; else saddle roof
|
||||
-- pr PseudoRandom number generator for reproducability
|
||||
witches.bh.simple_hut_place_hut_using_vm = function( data, materials, vm, pr )
|
||||
local p = data.p2;
|
||||
local sizex = data.sizex-1;
|
||||
local sizez = data.sizez-1;
|
||||
-- house too small or too large
|
||||
if( sizex < 2 or sizez < 2 or sizex>64 or sizez>64) then
|
||||
return nil;
|
||||
end
|
||||
|
||||
-- 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 );
|
||||
|
||||
-- each floor is 4 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
|
||||
|
||||
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
|
||||
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 );
|
||||
-- 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
|
||||
local max_trees = 2
|
||||
for dz = p.z-sizez+1, p.z-1 do
|
||||
-- path around the house
|
||||
if math.random(1,100) and max_trees >= 1 then
|
||||
|
||||
local tree_pos = {x=p.x-(sizex+20), y=p.y, z=dz}
|
||||
--default.grow_new_apple_tree
|
||||
if math.random() < .5 then
|
||||
minetest.spawn_tree(tree_pos,witches.acacia_tree)
|
||||
else
|
||||
minetest.spawn_tree(tree_pos,witches.apple_tree)
|
||||
end
|
||||
print("growing tree at "..minetest.pos_to_string(vector.round(tree_pos)))
|
||||
max_trees = max_trees - 1
|
||||
end
|
||||
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 );
|
||||
-- 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 );
|
||||
|
||||
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 );
|
||||
|
||||
-- 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);
|
||||
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;
|
||||
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,
|
||||
} );
|
|
@ -1,3 +1,3 @@
|
|||
default
|
||||
mobs
|
||||
|
||||
handle_schematics?
|
||||
|
|
28
init.lua
28
init.lua
|
@ -5,7 +5,7 @@
|
|||
local path = minetest.get_modpath("witches")
|
||||
witches = {}
|
||||
|
||||
witches.version = "20200719"
|
||||
witches.version = "20200720"
|
||||
print("this is Witches "..witches.version)
|
||||
|
||||
-- Strips any kind of escape codes (translation, colors) from a string
|
||||
|
@ -59,8 +59,21 @@ end
|
|||
dofile(path .. "/utilities.lua")
|
||||
dofile(path .. "/ui.lua")
|
||||
dofile(path .. "/items.lua")
|
||||
dofile(path .. "/nodes.lua")
|
||||
|
||||
if not handle_schematics then
|
||||
return
|
||||
else
|
||||
|
||||
dofile(path .. "/basic_houses.lua")
|
||||
print("handle_schematics found! Witch houses enabled!")
|
||||
end
|
||||
print("enter the witches! version: "..witches.version)
|
||||
|
||||
print(minetest.colorize("red","sometext"))
|
||||
|
||||
print("crgbtest: " ..colorsRGB.RGB("red"))
|
||||
|
||||
local variance = witches.variance
|
||||
local rnd_color = witches.rnd_color
|
||||
local rnd_colors = witches.rnd_colors
|
||||
|
@ -68,17 +81,20 @@ local hair_colors = witches.hair_colors
|
|||
|
||||
local spawning = {
|
||||
generic = {
|
||||
nodes = {"group:stone"},
|
||||
neighbors = "air",
|
||||
min_light = 0,
|
||||
nodes = {"group:wood","default:mossycobble","default:cobble"},
|
||||
neighbors = {"air","default:chest","doors:wood_witch_a"},
|
||||
min_light = 5,
|
||||
max_light = 15,
|
||||
interval = 30,
|
||||
chance = 1000,
|
||||
chance = 10,
|
||||
active_object_count = 2,
|
||||
min_height = 0,
|
||||
max_height = 200,
|
||||
day_toggle = nil,
|
||||
on_spawn = nil,
|
||||
on_spawn = function(self)
|
||||
local pos = self.object:get_pos()
|
||||
print(self.secret_name.." spawned at ".. minetest.pos_to_string(vector.round(pos)))
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
2
mod.conf
2
mod.conf
|
@ -1,4 +1,4 @@
|
|||
name = witches
|
||||
descriptions = adds witches
|
||||
depends = default, mobs
|
||||
optional_depends = none
|
||||
optional_depends = handle_schematics
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
local S = minetest.get_translator("witches")
|
||||
if not doors then
|
||||
print("doors mod not found!")
|
||||
return
|
||||
else
|
||||
print("doors active")
|
||||
doors.register("door_wood_witch", {
|
||||
tiles = {{ name = "doors_door_wood.png", backface_culling = true }},
|
||||
description = S("Wooden Door"),
|
||||
inventory_image = "doors_item_wood.png",
|
||||
groups = {node = 1, choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
|
||||
--[[
|
||||
recipe = {
|
||||
{"group:wood", "group:wood"},
|
||||
{"group:wood", "group:wood"},
|
||||
{"group:wood", "group:wood"},
|
||||
}
|
||||
--]]
|
||||
})
|
||||
end
|
||||
|
||||
witches.acacia_tree={
|
||||
axiom="FFFFFFccccA",
|
||||
rules_a = "[B]//[B]//[B]//[B]",
|
||||
rules_b = "&TTTT&TT^^G&&----GGGGGG++GGG++" -- line up with the "canvas" edge
|
||||
.."fffffRfGG++G++" -- first layer, drawn in a zig-zag raster pattern
|
||||
.."Gffffffff--G--"
|
||||
.."ffffRfffG++G++"
|
||||
.."fffffffff--G--"
|
||||
.."fffffffff++G++"
|
||||
.."ffRffffff--G--"
|
||||
.."ffffffffG++G++"
|
||||
.."GffffRfff--G--"
|
||||
.."fffffffGG"
|
||||
.."^^G&&----GGGGGGG++GGGGGG++" -- re-align to second layer canvas edge
|
||||
.."ffffGGG++G++" -- second layer
|
||||
.."GGfffff--G--"
|
||||
.."ffRfffG++G++"
|
||||
.."fffffff--G--"
|
||||
.."ffffRfG++G++"
|
||||
.."GGfffff--G--"
|
||||
.."ffRfGGG",
|
||||
rules_c = "/",
|
||||
trunk="default:tree",
|
||||
leaves="default:leaves",
|
||||
angle=45,
|
||||
iterations=3,
|
||||
random_level=0,
|
||||
trunk_type="single",
|
||||
thin_branches=true,
|
||||
fruit_chance=5,
|
||||
fruit="default:apple"
|
||||
}
|
||||
|
||||
witches.apple_tree={
|
||||
axiom="FFFFFAFFBF",
|
||||
rules_a="[&&&FFFFF&&FFFF][&&&++++FFFFF&&FFFF][&&&----FFFFF&&FFFF]",
|
||||
rules_b="[&&&++FFFFF&&FFFF][&&&--FFFFF&&FFFF][&&&------FFFFF&&FFFF]",
|
||||
trunk="default:tree",
|
||||
leaves="default:leaves",
|
||||
angle=30,
|
||||
iterations=2,
|
||||
random_level=1,
|
||||
trunk_type="single",
|
||||
thin_branches=true,
|
||||
fruit_chance=5,
|
||||
fruit="default:apple"
|
||||
}
|
179
utilities.lua
179
utilities.lua
|
@ -393,9 +393,180 @@ end
|
|||
|
||||
|
||||
|
||||
--- Our mobs, territories, etc can have randomly generated names.
|
||||
-- @name_parts is the name parts table: {list_a = "foo bar baz"}
|
||||
-- @rules are the list table key names in order of how they will be chosen
|
||||
-- "-" and "\'" are rules that can be used to add a hyphen or apostrophe respectively
|
||||
|
||||
|
||||
-- modified from https://snipplr.com/view/40782/color-to-rgb-value-table-in-lua
|
||||
-- so that it won't crash on undefined name (just returns the name in that case)
|
||||
-- FreeLikeGNU
|
||||
|
||||
colorsRGB = {
|
||||
aliceblue = {240, 248, 255},
|
||||
antiquewhite = {250, 235, 215},
|
||||
aqua = { 0, 255, 255},
|
||||
aquamarine = {127, 255, 212},
|
||||
azure = {240, 255, 255},
|
||||
beige = {245, 245, 220},
|
||||
bisque = {255, 228, 196},
|
||||
black = { 0, 0, 0},
|
||||
blanchedalmond = {255, 235, 205},
|
||||
blue = { 0, 0, 255},
|
||||
blueviolet = {138, 43, 226},
|
||||
brown = {165, 42, 42},
|
||||
burlywood = {222, 184, 135},
|
||||
cadetblue = { 95, 158, 160},
|
||||
chartreuse = {127, 255, 0},
|
||||
chocolate = {210, 105, 30},
|
||||
coral = {255, 127, 80},
|
||||
cornflowerblue = {100, 149, 237},
|
||||
cornsilk = {255, 248, 220},
|
||||
crimson = {220, 20, 60},
|
||||
cyan = { 0, 255, 255},
|
||||
darkblue = { 0, 0, 139},
|
||||
darkcyan = { 0, 139, 139},
|
||||
darkgoldenrod = {184, 134, 11},
|
||||
darkgray = {169, 169, 169},
|
||||
darkgreen = { 0, 100, 0},
|
||||
darkgrey = {169, 169, 169},
|
||||
darkkhaki = {189, 183, 107},
|
||||
darkmagenta = {139, 0, 139},
|
||||
darkolivegreen = { 85, 107, 47},
|
||||
darkorange = {255, 140, 0},
|
||||
darkorchid = {153, 50, 204},
|
||||
darkred = {139, 0, 0},
|
||||
darksalmon = {233, 150, 122},
|
||||
darkseagreen = {143, 188, 143},
|
||||
darkslateblue = { 72, 61, 139},
|
||||
darkslategray = { 47, 79, 79},
|
||||
darkslategrey = { 47, 79, 79},
|
||||
darkturquoise = { 0, 206, 209},
|
||||
darkviolet = {148, 0, 211},
|
||||
deeppink = {255, 20, 147},
|
||||
deepskyblue = { 0, 191, 255},
|
||||
dimgray = {105, 105, 105},
|
||||
dimgrey = {105, 105, 105},
|
||||
dodgerblue = { 30, 144, 255},
|
||||
firebrick = {178, 34, 34},
|
||||
floralwhite = {255, 250, 240},
|
||||
forestgreen = { 34, 139, 34},
|
||||
fuchsia = {255, 0, 255},
|
||||
gainsboro = {220, 220, 220},
|
||||
ghostwhite = {248, 248, 255},
|
||||
gold = {255, 215, 0},
|
||||
goldenrod = {218, 165, 32},
|
||||
gray = {128, 128, 128},
|
||||
grey = {128, 128, 128},
|
||||
green = { 0, 128, 0},
|
||||
greenyellow = {173, 255, 47},
|
||||
honeydew = {240, 255, 240},
|
||||
hotpink = {255, 105, 180},
|
||||
indianred = {205, 92, 92},
|
||||
indigo = { 75, 0, 130},
|
||||
ivory = {255, 255, 240},
|
||||
khaki = {240, 230, 140},
|
||||
lavender = {230, 230, 250},
|
||||
lavenderblush = {255, 240, 245},
|
||||
lawngreen = {124, 252, 0},
|
||||
lemonchiffon = {255, 250, 205},
|
||||
lightblue = {173, 216, 230},
|
||||
lightcoral = {240, 128, 128},
|
||||
lightcyan = {224, 255, 255},
|
||||
lightgoldenrodyellow = {250, 250, 210},
|
||||
lightgray = {211, 211, 211},
|
||||
lightgreen = {144, 238, 144},
|
||||
lightgrey = {211, 211, 211},
|
||||
lightpink = {255, 182, 193},
|
||||
lightsalmon = {255, 160, 122},
|
||||
lightseagreen = { 32, 178, 170},
|
||||
lightskyblue = {135, 206, 250},
|
||||
lightslategray = {119, 136, 153},
|
||||
lightslategrey = {119, 136, 153},
|
||||
lightsteelblue = {176, 196, 222},
|
||||
lightyellow = {255, 255, 224},
|
||||
lime = { 0, 255, 0},
|
||||
limegreen = { 50, 205, 50},
|
||||
linen = {250, 240, 230},
|
||||
magenta = {255, 0, 255},
|
||||
maroon = {128, 0, 0},
|
||||
mediumaquamarine = {102, 205, 170},
|
||||
mediumblue = { 0, 0, 205},
|
||||
mediumorchid = {186, 85, 211},
|
||||
mediumpurple = {147, 112, 219},
|
||||
mediumseagreen = { 60, 179, 113},
|
||||
mediumslateblue = {123, 104, 238},
|
||||
mediumspringgreen = { 0, 250, 154},
|
||||
mediumturquoise = { 72, 209, 204},
|
||||
mediumvioletred = {199, 21, 133},
|
||||
midnightblue = { 25, 25, 112},
|
||||
mintcream = {245, 255, 250},
|
||||
mistyrose = {255, 228, 225},
|
||||
moccasin = {255, 228, 181},
|
||||
navajowhite = {255, 222, 173},
|
||||
navy = { 0, 0, 128},
|
||||
oldlace = {253, 245, 230},
|
||||
olive = {128, 128, 0},
|
||||
olivedrab = {107, 142, 35},
|
||||
orange = {255, 165, 0},
|
||||
orangered = {255, 69, 0},
|
||||
orchid = {218, 112, 214},
|
||||
palegoldenrod = {238, 232, 170},
|
||||
palegreen = {152, 251, 152},
|
||||
paleturquoise = {175, 238, 238},
|
||||
palevioletred = {219, 112, 147},
|
||||
papayawhip = {255, 239, 213},
|
||||
peachpuff = {255, 218, 185},
|
||||
peru = {205, 133, 63},
|
||||
pink = {255, 192, 203},
|
||||
plum = {221, 160, 221},
|
||||
powderblue = {176, 224, 230},
|
||||
purple = {128, 0, 128},
|
||||
red = {255, 0, 0},
|
||||
rosybrown = {188, 143, 143},
|
||||
royalblue = { 65, 105, 225},
|
||||
saddlebrown = {139, 69, 19},
|
||||
salmon = {250, 128, 114},
|
||||
sandybrown = {244, 164, 96},
|
||||
seagreen = { 46, 139, 87},
|
||||
seashell = {255, 245, 238},
|
||||
sienna = {160, 82, 45},
|
||||
silver = {192, 192, 192},
|
||||
skyblue = {135, 206, 235},
|
||||
slateblue = {106, 90, 205},
|
||||
slategray = {112, 128, 144},
|
||||
slategrey = {112, 128, 144},
|
||||
snow = {255, 250, 250},
|
||||
springgreen = { 0, 255, 127},
|
||||
steelblue = { 70, 130, 180},
|
||||
tan = {210, 180, 140},
|
||||
teal = { 0, 128, 128},
|
||||
thistle = {216, 191, 216},
|
||||
tomato = {255, 99, 71},
|
||||
turquoise = { 64, 224, 208},
|
||||
violet = {238, 130, 238},
|
||||
wheat = {245, 222, 179},
|
||||
white = {255, 255, 255},
|
||||
whitesmoke = {245, 245, 245},
|
||||
yellow = {255, 255, 0},
|
||||
yellowgreen = {154, 205, 50}
|
||||
}
|
||||
|
||||
colorsRGB.R = function (name)
|
||||
return colorsRGB[name][1]
|
||||
end
|
||||
|
||||
colorsRGB.G = function (name)
|
||||
return colorsRGB[name][2]
|
||||
end
|
||||
|
||||
colorsRGB.B = function (name)
|
||||
return colorsRGB[name][3]
|
||||
end
|
||||
|
||||
colorsRGB.RGB = function (name)
|
||||
if colorsRGB[name] then
|
||||
local values = colorsRGB[name][1]..colorsRGB[name][2]..colorsRGB[name][3]
|
||||
return values
|
||||
else
|
||||
return name
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue