forked from VoxeLibre/VoxeLibre
Compare commits
4 Commits
master
...
procedural
Author | SHA1 | Date |
---|---|---|
teknomunk | 1e3f3ca172 | |
teknomunk | dd513b08df | |
teknomunk | 860f2f1ff5 | |
teknomunk | c379cf9efe |
|
@ -0,0 +1,246 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
local function debug(f)
|
||||
minetest.log("warning",f)
|
||||
end
|
||||
|
||||
local function is_occupied(state, pos)
|
||||
return state.occupied[ tostring(pos) ]
|
||||
end
|
||||
local function set_occupied(state, pos)
|
||||
state.occupied[ tostring(pos) ] = true
|
||||
end
|
||||
|
||||
local function is_in_bounds(state, pos)
|
||||
local struct = state.struct
|
||||
|
||||
if pos.x < 0 or pos.x >= struct.grid_limit.x then return false end
|
||||
if pos.y < 0 or pos.y >= struct.grid_limit.y then return false end
|
||||
if pos.z < 0 or pos.z >= struct.grid_limit.z then return false end
|
||||
|
||||
return true
|
||||
end
|
||||
local function rotate_rule(rule, rot)
|
||||
if rot == 0 then
|
||||
return rule
|
||||
elseif rot == 2 then
|
||||
return {
|
||||
groups = rule.groups,
|
||||
dir = -rule.dir,
|
||||
pos = rule.pos
|
||||
}
|
||||
end
|
||||
|
||||
return rule
|
||||
end
|
||||
local function rotate_rules(rules, rot)
|
||||
local new_rules = {}
|
||||
for i,rule in ipairs(rules) do
|
||||
new_rules[i] = rotate_rule(rule, rot)
|
||||
end
|
||||
return new_rules
|
||||
end
|
||||
local function does_rule_match(conditions, rule)
|
||||
-- Rotate 180
|
||||
local rotated = rotate_rule(conditions,2)
|
||||
|
||||
-- Make sure at least one group overlaps
|
||||
if rotated.dir ~= rule.dir then return false end
|
||||
for k,v in pairs(conditions.groups or{}) do
|
||||
if rule.groups and rule.groups[k] == v then return true end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function add_node_pos(state, rule, new_grid_pos)
|
||||
if not state:is_in_bounds(new_grid_pos) then
|
||||
debug(tostring(new_grid_pos).." is out of bounds")
|
||||
return
|
||||
end
|
||||
if state:is_occupied(new_grid_pos) then
|
||||
debug(tostring(new_grid_pos).." is already occupied")
|
||||
return
|
||||
end
|
||||
|
||||
-- Check if the node is already in the list and add the rule if it is
|
||||
for _,n in ipairs(state.nodes) do
|
||||
if n.pos == new_grid_pos then
|
||||
n.rules[#n.rules +1] = rule
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Append the node
|
||||
state.nodes[#state.nodes + 1] = { pos = new_grid_pos, rules = {rule}}
|
||||
debug("adding "..tostring(new_grid_pos))
|
||||
end
|
||||
|
||||
local function place_part(state, idx, rot, grid_pos)
|
||||
local root_pos = state.root_pos
|
||||
local struct = state.struct
|
||||
local part = struct.parts[idx]
|
||||
|
||||
-- Make sure none of the spaces are occupied and all are in bounds
|
||||
for x=1,part.size.x do
|
||||
for y=1,part.size.y do
|
||||
for z=1,part.size.z do
|
||||
local pn = vector.offset(grid_pos, x-1, y-1, z-1)
|
||||
if state:is_occupied(pn) then return end
|
||||
if not state:is_in_bounds(pn) then return end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Place the part
|
||||
debug("Placing part #"..tostring(idx).." ("..part.file..") at grid_pos="..tostring(grid_pos)..", root_pos="..tostring(root_pos))
|
||||
local pos = root_pos + vector.new(
|
||||
grid_pos.x * struct.grid_size.x,
|
||||
grid_pos.y * struct.grid_size.y,
|
||||
grid_pos.z * struct.grid_size.z
|
||||
)
|
||||
minetest.place_schematic(pos, modpath.."/schematics/".. struct.name .. "/" .. part.file, ({"0","90","180","270"})[rot], nil, false)
|
||||
|
||||
-- Run hook
|
||||
if part.after_place then
|
||||
part.after_place(state, pos)
|
||||
end
|
||||
|
||||
-- Handle loot
|
||||
if part.loot then
|
||||
local p2 = pos + struct.grid_size
|
||||
mcl_structures.fill_chests(pos, p2, part.loot or struct.loot, state.pr)
|
||||
end
|
||||
|
||||
-- Set positions as occupied
|
||||
for x=1,part.size.x do
|
||||
for y=1,part.size.y do
|
||||
for z=1,part.size.z do
|
||||
local pn = vector.offset(grid_pos, x-1, y-1, z-1)
|
||||
state:set_occupied(pn)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Add nodes to the state
|
||||
for _,rule in ipairs(part.rules or {}) do
|
||||
state:add_node_pos(rule, grid_pos + (rule.dir or vector.new(0,0,0)) + (rule.pos or vector.new(0,0,0)))
|
||||
end
|
||||
end
|
||||
|
||||
local function do_part_rules_contain(part_rules, rule)
|
||||
for _,r in ipairs(part_rules) do
|
||||
if does_rule_match(rule, r) then return true end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function do_part_rules_match(state, pid, rot, node)
|
||||
local part_rules = state.struct.parts[pid].rules or {}
|
||||
|
||||
if node.rules then
|
||||
for _,r in ipairs(node.rules) do
|
||||
if not do_part_rules_contain(part_rules, r) then
|
||||
debug("No match for rule")
|
||||
debug(dump(r))
|
||||
debug(dump(part_rules))
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function select_part(state, node)
|
||||
local pr = state.pr
|
||||
local struct = state.struct
|
||||
|
||||
local possible_parts = {}
|
||||
local total_weight = 0
|
||||
|
||||
debug("node="..dump(node))
|
||||
for i,part in ipairs(struct.parts) do
|
||||
debug("checking "..part.file)
|
||||
local valid_part = true
|
||||
|
||||
if part.can_use and not part.can_use(state) then
|
||||
debug("can't use")
|
||||
valid_part = false
|
||||
end
|
||||
if not do_part_rules_match(state, i, 0, node) then valid_part = false end
|
||||
|
||||
if valid_part then
|
||||
debug("possible part: "..tostring(part.file))
|
||||
possible_parts[#possible_parts+1] = {i=i,part=part}
|
||||
total_weight = total_weight + (part.weight or 1)
|
||||
end
|
||||
end
|
||||
|
||||
if total_weight == 0 then return 0,0 end
|
||||
|
||||
local w = pr:next(1,total_weight)
|
||||
for _,p in ipairs(possible_parts) do
|
||||
if w <= (p.part.weight or 1) then
|
||||
return p.i,0
|
||||
end
|
||||
|
||||
w = w - (p.part.weight or 1)
|
||||
end
|
||||
|
||||
return 0,0
|
||||
end
|
||||
|
||||
function mcl_procedural_structures:place(name, root_pos, seed)
|
||||
local state = {
|
||||
root_pos = root_pos,
|
||||
occupied = {},
|
||||
nodes = {},
|
||||
user = {},
|
||||
|
||||
-- functions
|
||||
is_occupied = is_occupied,
|
||||
set_occupied = set_occupied,
|
||||
is_in_bounds = is_in_bounds,
|
||||
place_part = place_part,
|
||||
select_part = select_part,
|
||||
add_node_pos = add_node_pos,
|
||||
}
|
||||
|
||||
-- Get the structure information
|
||||
local struct = self.structures[name]
|
||||
if not struct then return end
|
||||
state.struct = struct
|
||||
|
||||
-- Handle structure-specific setup
|
||||
if struct.before_place then struct.before_place(state) end
|
||||
|
||||
-- Insert a default starting location if none was inserted by the structure
|
||||
if #state.nodes == 0 then
|
||||
state.nodes[1] = {pos = vector.new(0,0,0)}
|
||||
end
|
||||
|
||||
-- Initialize random numbers from seed
|
||||
local pr = PseudoRandom(seed)
|
||||
state.pr = pr
|
||||
|
||||
local nodes = state.nodes
|
||||
while #nodes > 0 do
|
||||
debug("Nodes remaining: "..tostring(#nodes))
|
||||
-- Pull out one node
|
||||
local j = pr:next(1,#nodes)
|
||||
local node = nodes[j]
|
||||
if j ~= #nodes then
|
||||
nodes[j] = nodes[#nodes]
|
||||
end
|
||||
nodes[#nodes] = nil
|
||||
|
||||
-- Place a schematic for this node if not already occupied
|
||||
if not state:is_occupied(node) then
|
||||
local id,rot = state:select_part(node)
|
||||
state:place_part( id, rot, node.pos )
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local S = minetest.get_translator(modname)
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
mcl_procedural_structures = {
|
||||
structures = {}
|
||||
}
|
||||
|
||||
dofile(modpath.."/api.lua")
|
||||
mcl_procedural_structures.structures.nether_fortress = dofile(modpath.."/nether_fortress.lua")
|
||||
|
||||
minetest.register_chatcommand("genstruct",{
|
||||
params = "dungeon",
|
||||
description = S("Generate a procedural structure near your position"),
|
||||
privs = {debug = true},
|
||||
func = function(name, param)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then return end
|
||||
|
||||
local pos = player:get_pos()
|
||||
if not pos then return end
|
||||
pos = vector.round(pos)
|
||||
|
||||
mcl_procedural_structures:place( "nether_fortress", vector.offset(pos,14,0,14), 1)
|
||||
end
|
||||
})
|
|
@ -0,0 +1,4 @@
|
|||
name = mcl2_procedural_structures
|
||||
author = teknomunk
|
||||
description = Procedurally generate structures from components
|
||||
depends = mcl_init, mcl_structures, mcl_mobspawners
|
|
@ -0,0 +1,318 @@
|
|||
local BLAZE_SPAWNER_MAX_LIGHT = 11
|
||||
|
||||
loot_table = {
|
||||
["mcl_chests:chest_small" ] ={
|
||||
{
|
||||
stacks_min = 1,
|
||||
stacks_max = 2,
|
||||
items = {
|
||||
--{ itemstring = "FIXME:spectral_arrow", weight = 1, amount_min = 10, amount_max=28 },
|
||||
{ itemstring = "mcl_blackstone:blackstone_gilded", weight = 1, amount_min = 8, amount_max=12 },
|
||||
{ itemstring = "mcl_core:iron_ingot", weight = 1, amount_min = 4, amount_max=9 },
|
||||
{ itemstring = "mcl_core:gold_ingot", weight = 1, amount_min = 4, amount_max=9 },
|
||||
{ itemstring = "mcl_core:crying_obsidian", weight = 1, amount_min = 3, amount_max=8 },
|
||||
{ itemstring = "mcl_bows:crossbow", weight = 1, func = function(stack, pr)
|
||||
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}, pr)
|
||||
end },
|
||||
{ itemstring = "mcl_core:goldblock", weight = 1, },
|
||||
{ itemstring = "mcl_tools:sword_gold", weight = 1, },
|
||||
{ itemstring = "mcl_tools:axe_gold", weight = 1, func = function(stack, pr)
|
||||
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}, pr)
|
||||
end },
|
||||
{ itemstring = "mcl_armor:helmet_gold", weight = 1, func = function(stack, pr)
|
||||
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}, pr)
|
||||
end },
|
||||
{ itemstring = "mcl_armor:chestplate_gold", weight = 1, func = function(stack, pr)
|
||||
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}, pr)
|
||||
end },
|
||||
{ itemstring = "mcl_armor:leggings_gold", weight = 1, func = function(stack, pr)
|
||||
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}, pr)
|
||||
end },
|
||||
{ itemstring = "mcl_armor:boots_gold", weight = 1, func = function(stack, pr)
|
||||
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}, pr)
|
||||
end },
|
||||
}
|
||||
},
|
||||
{
|
||||
stacks_min = 2,
|
||||
stacks_max = 4,
|
||||
items = {
|
||||
{ itemstring = "mcl_bows:arrow", weight = 4, amount_min = 5, amount_max=17 },
|
||||
{ itemstring = "mcl_mobitems:string", weight = 4, amount_min = 1, amount_max=6 },
|
||||
{ itemstring = "mcl_core:iron_nugget", weight = 1, amount_min = 2, amount_max = 6 },
|
||||
{ itemstring = "mcl_core:gold_nugget", weight = 1, amount_min = 2, amount_max = 6 },
|
||||
{ itemstring = "mcl_mobitems:leather", weight = 1, amount_min = 1, amount_max = 3 },
|
||||
}
|
||||
},
|
||||
{
|
||||
stacks_min = 1,
|
||||
stacks_max = 1,
|
||||
items = {
|
||||
{ itemstring = "mcl_compass:lodestone" },
|
||||
{ itemstring = "mcl_armor:rib" },
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
return {
|
||||
name = "nether_fortress",
|
||||
grid_size = vector.new(7,4,7),
|
||||
grid_limit = vector.new(5,3,5),
|
||||
loot = loot_table,
|
||||
parts = {
|
||||
-- never access this part
|
||||
[0]={
|
||||
file = "template_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
},
|
||||
|
||||
{
|
||||
file = "corner_1_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
weight = 5,
|
||||
rules = {
|
||||
{ dir = vector.new( 0, 0,-1), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 }, },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { wall=1 }, },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "tee_1_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
weight = 8,
|
||||
rules = {
|
||||
{ dir = vector.new( 0, 0,-1), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { wall=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "cross_glowstone_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
weight = 7,
|
||||
rules = {
|
||||
{ dir = vector.new( 0, 0,-1), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { corridor=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "cross_hidden_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
weight = 2,
|
||||
rules = {
|
||||
{ dir = vector.new( 0, 0,-1), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { corridor=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "cross_fake_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
weight = 6,
|
||||
rules = {
|
||||
{ dir = vector.new( 0, 0,-1), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { corridor=1 } },
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
file = "corridor_1_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
weight = 3,
|
||||
rules = {
|
||||
{ dir = vector.new( 1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "corridor_2_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
weight = 3,
|
||||
rules = {
|
||||
{ dir = vector.new( 1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "corridor_3_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
weight = 3,
|
||||
rules = {
|
||||
{ dir = vector.new( 1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 } },
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
file = "quartz_lava_well_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
can_use = function(state)
|
||||
return not state.user.has_lava_well
|
||||
end,
|
||||
after_place = function(state, pos)
|
||||
state.user.has_lava_well = true
|
||||
end,
|
||||
rules = {
|
||||
{ dir = vector.new( 1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "hall_with_nether_wart_1x2x1.mts",
|
||||
size = vector.new(2,1,1),
|
||||
weight = 2,
|
||||
rules = {
|
||||
{ dir = vector.new( 1, 0, 0), pos = vector.new(1,0,0), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "lava_tunnel_1x2x1.mts",
|
||||
size = vector.new(2,1,1),
|
||||
weight = 2,
|
||||
rules = {
|
||||
{ dir = vector.new( 1, 0, 0), pos = vector.new(1,0,0), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } }
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "courtyard_lava_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
rules = {
|
||||
{ dir = vector.new(-1, 0, 0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "stairs_1x1x2.mts",
|
||||
size = vector.new(1,2,1),
|
||||
rules = {
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 } },
|
||||
|
||||
{ dir = vector.new( 1, 0, 0), pos = vector.new(0,1,0), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), pos = vector.new(0,1,0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), pos = vector.new(0,1,0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), pos = vector.new(0,1,0), groups = { wall=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "stairs_1x1x3.mts",
|
||||
size = vector.new(1,3,1),
|
||||
rules = {
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 } },
|
||||
|
||||
{ dir = vector.new( 0, 0, 1), pos = vector.new(0,1,0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), pos = vector.new(0,1,0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), pos = vector.new(0,1,0), groups = { wall=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), pos = vector.new(0,1,0), groups = { wall=1 } },
|
||||
|
||||
{ dir = vector.new( 1, 0, 0), pos = vector.new(0,2,0) },
|
||||
{ dir = vector.new(-1, 0, 0), pos = vector.new(0,2,0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), pos = vector.new(0,2,0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), pos = vector.new(0,2,0), groups = { wall=1 } },
|
||||
}
|
||||
},
|
||||
{
|
||||
file = "mess_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
rules = {
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 } },
|
||||
},
|
||||
loot = {
|
||||
["mcl_chests:chest_small"] = {{
|
||||
stacks_min = 3,
|
||||
stacks_max = 9,
|
||||
items = {
|
||||
{ itemstring = "mcl_mobitems:cooked_porkchop", weight = 10, amount_min = 1, amount_max = 5 },
|
||||
{ itemstring = "mcl_mobitems:porkchop", weight = 10, amount_min = 1, amount_max = 30 },
|
||||
{ itemstring = "mcl_mobitems:string", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_mobitems:rotten_flesh", weight = 20, amount_min = 5, amount_max = 16 },
|
||||
{ itemstring = "mcl_core:gold_nugget", weight = 15, amount_min = 4, amount_max = 9 },
|
||||
{ itemstring = "mcl_core:iron_nugget", weight = 15, amount_min = 4, amount_max = 9 },
|
||||
{ itemstring = "mcl_mobitems:leather", weight = 15, amount_min = 1, amount_max = 4 },
|
||||
}
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "mason_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
rules = {
|
||||
{ dir = vector.new(-1, 0, 0), },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 } },
|
||||
},
|
||||
loot = {
|
||||
["mcl_barrels:barrel_closed"] = {{
|
||||
stacks_min = 3,
|
||||
stacks_max = 12,
|
||||
items = {
|
||||
{ itemstring = "mcl_blackstone:blackstone_gilded", weight = 1, amount_min = 8, amount_max = 12 },
|
||||
{ itemstring = "mcl_blackstone:blackstone", weight = 10, amount_min = 8, amount_max=12 },
|
||||
{ itemstring = "mcl_core:gold_nugget", weight = 15, amount_min = 4, amount_max = 9 },
|
||||
{ itemstring = "mcl_core:gold_ingot", weight = 1, amount_min = 4, amount_max=9 },
|
||||
{ itemstring = "mcl_core:goldblock", weight = 1, },
|
||||
{ itemstring = "mcl_nether:quartz", weight = 5, amount_min = 1, amount_max = 15 },
|
||||
}
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "spawner_1x1x2.mts",
|
||||
size = vector.new(1,2,1),
|
||||
rules = {
|
||||
{ dir = vector.new(-1, 0, 0) },
|
||||
{ dir = vector.new( 1, 0, 0) },
|
||||
{ dir = vector.new( 0, 0, 1) },
|
||||
{ dir = vector.new( 0, 0,-1) },
|
||||
|
||||
{ dir = vector.new(-1, 0, 0), pos = vector.new(0,1,0) },
|
||||
{ dir = vector.new( 1, 0, 0), pos = vector.new(0,1,0) },
|
||||
{ dir = vector.new( 0, 0, 1), pos = vector.new(0,1,0) },
|
||||
{ dir = vector.new( 0, 0,-1), pos = vector.new(0,1,0) },
|
||||
},
|
||||
loot = loot_table,
|
||||
can_use = function(state)
|
||||
return (state.user.spawners or 0) < 2
|
||||
end,
|
||||
after_place = function(state, pos)
|
||||
-- Track how many blaze spawners we have placed
|
||||
state.user.spawners = ( state.user.spawnders or 0 ) + 1
|
||||
|
||||
--[[
|
||||
local nodes = minetest.find_nodes_in_area(pos,vector.offset(pos,7,4*2+1,7),{"mcl_mobspawners:spawner"})
|
||||
for _,p in ipairs(nodes) do
|
||||
mcl_mobspawners.setup_spawner(p, "mobs_mc:blaze", 0, BLAZE_SPAWNER_MAX_LIGHT, 10, 8, 0)
|
||||
end
|
||||
--]]
|
||||
end
|
||||
},
|
||||
},
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,246 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
local function debug(f)
|
||||
minetest.log("warning",f)
|
||||
end
|
||||
|
||||
local function is_occupied(state, pos)
|
||||
return state.occupied[ tostring(pos) ]
|
||||
end
|
||||
local function set_occupied(state, pos)
|
||||
state.occupied[ tostring(pos) ] = true
|
||||
end
|
||||
|
||||
local function is_in_bounds(state, pos)
|
||||
local struct = state.struct
|
||||
|
||||
if pos.x < 0 or pos.x >= struct.grid_limit.x then return false end
|
||||
if pos.y < 0 or pos.y >= struct.grid_limit.y then return false end
|
||||
if pos.z < 0 or pos.z >= struct.grid_limit.z then return false end
|
||||
|
||||
return true
|
||||
end
|
||||
local function rotate_rule(rule, rot)
|
||||
if rot == 0 then
|
||||
return rule
|
||||
elseif rot == 2 then
|
||||
return {
|
||||
groups = rule.groups,
|
||||
dir = -rule.dir,
|
||||
pos = rule.pos
|
||||
}
|
||||
end
|
||||
|
||||
return rule
|
||||
end
|
||||
local function rotate_rules(rules, rot)
|
||||
local new_rules = {}
|
||||
for i,rule in ipairs(rules) do
|
||||
new_rules[i] = rotate_rule(rule, rot)
|
||||
end
|
||||
return new_rules
|
||||
end
|
||||
local function does_rule_match(conditions, rule)
|
||||
-- Rotate 180
|
||||
local rotated = rotate_rule(conditions,2)
|
||||
|
||||
-- Make sure at least one group overlaps
|
||||
if rotated.dir ~= rule.dir then return false end
|
||||
for k,v in pairs(conditions.groups or{}) do
|
||||
if rule.groups and rule.groups[k] == v then return true end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function add_node_pos(state, rule, new_grid_pos)
|
||||
if not state:is_in_bounds(new_grid_pos) then
|
||||
debug(tostring(new_grid_pos).." is out of bounds")
|
||||
return
|
||||
end
|
||||
if state:is_occupied(new_grid_pos) then
|
||||
debug(tostring(new_grid_pos).." is already occupied")
|
||||
return
|
||||
end
|
||||
|
||||
-- Check if the node is already in the list and add the rule if it is
|
||||
for _,n in ipairs(state.nodes) do
|
||||
if n.pos == new_grid_pos then
|
||||
n.rules[#n.rules +1] = rule
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Append the node
|
||||
state.nodes[#state.nodes + 1] = { pos = new_grid_pos, rules = {rule}}
|
||||
debug("adding "..tostring(new_grid_pos))
|
||||
end
|
||||
|
||||
local function place_part(state, idx, rot, grid_pos)
|
||||
local root_pos = state.root_pos
|
||||
local struct = state.struct
|
||||
local part = struct.parts[idx]
|
||||
|
||||
-- Make sure none of the spaces are occupied and all are in bounds
|
||||
for x=1,part.size.x do
|
||||
for y=1,part.size.y do
|
||||
for z=1,part.size.z do
|
||||
local pn = vector.offset(grid_pos, x-1, y-1, z-1)
|
||||
if state:is_occupied(pn) then return end
|
||||
if not state:is_in_bounds(pn) then return end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Place the part
|
||||
debug("Placing part #"..tostring(idx).." ("..part.file..") at grid_pos="..tostring(grid_pos)..", root_pos="..tostring(root_pos))
|
||||
local pos = root_pos + vector.new(
|
||||
grid_pos.x * struct.grid_size.x,
|
||||
grid_pos.y * struct.grid_size.y,
|
||||
grid_pos.z * struct.grid_size.z
|
||||
)
|
||||
minetest.place_schematic(pos, modpath.."/schematics/".. struct.name .. "/" .. part.file, ({"0","90","180","270"})[rot], nil, false)
|
||||
|
||||
-- Run hook
|
||||
if part.after_place then
|
||||
part.after_place(state, pos)
|
||||
end
|
||||
|
||||
-- Handle loot
|
||||
if part.loot then
|
||||
local p2 = pos + struct.grid_size
|
||||
mcl_structures.fill_chests(pos, p2, part.loot or struct.loot, state.pr)
|
||||
end
|
||||
|
||||
-- Set positions as occupied
|
||||
for x=1,part.size.x do
|
||||
for y=1,part.size.y do
|
||||
for z=1,part.size.z do
|
||||
local pn = vector.offset(grid_pos, x-1, y-1, z-1)
|
||||
state:set_occupied(pn)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Add nodes to the state
|
||||
for _,rule in ipairs(part.rules or {}) do
|
||||
state:add_node_pos(rule, grid_pos + (rule.dir or vector.new(0,0,0)) + (rule.pos or vector.new(0,0,0)))
|
||||
end
|
||||
end
|
||||
|
||||
local function do_part_rules_contain(part_rules, rule)
|
||||
for _,r in ipairs(part_rules) do
|
||||
if does_rule_match(rule, r) then return true end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function do_part_rules_match(state, pid, rot, node)
|
||||
local part_rules = state.struct.parts[pid].rules or {}
|
||||
|
||||
if node.rules then
|
||||
for _,r in ipairs(node.rules) do
|
||||
if not do_part_rules_contain(part_rules, r) then
|
||||
debug("No match for rule")
|
||||
debug(dump(r))
|
||||
debug(dump(part_rules))
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function select_part(state, node)
|
||||
local pr = state.pr
|
||||
local struct = state.struct
|
||||
|
||||
local possible_parts = {}
|
||||
local total_weight = 0
|
||||
|
||||
debug("node="..dump(node))
|
||||
for i,part in ipairs(struct.parts) do
|
||||
debug("checking "..part.file)
|
||||
local valid_part = true
|
||||
|
||||
if part.can_use and not part.can_use(state) then
|
||||
debug("can't use")
|
||||
valid_part = false
|
||||
end
|
||||
if not do_part_rules_match(state, i, 0, node) then valid_part = false end
|
||||
|
||||
if valid_part then
|
||||
debug("possible part: "..tostring(part.file))
|
||||
possible_parts[#possible_parts+1] = {i=i,part=part}
|
||||
total_weight = total_weight + (part.weight or 1)
|
||||
end
|
||||
end
|
||||
|
||||
if total_weight == 0 then return 0,0 end
|
||||
|
||||
local w = pr:next(1,total_weight)
|
||||
for _,p in ipairs(possible_parts) do
|
||||
if w <= (p.part.weight or 1) then
|
||||
return p.i,0
|
||||
end
|
||||
|
||||
w = w - (p.part.weight or 1)
|
||||
end
|
||||
|
||||
return 0,0
|
||||
end
|
||||
|
||||
function mcl_procedural_structures:place(name, root_pos, seed)
|
||||
local state = {
|
||||
root_pos = root_pos,
|
||||
occupied = {},
|
||||
nodes = {},
|
||||
user = {},
|
||||
|
||||
-- functions
|
||||
is_occupied = is_occupied,
|
||||
set_occupied = set_occupied,
|
||||
is_in_bounds = is_in_bounds,
|
||||
place_part = place_part,
|
||||
select_part = select_part,
|
||||
add_node_pos = add_node_pos,
|
||||
}
|
||||
|
||||
-- Get the structure information
|
||||
local struct = self.structures[name]
|
||||
if not struct then return end
|
||||
state.struct = struct
|
||||
|
||||
-- Handle structure-specific setup
|
||||
if struct.before_place then struct.before_place(state) end
|
||||
|
||||
-- Insert a default starting location if none was inserted by the structure
|
||||
if #state.nodes == 0 then
|
||||
state.nodes[1] = {pos = vector.new(0,0,0)}
|
||||
end
|
||||
|
||||
-- Initialize random numbers from seed
|
||||
local pr = PseudoRandom(seed)
|
||||
state.pr = pr
|
||||
|
||||
local nodes = state.nodes
|
||||
while #nodes > 0 do
|
||||
debug("Nodes remaining: "..tostring(#nodes))
|
||||
-- Pull out one node
|
||||
local j = pr:next(1,#nodes)
|
||||
local node = nodes[j]
|
||||
if j ~= #nodes then
|
||||
nodes[j] = nodes[#nodes]
|
||||
end
|
||||
nodes[#nodes] = nil
|
||||
|
||||
-- Place a schematic for this node if not already occupied
|
||||
if not state:is_occupied(node) then
|
||||
local id,rot = state:select_part(node)
|
||||
state:place_part( id, rot, node.pos )
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local S = minetest.get_translator(modname)
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
mcl_procedural_structures = {
|
||||
structures = {}
|
||||
}
|
||||
|
||||
dofile(modpath.."/api.lua")
|
||||
dofile(modpath.."/nether_fortress.lua")
|
||||
|
||||
minetest.register_chatcommand("genstruct",{
|
||||
params = "dungeon",
|
||||
description = S("Generate a procedural structure near your position"),
|
||||
privs = {debug = true},
|
||||
func = function(name, param)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then return end
|
||||
|
||||
local pos = player:get_pos()
|
||||
if not pos then return end
|
||||
pos = vector.round(pos)
|
||||
|
||||
mcl_procedural_structures:place( "nether_fortress", vector.offset(pos,14,0,14), 1)
|
||||
end
|
||||
})
|
|
@ -0,0 +1,4 @@
|
|||
name = mcl_procedural_structures
|
||||
author = teknomunk
|
||||
description = Procedurally generate structures from components
|
||||
depends = mcl_init, mcl_structures, mcl_mobspawners
|
|
@ -0,0 +1,318 @@
|
|||
local BLAZE_SPAWNER_MAX_LIGHT = 11
|
||||
|
||||
loot_table = {
|
||||
["mcl_chests:chest_small" ] ={
|
||||
{
|
||||
stacks_min = 1,
|
||||
stacks_max = 2,
|
||||
items = {
|
||||
--{ itemstring = "FIXME:spectral_arrow", weight = 1, amount_min = 10, amount_max=28 },
|
||||
{ itemstring = "mcl_blackstone:blackstone_gilded", weight = 1, amount_min = 8, amount_max=12 },
|
||||
{ itemstring = "mcl_core:iron_ingot", weight = 1, amount_min = 4, amount_max=9 },
|
||||
{ itemstring = "mcl_core:gold_ingot", weight = 1, amount_min = 4, amount_max=9 },
|
||||
{ itemstring = "mcl_core:crying_obsidian", weight = 1, amount_min = 3, amount_max=8 },
|
||||
{ itemstring = "mcl_bows:crossbow", weight = 1, func = function(stack, pr)
|
||||
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}, pr)
|
||||
end },
|
||||
{ itemstring = "mcl_core:goldblock", weight = 1, },
|
||||
{ itemstring = "mcl_tools:sword_gold", weight = 1, },
|
||||
{ itemstring = "mcl_tools:axe_gold", weight = 1, func = function(stack, pr)
|
||||
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}, pr)
|
||||
end },
|
||||
{ itemstring = "mcl_armor:helmet_gold", weight = 1, func = function(stack, pr)
|
||||
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}, pr)
|
||||
end },
|
||||
{ itemstring = "mcl_armor:chestplate_gold", weight = 1, func = function(stack, pr)
|
||||
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}, pr)
|
||||
end },
|
||||
{ itemstring = "mcl_armor:leggings_gold", weight = 1, func = function(stack, pr)
|
||||
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}, pr)
|
||||
end },
|
||||
{ itemstring = "mcl_armor:boots_gold", weight = 1, func = function(stack, pr)
|
||||
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}, pr)
|
||||
end },
|
||||
}
|
||||
},
|
||||
{
|
||||
stacks_min = 2,
|
||||
stacks_max = 4,
|
||||
items = {
|
||||
{ itemstring = "mcl_bows:arrow", weight = 4, amount_min = 5, amount_max=17 },
|
||||
{ itemstring = "mcl_mobitems:string", weight = 4, amount_min = 1, amount_max=6 },
|
||||
{ itemstring = "mcl_core:iron_nugget", weight = 1, amount_min = 2, amount_max = 6 },
|
||||
{ itemstring = "mcl_core:gold_nugget", weight = 1, amount_min = 2, amount_max = 6 },
|
||||
{ itemstring = "mcl_mobitems:leather", weight = 1, amount_min = 1, amount_max = 3 },
|
||||
}
|
||||
},
|
||||
{
|
||||
stacks_min = 1,
|
||||
stacks_max = 1,
|
||||
items = {
|
||||
{ itemstring = "mcl_compass:lodestone" },
|
||||
{ itemstring = "mcl_armor:rib" },
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
mcl_procedural_structures.structures.nether_fortress = {
|
||||
name = "nether_fortress",
|
||||
grid_size = vector.new(7,4,7),
|
||||
grid_limit = vector.new(5,3,5),
|
||||
loot = loot_table,
|
||||
parts = {
|
||||
-- never access this part
|
||||
[0]={
|
||||
file = "template_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
},
|
||||
|
||||
{
|
||||
file = "corner_1_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
weight = 5,
|
||||
rules = {
|
||||
{ dir = vector.new( 0, 0,-1), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 }, },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { wall=1 }, },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "tee_1_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
weight = 8,
|
||||
rules = {
|
||||
{ dir = vector.new( 0, 0,-1), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { wall=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "cross_glowstone_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
weight = 7,
|
||||
rules = {
|
||||
{ dir = vector.new( 0, 0,-1), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { corridor=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "cross_hidden_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
weight = 2,
|
||||
rules = {
|
||||
{ dir = vector.new( 0, 0,-1), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { corridor=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "cross_fake_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
weight = 6,
|
||||
rules = {
|
||||
{ dir = vector.new( 0, 0,-1), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { corridor=1 } },
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
file = "corridor_1_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
weight = 3,
|
||||
rules = {
|
||||
{ dir = vector.new( 1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "corridor_2_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
weight = 3,
|
||||
rules = {
|
||||
{ dir = vector.new( 1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "corridor_3_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
weight = 3,
|
||||
rules = {
|
||||
{ dir = vector.new( 1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 } },
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
file = "quartz_lava_well_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
can_use = function(state)
|
||||
return not state.user.has_lava_well
|
||||
end,
|
||||
after_place = function(state, pos)
|
||||
state.user.has_lava_well = true
|
||||
end,
|
||||
rules = {
|
||||
{ dir = vector.new( 1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "hall_with_nether_wart_1x2x1.mts",
|
||||
size = vector.new(2,1,1),
|
||||
weight = 2,
|
||||
rules = {
|
||||
{ dir = vector.new( 1, 0, 0), pos = vector.new(1,0,0), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "lava_tunnel_1x2x1.mts",
|
||||
size = vector.new(2,1,1),
|
||||
weight = 2,
|
||||
rules = {
|
||||
{ dir = vector.new( 1, 0, 0), pos = vector.new(1,0,0), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } }
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "courtyard_lava_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
rules = {
|
||||
{ dir = vector.new(-1, 0, 0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "stairs_1x1x2.mts",
|
||||
size = vector.new(1,2,1),
|
||||
rules = {
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 } },
|
||||
|
||||
{ dir = vector.new( 1, 0, 0), pos = vector.new(0,1,0), groups = { corridor=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), pos = vector.new(0,1,0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), pos = vector.new(0,1,0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), pos = vector.new(0,1,0), groups = { wall=1 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "stairs_1x1x3.mts",
|
||||
size = vector.new(1,3,1),
|
||||
rules = {
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 } },
|
||||
|
||||
{ dir = vector.new( 0, 0, 1), pos = vector.new(0,1,0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), pos = vector.new(0,1,0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), pos = vector.new(0,1,0), groups = { wall=1 } },
|
||||
{ dir = vector.new(-1, 0, 0), pos = vector.new(0,1,0), groups = { wall=1 } },
|
||||
|
||||
{ dir = vector.new( 1, 0, 0), pos = vector.new(0,2,0) },
|
||||
{ dir = vector.new(-1, 0, 0), pos = vector.new(0,2,0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), pos = vector.new(0,2,0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), pos = vector.new(0,2,0), groups = { wall=1 } },
|
||||
}
|
||||
},
|
||||
{
|
||||
file = "mess_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
rules = {
|
||||
{ dir = vector.new(-1, 0, 0), groups = { corridor=1 } },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 } },
|
||||
},
|
||||
loot = {
|
||||
["mcl_chests:chest_small"] = {{
|
||||
stacks_min = 3,
|
||||
stacks_max = 9,
|
||||
items = {
|
||||
{ itemstring = "mcl_mobitems:cooked_porkchop", weight = 10, amount_min = 1, amount_max = 5 },
|
||||
{ itemstring = "mcl_mobitems:porkchop", weight = 10, amount_min = 1, amount_max = 30 },
|
||||
{ itemstring = "mcl_mobitems:string", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_mobitems:rotten_flesh", weight = 20, amount_min = 5, amount_max = 16 },
|
||||
{ itemstring = "mcl_core:gold_nugget", weight = 15, amount_min = 4, amount_max = 9 },
|
||||
{ itemstring = "mcl_core:iron_nugget", weight = 15, amount_min = 4, amount_max = 9 },
|
||||
{ itemstring = "mcl_mobitems:leather", weight = 15, amount_min = 1, amount_max = 4 },
|
||||
}
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "mason_1x1x1.mts",
|
||||
size = vector.new(1,1,1),
|
||||
rules = {
|
||||
{ dir = vector.new(-1, 0, 0), },
|
||||
{ dir = vector.new( 1, 0, 0), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0,-1), groups = { wall=1 } },
|
||||
{ dir = vector.new( 0, 0, 1), groups = { wall=1 } },
|
||||
},
|
||||
loot = {
|
||||
["mcl_barrels:barrel_closed"] = {{
|
||||
stacks_min = 3,
|
||||
stacks_max = 12,
|
||||
items = {
|
||||
{ itemstring = "mcl_blackstone:blackstone_gilded", weight = 1, amount_min = 8, amount_max = 12 },
|
||||
{ itemstring = "mcl_blackstone:blackstone", weight = 10, amount_min = 8, amount_max=12 },
|
||||
{ itemstring = "mcl_core:gold_nugget", weight = 15, amount_min = 4, amount_max = 9 },
|
||||
{ itemstring = "mcl_core:gold_ingot", weight = 1, amount_min = 4, amount_max=9 },
|
||||
{ itemstring = "mcl_core:goldblock", weight = 1, },
|
||||
{ itemstring = "mcl_nether:quartz", weight = 5, amount_min = 1, amount_max = 15 },
|
||||
}
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
file = "spawner_1x1x2.mts",
|
||||
size = vector.new(1,2,1),
|
||||
rules = {
|
||||
{ dir = vector.new(-1, 0, 0) },
|
||||
{ dir = vector.new( 1, 0, 0) },
|
||||
{ dir = vector.new( 0, 0, 1) },
|
||||
{ dir = vector.new( 0, 0,-1) },
|
||||
|
||||
{ dir = vector.new(-1, 0, 0), pos = vector.new(0,1,0) },
|
||||
{ dir = vector.new( 1, 0, 0), pos = vector.new(0,1,0) },
|
||||
{ dir = vector.new( 0, 0, 1), pos = vector.new(0,1,0) },
|
||||
{ dir = vector.new( 0, 0,-1), pos = vector.new(0,1,0) },
|
||||
},
|
||||
loot = loot_table,
|
||||
can_use = function(state)
|
||||
return (state.user.spawners or 0) < 2
|
||||
end,
|
||||
after_place = function(state, pos)
|
||||
-- Track how many blaze spawners we have placed
|
||||
state.user.spawners = ( state.user.spawnders or 0 ) + 1
|
||||
|
||||
--[[
|
||||
local nodes = minetest.find_nodes_in_area(pos,vector.offset(pos,7,4*2+1,7),{"mcl_mobspawners:spawner"})
|
||||
for _,p in ipairs(nodes) do
|
||||
mcl_mobspawners.setup_spawner(p, "mobs_mc:blaze", 0, BLAZE_SPAWNER_MAX_LIGHT, 10, 8, 0)
|
||||
end
|
||||
--]]
|
||||
end
|
||||
},
|
||||
},
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue