forked from VoxeLibre/VoxeLibre
Compare commits
25 Commits
master
...
new_mapgen
Author | SHA1 | Date |
---|---|---|
kay27 | 888251e3ec | |
kay27 | b91d8875f3 | |
kay27 | 8eb0edaf51 | |
kay27 | 4bd06723b4 | |
kay27 | b565de7122 | |
kay27 | 74257f5ff2 | |
kay27 | ca37c60511 | |
kay27 | 9dadbb2bb4 | |
kay27 | 18c815fbf1 | |
kay27 | cc064636a9 | |
kay27 | 398f51b1da | |
kay27 | 9fe692fb6f | |
kay27 | 605bb8c619 | |
kay27 | 53cecf7b41 | |
kay27 | 792c740a4d | |
kay27 | 34ab356193 | |
kay27 | 03371421d8 | |
kay27 | 54ea8ba6b1 | |
kay27 | 229f821758 | |
kay27 | bb008d6341 | |
kay27 | 682d2b3229 | |
kay27 | f592437e8a | |
kay27 | a639630b32 | |
kay27 | 679a1db436 | |
kay27 | b3e8f24876 |
|
@ -24,240 +24,9 @@ mcl_vars.inventory_header = ""
|
|||
-- Tool wield size
|
||||
mcl_vars.tool_wield_scale = { x = 1.8, y = 1.8, z = 1 }
|
||||
|
||||
-- Mapgen variables
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
local minecraft_height_limit = 256
|
||||
local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true"
|
||||
local singlenode = mg_name == "singlenode"
|
||||
|
||||
-- Calculate mapgen_edge_min/mapgen_edge_max
|
||||
mcl_vars.chunksize = math.max(1, tonumber(minetest.get_mapgen_setting("chunksize")) or 5)
|
||||
mcl_vars.MAP_BLOCKSIZE = math.max(1, minetest.MAP_BLOCKSIZE or 16)
|
||||
mcl_vars.mapgen_limit = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000)
|
||||
mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max(1, minetest.MAX_MAP_GENERATION_LIMIT or 31000)
|
||||
local central_chunk_offset = -math.floor(mcl_vars.chunksize / 2)
|
||||
mcl_vars.central_chunk_offset_in_nodes = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
||||
mcl_vars.chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE
|
||||
local central_chunk_min_pos = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
||||
local central_chunk_max_pos = central_chunk_min_pos + mcl_vars.chunk_size_in_nodes - 1
|
||||
local ccfmin = central_chunk_min_pos - mcl_vars.MAP_BLOCKSIZE -- Fullminp/fullmaxp of central chunk, in nodes
|
||||
local ccfmax = central_chunk_max_pos + mcl_vars.MAP_BLOCKSIZE
|
||||
local mapgen_limit_b = math.floor(math.min(mcl_vars.mapgen_limit, mcl_vars.MAX_MAP_GENERATION_LIMIT) / mcl_vars.MAP_BLOCKSIZE)
|
||||
local mapgen_limit_min = -mapgen_limit_b * mcl_vars.MAP_BLOCKSIZE
|
||||
local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_vars.MAP_BLOCKSIZE - 1
|
||||
local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / mcl_vars.chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk
|
||||
local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / mcl_vars.chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits.
|
||||
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * mcl_vars.chunk_size_in_nodes
|
||||
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * mcl_vars.chunk_size_in_nodes
|
||||
|
||||
local function coordinate_to_block(x)
|
||||
return math.floor(x / mcl_vars.MAP_BLOCKSIZE)
|
||||
end
|
||||
|
||||
local function coordinate_to_chunk(x)
|
||||
return math.floor((coordinate_to_block(x) - central_chunk_offset) / mcl_vars.chunksize)
|
||||
end
|
||||
|
||||
function mcl_vars.pos_to_block(pos)
|
||||
return {
|
||||
x = coordinate_to_block(pos.x),
|
||||
y = coordinate_to_block(pos.y),
|
||||
z = coordinate_to_block(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
function mcl_vars.pos_to_chunk(pos)
|
||||
return {
|
||||
x = coordinate_to_chunk(pos.x),
|
||||
y = coordinate_to_chunk(pos.y),
|
||||
z = coordinate_to_chunk(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / mcl_vars.chunk_size_in_nodes)
|
||||
local k_positive_z = k_positive * 2
|
||||
local k_positive_y = k_positive_z * k_positive_z
|
||||
|
||||
function mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
local c = mcl_vars.pos_to_chunk(pos)
|
||||
return
|
||||
(c.y + k_positive) * k_positive_y +
|
||||
(c.z + k_positive) * k_positive_z +
|
||||
c.x + k_positive
|
||||
end
|
||||
|
||||
if not superflat and not singlenode then
|
||||
-- Normal mode
|
||||
--[[ Realm stacking (h is for height)
|
||||
- Overworld (h>=256)
|
||||
- Void (h>=1000)
|
||||
- Realm Barrier (h=11), to allow escaping the End
|
||||
- End (h>=256)
|
||||
- Void (h>=1000)
|
||||
- Nether (h=128)
|
||||
- Void (h>=1000)
|
||||
]]
|
||||
|
||||
-- Overworld
|
||||
mcl_vars.mg_overworld_min = -62
|
||||
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
|
||||
mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min + 4
|
||||
mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min + 10
|
||||
mcl_vars.mg_lava = true
|
||||
mcl_vars.mg_bedrock_is_rough = true
|
||||
|
||||
elseif singlenode then
|
||||
mcl_vars.mg_overworld_min = -66
|
||||
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
|
||||
mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min
|
||||
mcl_vars.mg_lava = false
|
||||
mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_is_rough = false
|
||||
else
|
||||
-- Classic superflat
|
||||
local ground = minetest.get_mapgen_setting("mgflat_ground_level")
|
||||
ground = tonumber(ground)
|
||||
if not ground then
|
||||
ground = 8
|
||||
end
|
||||
mcl_vars.mg_overworld_min = ground - 3
|
||||
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
|
||||
mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min
|
||||
mcl_vars.mg_lava = false
|
||||
mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_is_rough = false
|
||||
end
|
||||
|
||||
mcl_vars.mg_overworld_max = mcl_vars.mapgen_edge_max
|
||||
|
||||
-- The Nether (around Y = -29000)
|
||||
mcl_vars.mg_nether_min = -29067 -- Carefully chosen to be at a mapchunk border
|
||||
mcl_vars.mg_nether_max = mcl_vars.mg_nether_min + 128
|
||||
mcl_vars.mg_bedrock_nether_bottom_min = mcl_vars.mg_nether_min
|
||||
mcl_vars.mg_bedrock_nether_top_max = mcl_vars.mg_nether_max
|
||||
if not superflat then
|
||||
mcl_vars.mg_bedrock_nether_bottom_max = mcl_vars.mg_bedrock_nether_bottom_min + 4
|
||||
mcl_vars.mg_bedrock_nether_top_min = mcl_vars.mg_bedrock_nether_top_max - 4
|
||||
mcl_vars.mg_lava_nether_max = mcl_vars.mg_nether_min + 31
|
||||
else
|
||||
-- Thin bedrock in classic superflat mapgen
|
||||
mcl_vars.mg_bedrock_nether_bottom_max = mcl_vars.mg_bedrock_nether_bottom_min
|
||||
mcl_vars.mg_bedrock_nether_top_min = mcl_vars.mg_bedrock_nether_top_max
|
||||
mcl_vars.mg_lava_nether_max = mcl_vars.mg_nether_min + 2
|
||||
end
|
||||
if mg_name == "flat" then
|
||||
if superflat then
|
||||
mcl_vars.mg_flat_nether_floor = mcl_vars.mg_bedrock_nether_bottom_max + 4
|
||||
mcl_vars.mg_flat_nether_ceiling = mcl_vars.mg_bedrock_nether_bottom_max + 52
|
||||
else
|
||||
mcl_vars.mg_flat_nether_floor = mcl_vars.mg_lava_nether_max + 4
|
||||
mcl_vars.mg_flat_nether_ceiling = mcl_vars.mg_lava_nether_max + 52
|
||||
end
|
||||
end
|
||||
|
||||
-- The End (surface at ca. Y = -27000)
|
||||
mcl_vars.mg_end_min = -27073 -- Carefully chosen to be at a mapchunk border
|
||||
mcl_vars.mg_end_max_official = mcl_vars.mg_end_min + minecraft_height_limit
|
||||
mcl_vars.mg_end_max = mcl_vars.mg_overworld_min - 2000
|
||||
mcl_vars.mg_end_platform_pos = { x = 100, y = mcl_vars.mg_end_min + 74, z = 0 }
|
||||
|
||||
-- Realm barrier used to safely separate the End from the void below the Overworld
|
||||
mcl_vars.mg_realm_barrier_overworld_end_max = mcl_vars.mg_end_max
|
||||
mcl_vars.mg_realm_barrier_overworld_end_min = mcl_vars.mg_end_max - 11
|
||||
|
||||
-- Use MineClone 2-style dungeons
|
||||
mcl_vars.mg_dungeons = true
|
||||
|
||||
-- Set default stack sizes
|
||||
minetest.nodedef_default.stack_max = 64
|
||||
minetest.craftitemdef_default.stack_max = 64
|
||||
|
||||
-- Set random seed for all other mods (Remember to make sure no other mod calls this function)
|
||||
math.randomseed(os.time())
|
||||
|
||||
local chunks = {} -- intervals of chunks generated
|
||||
function mcl_vars.add_chunk(pos)
|
||||
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
local prev
|
||||
for i, d in pairs(chunks) do
|
||||
if n <= d[2] then -- we've found it
|
||||
if (n == d[2]) or (n >= d[1]) then return end -- already here
|
||||
if n == d[1]-1 then -- right before:
|
||||
if prev and (prev[2] == n-1) then
|
||||
prev[2] = d[2]
|
||||
table.remove(chunks, i)
|
||||
return
|
||||
end
|
||||
d[1] = n
|
||||
return
|
||||
end
|
||||
if prev and (prev[2] == n-1) then --join to previous
|
||||
prev[2] = n
|
||||
return
|
||||
end
|
||||
table.insert(chunks, i, {n, n}) -- insert new interval before i
|
||||
return
|
||||
end
|
||||
prev = d
|
||||
end
|
||||
chunks[#chunks+1] = {n, n}
|
||||
end
|
||||
function mcl_vars.is_generated(pos)
|
||||
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
for i, d in pairs(chunks) do
|
||||
if n <= d[2] then
|
||||
return (n >= d[1])
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- "Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like mt 5.4 does.
|
||||
-- p: Position, if it's wrong, {name="error"} node will return.
|
||||
-- force: optional (default: false) - Do the maximum to still read the node within us_timeout.
|
||||
-- us_timeout: optional (default: 244 = 0.000244 s = 1/80/80/80), set it at least to 3000000 to let mapgen to finish its job.
|
||||
--
|
||||
-- returns node definition, eg. {name="air"}. Unfortunately still can return {name="ignore"}.
|
||||
function mcl_vars.get_node(p, force, us_timeout)
|
||||
-- check initial circumstances
|
||||
if not p or not p.x or not p.y or not p.z then return {name="error"} end
|
||||
|
||||
-- try common way
|
||||
local node = minetest.get_node(p)
|
||||
if node.name ~= "ignore" then
|
||||
return node
|
||||
end
|
||||
|
||||
-- copy table to get sure it won't changed by other threads
|
||||
local pos = {x=p.x,y=p.y,z=p.z}
|
||||
|
||||
-- try LVM
|
||||
minetest.get_voxel_manip():read_from_map(pos, pos)
|
||||
node = minetest.get_node(pos)
|
||||
if node.name ~= "ignore" or not force then
|
||||
return node
|
||||
end
|
||||
|
||||
-- all ways failed - need to emerge (or forceload if generated)
|
||||
local us_timeout = us_timeout or 244
|
||||
if mcl_vars.is_generated(pos) then
|
||||
minetest.chat_send_all("IMPOSSIBLE! Please report this to MCL2 issue tracker!")
|
||||
minetest.forceload_block(pos)
|
||||
else
|
||||
minetest.emerge_area(pos, pos)
|
||||
end
|
||||
|
||||
local t = minetest.get_us_time()
|
||||
|
||||
node = minetest.get_node(pos)
|
||||
|
||||
while (not node or node.name == "ignore") and (minetest.get_us_time() - t < us_timeout) do
|
||||
node = minetest.get_node(pos)
|
||||
end
|
||||
|
||||
return node
|
||||
-- it still can return "ignore", LOL, even if force = true, but only after time out
|
||||
end
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
# mcl_mapgen
|
||||
------------
|
||||
Helps to avoid problems caused by 'chunk-in-shell' feature of mapgen.cpp.
|
||||
|
||||
It also queues your generators to run them in proper order:
|
||||
|
||||
### mcl_mapgen.register_on_generated(lvm_callback_function, order_number)
|
||||
-------------------------------------------------------------------------
|
||||
Replacement of engine API function `minetest.register_on_generated(function(vm_context))`
|
||||
|
||||
It is still unsafe. Cavegen part can and will overwrite outer 1-block layer of the chunk which is expected to be generated.
|
||||
|
||||
Nodes marked as `is_ground_content` could be overwritten. Air and water are usually 'ground content' too.
|
||||
For Minetest 5.4 it doesn't recommended to place blocks within lvm callback function.
|
||||
|
||||
See https://git.minetest.land/MineClone2/MineClone2/issues/1395
|
||||
|
||||
* `lvm_callback_function`: chunk callback LVM function definition:
|
||||
* `function(vm_context)`:
|
||||
* `vm_context` will pass into next lvm callback function from the queue!
|
||||
* `vm_context`: a table which already contains some LVM data as the fields, and some of them can be added in your lvm callback function:
|
||||
* `vm`: curent voxel manipulator object itself;
|
||||
* `chunkseed`: seed of this mapchunk;
|
||||
* `minp` & `maxp`: minimum and maximum chunk position;
|
||||
* `emin` & `emax`: minimum and maximum chunk position WITH SHELL AROUND IT;
|
||||
* `area`: voxel area, can be helpful to access data;
|
||||
* `data`: LVM buffer data array, data loads into it before the callbacks;
|
||||
* `write`: set it to true in your lvm callback functionm, if you changed `data` and want to write it;
|
||||
* `param2_data`: LVM buffer data array of `param2`, *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - you load it yourself:
|
||||
* `vm_context.param2_data = vm_context.param2_data or vm_context.vm:get_param2_data(vm_context.lvm_param2_buffer)`
|
||||
* `write_param2`: set it to true in your lvm callback function, if you used `param2_data` and want to write it;
|
||||
* `light`: LVM buffer data array of light, *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - you load it yourself:
|
||||
* `vm_context.light = vm_context.light or vm_context.vm.get_light_data(vm_context.lvm_light_buffer)`
|
||||
* `write_light`: set it to true in your lvm callback function, if you used `light` and want to write it;
|
||||
* `lvm_param2_buffer`: static `param2` buffer pointer, used to load `param2_data` array;
|
||||
* `shadow`: set it to false to disable shadow propagation;
|
||||
* `heightmap`: mapgen object contanting y coordinates of ground level,
|
||||
* *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - load it yourself:
|
||||
* `vm_context.heightmap = vm_context.heightmap or minetest.get_mapgen_object('heightmap')`
|
||||
* `biomemap`: mapgen object contanting biome IDs of nodes,
|
||||
* *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - load it yourself:
|
||||
* `vm_context.biomemap = vm_context.biomemap or minetest.get_mapgen_object('biomemap')`
|
||||
* `heatmap`: mapgen object contanting temperature values of nodes,
|
||||
* *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - load it yourself:
|
||||
* `vm_context.heatmap = vm_context.heatmap or minetest.get_mapgen_object('heatmap')`
|
||||
* `humiditymap`: mapgen object contanting humidity values of nodes,
|
||||
* *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - load it yourself:
|
||||
* `vm_context.humiditymap = vm_context.humiditymap or minetest.get_mapgen_object('humiditymap')`
|
||||
* `gennotify`: mapgen object contanting mapping table of structures, see Minetest Lua API for explanation,
|
||||
* *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - load it yourself:
|
||||
* `vm_context.gennotify = vm_context.gennotify or minetest.get_mapgen_object('gennotify')`
|
||||
* `order_number` (optional): the less, the earlier,
|
||||
* e.g. `mcl_mapgen.order.BUILDINGS` or `mcl_mapgen.order.LARGE_BUILDINGS`
|
||||
|
||||
### mcl_mapgen.register_mapgen_block_lvm(lvm_callback_function, order_number)
|
||||
-----------------------------------------------------------------------------
|
||||
Registers lvm callback function to be called when current block (usually 16x16x16 nodes) generation is REALLY 100% finished.
|
||||
|
||||
`vm_context` passes into lvm callback function.
|
||||
* `lvm_callback_function`: the block callback LVM function definition - same as for chunks - see definition example above;
|
||||
* `order_number` (optional): the less, the earlier,
|
||||
* e.g. `mcl_mapgen.order.BUILDINGS` or `mcl_mapgen.order.LARGE_BUILDINGS`
|
||||
|
||||
### mcl_mapgen.register_mapgen_block(node_callback_function, order_number)
|
||||
--------------------------------------------------------------------------
|
||||
Registers node_callback function to be called when current block (usually 16x16x16 nodes) generation is REALLY 100% finished.
|
||||
* `node_callback_function`: node callback function definition:
|
||||
* `function(minp, maxp, seed)`:
|
||||
* `minp` & `maxp`: minimum and maximum block position;
|
||||
* `seed`: seed of this mapblock;
|
||||
* `order_number` (optional): the less, the earlier,
|
||||
* e.g. `mcl_mapgen.order.BUILDINGS` or `mcl_mapgen.order.LARGE_BUILDINGS`
|
||||
|
||||
### mcl_mapgen.register_mapgen(callback_function, order_number)
|
||||
---------------------------------------------------------------
|
||||
Registers callback function to be called when current chunk generation is REALLY 100% finished.
|
||||
|
||||
For LVM it's the most frustrating function from this mod.
|
||||
|
||||
It can't provide you access to mapgen objects. They are probably gone long ago.
|
||||
|
||||
Don't use it for accessing mapgen objects please.
|
||||
|
||||
To use VM you have to run `vm_context.vm = mcl_mapgen.get_voxel_manip(vm_context.emin, vm_context.emax)`.
|
||||
* `callback_function`: callback function definition:
|
||||
* `function(minp, maxp, seed, vm_context)`:
|
||||
* `minp` & `maxp`: minimum and maximum block position;
|
||||
* `seed`: seed of this mapblock;
|
||||
* `vm_context`: a table - see description above.
|
||||
* `order_number` (optional): the less, the earlier.
|
||||
|
||||
### mcl_mapgen.register_mapgen_lvm(lvm_callback_function, order_number)
|
||||
-----------------------------------------------------------------------
|
||||
Registers lvm callback function to be called when current chunk generation is REALLY 100% finished.
|
||||
|
||||
It's the most frustrating function from this mod. It can't provide you access to mapgen objects. They are probably gone long ago.
|
||||
|
||||
Don't use it for accessing mapgen objects please.
|
||||
|
||||
`vm_context` passes into lvm callback function.
|
||||
* `lvm_callback_function`: the block callback LVM function definition - same as above;
|
||||
* `order_number` (optional): the less, the earlier.
|
||||
|
||||
### mcl_mapgen.get_far_node(pos)
|
||||
--------------------------------
|
||||
Returns node if it is generated, otherwise returns `{name = "ignore"}`.
|
||||
|
||||
### mcl_mapgen.clamp_to_chunk(x, size)
|
||||
--------------------------------------
|
||||
Returns new `x`, slighty tuned to make structure of size `size` be within single chunk side of 80 nodes.
|
||||
|
||||
### function mcl_mapgen.get_chunk_beginning(x)
|
||||
----------------------------------------------
|
||||
Returns chunk beginning of `x`. It is the same as `minp.axis` for per-chunk callbacks, but we don't always have `minp`.
|
||||
|
||||
## Constants:
|
||||
* `mcl_mapgen.EDGE_MIN`, `mcl_mapgen.EDGE_MAX` - world edges, min & max.
|
||||
* `mcl_mapgen.seed`, `mcl_mapgen.name` - mapgen seed & name.
|
||||
* `mcl_mapgen.v6`, `mcl_mapgen.superflat`, `mcl_mapgen.singlenode` - is mapgen v6, superflat, singlenode.
|
||||
* `mcl_mapgen.normal` is mapgen normal (not superflat or singlenode).
|
|
@ -0,0 +1,574 @@
|
|||
mcl_mapgen = {}
|
||||
|
||||
local order = { -- mcl_mapgen.order...
|
||||
DEFAULT = 5000,
|
||||
CHORUS = 100000,
|
||||
BUILDINGS = 200000,
|
||||
VILLAGES = 900000,
|
||||
DUNGEONS = 950000,
|
||||
STRONGHOLDS = 999999,
|
||||
OCEAN_MONUMENT = 1000000,
|
||||
LARGE_BUILDINGS = 2000000,
|
||||
}
|
||||
|
||||
-- Begin of Compatibility stuff
|
||||
|
||||
local function unsigned(v)
|
||||
if v < 0 then
|
||||
v = 0x100000000 - (math.abs(v) % 0x100000000)
|
||||
end
|
||||
return v % 0x100000000
|
||||
end
|
||||
|
||||
if bit == nil then
|
||||
bit = {}
|
||||
function bit.bxor(a, b)
|
||||
local a = unsigned(a)
|
||||
local b = unsigned(b)
|
||||
local c = 0
|
||||
for n = 31, 0, -1 do
|
||||
local mask = math.floor(2^n)
|
||||
if (a >= mask) ~= (b >= mask) then
|
||||
c = c + mask
|
||||
end
|
||||
a = a % mask
|
||||
b = b % mask
|
||||
end
|
||||
return c
|
||||
end
|
||||
end
|
||||
|
||||
if vector.metatable == nil then
|
||||
function math.round(x)
|
||||
if x >= 0 then
|
||||
return math.floor(x + 0.5)
|
||||
end
|
||||
return math.ceil(x - 0.5)
|
||||
end
|
||||
dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/vector.lua")
|
||||
end
|
||||
|
||||
-- End of compatibility stuff
|
||||
|
||||
local math_floor = math.floor
|
||||
local math_max = math.max
|
||||
local minetest_get_node = minetest.get_node
|
||||
local minetest_get_voxel_manip = minetest.get_voxel_manip
|
||||
local minetest_log = minetest.log
|
||||
local minetest_pos_to_string = minetest.pos_to_string
|
||||
|
||||
-- Calculate mapgen_edge_min/mapgen_edge_max
|
||||
mcl_mapgen.CS = math_max(1, tonumber(minetest.get_mapgen_setting("chunksize")) or 5)
|
||||
mcl_mapgen.BS = math_max(1, core.MAP_BLOCKSIZE or 16)
|
||||
mcl_mapgen.LIMIT = math_max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000)
|
||||
mcl_mapgen.MAX_LIMIT = 31000 -- MAX_MAP_GENERATION_LIMIT, https://github.com/minetest/minetest/issues/10428
|
||||
mcl_mapgen.OFFSET = - math_floor(mcl_mapgen.CS / 2)
|
||||
mcl_mapgen.OFFSET_NODES = mcl_mapgen.OFFSET * mcl_mapgen.BS
|
||||
mcl_mapgen.CS_NODES = mcl_mapgen.CS * mcl_mapgen.BS
|
||||
mcl_mapgen.LAST_BLOCK = mcl_mapgen.CS - 1
|
||||
mcl_mapgen.LAST_NODE_IN_BLOCK = mcl_mapgen.BS - 1
|
||||
mcl_mapgen.LAST_NODE_IN_CHUNK = mcl_mapgen.CS_NODES - 1
|
||||
mcl_mapgen.HALF_CS_NODES = math_floor(mcl_mapgen.CS_NODES / 2)
|
||||
mcl_mapgen.HALF_BS = math_floor(mcl_mapgen.BS / 2)
|
||||
mcl_mapgen.CS_3D = mcl_mapgen.CS^3
|
||||
mcl_mapgen.CHUNK_WITH_SHELL = mcl_mapgen.CS + 2
|
||||
mcl_mapgen.CHUNK_WITH_SHELL_3D = mcl_mapgen.CHUNK_WITH_SHELL^3
|
||||
|
||||
local central_chunk_min_pos = mcl_mapgen.OFFSET * mcl_mapgen.BS
|
||||
local central_chunk_max_pos = central_chunk_min_pos + mcl_mapgen.CS_NODES - 1
|
||||
|
||||
local ccfmin = central_chunk_min_pos - mcl_mapgen.BS -- Fullminp/fullmaxp of central chunk, in nodes
|
||||
local ccfmax = central_chunk_max_pos + mcl_mapgen.BS
|
||||
|
||||
local mapgen_limit_b = math_floor(math.min(mcl_mapgen.LIMIT, mcl_mapgen.MAX_LIMIT) / mcl_mapgen.BS)
|
||||
local mapgen_limit_min = - mapgen_limit_b * mcl_mapgen.BS
|
||||
local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_mapgen.BS - 1
|
||||
|
||||
local numcmin = math_max(math_floor((ccfmin - mapgen_limit_min) / mcl_mapgen.CS_NODES), 0) -- Number of complete chunks from central chunk
|
||||
local numcmax = math_max(math_floor((mapgen_limit_max - ccfmax) / mcl_mapgen.CS_NODES), 0) -- fullminp/fullmaxp to effective mapgen limits.
|
||||
|
||||
mcl_mapgen.EDGE_MIN = central_chunk_min_pos - numcmin * mcl_mapgen.CS_NODES
|
||||
mcl_mapgen.EDGE_MAX = central_chunk_max_pos + numcmax * mcl_mapgen.CS_NODES
|
||||
|
||||
minetest_log("action", "[mcl_mapgen] World edges: mcl_mapgen.EDGE_MIN = " .. tostring(mcl_mapgen.EDGE_MIN) .. ", mcl_mapgen.EDGE_MAX = " .. tostring(mcl_mapgen.EDGE_MAX))
|
||||
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Mapgen variables
|
||||
local overworld, end_, nether = {}, {}, {}
|
||||
local seed = minetest.get_mapgen_setting("seed")
|
||||
mcl_mapgen.seed = seed
|
||||
mcl_mapgen.name = minetest.get_mapgen_setting("mg_name")
|
||||
mcl_mapgen.v6 = mcl_mapgen.name == "v6"
|
||||
mcl_mapgen.flat = mcl_mapgen.name == "flat"
|
||||
mcl_mapgen.superflat = mcl_mapgen.flat and minetest.get_mapgen_setting("mcl_superflat_classic") == "true"
|
||||
mcl_mapgen.singlenode = mcl_mapgen.name == "singlenode"
|
||||
mcl_mapgen.normal = not mcl_mapgen.superflat and not mcl_mapgen.singlenode
|
||||
local flat, superflat, singlenode, normal = mcl_mapgen.flat, mcl_mapgen.superflat, mcl_mapgen.singlenode, mcl_mapgen.normal
|
||||
|
||||
minetest_log("action", "[mcl_mapgen] Mapgen mode: " .. (normal and "normal" or (superflat and "superflat" or (flat and "flat" or "singlenode"))))
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Generator queues
|
||||
local queue_unsafe_engine = {}
|
||||
local queue_chunks_nodes = {}
|
||||
local queue_chunks_lvm = {}
|
||||
local queue_blocks_nodes = {}
|
||||
local queue_blocks_lvm = {}
|
||||
|
||||
-- Requirements. 0 means 'none', greater than 0 means 'required'
|
||||
local block = 0
|
||||
local queue_blocks_lvm_counter = 0
|
||||
local lvm_chunk = 0
|
||||
local param2 = 0
|
||||
local nodes_block = 0
|
||||
local nodes_chunk = 0
|
||||
local safe_functions = 0
|
||||
|
||||
local BS, CS = mcl_mapgen.BS, mcl_mapgen.CS -- Mapblock size (in nodes), Mapchunk size (in blocks)
|
||||
local offset = mcl_mapgen.OFFSET -- Central mapchunk offset (in blocks)
|
||||
local CS_NODES = mcl_mapgen.CS_NODES
|
||||
local LAST_BLOCK = mcl_mapgen.LAST_BLOCK
|
||||
local LAST_NODE_IN_BLOCK = mcl_mapgen.LAST_NODE_IN_BLOCK
|
||||
local LAST_NODE_IN_CHUNK = mcl_mapgen.LAST_NODE_IN_CHUNK
|
||||
local HALF_CS_NODES = mcl_mapgen.HALF_CS_NODES
|
||||
local CS_3D = mcl_mapgen.CS_3D
|
||||
local CHUNK_WITH_SHELL = mcl_mapgen.CHUNK_WITH_SHELL
|
||||
local CHUNK_WITH_SHELL_3D = mcl_mapgen.CHUNK_WITH_SHELL_3D
|
||||
|
||||
local DEFAULT_ORDER = order.DEFAULT
|
||||
|
||||
function mcl_mapgen.register_on_generated(callback_function, order)
|
||||
queue_unsafe_engine[#queue_unsafe_engine+1] = {i = order or DEFAULT_ORDER, f = callback_function}
|
||||
table.sort(queue_unsafe_engine, function(a, b) return (a.i <= b.i) end)
|
||||
end
|
||||
function mcl_mapgen.register_mapgen(callback_function, order)
|
||||
nodes_chunk = nodes_chunk + 1
|
||||
safe_functions = safe_functions + 1
|
||||
queue_chunks_nodes[nodes_chunk] = {i = order or DEFAULT_ORDER, f = callback_function}
|
||||
table.sort(queue_chunks_nodes, function(a, b) return (a.i <= b.i) end)
|
||||
end
|
||||
function mcl_mapgen.register_mapgen_lvm(callback_function, order)
|
||||
lvm_chunk = lvm_chunk + 1
|
||||
safe_functions = safe_functions + 1
|
||||
queue_chunks_lvm[lvm_chunk] = {i = order or DEFAULT_ORDER, f = callback_function}
|
||||
table.sort(queue_chunks_lvm, function(a, b) return (a.i <= b.i) end)
|
||||
end
|
||||
function mcl_mapgen.register_mapgen_block(callback_function, order)
|
||||
block = block + 1
|
||||
nodes_block = nodes_block + 1
|
||||
safe_functions = safe_functions + 1
|
||||
queue_blocks_nodes[nodes_block] = {i = order or DEFAULT_ORDER, f = callback_function}
|
||||
table.sort(queue_blocks_nodes, function(a, b) return (a.i <= b.i) end)
|
||||
end
|
||||
function mcl_mapgen.register_mapgen_block_lvm(callback_function, order)
|
||||
block = block + 1
|
||||
queue_blocks_lvm_counter = queue_blocks_lvm_counter + 1
|
||||
safe_functions = safe_functions + 1
|
||||
queue_blocks_lvm[queue_blocks_lvm_counter] = {order = order or DEFAULT_ORDER, callback_function = callback_function}
|
||||
table.sort(queue_blocks_lvm, function(a, b) return (a.order <= b.order) end)
|
||||
end
|
||||
|
||||
local vm_context -- here will be many references and flags, like: param2, light_data, heightmap, biomemap, heatmap, humiditymap, gennotify, write_lvm, write_param2, shadow
|
||||
local data, param2_data, light, area
|
||||
local lvm_buffer, lvm_param2_buffer, lvm_light_buffer = {}, {}, {} -- Static buffer pointers
|
||||
|
||||
local all_blocks_in_chunk = {}
|
||||
for x = -1, LAST_BLOCK+1 do
|
||||
for y = -1, LAST_BLOCK+1 do
|
||||
for z = -1, LAST_BLOCK+1 do
|
||||
all_blocks_in_chunk[CHUNK_WITH_SHELL * (CHUNK_WITH_SHELL * y + z) + x] = vector.new(x, y, z)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local chunk_scan_range = {
|
||||
[-CS_NODES] = {-1 , -1 },
|
||||
[ 0 ] = {-1 , LAST_BLOCK+1},
|
||||
[ CS_NODES] = {LAST_BLOCK+1, LAST_BLOCK+1},
|
||||
}
|
||||
|
||||
local function is_chunk_finished(minp)
|
||||
local center = vector.add(minp, HALF_CS_NODES)
|
||||
for check_x = center.x - CS_NODES, center.x + CS_NODES, CS_NODES do
|
||||
for check_y = center.y - CS_NODES, center.y + CS_NODES, CS_NODES do
|
||||
for check_z = center.z - CS_NODES, center.z + CS_NODES, CS_NODES do
|
||||
local pos = vector.new(check_x, check_y, check_z)
|
||||
if pos ~= center then
|
||||
minetest_get_voxel_manip():read_from_map(pos, pos)
|
||||
local node = minetest_get_node(pos)
|
||||
if node.name == "ignore" then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function uint32_t(v)
|
||||
if v >= 0 then
|
||||
return v % 0x100000000
|
||||
end
|
||||
return 0x100000000 - (math.abs(v) % 0x100000000)
|
||||
end
|
||||
|
||||
local function get_block_seed(pos, current_seed)
|
||||
local current_seed = current_seed or uint32_t(tonumber(seed))
|
||||
return uint32_t(uint32_t(23 * pos.x) + uint32_t(42123 * pos.y) + uint32_t(38134234 * pos.z) + current_seed)
|
||||
end
|
||||
|
||||
local function get_block_seed2(pos, current_seed)
|
||||
local current_seed = current_seed or uint32_t(tonumber(seed))
|
||||
local n = uint32_t(uint32_t(1619 * pos.x) + uint32_t(31337 * pos.y) + uint32_t(52591 * pos.z) + uint32_t(1013 * current_seed))
|
||||
n = bit.bxor(bit.rshift(n, 13), n)
|
||||
local seed = uint32_t((n * uint32_t(n * n * 60493 + 19990303) + 1376312589))
|
||||
return seed
|
||||
end
|
||||
|
||||
local function get_block_seed3(pos, current_seed)
|
||||
local current_seed = uint32_t(current_seed or uint32_t(tonumber(seed)))
|
||||
local x = uint32_t((pos.x + 32768) * 13)
|
||||
local y = uint32_t((pos.y + 32767) * 13873)
|
||||
local z = uint32_t((pos.z + 76705) * 115249)
|
||||
local seed = uint32_t(bit.bxor(current_seed, x, y, z))
|
||||
return seed
|
||||
end
|
||||
|
||||
minetest.register_on_generated(function(minp, maxp, chunkseed)
|
||||
local minp, maxp, chunkseed = minp, maxp, chunkseed
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
data = vm:get_data(lvm_buffer)
|
||||
area = VoxelArea:new({MinEdge=emin, MaxEdge=emax})
|
||||
vm_context = {
|
||||
data = data,
|
||||
param2_data = param2_data,
|
||||
light = light,
|
||||
area = area,
|
||||
lvm_buffer = lvm_buffer,
|
||||
lvm_param2_buffer = lvm_param2_buffer,
|
||||
lvm_light_buffer = lvm_light_buffer,
|
||||
vm = vm,
|
||||
emin = emin,
|
||||
emax = emax,
|
||||
minp = minp,
|
||||
maxp = maxp,
|
||||
chunkseed = chunkseed,
|
||||
}
|
||||
|
||||
local current_blocks = {}
|
||||
local current_chunks = {}
|
||||
if safe_functions > 0 then
|
||||
local ready_blocks = table.copy(all_blocks_in_chunk)
|
||||
local p0 = vector.new(minp)
|
||||
local center = vector.add(p0, HALF_CS_NODES)
|
||||
for x = -CS_NODES, CS_NODES, CS_NODES do
|
||||
for y = -CS_NODES, CS_NODES, CS_NODES do
|
||||
for z = -CS_NODES, CS_NODES, CS_NODES do
|
||||
if x ~= 0 or y ~= 0 or z ~= 0 then
|
||||
local offset = vector.new(x, y, z)
|
||||
local pos = center + offset
|
||||
minetest_get_voxel_manip():read_from_map(pos, pos)
|
||||
local node = minetest_get_node(pos)
|
||||
local is_generated = node.name ~= "ignore"
|
||||
if is_generated then
|
||||
local adjacent_chunk_pos = p0 + offset
|
||||
if is_chunk_finished(adjacent_chunk_pos) then
|
||||
current_chunks[#current_chunks + 1] = adjacent_chunk_pos
|
||||
end
|
||||
else
|
||||
local scan_range_x = chunk_scan_range[x]
|
||||
for cut_x = scan_range_x[1], scan_range_x[2] do
|
||||
local scan_range_y = chunk_scan_range[y]
|
||||
for cut_y = scan_range_y[1], scan_range_y[2] do
|
||||
local scan_range_z = chunk_scan_range[z]
|
||||
for cut_z = scan_range_z[1], scan_range_z[2] do
|
||||
ready_blocks[CHUNK_WITH_SHELL * (CHUNK_WITH_SHELL * cut_y + cut_z) + cut_x] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local number_of_blocks = 0
|
||||
for k, offset in pairs(ready_blocks) do
|
||||
if queue_blocks_lvm_counter > 0 or nodes_block > 0 then
|
||||
local block_minp = p0 + vector.multiply(offset, BS)
|
||||
local block_maxp = vector.add(block_minp, LAST_NODE_IN_BLOCK)
|
||||
local blockseed = get_block_seed3(block_minp)
|
||||
vm_context.minp, vm_context.maxp, vm_context.blockseed = block_minp, block_maxp, blockseed
|
||||
-- --
|
||||
-- mcl_mapgen.register_mapgen_block_lvm(function(vm_context), order_number) --
|
||||
-- --
|
||||
for _, v in pairs(queue_blocks_lvm) do
|
||||
v.callback_function(vm_context)
|
||||
end
|
||||
if nodes_block > 0 then
|
||||
current_blocks[#current_blocks + 1] = { minp = block_minp, maxp = block_maxp, blockseed = blockseed }
|
||||
end
|
||||
end
|
||||
number_of_blocks = number_of_blocks + 1
|
||||
end
|
||||
if number_of_blocks == CHUNK_WITH_SHELL_3D then
|
||||
current_chunks[#current_chunks + 1] = p0
|
||||
end
|
||||
end
|
||||
|
||||
if #queue_unsafe_engine > 0 then
|
||||
vm_context.minp, vm_context.maxp = minp, maxp
|
||||
-- * U N S A F E --
|
||||
-- mcl_mapgen.register_on_generated(function(vm_context), order_number) --
|
||||
-- * U N S A F E --
|
||||
for _, v in pairs(queue_unsafe_engine) do
|
||||
v.f(vm_context)
|
||||
end
|
||||
if vm_context.write then
|
||||
vm:set_data(data)
|
||||
end
|
||||
if vm_context.write_param2 then
|
||||
vm:set_param2_data(vm_context.param2_data)
|
||||
end
|
||||
if vm_context.write_light then
|
||||
vm:set_light_data(light)
|
||||
end
|
||||
if vm_context.write or vm_context.write_param2 or vm_context.write_light then
|
||||
vm:calc_lighting(minp, maxp, (vm_context.shadow ~= nil) or true)
|
||||
vm:write_to_map()
|
||||
vm:update_liquids()
|
||||
elseif vm_context.calc_lighting then
|
||||
vm:calc_lighting(minp, maxp, (vm_context.shadow ~= nil) or true)
|
||||
end
|
||||
end
|
||||
|
||||
for i, chunk_minp in pairs(current_chunks) do
|
||||
local chunk_maxp = vector.add(chunk_minp, LAST_NODE_IN_CHUNK)
|
||||
local current_chunk_seed = get_block_seed3(vector.subtract(chunk_minp, BS))
|
||||
area = VoxelArea:new({MinEdge=minp, MaxEdge=maxp})
|
||||
vm_context = {
|
||||
data = data,
|
||||
param2_data = param2_data,
|
||||
light = light,
|
||||
area = area,
|
||||
lvm_buffer = lvm_buffer,
|
||||
lvm_param2_buffer = lvm_param2_buffer,
|
||||
lvm_light_buffer = lvm_light_buffer,
|
||||
emin = chunk_minp,
|
||||
emax = chunk_maxp,
|
||||
minp = chunk_minp,
|
||||
maxp = chunk_maxp,
|
||||
chunkseed = current_chunk_seed,
|
||||
}
|
||||
-- --
|
||||
-- mcl_mapgen.register_mapgen_lvm(function(vm_context), order_number) --
|
||||
-- --
|
||||
for _, v in pairs(queue_chunks_lvm) do
|
||||
v.f(vm_context)
|
||||
end
|
||||
-- --
|
||||
-- mcl_mapgen.register_mapgen(function(minp, maxp, chunkseed, vm_context), order_number) --
|
||||
-- --
|
||||
for _, v in pairs(queue_chunks_nodes) do
|
||||
v.f(chunk_minp, chunk_maxp, current_chunk_seed, vm_context)
|
||||
end
|
||||
if vm_context.write or vm_context.write_param2 or vm_context.write_light then
|
||||
if vm_context.write then
|
||||
vm:set_data(data)
|
||||
end
|
||||
if vm_context.write_param2 then
|
||||
vm:set_param2_data(param2_data)
|
||||
end
|
||||
if vm_context.write_light then
|
||||
vm:set_light_data(light)
|
||||
end
|
||||
-- caused error from torches (?)
|
||||
-- vm:calc_lighting(minp, maxp, vm_context.shadow or true)
|
||||
vm:write_to_map()
|
||||
vm:update_liquids()
|
||||
elseif vm_context.calc_lighting then
|
||||
vm:calc_lighting(minp, maxp, (vm_context.shadow ~= nil) or true)
|
||||
end
|
||||
end
|
||||
|
||||
for _, b in pairs(current_blocks) do
|
||||
-- --
|
||||
-- mcl_mapgen.register_mapgen_block(function(minp, maxp, blockseed), order_number) --
|
||||
-- --
|
||||
for _, v in pairs(queue_blocks_nodes) do
|
||||
v.f(b.minp, b.maxp, b.blockseed)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_generated = mcl_mapgen.register_chunk_generator
|
||||
|
||||
function mcl_mapgen.get_far_node(p)
|
||||
local p = p
|
||||
local node = minetest_get_node(p)
|
||||
if node.name ~= "ignore" then return node end
|
||||
minetest_get_voxel_manip():read_from_map(p, p)
|
||||
return minetest_get_node(p)
|
||||
end
|
||||
|
||||
local function coordinate_to_block(x)
|
||||
return math_floor(x / BS)
|
||||
end
|
||||
|
||||
local function coordinate_to_chunk(x)
|
||||
return math_floor((coordinate_to_block(x) - offset) / CS)
|
||||
end
|
||||
|
||||
function mcl_mapgen.pos_to_block(pos)
|
||||
return {
|
||||
x = coordinate_to_block(pos.x),
|
||||
y = coordinate_to_block(pos.y),
|
||||
z = coordinate_to_block(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
function mcl_mapgen.pos_to_chunk(pos)
|
||||
return {
|
||||
x = coordinate_to_chunk(pos.x),
|
||||
y = coordinate_to_chunk(pos.y),
|
||||
z = coordinate_to_chunk(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
local k_positive = math.ceil(mcl_mapgen.MAX_LIMIT / mcl_mapgen.CS_NODES)
|
||||
local k_positive_z = k_positive * 2
|
||||
local k_positive_y = k_positive_z * k_positive_z
|
||||
|
||||
function mcl_mapgen.get_chunk_number(pos) -- unsigned int
|
||||
local c = mcl_mapgen.pos_to_chunk(pos)
|
||||
return
|
||||
(c.y + k_positive) * k_positive_y +
|
||||
(c.z + k_positive) * k_positive_z +
|
||||
c.x + k_positive
|
||||
end
|
||||
|
||||
mcl_mapgen.minecraft_height_limit = 256
|
||||
|
||||
mcl_mapgen.bedrock_is_rough = normal
|
||||
|
||||
-- Overworld
|
||||
overworld.min = -62
|
||||
if superflat then
|
||||
mcl_mapgen.ground = tonumber(minetest.get_mapgen_setting("mgflat_ground_level")) or 8
|
||||
overworld.min = mcl_mapgen.ground - 3
|
||||
end
|
||||
-- if singlenode then mcl_mapgen.overworld.min = -66 end -- DONT KNOW WHY
|
||||
overworld.max = mcl_mapgen.EDGE_MAX
|
||||
|
||||
overworld.bedrock_min = overworld.min
|
||||
overworld.bedrock_max = overworld.bedrock_min + (mcl_mapgen.bedrock_is_rough and 4 or 0)
|
||||
|
||||
mcl_mapgen.lava = normal
|
||||
overworld.lava_max = overworld.min + (normal and 10 or 0)
|
||||
|
||||
|
||||
-- The Nether (around Y = -29000)
|
||||
nether.min = -29067 -- Carefully chosen to be at a mapchunk border
|
||||
nether.max = nether.min + 128
|
||||
nether.bedrock_bottom_min = nether.min
|
||||
nether.bedrock_top_max = nether.max
|
||||
if not superflat then
|
||||
nether.bedrock_bottom_max = nether.bedrock_bottom_min + 4
|
||||
nether.bedrock_top_min = nether.bedrock_top_max - 4
|
||||
nether.lava_max = nether.min + 31
|
||||
else
|
||||
-- Thin bedrock in classic superflat mapgen
|
||||
nether.bedrock_bottom_max = nether.bedrock_bottom_min
|
||||
nether.bedrock_top_min = nether.bedrock_top_max
|
||||
nether.lava_max = nether.min + 2
|
||||
end
|
||||
if superflat then
|
||||
nether.flat_floor = nether.bedrock_bottom_max + 4
|
||||
nether.flat_ceiling = nether.bedrock_bottom_max + 52
|
||||
elseif flat then
|
||||
nether.flat_floor = nether.lava_max + 4
|
||||
nether.flat_ceiling = nether.lava_max + 52
|
||||
end
|
||||
|
||||
-- The End (surface at ca. Y = -27000)
|
||||
end_.min = -27073 -- Carefully chosen to be at a mapchunk border
|
||||
end_.max = overworld.min - 2000
|
||||
end_.platform_pos = { x = 100, y = end_.min + 74, z = 0 }
|
||||
|
||||
-- Realm barrier used to safely separate the End from the void below the Overworld
|
||||
mcl_mapgen.realm_barrier_overworld_end_max = end_.max
|
||||
mcl_mapgen.realm_barrier_overworld_end_min = end_.max - 11
|
||||
|
||||
-- Use MineClone 2-style dungeons for normal mapgen
|
||||
mcl_mapgen.dungeons = normal
|
||||
|
||||
mcl_mapgen.overworld = overworld
|
||||
mcl_mapgen.end_ = end_
|
||||
mcl_mapgen["end"] = mcl_mapgen.end_
|
||||
mcl_mapgen.nether = nether
|
||||
|
||||
mcl_mapgen.order = order
|
||||
|
||||
function mcl_mapgen.get_voxel_manip(vm_context)
|
||||
if vm_context.vm then
|
||||
return vm
|
||||
end
|
||||
vm_context.vm = minetest.get_voxel_manip(vm_context.emin, vm_context.emax)
|
||||
vm_context.emin, vm_context.emax = vm_context.vm:read_from_map(vm_context.emin, vm_context.emax)
|
||||
vm_context.area = VoxelArea:new({MinEdge=vm_context.emin, MaxEdge=vm_context.emax})
|
||||
return vm_context.vm
|
||||
end
|
||||
|
||||
function mcl_mapgen.clamp_to_chunk(x, size)
|
||||
if not size then
|
||||
minetest.log("warning", "[mcl_mapgen] Couldn't clamp " .. tostring(x) .. " - missing size")
|
||||
return x
|
||||
end
|
||||
if size > CS_NODES then
|
||||
minetest.log("warning", "[mcl_mapgen] Couldn't clamp " .. tostring(x) .. " - given size " .. tostring(size) .. " greater than chunk size " .. tostring(mcl_mapgen.CS_NODES))
|
||||
return x
|
||||
end
|
||||
local offset_in_chunk = (x + central_chunk_min_pos) % CS_NODES
|
||||
local x2_in_chunk = offset_in_chunk + size
|
||||
if x2_in_chunk <= CS_NODES then
|
||||
return x
|
||||
end
|
||||
local overflow = x2_in_chunk - CS_NODES
|
||||
if overflow > size / 2 then
|
||||
local next_x = x + (size - overflow)
|
||||
if next_x < mcl_mapgen.EDGE_MAX then
|
||||
return next_x
|
||||
end
|
||||
end
|
||||
return x - overflow
|
||||
end
|
||||
|
||||
function mcl_mapgen.get_chunk_beginning(x)
|
||||
if tonumber(x) then
|
||||
return x - ((x + central_chunk_min_pos) % CS_NODES)
|
||||
end
|
||||
if x.x then
|
||||
return {
|
||||
x = mcl_mapgen.get_chunk_beginning(x.x),
|
||||
y = mcl_mapgen.get_chunk_beginning(x.y),
|
||||
z = mcl_mapgen.get_chunk_beginning(x.z)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_mapgen.get_chunk_ending(x)
|
||||
if tonumber(x) then
|
||||
return mcl_mapgen.get_chunk_beginning(x) + LAST_NODE_IN_CHUNK
|
||||
end
|
||||
if x.x then
|
||||
return {
|
||||
x = mcl_mapgen.get_chunk_beginning(x.x) + LAST_NODE_IN_CHUNK,
|
||||
y = mcl_mapgen.get_chunk_beginning(x.y) + LAST_NODE_IN_CHUNK,
|
||||
z = mcl_mapgen.get_chunk_beginning(x.z) + LAST_NODE_IN_CHUNK
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
mcl_mapgen.get_block_seed = get_block_seed
|
||||
mcl_mapgen.get_block_seed2 = get_block_seed2
|
||||
mcl_mapgen.get_block_seed3 = get_block_seed3
|
|
@ -0,0 +1,4 @@
|
|||
name = mcl_mapgen
|
||||
author = kay27
|
||||
description = MineClone 2/5 MapGen Basic Stuff
|
||||
depends = mcl_init
|
|
@ -0,0 +1,362 @@
|
|||
--[[
|
||||
Vector helpers
|
||||
Note: The vector.*-functions must be able to accept old vectors that had no metatables
|
||||
]]
|
||||
|
||||
-- localize functions
|
||||
local setmetatable = setmetatable
|
||||
|
||||
vector = {}
|
||||
|
||||
local metatable = {}
|
||||
vector.metatable = metatable
|
||||
|
||||
local xyz = {"x", "y", "z"}
|
||||
|
||||
-- only called when rawget(v, key) returns nil
|
||||
function metatable.__index(v, key)
|
||||
return rawget(v, xyz[key]) or vector[key]
|
||||
end
|
||||
|
||||
-- only called when rawget(v, key) returns nil
|
||||
function metatable.__newindex(v, key, value)
|
||||
rawset(v, xyz[key] or key, value)
|
||||
end
|
||||
|
||||
-- constructors
|
||||
|
||||
local function fast_new(x, y, z)
|
||||
return setmetatable({x = x, y = y, z = z}, metatable)
|
||||
end
|
||||
|
||||
function vector.new(a, b, c)
|
||||
if a and b and c then
|
||||
return fast_new(a, b, c)
|
||||
end
|
||||
|
||||
-- deprecated, use vector.copy and vector.zero directly
|
||||
if type(a) == "table" then
|
||||
return vector.copy(a)
|
||||
else
|
||||
assert(not a, "Invalid arguments for vector.new()")
|
||||
return vector.zero()
|
||||
end
|
||||
end
|
||||
|
||||
function vector.zero()
|
||||
return fast_new(0, 0, 0)
|
||||
end
|
||||
|
||||
function vector.copy(v)
|
||||
assert(v.x and v.y and v.z, "Invalid vector passed to vector.copy()")
|
||||
return fast_new(v.x, v.y, v.z)
|
||||
end
|
||||
|
||||
function vector.from_string(s, init)
|
||||
local x, y, z, np = string.match(s, "^%s*%(%s*([^%s,]+)%s*[,%s]%s*([^%s,]+)%s*[,%s]" ..
|
||||
"%s*([^%s,]+)%s*[,%s]?%s*%)()", init)
|
||||
x = tonumber(x)
|
||||
y = tonumber(y)
|
||||
z = tonumber(z)
|
||||
if not (x and y and z) then
|
||||
return nil
|
||||
end
|
||||
return fast_new(x, y, z), np
|
||||
end
|
||||
|
||||
function vector.to_string(v)
|
||||
return string.format("(%g, %g, %g)", v.x, v.y, v.z)
|
||||
end
|
||||
metatable.__tostring = vector.to_string
|
||||
|
||||
function vector.equals(a, b)
|
||||
return a.x == b.x and
|
||||
a.y == b.y and
|
||||
a.z == b.z
|
||||
end
|
||||
metatable.__eq = vector.equals
|
||||
|
||||
-- unary operations
|
||||
|
||||
function vector.length(v)
|
||||
return math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z)
|
||||
end
|
||||
-- Note: we can not use __len because it is already used for primitive table length
|
||||
|
||||
function vector.normalize(v)
|
||||
local len = vector.length(v)
|
||||
if len == 0 then
|
||||
return fast_new(0, 0, 0)
|
||||
else
|
||||
return vector.divide(v, len)
|
||||
end
|
||||
end
|
||||
|
||||
function vector.floor(v)
|
||||
return vector.apply(v, math.floor)
|
||||
end
|
||||
|
||||
function vector.round(v)
|
||||
return fast_new(
|
||||
math.round(v.x),
|
||||
math.round(v.y),
|
||||
math.round(v.z)
|
||||
)
|
||||
end
|
||||
|
||||
function vector.apply(v, func)
|
||||
return fast_new(
|
||||
func(v.x),
|
||||
func(v.y),
|
||||
func(v.z)
|
||||
)
|
||||
end
|
||||
|
||||
function vector.distance(a, b)
|
||||
local x = a.x - b.x
|
||||
local y = a.y - b.y
|
||||
local z = a.z - b.z
|
||||
return math.sqrt(x * x + y * y + z * z)
|
||||
end
|
||||
|
||||
function vector.direction(pos1, pos2)
|
||||
return vector.subtract(pos2, pos1):normalize()
|
||||
end
|
||||
|
||||
function vector.angle(a, b)
|
||||
local dotp = vector.dot(a, b)
|
||||
local cp = vector.cross(a, b)
|
||||
local crossplen = vector.length(cp)
|
||||
return math.atan2(crossplen, dotp)
|
||||
end
|
||||
|
||||
function vector.dot(a, b)
|
||||
return a.x * b.x + a.y * b.y + a.z * b.z
|
||||
end
|
||||
|
||||
function vector.cross(a, b)
|
||||
return fast_new(
|
||||
a.y * b.z - a.z * b.y,
|
||||
a.z * b.x - a.x * b.z,
|
||||
a.x * b.y - a.y * b.x
|
||||
)
|
||||
end
|
||||
|
||||
function metatable.__unm(v)
|
||||
return fast_new(-v.x, -v.y, -v.z)
|
||||
end
|
||||
|
||||
-- add, sub, mul, div operations
|
||||
|
||||
function vector.add(a, b)
|
||||
if type(b) == "table" then
|
||||
return fast_new(
|
||||
a.x + b.x,
|
||||
a.y + b.y,
|
||||
a.z + b.z
|
||||
)
|
||||
else
|
||||
return fast_new(
|
||||
a.x + b,
|
||||
a.y + b,
|
||||
a.z + b
|
||||
)
|
||||
end
|
||||
end
|
||||
function metatable.__add(a, b)
|
||||
return fast_new(
|
||||
a.x + b.x,
|
||||
a.y + b.y,
|
||||
a.z + b.z
|
||||
)
|
||||
end
|
||||
|
||||
function vector.subtract(a, b)
|
||||
if type(b) == "table" then
|
||||
return fast_new(
|
||||
a.x - b.x,
|
||||
a.y - b.y,
|
||||
a.z - b.z
|
||||
)
|
||||
else
|
||||
return fast_new(
|
||||
a.x - b,
|
||||
a.y - b,
|
||||
a.z - b
|
||||
)
|
||||
end
|
||||
end
|
||||
function metatable.__sub(a, b)
|
||||
return fast_new(
|
||||
a.x - b.x,
|
||||
a.y - b.y,
|
||||
a.z - b.z
|
||||
)
|
||||
end
|
||||
|
||||
function vector.multiply(a, b)
|
||||
if type(b) == "table" then
|
||||
return fast_new(
|
||||
a.x * b.x,
|
||||
a.y * b.y,
|
||||
a.z * b.z
|
||||
)
|
||||
else
|
||||
return fast_new(
|
||||
a.x * b,
|
||||
a.y * b,
|
||||
a.z * b
|
||||
)
|
||||
end
|
||||
end
|
||||
function metatable.__mul(a, b)
|
||||
if type(a) == "table" then
|
||||
return fast_new(
|
||||
a.x * b,
|
||||
a.y * b,
|
||||
a.z * b
|
||||
)
|
||||
else
|
||||
return fast_new(
|
||||
a * b.x,
|
||||
a * b.y,
|
||||
a * b.z
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function vector.divide(a, b)
|
||||
if type(b) == "table" then
|
||||
return fast_new(
|
||||
a.x / b.x,
|
||||
a.y / b.y,
|
||||
a.z / b.z
|
||||
)
|
||||
else
|
||||
return fast_new(
|
||||
a.x / b,
|
||||
a.y / b,
|
||||
a.z / b
|
||||
)
|
||||
end
|
||||
end
|
||||
function metatable.__div(a, b)
|
||||
-- scalar/vector makes no sense
|
||||
return fast_new(
|
||||
a.x / b,
|
||||
a.y / b,
|
||||
a.z / b
|
||||
)
|
||||
end
|
||||
|
||||
-- misc stuff
|
||||
|
||||
function vector.offset(v, x, y, z)
|
||||
return fast_new(
|
||||
v.x + x,
|
||||
v.y + y,
|
||||
v.z + z
|
||||
)
|
||||
end
|
||||
|
||||
function vector.sort(a, b)
|
||||
return fast_new(math.min(a.x, b.x), math.min(a.y, b.y), math.min(a.z, b.z)),
|
||||
fast_new(math.max(a.x, b.x), math.max(a.y, b.y), math.max(a.z, b.z))
|
||||
end
|
||||
|
||||
function vector.check(v)
|
||||
return getmetatable(v) == metatable
|
||||
end
|
||||
|
||||
local function sin(x)
|
||||
if x % math.pi == 0 then
|
||||
return 0
|
||||
else
|
||||
return math.sin(x)
|
||||
end
|
||||
end
|
||||
|
||||
local function cos(x)
|
||||
if x % math.pi == math.pi / 2 then
|
||||
return 0
|
||||
else
|
||||
return math.cos(x)
|
||||
end
|
||||
end
|
||||
|
||||
function vector.rotate_around_axis(v, axis, angle)
|
||||
local cosangle = cos(angle)
|
||||
local sinangle = sin(angle)
|
||||
axis = vector.normalize(axis)
|
||||
-- https://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula
|
||||
local dot_axis = vector.multiply(axis, vector.dot(axis, v))
|
||||
local cross = vector.cross(v, axis)
|
||||
return vector.new(
|
||||
cross.x * sinangle + (v.x - dot_axis.x) * cosangle + dot_axis.x,
|
||||
cross.y * sinangle + (v.y - dot_axis.y) * cosangle + dot_axis.y,
|
||||
cross.z * sinangle + (v.z - dot_axis.z) * cosangle + dot_axis.z
|
||||
)
|
||||
end
|
||||
|
||||
function vector.rotate(v, rot)
|
||||
local sinpitch = sin(-rot.x)
|
||||
local sinyaw = sin(-rot.y)
|
||||
local sinroll = sin(-rot.z)
|
||||
local cospitch = cos(rot.x)
|
||||
local cosyaw = cos(rot.y)
|
||||
local cosroll = math.cos(rot.z)
|
||||
-- Rotation matrix that applies yaw, pitch and roll
|
||||
local matrix = {
|
||||
{
|
||||
sinyaw * sinpitch * sinroll + cosyaw * cosroll,
|
||||
sinyaw * sinpitch * cosroll - cosyaw * sinroll,
|
||||
sinyaw * cospitch,
|
||||
},
|
||||
{
|
||||
cospitch * sinroll,
|
||||
cospitch * cosroll,
|
||||
-sinpitch,
|
||||
},
|
||||
{
|
||||
cosyaw * sinpitch * sinroll - sinyaw * cosroll,
|
||||
cosyaw * sinpitch * cosroll + sinyaw * sinroll,
|
||||
cosyaw * cospitch,
|
||||
},
|
||||
}
|
||||
-- Compute matrix multiplication: `matrix` * `v`
|
||||
return vector.new(
|
||||
matrix[1][1] * v.x + matrix[1][2] * v.y + matrix[1][3] * v.z,
|
||||
matrix[2][1] * v.x + matrix[2][2] * v.y + matrix[2][3] * v.z,
|
||||
matrix[3][1] * v.x + matrix[3][2] * v.y + matrix[3][3] * v.z
|
||||
)
|
||||
end
|
||||
|
||||
function vector.dir_to_rotation(forward, up)
|
||||
forward = vector.normalize(forward)
|
||||
local rot = vector.new(math.asin(forward.y), -math.atan2(forward.x, forward.z), 0)
|
||||
if not up then
|
||||
return rot
|
||||
end
|
||||
assert(vector.dot(forward, up) < 0.000001,
|
||||
"Invalid vectors passed to vector.dir_to_rotation().")
|
||||
up = vector.normalize(up)
|
||||
-- Calculate vector pointing up with roll = 0, just based on forward vector.
|
||||
local forwup = vector.rotate(vector.new(0, 1, 0), rot)
|
||||
-- 'forwup' and 'up' are now in a plane with 'forward' as normal.
|
||||
-- The angle between them is the absolute of the roll value we're looking for.
|
||||
rot.z = vector.angle(forwup, up)
|
||||
|
||||
-- Since vector.angle never returns a negative value or a value greater
|
||||
-- than math.pi, rot.z has to be inverted sometimes.
|
||||
-- To determine wether this is the case, we rotate the up vector back around
|
||||
-- the forward vector and check if it worked out.
|
||||
local back = vector.rotate_around_axis(up, forward, -rot.z)
|
||||
|
||||
-- We don't use vector.equals for this because of floating point imprecision.
|
||||
if (back.x - forwup.x) * (back.x - forwup.x) +
|
||||
(back.y - forwup.y) * (back.y - forwup.y) +
|
||||
(back.z - forwup.z) * (back.z - forwup.z) > 0.0000001 then
|
||||
rot.z = -rot.z
|
||||
end
|
||||
return rot
|
||||
end
|
|
@ -0,0 +1,107 @@
|
|||
# mcl_time v2.2
|
||||
## by kay27 for MineClone 5
|
||||
---------------------------
|
||||
This mod counts time when all players sleep or some area is inactive.
|
||||
|
||||
It depends very much on `time_speed` configuration variable, which could be changed 'on the fly' by a chat command:
|
||||
* `/set time_speed 72`
|
||||
|
||||
If `time_speed` set to 0, this mod logs warnings and returns zeroes.
|
||||
|
||||
### mcl_time.get_seconds_irl()
|
||||
------------------------------
|
||||
Returns: Integer value of realtime (not in-game) seconds since world creation.
|
||||
|
||||
Usually this value grow smoothly. But when you skip the night being in the bed, or leave some area for some time, you may experience value jumps. That's basically the idea of this mod.
|
||||
|
||||
### mcl_time.get_number_of_times(last_time, interval, chance)
|
||||
-------------------------------------------------------------
|
||||
Returns the number of how many times something would probably happen if the area was active and we didn't skip the nights.
|
||||
|
||||
Arguments:
|
||||
* `last_time` - you pass last known for you value of `seconds_irl`
|
||||
* `interval` and `chance` - interval and chance like from ABM setup
|
||||
|
||||
Returns:
|
||||
* Integer number of how many times something would probably happen if the area was active all the time and we didn't skip the nights.
|
||||
* Integer value of in-real-life (not in-game) seconds since world creation.
|
||||
|
||||
### mcl_time.touch(pos)
|
||||
-----------------------
|
||||
This function 'toches' node at position `pos` by writing `_t` meta variable of `seconds_irl`.
|
||||
|
||||
### mcl_time.get_number_of_times_at_pos(pos, interval, chance)
|
||||
--------------------------------------------------------------
|
||||
Returns the number of how many times something would probably happen for node at pos `pos` if the area was active and we didn't skip the nights.
|
||||
It reads and updates meta variable `_t` from position `pos` and uses it as previous `seconds_irl`, so we don't need to remember it.
|
||||
|
||||
Argunments:
|
||||
* `pos` - node position
|
||||
* `interval` and `chance` - interval and chance like from ABM setup
|
||||
|
||||
Returns:
|
||||
* Integer number of how many times something would happen to the node at position `pos` if the area was active all the time and we didn't skip the nights.
|
||||
* For unclear conditions, like missing meta or zero `time_speed`, this function will return `0`.
|
||||
|
||||
### mcl_time.get_number_of_times_at_pos_or_1(pos, interval, chance)
|
||||
-------------------------------------------------------------------
|
||||
Returns the number of how many times something would probably happen for node at pos `pos` if the area was active and we didn't skip the nights.
|
||||
It reads and updates meta variable `_t` from position `pos` and uses it as previous `seconds_irl`, so we don't need to remember it.
|
||||
|
||||
Argunments:
|
||||
* `pos` - node position
|
||||
* `interval` and `chance` - interval and chance like from ABM setup
|
||||
|
||||
Returns:
|
||||
* Integer number of how many times something would happen to the node at position `pos` if the area was active all the time and we didn't skip the nights.
|
||||
* For unclear conditions, like missing meta or zero `time_speed`, this function will return `1`.
|
||||
|
||||
### mcl_time.get_number_of_times_at_pos_or_nil(pos, interval, chance)
|
||||
---------------------------------------------------------------------
|
||||
Returns the number of how many times something would probably happen for node at pos `pos` if the area was active and we didn't skip the nights.
|
||||
It reads and updates meta variable `_t` from position `pos` and uses it as previous `seconds_irl`, so we don't need to remember it.
|
||||
|
||||
Argunments:
|
||||
* `pos` - node position
|
||||
* `interval` and `chance` - interval and chance like from ABM setup
|
||||
|
||||
Returns:
|
||||
* Integer number of how many times something would happen to the node at position `pos` if the area was active all the time and we didn't skip the nights.
|
||||
* For unclear conditions, like missing meta or zero `time_speed`, this function will return `nil`.
|
||||
|
||||
### mcl_time.get_irl_seconds_passed_at_pos(pos)
|
||||
-----------------------------------------------
|
||||
Returns the number of how many in-real-life seconds would be passed for the node at position `pos`, if the area was active all the time and we didn't skip the nights.
|
||||
It uses node meta variable `_t` to calculate this value.
|
||||
|
||||
Argunments:
|
||||
* `pos` - node position
|
||||
|
||||
Returns:
|
||||
* Integer number of how many in-real-life seconds would be passed for the node at position `pos, if the area was active all the time and we didn't skip the nights.
|
||||
* For unclear conditions, like missing meta or zero `time_speed`, this function will return `0`.
|
||||
|
||||
### mcl_time.get_irl_seconds_passed_at_pos_or_1(pos)
|
||||
----------------------------------------------------
|
||||
Returns the number of how many in-real-life seconds would be passed for the node at position `pos`, if the area was active all the time and we didn't skip the nights.
|
||||
It uses node meta variable `_t` to calculate this value.
|
||||
|
||||
Argunments:
|
||||
* `pos` - node position
|
||||
|
||||
Returns:
|
||||
* Integer number of how many in-real-life seconds would be passed for the node at position `pos, if the area was active all the time and we didn't skip the nights.
|
||||
* For unclear conditions, like missing meta or zero `time_speed`, this function will return `1`.
|
||||
|
||||
### mcl_time.get_irl_seconds_passed_at_pos_or_nil(pos)
|
||||
----------------------------------------------------
|
||||
Returns the number of how many in-real-life seconds would be passed for the node at position `pos`, if the area was active all the time and we didn't skip the nights.
|
||||
It uses node meta variable `_t` to calculate this value.
|
||||
|
||||
Argunments:
|
||||
* `pos` - node position
|
||||
|
||||
Returns:
|
||||
* Integer number of how many in-real-life seconds would be passed for the node at position `pos, if the area was active all the time and we didn't skip the nights.
|
||||
* For unclear conditions, like missing meta or zero `time_speed`, this function will return `nil`.
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
mcl_time = {}
|
||||
|
||||
local time_update_interval = 2
|
||||
local retry_on_fail_interval = 500
|
||||
local default_time_speed = 72
|
||||
local save_to_storage_interval = 600
|
||||
local meta_name = "_t"
|
||||
|
||||
local current_time_update_interval = time_update_interval
|
||||
|
||||
local storage = minetest.get_mod_storage()
|
||||
local seconds_irl_public = tonumber(storage:get_string("seconds_irl")) or -2
|
||||
local last_save_seconds_irl = seconds_irl_public
|
||||
local next_save_seconds_irl = last_save_seconds_irl + save_to_storage_interval
|
||||
|
||||
local previous_seconds_irl = -2
|
||||
local time_speed_is_ok = true
|
||||
|
||||
local function get_seconds_irl()
|
||||
local time_speed = tonumber(minetest.settings:get("time_speed") or default_time_speed)
|
||||
if time_speed < 1 then
|
||||
if time_speed_is_ok then
|
||||
minetest.log("warning", "[mcl_time] time_speed < 1 - please increase to make mcl_time api work (default: " .. default_time_speed .. ")")
|
||||
time_speed_is_ok = false
|
||||
end
|
||||
return 0
|
||||
else
|
||||
if not time_speed_is_ok then
|
||||
minetest.log("warning", "[mcl_time] time_speed is now " .. time_speed)
|
||||
time_speed_is_ok = true
|
||||
end
|
||||
end
|
||||
local irl_multiplier = 86400 / time_speed
|
||||
local day_count = minetest.get_day_count()
|
||||
local timeofday = minetest.get_timeofday()
|
||||
local seconds_irl
|
||||
if not day_count or not timeofday then
|
||||
seconds_irl = seconds_irl_public
|
||||
else
|
||||
local days_ig = 0.0 + day_count + timeofday
|
||||
seconds_irl = days_ig * irl_multiplier
|
||||
end
|
||||
|
||||
if previous_seconds_irl == seconds_irl then
|
||||
current_time_update_interval = math.min(current_time_update_interval * 2, retry_on_fail_interval)
|
||||
minetest.log("warning", "[mcl_time] Time doesn't change! seconds_irl=" .. tostring(seconds_irl)
|
||||
.. ", day_count = " .. tostring(day_count) .. ", timeofday=" .. tostring(timeofday)
|
||||
.. " - increasing update interval to " .. tostring(current_time_update_interval))
|
||||
else
|
||||
previous_seconds_irl = seconds_irl
|
||||
if current_time_update_interval ~= time_update_interval then
|
||||
current_time_update_interval = time_update_interval
|
||||
minetest.log("action", "[mcl_time] Time is changing again: seconds_irl=" .. tostring(seconds_irl)
|
||||
.. ", day_count = " .. tostring(day_count) .. ", timeofday=" .. tostring(timeofday)
|
||||
.. ", update_interval=" .. tostring(current_time_update_interval))
|
||||
end
|
||||
end
|
||||
|
||||
if last_save_seconds_irl >= next_save_seconds_irl then
|
||||
storage:set_string("seconds_irl", tostring(seconds_irl))
|
||||
next_save_seconds_irl = seconds_irl + save_to_storage_interval
|
||||
end
|
||||
|
||||
return math.floor(seconds_irl)
|
||||
end
|
||||
|
||||
seconds_irl_public = get_seconds_irl()
|
||||
|
||||
function mcl_time.get_seconds_irl()
|
||||
return seconds_irl_public
|
||||
end
|
||||
|
||||
local function time_runner()
|
||||
seconds_irl_public = get_seconds_irl()
|
||||
minetest.after(current_time_update_interval, time_runner)
|
||||
end
|
||||
|
||||
function mcl_time.get_number_of_times(last_time, interval, chance)
|
||||
if not last_time then return 0, seconds_irl_publicend end
|
||||
if seconds_irl_public < 2 then return 0, seconds_irl_public end
|
||||
if not interval then return 0, seconds_irl_public end
|
||||
if not chance then return 0, seconds_irl_public end
|
||||
if interval < 1 then return 0, seconds_irl_public end
|
||||
if chance < 1 then return 0, seconds_irl_public end
|
||||
local number_of_intervals = (seconds_irl_public - last_time) / interval
|
||||
if number_of_intervals < 1 then return 0, seconds_irl_public end
|
||||
local average_chance = (1 + chance) / 2
|
||||
local number_of_times = math.floor(number_of_intervals / average_chance)
|
||||
return number_of_times, seconds_irl_public
|
||||
end
|
||||
|
||||
local get_number_of_times = mcl_time.get_number_of_times
|
||||
|
||||
function mcl_time.touch(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_int(meta_name, seconds_irl_public)
|
||||
end
|
||||
|
||||
function mcl_time.get_number_of_times_at_pos(pos, interval, chance)
|
||||
if not pos then return 0 end
|
||||
if not time_speed_is_ok then return 0 end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local last_time = meta:get_int(meta_name)
|
||||
meta:set_int(meta_name, seconds_irl_public)
|
||||
local number_of_times = (last_time <= 0) and 0 or get_number_of_times(last_time, interval, chance)
|
||||
return number_of_times
|
||||
end
|
||||
|
||||
local get_number_of_times_at_pos = mcl_time.get_number_of_times_at_pos
|
||||
|
||||
function mcl_time.get_number_of_times_at_pos_or_1(pos, interval, chance)
|
||||
return math.max(get_number_of_times_at_pos(pos, interval, chance), 1)
|
||||
end
|
||||
|
||||
function mcl_time.get_number_of_times_at_pos_or_nil(pos, interval, chance)
|
||||
local number_of_times_at_pos = get_number_of_times_at_pos(pos, interval, chance)
|
||||
if number_of_times_at_pos > 0 then
|
||||
return number_of_times_at_pos
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_time.get_irl_seconds_passed_at_pos(pos)
|
||||
if not pos then return 0 end
|
||||
if not time_speed_is_ok then return 0 end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local last_time = meta:get_int(meta_name)
|
||||
meta:set_int(meta_name, seconds_irl_public)
|
||||
local irl_seconds_passed = (last_time <= 0) and 0 or (seconds_irl_public - last_time)
|
||||
return irl_seconds_passed
|
||||
end
|
||||
|
||||
function mcl_time.get_irl_seconds_passed_at_pos_or_1(pos)
|
||||
if not pos then return 1 end
|
||||
if not time_speed_is_ok then return 1 end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local last_time = meta:get_int(meta_name)
|
||||
meta:set_int(meta_name, seconds_irl_public)
|
||||
local irl_seconds_passed = (last_time <= 0) and 1 or (seconds_irl_public - last_time)
|
||||
return irl_seconds_passed
|
||||
end
|
||||
|
||||
function mcl_time.get_irl_seconds_passed_at_pos_or_nil(pos)
|
||||
if not pos then return end
|
||||
if not time_speed_is_ok then return end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local last_time = meta:get_int(meta_name)
|
||||
meta:set_int(meta_name, seconds_irl_public)
|
||||
if last_time <= 0 then return end
|
||||
local delta_time = seconds_irl_public - last_time
|
||||
if delta_time <= 0 then return end
|
||||
meta:set_int(meta_name, seconds_irl_public)
|
||||
return delta_time
|
||||
end
|
||||
|
||||
time_runner()
|
||||
local day_count = minetest.get_day_count()
|
||||
local timeofday = minetest.get_timeofday()
|
||||
minetest.log("action", "[mcl_time] time runner started, current in-real-life seconds: " .. seconds_irl_public
|
||||
.. ", time_speed: " .. tostring(minetest.settings:get("time_speed"))
|
||||
.. ", day_count: " .. tostring(day_count)
|
||||
.. ", timeofday: " .. tostring(timeofday)
|
||||
.. ", update_interval=" .. tostring(current_time_update_interval)
|
||||
)
|
|
@ -0,0 +1,3 @@
|
|||
name = mcl_time
|
||||
author = kay27
|
||||
description = This mod counts time when all players sleep or some area is inactive
|
|
@ -5,25 +5,25 @@ local get_connected_players = minetest.get_connected_players
|
|||
-- For a given position, returns a 2-tuple:
|
||||
-- 1st return value: true if pos is in void
|
||||
-- 2nd return value: true if it is in the deadly part of the void
|
||||
local min1, min2, min3 = mcl_mapgen.overworld.min, mcl_mapgen.end_.min, mcl_mapgen.nether.min
|
||||
local max1, max2, max3 = mcl_mapgen.overworld.max, mcl_mapgen.end_.max, mcl_mapgen.nether.max+128
|
||||
function mcl_worlds.is_in_void(pos)
|
||||
local void =
|
||||
not ((pos.y < mcl_vars.mg_overworld_max and pos.y > mcl_vars.mg_overworld_min) or
|
||||
(pos.y < mcl_vars.mg_nether_max+128 and pos.y > mcl_vars.mg_nether_min) or
|
||||
(pos.y < mcl_vars.mg_end_max and pos.y > mcl_vars.mg_end_min))
|
||||
local y = pos.y
|
||||
local void = not ((y < max1 and y > min1) or (y < max2 and y > min2) or (y < max3 and y > min3))
|
||||
|
||||
local void_deadly = false
|
||||
local deadly_tolerance = 64 -- the player must be this many nodes “deep” into the void to be damaged
|
||||
if void then
|
||||
-- Overworld → Void → End → Void → Nether → Void
|
||||
if pos.y < mcl_vars.mg_overworld_min and pos.y > mcl_vars.mg_end_max then
|
||||
void_deadly = pos.y < mcl_vars.mg_overworld_min - deadly_tolerance
|
||||
elseif pos.y < mcl_vars.mg_end_min and pos.y > mcl_vars.mg_nether_max+128 then
|
||||
if y < min1 and y > max2 then
|
||||
void_deadly = y < min1 - deadly_tolerance
|
||||
elseif y < min2 and y > max3 then
|
||||
-- The void between End and Nether. Like usual, but here, the void
|
||||
-- *above* the Nether also has a small tolerance area, so player
|
||||
-- can fly above the Nether without getting hurt instantly.
|
||||
void_deadly = (pos.y < mcl_vars.mg_end_min - deadly_tolerance) and (pos.y > mcl_vars.mg_nether_max+128 + deadly_tolerance)
|
||||
elseif pos.y < mcl_vars.mg_nether_min then
|
||||
void_deadly = pos.y < mcl_vars.mg_nether_min - deadly_tolerance
|
||||
void_deadly = (y < min2 - deadly_tolerance) and (y > max3 + deadly_tolerance)
|
||||
elseif y < min3 then
|
||||
void_deadly = y < min3 - deadly_tolerance
|
||||
end
|
||||
end
|
||||
return void, void_deadly
|
||||
|
@ -35,12 +35,12 @@ end
|
|||
-- If the Y coordinate is not located in any dimension, it will return:
|
||||
-- nil, "void"
|
||||
function mcl_worlds.y_to_layer(y)
|
||||
if y >= mcl_vars.mg_overworld_min then
|
||||
return y - mcl_vars.mg_overworld_min, "overworld"
|
||||
elseif y >= mcl_vars.mg_nether_min and y <= mcl_vars.mg_nether_max+128 then
|
||||
return y - mcl_vars.mg_nether_min, "nether"
|
||||
elseif y >= mcl_vars.mg_end_min and y <= mcl_vars.mg_end_max then
|
||||
return y - mcl_vars.mg_end_min, "end"
|
||||
if y >= min1 then
|
||||
return y - min1, "overworld"
|
||||
elseif y >= min3 and y <= max3 then
|
||||
return y - min3, "nether"
|
||||
elseif y >= min2 and y <= max2 then
|
||||
return y - min2, "end"
|
||||
else
|
||||
return nil, "void"
|
||||
end
|
||||
|
@ -61,25 +61,25 @@ local pos_to_dimension = mcl_worlds.pos_to_dimension
|
|||
-- MineClone 2.
|
||||
-- mc_dimension is one of "overworld", "nether", "end" (default: "overworld").
|
||||
function mcl_worlds.layer_to_y(layer, mc_dimension)
|
||||
if mc_dimension == "overworld" or mc_dimension == nil then
|
||||
return layer + mcl_vars.mg_overworld_min
|
||||
if not mc_dimension or mc_dimension == "overworld" then
|
||||
return layer + min1
|
||||
elseif mc_dimension == "nether" then
|
||||
return layer + mcl_vars.mg_nether_min
|
||||
return layer + min3
|
||||
elseif mc_dimension == "end" then
|
||||
return layer + mcl_vars.mg_end_min
|
||||
return layer + min2
|
||||
end
|
||||
end
|
||||
|
||||
-- Takes a position and returns true if this position can have weather
|
||||
function mcl_worlds.has_weather(pos)
|
||||
-- Weather in the Overworld and the high part of the void below
|
||||
return pos.y <= mcl_vars.mg_overworld_max and pos.y >= mcl_vars.mg_overworld_min - 64
|
||||
return pos.y <= max1 and pos.y >= min1 - 64
|
||||
end
|
||||
|
||||
-- Takes a position and returns true if this position can have Nether dust
|
||||
function mcl_worlds.has_dust(pos)
|
||||
-- Weather in the Overworld and the high part of the void below
|
||||
return pos.y <= mcl_vars.mg_nether_max + 138 and pos.y >= mcl_vars.mg_nether_min - 10
|
||||
return pos.y <= max3 + 138 and pos.y >= min3 - 10
|
||||
end
|
||||
|
||||
-- Takes a position (pos) and returns true if compasses are working here
|
||||
|
@ -89,7 +89,7 @@ function mcl_worlds.compass_works(pos)
|
|||
if dim == "nether" or dim == "end" then
|
||||
return false
|
||||
elseif dim == "void" then
|
||||
return pos.y <= mcl_vars.mg_overworld_max and pos.y >= mcl_vars.mg_overworld_min - 64
|
||||
return pos.y <= max1 and pos.y >= min1 - 64
|
||||
else
|
||||
return true
|
||||
end
|
||||
|
@ -152,4 +152,3 @@ minetest.register_globalstep(function(dtime)
|
|||
dimtimer = 0
|
||||
end
|
||||
end)
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
name = mcl_worlds
|
||||
author = Wuzzy
|
||||
description = Utility functions for worlds and the “dimensions”.
|
||||
depends = mcl_init
|
||||
|
||||
depends = mcl_mapgen
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name = mcl_mobs
|
||||
author = PilzAdam
|
||||
description = Adds a mob API for mods to add animals or monsters, etc.
|
||||
depends = mcl_particles
|
||||
depends = mcl_mapgen, mcl_particles
|
||||
optional_depends = mcl_weather, mcl_explosions, mcl_hunger, mcl_worlds, invisibility, lucky_block, cmi, doc_identifier, mcl_armor, mcl_portals, mcl_experience
|
||||
|
|
|
@ -233,15 +233,15 @@ mobs_mc.override.spawn_height = {
|
|||
water = tonumber(minetest.settings:get("water_level")) or 0, -- Water level in the Overworld
|
||||
|
||||
-- Overworld boundaries (inclusive)
|
||||
overworld_min = mcl_vars.mg_overworld_min,
|
||||
overworld_max = mcl_vars.mg_overworld_max,
|
||||
overworld_min = mcl_mapgen.overworld.min,
|
||||
overworld_max = mcl_mapgen.overworld.max,
|
||||
|
||||
-- Nether boundaries (inclusive)
|
||||
nether_min = mcl_vars.mg_nether_min,
|
||||
nether_max = mcl_vars.mg_nether_max,
|
||||
nether_min = mcl_mapgen.nether.min,
|
||||
nether_max = mcl_mapgen.nether.max,
|
||||
|
||||
-- End boundaries (inclusive)
|
||||
end_min = mcl_vars.mg_end_min,
|
||||
end_max = mcl_vars.mg_end_max,
|
||||
end_min = mcl_mapgen.end_.min,
|
||||
end_max = mcl_mapgen.end_.max,
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
local refresh_interval = .63
|
||||
local huds = {}
|
||||
local default_debug = 3
|
||||
local after = minetest.after
|
||||
local get_connected_players = minetest.get_connected_players
|
||||
local get_biome_name = minetest.get_biome_name
|
||||
local get_biome_data = minetest.get_biome_data
|
||||
local format = string.format
|
||||
|
||||
local min1, min2, min3 = mcl_mapgen.overworld.min, mcl_mapgen.end_.min, mcl_mapgen.nether.min
|
||||
local max1, max2, max3 = mcl_mapgen.overworld.max, mcl_mapgen.end_.max, mcl_mapgen.nether.max + 128
|
||||
|
||||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
local S = minetest.get_translator(modname)
|
||||
local storage = minetest.get_mod_storage()
|
||||
local player_dbg = minetest.deserialize(storage:get_string("player_dbg") or "return {}") or {}
|
||||
|
||||
local function get_text(pos, bits)
|
||||
local bits = bits
|
||||
if bits == 0 then return "" end
|
||||
local y = pos.y
|
||||
if y >= min1 then
|
||||
y = y - min1
|
||||
elseif y >= min3 and y <= max3 then
|
||||
y = y - min3
|
||||
elseif y >= min2 and y <= max2 then
|
||||
y = y - min2
|
||||
end
|
||||
local biome_data = get_biome_data(pos)
|
||||
local biome_name = biome_data and get_biome_name(biome_data.biome) or "No biome"
|
||||
local text
|
||||
if bits == 1 then
|
||||
text = biome_name
|
||||
elseif bits == 2 then
|
||||
text = format("x:%.1f y:%.1f z:%.1f", pos.x, y, pos.z)
|
||||
elseif bits == 3 then
|
||||
text = format("%s x:%.1f y:%.1f z:%.1f", biome_name, pos.x, y, pos.z)
|
||||
end
|
||||
return text
|
||||
end
|
||||
|
||||
local function info()
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
local name = player:get_player_name()
|
||||
local pos = player:get_pos()
|
||||
local text = get_text(pos, player_dbg[name] or default_debug)
|
||||
local hud = huds[name]
|
||||
if not hud then
|
||||
local def = {
|
||||
hud_elem_type = "text",
|
||||
alignment = {x = 1, y = -1},
|
||||
scale = {x = 100, y = 100},
|
||||
position = {x = 0.0073, y = 0.989},
|
||||
text = text,
|
||||
style = 5,
|
||||
["number"] = 0xcccac0,
|
||||
z_index = 0,
|
||||
}
|
||||
local def_bg = table.copy(def)
|
||||
def_bg.offset = {x = 2, y = 1}
|
||||
def_bg["number"] = 0
|
||||
def_bg.z_index = -1
|
||||
huds[name] = {
|
||||
player:hud_add(def),
|
||||
player:hud_add(def_bg),
|
||||
text,
|
||||
}
|
||||
elseif text ~= hud[3] then
|
||||
hud[3] = text
|
||||
player:hud_change(huds[name][1], "text", text)
|
||||
player:hud_change(huds[name][2], "text", text)
|
||||
end
|
||||
end
|
||||
after(refresh_interval, info)
|
||||
end
|
||||
|
||||
minetest.register_on_authplayer(function(name, ip, is_success)
|
||||
if is_success then
|
||||
huds[name] = nil
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_chatcommand("debug",{
|
||||
description = S("Set debug bit mask: 0 = disable, 1 = biome name, 2 = coordinates, 3 = all"),
|
||||
func = function(name, params)
|
||||
local dbg = math.floor(tonumber(params) or default_debug)
|
||||
if dbg < 0 or dbg > 3 then
|
||||
minetest.chat_send_player(name, S("Error! Possible values are integer numbers from @1 to @2", 0, 3))
|
||||
return
|
||||
end
|
||||
if dbg == default_dbg then
|
||||
player_dbg[name] = nil
|
||||
else
|
||||
player_dbg[name] = dbg
|
||||
end
|
||||
minetest.chat_send_player(name, S("Debug bit mask set to @1", dbg))
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_on_shutdown(function()
|
||||
storage:set_string("player_dbg", minetest.serialize(player_dbg))
|
||||
end)
|
||||
|
||||
info()
|
|
@ -0,0 +1,4 @@
|
|||
# textdomain: mcl_info
|
||||
Set debug bit mask: 0 @= disable, 1 @= biome name, 2 @= coordinates, 3 @= all=Установка отладочной битовой маски: 0 @= отключить, 1 @= биом, 2 @= координаты, 3 @= всё
|
||||
Error! Possible values are integer numbers from @1 to @2=Ошибка! Допустимые значения - целые числа от @1 до @2
|
||||
Debug bit mask set to @1=Отладочной битовой маске присвоено значение @1
|
|
@ -0,0 +1,4 @@
|
|||
# textdomain: mcl_info
|
||||
Set debug bit mask: 0 @= disable, 1 @= biome name, 2 @= coordinates, 3 @= all=
|
||||
Error! Possible values are integer numbers from @1 to @2=
|
||||
Debug bit mask set to @1=
|
|
@ -0,0 +1,3 @@
|
|||
name = mcl_info
|
||||
description = Prints biome name and player position
|
||||
optional_depends = mcl_mapgen
|
|
@ -4,7 +4,8 @@
|
|||
|
||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
local mg_name = mcl_mapgen.name
|
||||
local v6 = mcl_mapgen.v6
|
||||
|
||||
local math = math
|
||||
local vector = vector
|
||||
|
@ -204,8 +205,23 @@ minetest.register_abm({
|
|||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
for _, object in pairs(minetest.get_objects_inside_radius(pos, 0.9)) do
|
||||
local entity = object:get_luaentity()
|
||||
if entity and entity.name == "__builtin:item" then
|
||||
if entity then
|
||||
local entity_name = entity.name
|
||||
if entity_name == "__builtin:item" then
|
||||
object:remove()
|
||||
elseif entity_name == "mcl_minecarts:minecart" then
|
||||
local pos = object:get_pos()
|
||||
local driver = entity._driver
|
||||
if driver then
|
||||
mcl_player.player_attached[driver] = nil
|
||||
local player = minetest.get_player_by_name(driver)
|
||||
player:set_detach()
|
||||
player:set_eye_offset({x=0, y=0, z=0},{x=0, y=0, z=0})
|
||||
mcl_player.player_set_animation(player, "stand" , 30)
|
||||
end
|
||||
minetest.add_item(pos, "mcl_minecarts:minecart")
|
||||
object:remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
local posses = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } }
|
||||
|
@ -367,7 +383,7 @@ function mcl_core.generate_tree(pos, tree_type, options)
|
|||
local balloon = options and options.balloon
|
||||
|
||||
if tree_type == nil or tree_type == OAK_TREE_ID then
|
||||
if mg_name == "v6" then
|
||||
if v6 then
|
||||
mcl_core.generate_v6_oak_tree(pos)
|
||||
else
|
||||
if balloon then
|
||||
|
@ -382,7 +398,7 @@ function mcl_core.generate_tree(pos, tree_type, options)
|
|||
if two_by_two then
|
||||
mcl_core.generate_huge_spruce_tree(pos)
|
||||
else
|
||||
if mg_name == "v6" then
|
||||
if v6 then
|
||||
mcl_core.generate_v6_spruce_tree(pos)
|
||||
else
|
||||
mcl_core.generate_spruce_tree(pos)
|
||||
|
@ -394,7 +410,7 @@ function mcl_core.generate_tree(pos, tree_type, options)
|
|||
if two_by_two then
|
||||
mcl_core.generate_huge_jungle_tree(pos)
|
||||
else
|
||||
if mg_name == "v6" then
|
||||
if v6 then
|
||||
mcl_core.generate_v6_jungle_tree(pos)
|
||||
else
|
||||
mcl_core.generate_jungle_tree(pos)
|
||||
|
@ -772,7 +788,7 @@ function mcl_core.generate_huge_jungle_tree(pos)
|
|||
end
|
||||
|
||||
|
||||
local grass_spread_randomizer = PseudoRandom(minetest.get_mapgen_setting("seed"))
|
||||
local grass_spread_randomizer = PseudoRandom(mcl_mapgen.seed)
|
||||
|
||||
function mcl_core.get_grass_palette_index(pos)
|
||||
local biome_data = minetest.get_biome_data(pos)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name = mcl_core
|
||||
description = Core items of MineClone 2: Basic biome blocks (dirt, sand, stones, etc.), derived items, glass, sugar cane, cactus, barrier, mining tools, hand, craftitems, and misc. items which don't really fit anywhere else.
|
||||
depends = mcl_autogroup, mcl_init, mcl_sounds, mcl_particles, mcl_util, mcl_worlds, doc_items, mcl_enchanting, mcl_colors
|
||||
depends = mcl_autogroup, mcl_init, mcl_sounds, mcl_particles, mcl_util, mcl_worlds, doc_items, mcl_enchanting, mcl_colors, mcl_mapgen
|
||||
optional_depends = doc
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
local S = minetest.get_translator(minetest.get_current_modname())
|
||||
|
||||
local math = math
|
||||
local table = table
|
||||
local math_random = math.random
|
||||
local math_floor = math.floor
|
||||
|
||||
--- Plant parts ---
|
||||
|
||||
|
@ -24,7 +24,7 @@ local chorus_flower_box = {
|
|||
-- Helper function
|
||||
local function round(num, idp)
|
||||
local mult = 10^(idp or 0)
|
||||
return math.floor(num * mult + 0.5) / mult
|
||||
return math_floor(num * mult + 0.5) / mult
|
||||
end
|
||||
|
||||
-- This is a list of nodes that SHOULD NOT call their detach function
|
||||
|
@ -344,6 +344,7 @@ end
|
|||
-- Grow a single step of a chorus plant at pos.
|
||||
-- Pos must be a chorus flower.
|
||||
function mcl_end.grow_chorus_plant_step(pos, node, pr)
|
||||
local pr = pr or PseudoRandom()
|
||||
local new_flower_buds = {}
|
||||
local above = { x = pos.x, y = pos.y + 1, z = pos.z }
|
||||
local node_above = minetest.get_node(above)
|
||||
|
@ -452,16 +453,20 @@ function mcl_end.grow_chorus_plant_step(pos, node, pr)
|
|||
return new_flower_buds
|
||||
end
|
||||
|
||||
local fast_randomizer = {
|
||||
next = function(self, min, max)
|
||||
return math_random(min, max)
|
||||
end
|
||||
}
|
||||
|
||||
--- ABM ---
|
||||
local seed = minetest.get_mapgen_setting("seed")
|
||||
local pr = PseudoRandom(seed)
|
||||
minetest.register_abm({
|
||||
label = "Chorus plant growth",
|
||||
nodenames = { "mcl_end:chorus_flower" },
|
||||
interval = 35.0,
|
||||
chance = 4.0,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
mcl_end.grow_chorus_plant_step(pos, node, pr)
|
||||
mcl_end.grow_chorus_plant_step(pos, node, fast_randomizer)
|
||||
end,
|
||||
})
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ minetest.register_entity("mcl_end:ender_eye", {
|
|||
|
||||
-- Save and restore age
|
||||
get_staticdata = function(self)
|
||||
return tostring(self._age)
|
||||
return tostring(self._age) or "0"
|
||||
end,
|
||||
on_activate = function(self, staticdata, dtime_s)
|
||||
local age = tonumber(staticdata)
|
||||
|
@ -87,7 +87,7 @@ minetest.register_craftitem("mcl_end:ender_eye", {
|
|||
end
|
||||
local origin = user:get_pos()
|
||||
origin.y = origin.y + 1.5
|
||||
local strongholds = mcl_structures.get_registered_structures("stronghold")
|
||||
local strongholds = mcl_structures.strongholds
|
||||
local dim = mcl_worlds.pos_to_dimension(origin)
|
||||
local is_creative = minetest.is_creative_enabled(user:get_player_name())
|
||||
|
||||
|
|
|
@ -2,6 +2,10 @@ local S = minetest.get_translator(minetest.get_current_modname())
|
|||
|
||||
local table = table
|
||||
|
||||
local interval = 35
|
||||
local chance = 11
|
||||
local max_interval = interval * chance
|
||||
|
||||
minetest.register_node("mcl_nether:nether_wart_0", {
|
||||
description = S("Premature Nether Wart (Stage 1)"),
|
||||
_doc_items_longdesc = S("A premature nether wart has just recently been planted on soul sand. Nether wart slowly grows on soul sand in 4 stages (the second and third stages look identical). Although nether wart is home to the Nether, it grows in any dimension."),
|
||||
|
@ -22,6 +26,7 @@ minetest.register_node("mcl_nether:nether_wart_0", {
|
|||
},
|
||||
groups = {dig_immediate=3, not_in_creative_inventory=1,plant=1,attached_node=1,dig_by_water=1,destroy_by_lava_flow=1,dig_by_piston=1},
|
||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
||||
on_construct = mcl_time.touch,
|
||||
})
|
||||
|
||||
minetest.register_node("mcl_nether:nether_wart_1", {
|
||||
|
@ -44,6 +49,7 @@ minetest.register_node("mcl_nether:nether_wart_1", {
|
|||
},
|
||||
groups = {dig_immediate=3, not_in_creative_inventory=1,plant=1,attached_node=1,dig_by_water=1,destroy_by_lava_flow=1,dig_by_piston=1},
|
||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
||||
on_construct = mcl_time.touch,
|
||||
})
|
||||
|
||||
minetest.register_node("mcl_nether:nether_wart_2", {
|
||||
|
@ -66,6 +72,7 @@ minetest.register_node("mcl_nether:nether_wart_2", {
|
|||
},
|
||||
groups = {dig_immediate=3, not_in_creative_inventory=1,plant=1,attached_node=1,dig_by_water=1,destroy_by_lava_flow=1,dig_by_piston=1},
|
||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
||||
on_construct = mcl_time.touch,
|
||||
})
|
||||
|
||||
minetest.register_node("mcl_nether:nether_wart", {
|
||||
|
@ -148,36 +155,59 @@ minetest.register_craftitem("mcl_nether:nether_wart_item", {
|
|||
|
||||
local names = {"mcl_nether:nether_wart_0", "mcl_nether:nether_wart_1", "mcl_nether:nether_wart_2"}
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Nether wart growth",
|
||||
nodenames = {"mcl_nether:nether_wart_0", "mcl_nether:nether_wart_1", "mcl_nether:nether_wart_2"},
|
||||
neighbors = {"group:soil_nether_wart"},
|
||||
interval = 35,
|
||||
chance = 11,
|
||||
action = function(pos, node)
|
||||
pos.y = pos.y-1
|
||||
if minetest.get_item_group(minetest.get_node(pos).name, "soil_nether_wart") == 0 then
|
||||
return
|
||||
end
|
||||
pos.y = pos.y+1
|
||||
local function grow(pos, node)
|
||||
local step = nil
|
||||
local node = node or minetest.get_node(pos)
|
||||
for i, name in ipairs(names) do
|
||||
if name == node.name then
|
||||
step = i
|
||||
break
|
||||
end
|
||||
end
|
||||
if step == nil then
|
||||
return
|
||||
end
|
||||
if not step then return end
|
||||
local new_node = {name = names[step + 1]}
|
||||
if new_node.name == nil then
|
||||
if not new_node.name then
|
||||
new_node.name = "mcl_nether:nether_wart"
|
||||
end
|
||||
new_node.param = node.param
|
||||
new_node.param2 = node.param2
|
||||
minetest.set_node(pos, new_node)
|
||||
end
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Nether wart growth",
|
||||
nodenames = {"mcl_nether:nether_wart_0", "mcl_nether:nether_wart_1", "mcl_nether:nether_wart_2"},
|
||||
neighbors = {"group:soil_nether_wart"},
|
||||
interval = interval,
|
||||
chance = 1,
|
||||
action = function(pos, node)
|
||||
pos.y = pos.y-1
|
||||
if minetest.get_item_group(minetest.get_node(pos).name, "soil_nether_wart") == 0 then
|
||||
return
|
||||
end
|
||||
pos.y = pos.y+1
|
||||
|
||||
for i = 1, mcl_time.get_number_of_times_at_pos(pos, interval, chance) do
|
||||
grow(pos)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_lbm({
|
||||
label = "Nether wart growth update",
|
||||
name = "mcl_nether:growth_warts",
|
||||
nodenames = {"mcl_nether:nether_wart_0", "mcl_nether:nether_wart_1", "mcl_nether:nether_wart_2"},
|
||||
run_at_every_load = true,
|
||||
action = function(pos, node)
|
||||
pos.y = pos.y-1
|
||||
if minetest.get_item_group(minetest.get_node(pos).name, "soil_nether_wart") == 0 then
|
||||
return
|
||||
end
|
||||
pos.y = pos.y+1
|
||||
for i = 1, mcl_time.get_number_of_times_at_pos(pos, interval, chance) do
|
||||
grow(pos)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
if minetest.get_modpath("doc") then
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name = mcl_portals
|
||||
description = Adds buildable portals to the Nether and End dimensions.
|
||||
depends = mcl_nether, mcl_end, mcl_particles, mcl_spawn, mcl_credits
|
||||
depends = mcl_mapgen, mcl_nether, mcl_end, mcl_particles, mcl_spawn, mcl_credits, mcl_structures
|
||||
optional_depends = awards, doc
|
||||
|
|
|
@ -6,12 +6,6 @@ local math = math
|
|||
|
||||
local has_doc = minetest.get_modpath("doc")
|
||||
|
||||
-- Parameters
|
||||
--local SPAWN_MIN = mcl_vars.mg_end_min+70
|
||||
--local SPAWN_MAX = mcl_vars.mg_end_min+98
|
||||
|
||||
--local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
|
||||
local function destroy_portal(pos)
|
||||
local neighbors = {
|
||||
{ x=1, y=0, z=0 },
|
||||
|
@ -184,7 +178,7 @@ function mcl_portals.end_teleport(obj, pos)
|
|||
-- Teleport to the End at a fixed position and generate a
|
||||
-- 5×5 obsidian platform below.
|
||||
|
||||
local platform_pos = mcl_vars.mg_end_platform_pos
|
||||
local platform_pos = mcl_mapgen.end_.platform_pos
|
||||
-- force emerge of target1 area
|
||||
minetest.get_voxel_manip():read_from_map(platform_pos, platform_pos)
|
||||
if not minetest.get_node_or_nil(platform_pos) then
|
||||
|
|
|
@ -19,7 +19,7 @@ local W_MIN, W_MAX = 4, 23
|
|||
local H_MIN, H_MAX = 5, 23
|
||||
local N_MIN, N_MAX = 6, (W_MAX-2) * (H_MAX-2)
|
||||
local TRAVEL_X, TRAVEL_Y, TRAVEL_Z = 8, 1, 8
|
||||
local LIM_MIN, LIM_MAX = mcl_vars.mapgen_edge_min, mcl_vars.mapgen_edge_max
|
||||
local LIM_MIN, LIM_MAX = mcl_mapgen.EDGE_MIN, mcl_mapgen.EDGE_MAX
|
||||
local PLAYER_COOLOFF, MOB_COOLOFF = 3, 14 -- for this many seconds they won't teleported again
|
||||
local TOUCH_CHATTER_TIME = 1 -- prevent multiple teleportation attempts caused by multiple portal touches, for this number of seconds
|
||||
local CHATTER_US = TOUCH_CHATTER_TIME * 1000000
|
||||
|
@ -27,8 +27,8 @@ local DELAY = 3 -- seconds before teleporting in Nether portal in Survival mo
|
|||
local DISTANCE_MAX = 128
|
||||
local PORTAL = "mcl_portals:portal"
|
||||
local OBSIDIAN = "mcl_core:obsidian"
|
||||
local O_Y_MIN, O_Y_MAX = max(mcl_vars.mg_overworld_min, -31), min(mcl_vars.mg_overworld_max, 2048)
|
||||
local N_Y_MIN, N_Y_MAX = mcl_vars.mg_bedrock_nether_bottom_min, mcl_vars.mg_bedrock_nether_top_min - H_MIN
|
||||
local O_Y_MIN, O_Y_MAX = max(mcl_mapgen.overworld.min, -31), min(mcl_mapgen.overworld.max, 2048)
|
||||
local N_Y_MIN, N_Y_MAX = mcl_mapgen.nether.bedrock_bottom_min, mcl_mapgen.nether.bedrock_top_min - H_MIN
|
||||
|
||||
-- Alpha and particles
|
||||
local node_particles_allowed = minetest.settings:get("mcl_node_particles") or "none"
|
||||
|
@ -66,7 +66,7 @@ minetest.register_on_shutdown(function()
|
|||
storage:set_string("nether_exits_keys", minetest.serialize(keys))
|
||||
end)
|
||||
|
||||
local get_node = mcl_vars.get_node
|
||||
local get_node = mcl_mapgen.get_far_node
|
||||
local set_node = minetest.set_node
|
||||
local registered_nodes = minetest.registered_nodes
|
||||
local is_protected = minetest.is_protected
|
||||
|
@ -137,19 +137,8 @@ local function find_exit(p, dx, dy, dz)
|
|||
if not p or not p.y or not p.z or not p.x then return end
|
||||
local dx, dy, dz = dx or DISTANCE_MAX, dy or DISTANCE_MAX, dz or DISTANCE_MAX
|
||||
if dx < 1 or dy < 1 or dz < 1 then return false end
|
||||
|
||||
--y values aren't used
|
||||
local x = floor(p.x)
|
||||
--local y = floor(p.y)
|
||||
local z = floor(p.z)
|
||||
|
||||
local x1 = x-dx+1
|
||||
--local y1 = y-dy+1
|
||||
local z1 = z-dz+1
|
||||
|
||||
local x2 = x+dx-1
|
||||
--local y2 = y+dy-1
|
||||
local z2 = z+dz-1
|
||||
local x, y, z = floor(p.x), floor(p.y), floor(p.z)
|
||||
local x1, y1, z1, x2, y2, z2 = x-dx+1, y-dy+1, z-dz+1, x+dx-1, y+dy-1, z+dz-1
|
||||
|
||||
local k1x, k2x = floor(x1/256), floor(x2/256)
|
||||
local k1z, k2z = floor(z1/256), floor(z2/256)
|
||||
|
@ -170,11 +159,27 @@ local function find_exit(p, dx, dy, dz)
|
|||
end
|
||||
end end
|
||||
|
||||
if t and abs(t.x-p.x) <= dx and abs(t.y-p.y) <= dy and abs(t.z-p.z) <= dz then
|
||||
if t and abs(t.x-x) <= dx and abs(t.y-y) <= dy and abs(t.z-z) <= dz then
|
||||
return t
|
||||
end
|
||||
end
|
||||
|
||||
-- This functon searches Nether portal nodes whitin distance specified and checks the node
|
||||
local function find_exit_with_check(p, dx, dy, dz)
|
||||
while true do
|
||||
local pos = find_exit(p, dx, dy, dz)
|
||||
if not pos then
|
||||
-- not found:
|
||||
return
|
||||
end
|
||||
if (get_node(pos).name == PORTAL) then
|
||||
return pos
|
||||
end
|
||||
-- I don't know the reason why it can happen, but if we're here, let's log it, remove this record and try again:
|
||||
log("warning", "[mcl_portals] Found faulty exit from Nether portal at " .. pos_to_string(pos) .. " - removed")
|
||||
remove_exit(pos)
|
||||
end
|
||||
end
|
||||
|
||||
-- Ping-Pong the coordinate for Fast Travelling, https://git.minetest.land/Wuzzy/MineClone2/issues/795#issuecomment-11058
|
||||
local function ping_pong(x, m, l1, l2)
|
||||
|
@ -365,7 +370,7 @@ function build_nether_portal(pos, width, height, orientation, name, clear_before
|
|||
return pos
|
||||
end
|
||||
|
||||
function mcl_portals.spawn_nether_portal(pos, rot, pr, name)
|
||||
function mcl_portals.spawn_nether_portal(pos, rot, pr, placer)
|
||||
if not pos then return end
|
||||
local o = 0
|
||||
if rot then
|
||||
|
@ -375,6 +380,10 @@ function mcl_portals.spawn_nether_portal(pos, rot, pr, name)
|
|||
o = random(0,1)
|
||||
end
|
||||
end
|
||||
local name
|
||||
if placer and placer:is_player() then
|
||||
name = placer:get_player_name()
|
||||
end
|
||||
build_nether_portal(pos, nil, nil, o, name, true)
|
||||
end
|
||||
|
||||
|
@ -447,7 +456,7 @@ local function create_portal_2(pos1, name, obj)
|
|||
end
|
||||
local exit = build_nether_portal(pos1, W_MIN-2, H_MIN-2, orientation, name)
|
||||
finalize_teleport(obj, exit)
|
||||
local cn = mcl_vars.get_chunk_number(pos1)
|
||||
local cn = mcl_mapgen.get_chunk_number(pos1)
|
||||
chunks[cn] = nil
|
||||
if queue[cn] then
|
||||
for next_obj, _ in pairs(queue[cn]) do
|
||||
|
@ -461,9 +470,9 @@ end
|
|||
|
||||
local function get_lava_level(pos, pos1, pos2)
|
||||
if pos.y > -1000 then
|
||||
return max(min(mcl_vars.mg_lava_overworld_max, pos2.y-1), pos1.y+1)
|
||||
return max(min(mcl_mapgen.overworld.lava_max, pos2.y-1), pos1.y+1)
|
||||
end
|
||||
return max(min(mcl_vars.mg_lava_nether_max, pos2.y-1), pos1.y+1)
|
||||
return max(min(mcl_mapgen.nether.lava_max, pos2.y-1), pos1.y+1)
|
||||
end
|
||||
|
||||
local function ecb_scan_area_2(blockpos, action, calls_remaining, param)
|
||||
|
@ -479,7 +488,7 @@ local function ecb_scan_area_2(blockpos, action, calls_remaining, param)
|
|||
for _, p in pairs(portals) do
|
||||
add_exit(p)
|
||||
end
|
||||
local exit = find_exit(pos)
|
||||
local exit = find_exit_with_check(pos)
|
||||
if exit then
|
||||
finalize_teleport(obj, exit)
|
||||
end
|
||||
|
@ -542,7 +551,7 @@ local function ecb_scan_area_2(blockpos, action, calls_remaining, param)
|
|||
end
|
||||
|
||||
local function create_portal(pos, limit1, limit2, name, obj)
|
||||
local cn = mcl_vars.get_chunk_number(pos)
|
||||
local cn = mcl_mapgen.get_chunk_number(pos)
|
||||
if chunks[cn] then
|
||||
local q = queue[cn] or {}
|
||||
q[obj] = true
|
||||
|
@ -555,8 +564,8 @@ local function create_portal(pos, limit1, limit2, name, obj)
|
|||
-- so we'll emerge single chunk only: 5x5x5 blocks, 80x80x80 nodes maximum
|
||||
-- and maybe one more chunk from below if (SCAN_2_MAP_CHUNKS = true)
|
||||
|
||||
local pos1 = add(mul(mcl_vars.pos_to_chunk(pos), mcl_vars.chunk_size_in_nodes), mcl_vars.central_chunk_offset_in_nodes)
|
||||
local pos2 = add(pos1, mcl_vars.chunk_size_in_nodes - 1)
|
||||
local pos1 = add(mul(mcl_mapgen.pos_to_chunk(pos), mcl_mapgen.CS_NODES), mcl_mapgen.OFFSET_NODES)
|
||||
local pos2 = add(pos1, mcl_mapgen.CS_NODES - 1)
|
||||
|
||||
if not SCAN_2_MAP_CHUNKS then
|
||||
if limit1 and limit1.x and limit1.y and limit1.z then
|
||||
|
@ -570,8 +579,8 @@ local function create_portal(pos, limit1, limit2, name, obj)
|
|||
end
|
||||
|
||||
-- Basically the copy of code above, with minor additions to continue the search in single additional chunk below:
|
||||
local next_chunk_1 = {x = pos1.x, y = pos1.y - mcl_vars.chunk_size_in_nodes, z = pos1.z}
|
||||
local next_chunk_2 = add(next_chunk_1, mcl_vars.chunk_size_in_nodes - 1)
|
||||
local next_chunk_1 = {x = pos1.x, y = pos1.y - mcl_mapgen.CS_NODES, z = pos1.z}
|
||||
local next_chunk_2 = add(next_chunk_1, mcl_mapgen.CS_NODES - 1)
|
||||
local next_pos = {x = pos.x, y=max(next_chunk_2.y, limit1.y), z = pos.z}
|
||||
if limit1 and limit1.x and limit1.y and limit1.z then
|
||||
pos1 = {x = max(min(limit1.x, pos.x), pos1.x), y = max(min(limit1.y, pos.y), pos1.y), z = max(min(limit1.z, pos.z), pos1.z)}
|
||||
|
@ -697,11 +706,12 @@ local function teleport_no_delay(obj, pos)
|
|||
name = obj:get_player_name()
|
||||
end
|
||||
|
||||
local exit = find_exit(target)
|
||||
local exit = find_exit_with_check(target)
|
||||
if exit then
|
||||
finalize_teleport(obj, exit)
|
||||
else
|
||||
dim = dimension_to_teleport[dim]
|
||||
if not dim then return end
|
||||
-- need to create arrival portal
|
||||
create_portal(target, limits[dim].pmin, limits[dim].pmax, name, obj)
|
||||
end
|
||||
|
@ -763,6 +773,8 @@ local function teleport(obj, portal_pos)
|
|||
minetest.after(DELAY, teleport_no_delay, obj, portal_pos)
|
||||
end
|
||||
|
||||
mcl_structures.register_structure({name = "nether_portal", place_function = mcl_portals.spawn_nether_portal})
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Nether portal teleportation and particles",
|
||||
nodenames = {PORTAL},
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 601 B After Width: | Height: | Size: 700 B |
Binary file not shown.
Before Width: | Height: | Size: 423 B After Width: | Height: | Size: 508 B |
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
|||
name = mcl_biomes
|
||||
author = maikerumine
|
||||
description = Adds the various biomes and biome-related things for non-v6 map generators.
|
||||
depends = mcl_init, mcl_mapgen_core, mcl_core, mcl_worlds, mcl_farming, mcl_flowers, mcl_end, mcl_ocean
|
||||
depends = mcl_mapgen, mcl_mapgen_core, mcl_core, mcl_worlds, mcl_farming, mcl_flowers, mcl_end, mcl_ocean
|
||||
|
|
|
@ -2,21 +2,19 @@
|
|||
|
||||
mcl_dungeons = {}
|
||||
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
|
||||
-- Are dungeons disabled?
|
||||
if mcl_vars.mg_dungeons == false or mg_name == "singlenode" then
|
||||
if mcl_mapgen.dungeons == false or mcl_mapgen.singlenode == true then
|
||||
return
|
||||
end
|
||||
|
||||
--lua locals
|
||||
--minetest
|
||||
local minetest_find_nodes_in_area = minetest.find_nodes_in_area
|
||||
local registered_nodes = minetest.registered_nodes
|
||||
local swap_node = minetest.swap_node
|
||||
local set_node = minetest.set_node
|
||||
local dir_to_facedir = minetest.dir_to_facedir
|
||||
local get_meta = minetest.get_meta
|
||||
local emerge_area = minetest.emerge_area
|
||||
|
||||
--vector
|
||||
local vector_add = vector.add
|
||||
|
@ -31,16 +29,15 @@ local math_min = math.min
|
|||
local math_max = math.max
|
||||
local math_ceil = math.ceil
|
||||
|
||||
--custom mcl_vars
|
||||
local get_node = mcl_vars.get_node
|
||||
local get_node = mcl_mapgen.get_far_node
|
||||
|
||||
|
||||
local min_y = math_max(mcl_vars.mg_overworld_min, mcl_vars.mg_bedrock_overworld_max) + 1
|
||||
local max_y = mcl_vars.mg_overworld_max - 1
|
||||
local min_y = math_max(mcl_mapgen.overworld.min, mcl_mapgen.overworld.bedrock_max) + 1
|
||||
local max_y = mcl_mapgen.overworld.max - 1
|
||||
-- Calculate the number of dungeon spawn attempts
|
||||
-- In Minecraft, there 8 dungeon spawn attempts Minecraft chunk (16*256*16 = 65536 blocks).
|
||||
-- Minetest chunks don't have this size, so scale the number accordingly.
|
||||
local attempts = math_ceil(((mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE) ^ 3) / 8192) -- 63 = 80*80*80/8192
|
||||
local attempts = math_ceil((mcl_mapgen.CS_NODES ^ 3) / 8192) -- 63 = 80*80*80/8192
|
||||
|
||||
local dungeonsizes = {
|
||||
{ x=5, y=4, z=5},
|
||||
|
@ -112,7 +109,7 @@ local loottable =
|
|||
}
|
||||
|
||||
-- Bonus loot for v6 mapgen: Otherwise unobtainable saplings.
|
||||
if mg_name == "v6" then
|
||||
if mcl_mapgen.v6 then
|
||||
table.insert(loottable, {
|
||||
stacks_min = 1,
|
||||
stacks_max = 3,
|
||||
|
@ -124,23 +121,26 @@ if mg_name == "v6" then
|
|||
})
|
||||
end
|
||||
|
||||
local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
|
||||
if calls_remaining >= 1 then return end
|
||||
--local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
|
||||
-- if calls_remaining >= 1 then return end
|
||||
-- local p1, _, dim, pr = param.p1, param.p2, param.dim, param.pr
|
||||
-- local check = not (param.dontcheck or false)
|
||||
local m1, m2 = 0, 0
|
||||
local function spawn_dungeon(p1, p2, dim, pr, dontcheck)
|
||||
|
||||
local p1, _, dim, pr = param.p1, param.p2, param.dim, param.pr
|
||||
local x, y, z = p1.x, p1.y, p1.z
|
||||
local check = not (param.dontcheck or false)
|
||||
local check = not (dontcheck or false)
|
||||
|
||||
-- Check floor and ceiling: Must be *completely* solid
|
||||
local y_floor = y
|
||||
local y_ceiling = y + dim.y + 1
|
||||
|
||||
if check then
|
||||
for tx = x+1, x+dim.x do
|
||||
for tz = z+1, z+dim.z do
|
||||
local fdef = registered_nodes[get_node({x = tx, y = y_floor , z = tz}).name]
|
||||
local cdef = registered_nodes[get_node({x = tx, y = y_ceiling, z = tz}).name]
|
||||
if not fdef or not fdef.walkable or not cdef or not cdef.walkable then return false end
|
||||
end
|
||||
local dim_x, dim_z = dim.x, dim.z
|
||||
local size = dim_z*dim_x
|
||||
if #minetest_find_nodes_in_area({x=x+1,y=y_floor,z=z+1}, {x=x+dim_z,y=y_floor,z=z+dim_z}, "group:walkabke") < size
|
||||
or #minetest_find_nodes_in_area({x=x+1,y=y_floor,z=z+1}, {x=x+dim_z,y=y_floor,z=z+dim_z}, "group:walkabke") < size then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -410,8 +410,7 @@ local function dungeons_nodes(minp, maxp, blockseed)
|
|||
local z = pr:next(minp.z, maxp.z-dim.z-1)
|
||||
local p1 = {x=x,y=y,z=z}
|
||||
local p2 = {x = x+dim.x+1, y = y+dim.y+1, z = z+dim.z+1}
|
||||
minetest.log("verbose","[mcl_dungeons] size=" ..minetest.pos_to_string(dim) .. ", emerge from "..minetest.pos_to_string(p1) .. " to " .. minetest.pos_to_string(p2))
|
||||
emerge_area(p1, p2, ecb_spawn_dungeon, {p1=p1, p2=p2, dim=dim, pr=pr})
|
||||
spawn_dungeon(p1, p2, dim, pr)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -419,8 +418,7 @@ function mcl_dungeons.spawn_dungeon(p1, _, pr)
|
|||
if not p1 or not pr or not p1.x or not p1.y or not p1.z then return end
|
||||
local dim = dungeonsizes[pr:next(1, #dungeonsizes)]
|
||||
local p2 = {x = p1.x+dim.x+1, y = p1.y+dim.y+1, z = p1.z+dim.z+1}
|
||||
minetest.log("verbose","[mcl_dungeons] size=" ..minetest.pos_to_string(dim) .. ", emerge from "..minetest.pos_to_string(p1) .. " to " .. minetest.pos_to_string(p2))
|
||||
emerge_area(p1, p2, ecb_spawn_dungeon, {p1=p1, p2=p2, dim=dim, pr=pr, dontcheck=true})
|
||||
spawn_dungeon(p1, p2, dim, pr, true)
|
||||
end
|
||||
|
||||
mcl_mapgen_core.register_generator("dungeons", nil, dungeons_nodes, 999999)
|
||||
mcl_mapgen.register_mapgen(dungeons_nodes, mcl_mapgen.order.DUNGEONS)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name = mcl_dungeons
|
||||
author = Wuzzy
|
||||
description = Generates random dungeons in the world
|
||||
depends = mcl_init, mcl_core, mcl_chests, mcl_mobs, mcl_mobspawners, mcl_mapgen_core, mobs_mc
|
||||
depends = mcl_mapgen, mcl_core, mcl_chests, mcl_mobs, mcl_mobspawners, mcl_mapgen_core, mobs_mc
|
||||
|
|
|
@ -10,25 +10,21 @@ local noisemap = PerlinNoiseMap({
|
|||
local c_end_stone = minetest.get_content_id("mcl_end:end_stone")
|
||||
local y_offset = -2
|
||||
|
||||
minetest.register_on_generated(function(minp, maxp)
|
||||
mcl_mapgen.register_on_generated(function(vm_context)
|
||||
local minp, maxp = vm_context.minp, vm_context.maxp
|
||||
if maxp.y < (-27025 + y_offset) or minp.y > (-27000 + y_offset + 4) or maxp.x < -75 or minp.x > 75 or maxp.z < -75 or minp.z > 75 then
|
||||
return
|
||||
end
|
||||
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
local data = vm:get_data()
|
||||
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
|
||||
local data = vm_context.data
|
||||
local area = vm_context.area
|
||||
local write = false
|
||||
for idx in area:iter(math.max(minp.x, -75), math.max(minp.y, -27025 + y_offset + 4), math.max(minp.z, -75), math.min(maxp.x, 75), math.min(maxp.y, -27000 + y_offset), math.min(maxp.z, 75)) do
|
||||
local pos = area:position(idx)
|
||||
local y = 27025 + pos.y - y_offset
|
||||
if noisemap[pos.x + 75 + 1][y + 1][pos.z + 75 + 1] > (math.abs(1 - y / 25) ^ 2 + math.abs(pos.x / 75) ^ 2 + math.abs(pos.z / 75) ^ 2) then
|
||||
data[idx] = c_end_stone
|
||||
write = true
|
||||
end
|
||||
end
|
||||
|
||||
vm:set_data(data)
|
||||
vm:calc_lighting()
|
||||
vm:update_liquids()
|
||||
vm:write_to_map()
|
||||
vm_context.write = vm_context.write or write
|
||||
end)
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
local c_dirt_with_grass = minetest.get_content_id("mcl_core:dirt_with_grass")
|
||||
local c_dirt_with_grass_snow = minetest.get_content_id("mcl_core:dirt_with_grass_snow")
|
||||
local c_top_snow = minetest.get_content_id("mcl_core:snow")
|
||||
local c_snow_block = minetest.get_content_id("mcl_core:snowblock")
|
||||
|
||||
mcl_mapgen.register_on_generated(function(vm_context)
|
||||
local minp, maxp = vm_context.minp, vm_context.maxp
|
||||
local min_y, max_y = minp.y, maxp.y
|
||||
if min_y > mcl_mapgen.overworld.max or max_y < mcl_mapgen.overworld.min then return end
|
||||
|
||||
vm_context.param2_data = vm_context.param2_data or vm:get_param2_data(vm_context.lvm_param2_buffer)
|
||||
vm_context.biomemap = vm_context.biomemap or minetest.get_mapgen_object("biomemap")
|
||||
local param2_data = vm_context.param2_data
|
||||
local biomemap = vm_context.biomemap
|
||||
local vm, data, area = vm_context.vm, vm_context.data, vm_context.area
|
||||
|
||||
local min_x, min_z = minp.x, minp.z
|
||||
local chunksize = max_y - min_y + 1
|
||||
|
||||
----- Interactive block fixing section -----
|
||||
----- The section to perform basic block overrides of the core mapgen generated world. -----
|
||||
|
||||
-- Snow and sand fixes. This code implements snow consistency
|
||||
-- and fixes floating sand and cut plants.
|
||||
-- A snowy grass block must be below a top snow or snow block at all times.
|
||||
|
||||
-- Set param2 (=color) of grass blocks.
|
||||
-- Clear snowy grass blocks without snow above to ensure consistency.
|
||||
local nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:dirt_with_grass", "mcl_core:dirt_with_grass_snow"})
|
||||
|
||||
for n=1, #nodes do
|
||||
local pos = nodes[n]
|
||||
local x, y, z = pos.x, pos.y, pos.z
|
||||
local p_pos = area:index(x, y, z)
|
||||
local p_pos_above = area:index(x, y + 1, z)
|
||||
local biomemap_offset = (z - min_z) * chunksize + x - min_x + 1
|
||||
local biome_id = biomemap[biomemap_offset]
|
||||
local biome_name = minetest.get_biome_name(biome_id)
|
||||
if biome_name then
|
||||
local biome = minetest.registered_biomes[biome_name]
|
||||
if biome and biome._mcl_biome_type then
|
||||
param2_data[p_pos] = biome._mcl_palette_index
|
||||
vm_context.write_param2 = true
|
||||
end
|
||||
end
|
||||
if data[p_pos] == c_dirt_with_grass_snow and p_pos_above and data[p_pos_above] ~= c_top_snow and data[p_pos_above] ~= c_snow_block then
|
||||
data[p_pos] = c_dirt_with_grass
|
||||
vm_context.write = true
|
||||
end
|
||||
end
|
||||
end, 999999999)
|
|
@ -0,0 +1,63 @@
|
|||
local c_water = minetest.get_content_id("mcl_core:water_source")
|
||||
local c_dirt = minetest.get_content_id("mcl_core:dirt")
|
||||
local c_clay = minetest.get_content_id("mcl_core:clay")
|
||||
|
||||
local perlin_clay
|
||||
|
||||
local math_max = math.max
|
||||
local math_min = math.min
|
||||
local math_floor = math.floor
|
||||
local math_abs = math.abs
|
||||
local offset = math_floor(mcl_mapgen.BS / 2)
|
||||
local minetest_get_item_group = minetest.get_item_group
|
||||
local minetest_get_name_from_content_id = minetest.get_name_from_content_id
|
||||
|
||||
mcl_mapgen.register_mapgen_block_lvm(function(c)
|
||||
local minp, maxp, blockseed, voxelmanip_data, voxelmanip_area = c.minp, c.maxp, c.blockseed, c.data, c.area
|
||||
local max_y = maxp.y
|
||||
if max_y < -7 then return end
|
||||
local min_y = minp.y
|
||||
if min_y > 0 then return end
|
||||
|
||||
c.vm = c.vm or mcl_mapgen.get_voxel_manip(c)
|
||||
|
||||
local pr = PseudoRandom(blockseed)
|
||||
|
||||
perlin_clay = perlin_clay or minetest.get_perlin({
|
||||
offset = 0.5,
|
||||
scale = 0.2,
|
||||
spread = {x = 5, y = 5, z = 5},
|
||||
seed = -316,
|
||||
octaves = 1,
|
||||
persist = 0.0
|
||||
})
|
||||
|
||||
for y = math_max(min_y, -8), math_min(max_y, 0) do
|
||||
-- Assume X and Z lengths are equal
|
||||
local x = minp.x + offset + pr:next(-2, 2)
|
||||
local z = minp.z + offset + pr:next(-2, 2)
|
||||
if perlin_clay:get_3d({x = x, y = y, z = z}) + pr:next(1, 20) > 19 then
|
||||
-- Get position and shift it a bit randomly so the clay do not obviously appear in a grid
|
||||
local water_pos = voxelmanip_area:index(x, y + 1, z)
|
||||
local water_node = voxelmanip_data[water_pos]
|
||||
if water_node == c_water or water_node == c_clay then
|
||||
local surface_pos = voxelmanip_area:index(x, y, z)
|
||||
local surface_node = voxelmanip_data[surface_pos]
|
||||
if (surface_node == c_dirt or surface_node == c_clay or minetest_get_item_group(minetest_get_name_from_content_id(surface_node), "sand") == 1) then
|
||||
local diamondsize = pr:next(1, 3)
|
||||
for x1 = -diamondsize, diamondsize do
|
||||
local abs_x1 = math_abs(x1)
|
||||
for z1 = -(diamondsize - abs_x1), diamondsize - abs_x1 do
|
||||
local ccpos = voxelmanip_area:index(x + x1, y, z + z1)
|
||||
local claycandidate = voxelmanip_data[ccpos]
|
||||
if voxelmanip_data[ccpos] == c_dirt or minetest_get_item_group(minetest_get_name_from_content_id(claycandidate), "sand") == 1 then
|
||||
voxelmanip_data[ccpos] = c_clay
|
||||
c.write = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,41 @@
|
|||
-- Nether Light:
|
||||
mcl_mapgen.register_mapgen_block_lvm(function(vm_context)
|
||||
local minp = vm_context.minp
|
||||
local miny = minp.y
|
||||
if miny > mcl_mapgen.nether.max then return end
|
||||
local maxp = vm_context.maxp
|
||||
local maxy = maxp.y
|
||||
if maxy < mcl_mapgen.nether.min then return end
|
||||
local p1 = {x = minp.x, y = math.max(miny, mcl_mapgen.nether.min), z = minp.z}
|
||||
local p2 = {x = maxp.x, y = math.min(maxy, mcl_mapgen.nether.max), z = maxp.z}
|
||||
vm_context.vm:set_lighting({day = 3, night = 4}, p1, p2)
|
||||
vm_context.write = true
|
||||
end, 999999999)
|
||||
|
||||
-- Nether Roof Light:
|
||||
mcl_mapgen.register_mapgen_block_lvm(function(vm_context)
|
||||
local minp = vm_context.minp
|
||||
local miny = minp.y
|
||||
if miny > mcl_mapgen.nether.max+127 then return end
|
||||
local maxp = vm_context.maxp
|
||||
local maxy = maxp.y
|
||||
if maxy <= mcl_mapgen.nether.max then return end
|
||||
local p1 = {x = minp.x, y = math.max(miny, mcl_mapgen.nether.max + 1), z = minp.z}
|
||||
local p2 = {x = maxp.x, y = math.min(maxy, mcl_mapgen.nether.max + 127), z = maxp.z}
|
||||
vm_context.vm:set_lighting({day = 15, night = 15}, p1, p2)
|
||||
vm_context.write = true
|
||||
end, 999999999)
|
||||
|
||||
-- End Light:
|
||||
mcl_mapgen.register_mapgen_block_lvm(function(vm_context)
|
||||
local minp = vm_context.minp
|
||||
local miny = minp.y
|
||||
if miny > mcl_mapgen.end_.max then return end
|
||||
local maxp = vm_context.maxp
|
||||
local maxy = maxp.y
|
||||
if maxy <= mcl_mapgen.end_.min then return end
|
||||
local p1 = {x = minp.x, y = math.max(miny, mcl_mapgen.end_.min), z = minp.z}
|
||||
local p2 = {x = maxp.x, y = math.min(maxy, mcl_mapgen.end_.max), z = maxp.z}
|
||||
vm_context.vm:set_lighting({day=15, night=15}, p1, p2)
|
||||
vm_context.write = true
|
||||
end, 9999999999)
|
|
@ -1,5 +1,5 @@
|
|||
name = mcl_mapgen_core
|
||||
author = Wuzzy
|
||||
description = The core of the MCL2 mapgen
|
||||
depends = mcl_init, mcl_core, biomeinfo, mcl_worlds, mcl_cocoas, mcl_sponges, mcl_ocean, mcl_stairs, mcl_monster_eggs, mcl_structures
|
||||
optional_depends = mclx_core
|
||||
depends = mcl_mapgen, mcl_init, mcl_core, biomeinfo, mcl_worlds
|
||||
optional_depends = mclx_core, mcl_cocoas, mcl_sponges, mcl_ocean, mcl_stairs, mcl_monster_eggs, mcl_structures, mcl_flowers, mcl_farming, mcl_mushrooms, mcl_nether
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
local v6 = mcl_mapgen.v6
|
||||
|
||||
local mcl_mushrooms = minetest.get_modpath("mcl_mushrooms")
|
||||
|
||||
local c_water = minetest.get_content_id("mcl_core:water_source")
|
||||
local c_stone = minetest.get_content_id("mcl_core:stone")
|
||||
local c_sand = minetest.get_content_id("mcl_core:sand")
|
||||
local c_dirt = minetest.get_content_id("mcl_core:dirt")
|
||||
|
||||
local c_soul_sand = minetest.get_content_id("mcl_nether:soul_sand")
|
||||
local c_netherrack = minetest.get_content_id("mcl_nether:netherrack")
|
||||
local c_nether_lava = minetest.get_content_id("mcl_nether:nether_lava_source")
|
||||
|
||||
-- Generate mushrooms in caves manually.
|
||||
-- Minetest's API does not support decorations in caves yet. :-(
|
||||
local function generate_underground_mushrooms(minp, maxp, seed)
|
||||
if not mcl_mushrooms then return end
|
||||
|
||||
local pr_shroom = PseudoRandom(seed-24359)
|
||||
-- Generate rare underground mushrooms
|
||||
-- TODO: Make them appear in groups, use Perlin noise
|
||||
local min, max = mcl_mapgen.overworld.lava_max + 4, 0
|
||||
if minp.y > max or maxp.y < min then
|
||||
return
|
||||
end
|
||||
|
||||
local bpos
|
||||
local stone = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_core:stone", "mcl_core:dirt", "mcl_core:mycelium", "mcl_core:podzol", "mcl_core:andesite", "mcl_core:diorite", "mcl_core:granite", "mcl_core:stone_with_coal", "mcl_core:stone_with_iron", "mcl_core:stone_with_gold"})
|
||||
|
||||
for n = 1, #stone do
|
||||
bpos = {x = stone[n].x, y = stone[n].y + 1, z = stone[n].z }
|
||||
|
||||
local l = minetest.get_node_light(bpos, 0.5)
|
||||
if bpos.y >= min and bpos.y <= max and l and l <= 12 and pr_shroom:next(1,1000) < 4 then
|
||||
if pr_shroom:next(1,2) == 1 then
|
||||
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_brown"})
|
||||
else
|
||||
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_red"})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Generate Nether decorations manually: Eternal fire, mushrooms
|
||||
-- Minetest's API does not support decorations in caves yet. :-(
|
||||
local function generate_nether_decorations(minp, maxp, seed)
|
||||
local pr_nether = PseudoRandom(seed+667)
|
||||
|
||||
if minp.y > mcl_mapgen.nether.max or maxp.y < mcl_mapgen.nether.min then
|
||||
return
|
||||
end
|
||||
|
||||
minetest.log("action", "[mcl_mapgen_core] Nether decorations " .. minetest.pos_to_string(minp) .. " ... " .. minetest.pos_to_string(maxp))
|
||||
|
||||
-- TODO: Generate everything based on Perlin noise instead of PseudoRandom
|
||||
|
||||
local bpos
|
||||
local rack = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_nether:netherrack"})
|
||||
local magma = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_nether:magma"})
|
||||
local ssand = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_nether:soul_sand"})
|
||||
|
||||
-- Helper function to spawn “fake” decoration
|
||||
local function special_deco(nodes, spawn_func)
|
||||
for n = 1, #nodes do
|
||||
bpos = {x = nodes[n].x, y = nodes[n].y + 1, z = nodes[n].z }
|
||||
|
||||
spawn_func(bpos)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Eternal fire on netherrack
|
||||
special_deco(rack, function(bpos)
|
||||
-- Eternal fire on netherrack
|
||||
if pr_nether:next(1,100) <= 3 then
|
||||
minetest.set_node(bpos, {name = "mcl_fire:eternal_fire"})
|
||||
end
|
||||
end)
|
||||
|
||||
-- Eternal fire on magma cubes
|
||||
special_deco(magma, function(bpos)
|
||||
if pr_nether:next(1,150) == 1 then
|
||||
minetest.set_node(bpos, {name = "mcl_fire:eternal_fire"})
|
||||
end
|
||||
end)
|
||||
|
||||
-- Mushrooms on netherrack
|
||||
-- Note: Spawned *after* the fire because of light level checks
|
||||
if mcl_mushrooms then
|
||||
special_deco(rack, function(bpos)
|
||||
local l = minetest.get_node_light(bpos, 0.5)
|
||||
if bpos.y > mcl_mapgen.nether.lava_max + 6 and l and l <= 12 and pr_nether:next(1,1000) <= 4 then
|
||||
-- TODO: Make mushrooms appear in groups, use Perlin noise
|
||||
if pr_nether:next(1,2) == 1 then
|
||||
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_brown"})
|
||||
else
|
||||
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_red"})
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
mcl_mapgen.register_mapgen(function(minp, maxp, seed, vm_context)
|
||||
local min_y, max_y = minp.y, maxp.y
|
||||
|
||||
-- Nether block fixes:
|
||||
-- * Replace water with Nether lava.
|
||||
-- * Replace stone, sand dirt in v6 so the Nether works in v6.
|
||||
if min_y > mcl_mapgen.nether.max or max_y < mcl_mapgen.nether.min then return end
|
||||
if v6 then
|
||||
local nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"})
|
||||
if #nodes < 1 then return end
|
||||
vm_context.write = true
|
||||
local data = vm_context.data
|
||||
local area = vm_context.area
|
||||
for n = 1, #nodes do
|
||||
local p_pos = area:index(nodes[n].x, nodes[n].y, nodes[n].z)
|
||||
if data[p_pos] == c_water then
|
||||
data[p_pos] = c_nether_lava
|
||||
elseif data[p_pos] == c_stone then
|
||||
data[p_pos] = c_netherrack
|
||||
elseif data[p_pos] == c_sand or data[p_pos] == c_dirt then
|
||||
data[p_pos] = c_soul_sand
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
||||
|
||||
generate_underground_mushrooms(minp, maxp, seed)
|
||||
generate_nether_decorations(minp, maxp, seed)
|
||||
end, 1)
|
|
@ -0,0 +1,57 @@
|
|||
local nether_wart_chance
|
||||
if mcl_mapgen.v6 then
|
||||
nether_wart_chance = 85
|
||||
else
|
||||
nether_wart_chance = 170
|
||||
end
|
||||
|
||||
local y_min = mcl_mapgen.nether.min
|
||||
local y_max = mcl_mapgen.nether.max
|
||||
local place_on = {"group:soil_nether_wart"}
|
||||
|
||||
local block_size = mcl_mapgen.BS
|
||||
local decrease_search_area = math.min(2, math.floor(block_size/2))
|
||||
local search_area_size = math.max(block_size - 2 * decrease_search_area, math.max(1, math.ceil(nether_wart_chance^(1/3))))
|
||||
nether_wart_chance = math.floor(nether_wart_chance * (search_area_size^3) / (block_size^3))
|
||||
local nether_wart_chance_threshold = nether_wart_chance
|
||||
local minetest_swap_node = minetest.swap_node
|
||||
|
||||
local wart_perlin
|
||||
local noise_params = {
|
||||
offset = 0.4,
|
||||
scale = 0.4,
|
||||
spread = {x = block_size, y = block_size, z = block_size},
|
||||
seed = 238742,
|
||||
octaves = 1,
|
||||
persist = 0.5,
|
||||
}
|
||||
|
||||
minetest.log("action", "Nether Wart block_size=" .. block_size .. ", search_area_size=" .. search_area_size .. ", per-area nether_wart_chance=" .. nether_wart_chance)
|
||||
|
||||
local minetest_find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air
|
||||
local minetest_get_perlin = minetest.get_perlin
|
||||
|
||||
mcl_mapgen.register_mapgen_block(function(minp, maxp, seed)
|
||||
local minp = minp
|
||||
local y1 = minp.y
|
||||
if y1 > y_max then return end
|
||||
|
||||
local maxp = maxp
|
||||
local y2 = maxp.y
|
||||
if y2 < y_min then return end
|
||||
|
||||
local p1 = {x = minp.x + decrease_search_area, y = y1 + decrease_search_area, z = minp.z + decrease_search_area}
|
||||
local p2 = {x = maxp.x - decrease_search_area, y = y2 - decrease_search_area, z = maxp.z - decrease_search_area}
|
||||
|
||||
local pos_list = minetest_find_nodes_in_area_under_air(p1, p2, place_on)
|
||||
local pr = PseudoRandom(seed)
|
||||
wart_perlin = wart_perlin or minetest_get_perlin(noise_params)
|
||||
|
||||
for i = 1, #pos_list do
|
||||
local pos = pos_list[i]
|
||||
if pr:next(1, nether_wart_chance) + wart_perlin:get_3d(pos) >= nether_wart_chance_threshold then
|
||||
pos.y = pos.y + 1
|
||||
minetest.swap_node(pos, {name = "mcl_nether:nether_wart"})
|
||||
end
|
||||
end
|
||||
end, 999999999)
|
|
@ -0,0 +1,251 @@
|
|||
-- Generate tree decorations in the bounding box. This adds:
|
||||
-- * Cocoa at jungle trees
|
||||
-- * Jungle tree vines
|
||||
-- * Oak vines in swamplands
|
||||
|
||||
local minetest_find_nodes_in_area = minetest.find_nodes_in_area
|
||||
local minetest_find_node_near = minetest.find_node_near
|
||||
local minetest_get_node_light = minetest.get_node_light
|
||||
local minetest_dir_to_facedir = minetest.dir_to_facedir
|
||||
local minetest_dir_to_wallmounted = minetest.dir_to_wallmounted
|
||||
local table_copy = table.copy
|
||||
local vector_subtract = vector.subtract
|
||||
local vector_add = vector.add
|
||||
local math_max = math.max
|
||||
local math_ceil = math.ceil
|
||||
local math_abs = math.abs
|
||||
|
||||
local c_air = minetest.CONTENT_AIR
|
||||
local c_cocoas
|
||||
local c_jungleleaves = minetest.get_content_id("mcl_core:jungleleaves")
|
||||
local c_leaves = minetest.get_content_id("mcl_core:leaves")
|
||||
local c_vine = minetest.get_content_id("mcl_core:vine")
|
||||
|
||||
if minetest.get_modpath("mcl_cocoas") then
|
||||
c_cocoas = {
|
||||
minetest.get_content_id("mcl_cocoas:cocoa_1"),
|
||||
minetest.get_content_id("mcl_cocoas:cocoa_2"),
|
||||
minetest.get_content_id("mcl_cocoas:cocoa_3"),
|
||||
}
|
||||
end
|
||||
|
||||
local swampland
|
||||
local swampland_shore
|
||||
local jungle
|
||||
local jungle_shore
|
||||
local jungle_m
|
||||
local jungle_m_shore
|
||||
local jungle_edge
|
||||
local jungle_edge_shore
|
||||
local jungle_edge_m
|
||||
local jungle_edge_m_shore
|
||||
|
||||
local perlin_vines, perlin_vines_fine, perlin_vines_upwards, perlin_vines_length, perlin_vines_density
|
||||
|
||||
local dirs = {
|
||||
{x = 1, y = 0, z = 0},
|
||||
{x = -1, y = 0, z = 0},
|
||||
{x = 0, y = 0, z = 1},
|
||||
{x = 0, y = 0, z = -1},
|
||||
}
|
||||
|
||||
local function generate_tree_decorations(vm_context)
|
||||
local maxp = vm_context.maxp
|
||||
if maxp.y < 0 then return end
|
||||
local minp = vm_context.minp
|
||||
|
||||
local data = vm_context.data
|
||||
vm_context.param2_data = vm_context.param2_data or vm_context.vm:get_param2_data(vm_context.lvm_param2_buffer)
|
||||
local param2_data = vm_context.param2_data
|
||||
local area = vm_context.area
|
||||
|
||||
local biomemap = vm_context.biomemap
|
||||
|
||||
local pr = PseudoRandom(vm_context.chunkseed)
|
||||
|
||||
local oaktree, oakleaves, jungletree, jungleleaves = {}, {}, {}, {}
|
||||
|
||||
-- Modifier for Jungle M biome: More vines and cocoas
|
||||
local dense_vegetation = false
|
||||
|
||||
if biomemap then
|
||||
swampland = swampland or minetest.get_biome_id("Swampland")
|
||||
swampland_shore = swampland_shore or minetest.get_biome_id("Swampland_shore")
|
||||
jungle = jungle or minetest.get_biome_id("Jungle")
|
||||
jungle_shore = jungle_shore or minetest.get_biome_id("Jungle_shore")
|
||||
jungle_m = jungle_m or minetest.get_biome_id("JungleM")
|
||||
jungle_m_shore = jungle_m_shore or minetest.get_biome_id("JungleM_shore")
|
||||
jungle_edge = jungle_edge or minetest.get_biome_id("JungleEdge")
|
||||
jungle_edge_shore = jungle_edge_shore or minetest.get_biome_id("JungleEdge_shore")
|
||||
jungle_edge_m = jungle_edge_m or minetest.get_biome_id("JungleEdgeM")
|
||||
jungle_edge_m_shore = jungle_edge_m_shore or minetest.get_biome_id("JungleEdgeM_shore")
|
||||
|
||||
-- Biome map available: Check if the required biome (jungle or swampland)
|
||||
-- is in this mapchunk. We are only interested in trees in the correct biome.
|
||||
-- The nodes are added if the correct biome is *anywhere* in the mapchunk.
|
||||
-- TODO: Strictly generate vines in the correct biomes only.
|
||||
local swamp_biome_found, jungle_biome_found = false, false
|
||||
for b=1, #biomemap do
|
||||
local id = biomemap[b]
|
||||
|
||||
if not swamp_biome_found and (id == swampland or id == swampland_shore) then
|
||||
oaktree = minetest_find_nodes_in_area(minp, maxp, {"mcl_core:tree"})
|
||||
oakleaves = minetest_find_nodes_in_area(minp, maxp, {"mcl_core:leaves"})
|
||||
swamp_biome_found = true
|
||||
end
|
||||
if not jungle_biome_found and (id == jungle or id == jungle_shore or id == jungle_m or id == jungle_m_shore or id == jungle_edge or id == jungle_edge_shore or id == jungle_edge_m or id == jungle_edge_m_shore) then
|
||||
jungletree = minetest_find_nodes_in_area(minp, maxp, {"mcl_core:jungletree"})
|
||||
jungleleaves = minetest_find_nodes_in_area(minp, maxp, {"mcl_core:jungleleaves"})
|
||||
jungle_biome_found = true
|
||||
end
|
||||
if not dense_vegetation and (id == jungle_m or id == jungle_m_shore) then
|
||||
dense_vegetation = true
|
||||
end
|
||||
if swamp_biome_found and jungle_biome_found and dense_vegetation then
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
-- If there is no biome map, we just count all jungle things we can find.
|
||||
-- Oak vines will not be generated.
|
||||
jungletree = minetest_find_nodes_in_area(minp, maxp, {"mcl_core:jungletree"})
|
||||
jungleleaves = minetest_find_nodes_in_area(minp, maxp, {"mcl_core:jungleleaves"})
|
||||
end
|
||||
|
||||
local pos, treepos, dir
|
||||
|
||||
if c_cocoas then
|
||||
local cocoachance = 40
|
||||
if dense_vegetation then
|
||||
cocoachance = 32
|
||||
end
|
||||
|
||||
-- Pass 1: Generate cocoas at jungle trees
|
||||
for n = 1, #jungletree do
|
||||
|
||||
pos = table_copy(jungletree[n])
|
||||
treepos = table_copy(pos)
|
||||
|
||||
if minetest_find_node_near(pos, 1, {"mcl_core:jungleleaves"}) then
|
||||
|
||||
dir = pr:next(1, cocoachance)
|
||||
|
||||
if dir == 1 then
|
||||
pos.z = pos.z + 1
|
||||
elseif dir == 2 then
|
||||
pos.z = pos.z - 1
|
||||
elseif dir == 3 then
|
||||
pos.x = pos.x + 1
|
||||
elseif dir == 4 then
|
||||
pos.x = pos.x -1
|
||||
end
|
||||
|
||||
local p_pos = area:index(pos.x, pos.y, pos.z)
|
||||
local l = minetest_get_node_light(pos)
|
||||
|
||||
if dir < 5
|
||||
and data[p_pos] == c_air
|
||||
and l and l > 12 then
|
||||
local c = pr:next(1, 3)
|
||||
data[p_pos] = c_cocoas[c]
|
||||
vm_context.write = true
|
||||
param2_data[p_pos] = minetest_dir_to_facedir(vector_subtract(treepos, pos))
|
||||
vm_context.write_param2 = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Pass 2: Generate vines at jungle wood, jungle leaves in jungle and oak wood, oak leaves in swampland
|
||||
perlin_vines = perlin_vines or minetest.get_perlin(555, 4, 0.6, 500)
|
||||
perlin_vines_fine = perlin_vines_fine or minetest.get_perlin(43000, 3, 0.6, 1)
|
||||
perlin_vines_length = perlin_vines_length or minetest.get_perlin(435, 4, 0.6, 75)
|
||||
perlin_vines_upwards = perlin_vines_upwards or minetest.get_perlin(436, 3, 0.6, 10)
|
||||
perlin_vines_density = perlin_vines_density or minetest.get_perlin(436, 3, 0.6, 500)
|
||||
|
||||
-- Extra long vines in Jungle M
|
||||
local maxvinelength = 7
|
||||
if dense_vegetation then
|
||||
maxvinelength = 14
|
||||
end
|
||||
local treething
|
||||
for i=1, 4 do
|
||||
if i==1 then
|
||||
treething = jungletree
|
||||
elseif i == 2 then
|
||||
treething = jungleleaves
|
||||
elseif i == 3 then
|
||||
treething = oaktree
|
||||
elseif i == 4 then
|
||||
treething = oakleaves
|
||||
end
|
||||
|
||||
for n = 1, #treething do
|
||||
pos = treething[n]
|
||||
|
||||
treepos = table_copy(pos)
|
||||
|
||||
for d = 1, #dirs do
|
||||
local pos = vector_add(pos, dirs[d])
|
||||
local p_pos = area:index(pos.x, pos.y, pos.z)
|
||||
|
||||
local vine_threshold = math_max(0.33333, perlin_vines_density:get_2d(pos))
|
||||
if dense_vegetation then
|
||||
vine_threshold = vine_threshold * (2/3)
|
||||
end
|
||||
|
||||
if perlin_vines:get_2d(pos) > -1.0 and perlin_vines_fine:get_3d(pos) > vine_threshold and data[p_pos] == c_air then
|
||||
|
||||
local rdir = {}
|
||||
rdir.x = -dirs[d].x
|
||||
rdir.y = dirs[d].y
|
||||
rdir.z = -dirs[d].z
|
||||
local param2 = minetest_dir_to_wallmounted(rdir)
|
||||
|
||||
-- Determine growth direction
|
||||
local grow_upwards = false
|
||||
-- Only possible on the wood, not on the leaves
|
||||
if i == 1 then
|
||||
grow_upwards = perlin_vines_upwards:get_3d(pos) > 0.8
|
||||
end
|
||||
if grow_upwards then
|
||||
-- Grow vines up 1-4 nodes, even through jungleleaves.
|
||||
-- This may give climbing access all the way to the top of the tree :-)
|
||||
-- But this will be fairly rare.
|
||||
local length = math_ceil(math_abs(perlin_vines_length:get_3d(pos)) * 4)
|
||||
for l=0, length-1 do
|
||||
local t_pos = area:index(treepos.x, treepos.y, treepos.z)
|
||||
|
||||
if (data[p_pos] == c_air or data[p_pos] == c_jungleleaves or data[p_pos] == c_leaves) and mcl_core.supports_vines(minetest.get_name_from_content_id(data[t_pos])) then
|
||||
data[p_pos] = c_vine
|
||||
param2_data[p_pos] = param2
|
||||
vm_context.write = true
|
||||
else
|
||||
break
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
p_pos = area:index(pos.x, pos.y, pos.z)
|
||||
treepos.y = treepos.y + 1
|
||||
end
|
||||
else
|
||||
-- Grow vines down, length between 1 and maxvinelength
|
||||
local length = math_ceil(math_abs(perlin_vines_length:get_3d(pos)) * maxvinelength)
|
||||
for l=0, length-1 do
|
||||
if data[p_pos] == c_air then
|
||||
data[p_pos] = c_vine
|
||||
param2_data[p_pos] = param2
|
||||
vm_context.write = true
|
||||
else
|
||||
break
|
||||
end
|
||||
pos.y = pos.y - 1
|
||||
p_pos = area:index(pos.x, pos.y, pos.z)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
mcl_mapgen.register_on_generated(generate_tree_decorations, 0)
|
|
@ -0,0 +1,49 @@
|
|||
local c_air = minetest.CONTENT_AIR
|
||||
|
||||
mcl_mapgen.register_on_generated(function(vm_context)
|
||||
local minp, maxp = vm_context.minp, vm_context.maxp
|
||||
|
||||
if minp.y <= mcl_mapgen.end_.max and maxp.y >= mcl_mapgen.end_.min then
|
||||
local nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"})
|
||||
if #nodes > 0 then
|
||||
for _, n in pairs(nodes) do
|
||||
data[area:index(n.x, n.y, n.z)] = c_air
|
||||
end
|
||||
end
|
||||
vm_context.write = true
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
if minp.y > mcl_mapgen.overworld.max or maxp.y < mcl_mapgen.overworld.min then return end
|
||||
local vm, data, area = vm_context.vm, vm_context.data, vm_context.area
|
||||
|
||||
--[[ Remove broken double plants caused by v6 weirdness.
|
||||
v6 might break the bottom part of double plants because of how it works.
|
||||
There are 3 possibilities:
|
||||
1) Jungle: Top part is placed on top of a jungle tree or fern (=v6 jungle grass).
|
||||
This is because the schematic might be placed even if some nodes of it
|
||||
could not be placed because the destination was already occupied.
|
||||
TODO: A better fix for this would be if schematics could abort placement
|
||||
altogether if ANY of their nodes could not be placed.
|
||||
2) Cavegen: Removes the bottom part, the upper part floats
|
||||
3) Mudflow: Same as 2) ]]
|
||||
local plants = minetest.find_nodes_in_area(minp, maxp, "group:double_plant")
|
||||
for n = 1, #plants do
|
||||
local node = vm:get_node_at(plants[n])
|
||||
local is_top = minetest.get_item_group(node.name, "double_plant") == 2
|
||||
if is_top then
|
||||
local p_pos = area:index(plants[n].x, plants[n].y-1, plants[n].z)
|
||||
if p_pos then
|
||||
node = vm:get_node_at({x=plants[n].x, y=plants[n].y-1, z=plants[n].z})
|
||||
local is_bottom = minetest.get_item_group(node.name, "double_plant") == 1
|
||||
if not is_bottom then
|
||||
p_pos = area:index(plants[n].x, plants[n].y, plants[n].z)
|
||||
data[p_pos] = c_air
|
||||
vm_context.write = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end, 999999999)
|
|
@ -0,0 +1,104 @@
|
|||
-- Check: v7 apple 2320,4,-12558
|
||||
|
||||
local chance_per_chunk = 5
|
||||
local noise_multiplier = 1
|
||||
local random_offset = 12342
|
||||
local struct_threshold = chance_per_chunk
|
||||
local mcl_structures_get_perlin_noise_level = mcl_structures.get_perlin_noise_level
|
||||
|
||||
local mcl_mapgen_get_far_node = mcl_mapgen.get_far_node
|
||||
local minetest_log = minetest.log
|
||||
local minetest_place_schematic = minetest.place_schematic
|
||||
local minetest_pos_to_string = minetest.pos_to_string
|
||||
local minetest_swap_node = minetest.swap_node
|
||||
|
||||
local path = minetest.get_modpath("mcl_ocean_monument") .. "/schematics/ocean_monument.mts"
|
||||
|
||||
local water = "mcl_core:water_source"
|
||||
local air = "air"
|
||||
local ice = "mcl_core:ice"
|
||||
|
||||
local leg_materials = {
|
||||
"mcl_ocean:prismarine_brick",
|
||||
"mcl_ocean:prismarine",
|
||||
}
|
||||
local what_we_can_replace_by_legs = {
|
||||
water,
|
||||
air,
|
||||
"mcl_core:water_flowing",
|
||||
"mcl_core:stone",
|
||||
}
|
||||
|
||||
local leg_search_quick_index = {}
|
||||
for _, v in pairs(leg_materials) do
|
||||
leg_search_quick_index[v] = true
|
||||
end
|
||||
|
||||
local leg_replace_quick_index = {}
|
||||
for _, v in pairs(what_we_can_replace_by_legs) do
|
||||
leg_replace_quick_index[v] = true
|
||||
end
|
||||
|
||||
local y_wanted = mcl_mapgen.OFFSET_NODES -- supposed to be -32
|
||||
local y_bottom = mcl_mapgen.overworld.min -- -62
|
||||
|
||||
mcl_mapgen.register_mapgen(function(minp, maxp, seed)
|
||||
local minp = minp
|
||||
local y = minp.y
|
||||
if y ~= y_wanted then return end
|
||||
|
||||
local pr = PseudoRandom(seed + random_offset)
|
||||
local random_number = pr:next(1, chance_per_chunk)
|
||||
local noise = mcl_structures_get_perlin_noise_level(minp) * noise_multiplier
|
||||
if not noise or (random_number + noise) < struct_threshold then return end
|
||||
|
||||
local x, z = minp.x, minp.z
|
||||
|
||||
-- scan the ocean - it should be the ocean:
|
||||
for i = 1, pr:next(10, 100) do
|
||||
local pos = {x = pr:next(15, 64) + x, y = pr:next(0, 25) - 25, z = pr:next(15, 64) + z}
|
||||
local node_name = mcl_mapgen_get_far_node(pos).name
|
||||
if node_name ~= water then return end
|
||||
end
|
||||
|
||||
-- scan nodes above water level - there should be the air:
|
||||
for i = 1, pr:next(10, 100) do
|
||||
local pos = {x = pr:next(0, 79) + x, y = 2, z = pr:next(0,79) + z}
|
||||
local node_name = mcl_mapgen_get_far_node(pos).name
|
||||
if node_name ~= air then return end
|
||||
end
|
||||
|
||||
-- scan ocean surface - allow only water and ice:
|
||||
for i = 1, pr:next(10,100) do
|
||||
local pos = {x=pr:next(0, 79)+x, y=1, z=pr:next(0,79)+z}
|
||||
local node_name = mcl_mapgen_get_far_node(pos).name
|
||||
if node_name ~= water and node_name ~= ice then return end
|
||||
end
|
||||
|
||||
-- random rotation:
|
||||
local rotation = pr:next(0, 3)
|
||||
local rotation_str = tostring(rotation * 90)
|
||||
minetest_place_schematic(minp, path, rotation_str, nil, true)
|
||||
|
||||
-- search prismarine legs at base level and continue them up to the bottom:
|
||||
for x = x, maxp.x do
|
||||
for z = z, maxp.z do
|
||||
local pos = {x = x, y = y, z = z}
|
||||
local node_name = mcl_mapgen_get_far_node(pos).name
|
||||
if leg_search_quick_index[node_name] then
|
||||
local node_leg = {name = node_name}
|
||||
for y = y - 1, y_bottom, -1 do
|
||||
pos.y = y
|
||||
local next_name = mcl_mapgen_get_far_node(pos).name
|
||||
if not leg_replace_quick_index[next_name] then
|
||||
break
|
||||
end
|
||||
minetest_swap_node(pos, node_leg)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest_log("action", "[mcl_ocean_monument] Placed at " .. minetest_pos_to_string(minp) .. ", " .. rotation_str .. " deg.")
|
||||
|
||||
end, mcl_mapgen.order.OCEAN_MONUMENT)
|
|
@ -0,0 +1,4 @@
|
|||
name = mcl_ocean_monument
|
||||
author = TrashPanda
|
||||
description = Adds Ocean Monument, https://git.minetest.land/MineClone2/MineClone2/issues/958#issuecomment-14102
|
||||
depends = mcl_mapgen, mcl_structures
|
Binary file not shown.
|
@ -1,106 +1 @@
|
|||
-- Generate strongholds.
|
||||
|
||||
-- A total of 128 strongholds are generated in rings around the world origin.
|
||||
-- This is the list of rings, starting with the innermost ring first.
|
||||
local stronghold_rings = {
|
||||
-- amount: Number of strongholds in ring.
|
||||
-- min, max: Minimum and maximum distance from (X=0, Z=0).
|
||||
{ amount = 3, min = 1408, max = 2688 },
|
||||
{ amount = 6, min = 4480, max = 5760 },
|
||||
{ amount = 10, min = 7552, max = 8832 },
|
||||
{ amount = 15, min = 10624, max = 11904 },
|
||||
{ amount = 21, min = 13696, max = 14976 },
|
||||
{ amount = 28, min = 16768, max = 18048 },
|
||||
{ amount = 36, min = 19840, max = 21120 },
|
||||
{ amount = 9, min = 22912, max = 24192 },
|
||||
}
|
||||
|
||||
local strongholds = {}
|
||||
local strongholds_inited = false
|
||||
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true"
|
||||
|
||||
-- Determine the stronghold positions and store them into the strongholds table.
|
||||
-- The stronghold positions are based on the world seed.
|
||||
-- The actual position might be offset by a few blocks because it might be shifted
|
||||
-- to make sure the end portal room is completely within the boundaries of a mapchunk.
|
||||
local function init_strongholds()
|
||||
if strongholds_inited then
|
||||
return
|
||||
end
|
||||
-- Don't generate strongholds in singlenode
|
||||
if mg_name == "singlenode" then
|
||||
strongholds_inited = true
|
||||
return
|
||||
end
|
||||
local seed = tonumber(minetest.get_mapgen_setting("seed"))
|
||||
local pr = PseudoRandom(seed)
|
||||
for s=1, #stronghold_rings do
|
||||
local ring = stronghold_rings[s]
|
||||
|
||||
-- Get random angle
|
||||
local angle = pr:next()
|
||||
-- Scale angle to 0 .. 2*math.pi
|
||||
angle = (angle / 32767) * (math.pi*2)
|
||||
for a=1, ring.amount do
|
||||
local dist = pr:next(ring.min, ring.max)
|
||||
local y
|
||||
if superflat then
|
||||
y = mcl_vars.mg_bedrock_overworld_max + 3
|
||||
else
|
||||
y = pr:next(mcl_vars.mg_bedrock_overworld_max+1, mcl_vars.mg_overworld_min+48)
|
||||
end
|
||||
local pos = { x = math.cos(angle) * dist, y = y, z = math.sin(angle) * dist }
|
||||
pos = vector.round(pos)
|
||||
table.insert(strongholds, { pos = pos, generated = false })
|
||||
|
||||
-- Rotate angle by (360 / amount) degrees.
|
||||
-- This will cause the angles to be evenly distributed in the stronghold ring
|
||||
angle = math.fmod(angle + ((math.pi*2) / ring.amount), math.pi*2)
|
||||
end
|
||||
end
|
||||
|
||||
mcl_structures.register_structures("stronghold", table.copy(strongholds))
|
||||
|
||||
strongholds_inited = true
|
||||
end
|
||||
|
||||
-- Stronghold generation for register_on_generated.
|
||||
local function generate_strongholds(minp, maxp, blockseed)
|
||||
local pr = PseudoRandom(blockseed)
|
||||
for s=1, #strongholds do
|
||||
if not strongholds[s].generated then
|
||||
local pos = strongholds[s].pos
|
||||
if minp.x <= pos.x and maxp.x >= pos.x and minp.z <= pos.z and maxp.z >= pos.z and minp.y <= pos.y and maxp.y >= pos.y then
|
||||
-- Make sure the end portal room is completely within the current mapchunk
|
||||
-- The original pos is changed intentionally.
|
||||
if pos.x - 6 < minp.x then
|
||||
pos.x = minp.x + 7
|
||||
end
|
||||
if pos.x + 6 > maxp.x then
|
||||
pos.x = maxp.x - 7
|
||||
end
|
||||
if pos.y - 4 < minp.y then
|
||||
pos.y = minp.y + 5
|
||||
end
|
||||
if pos.y + 4 > maxp.y then
|
||||
pos.y = maxp.y - 5
|
||||
end
|
||||
if pos.z - 6 < minp.z then
|
||||
pos.z = minp.z + 7
|
||||
end
|
||||
if pos.z + 6 > maxp.z then
|
||||
pos.z = maxp.z - 7
|
||||
end
|
||||
|
||||
mcl_structures.call_struct(pos, "end_portal_shrine", nil, pr)
|
||||
strongholds[s].generated = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
init_strongholds()
|
||||
|
||||
mcl_mapgen_core.register_generator("strongholds", nil, generate_strongholds, 999999)
|
||||
-- moved into mcl_structures
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
name = mcl_strongholds
|
||||
author = Wuzzy
|
||||
description = Generates strongholds with end portals in the Overworld
|
||||
depends = mcl_init, mcl_structures, mcl_mapgen_core
|
||||
description = Mod has been moved into mcl_structures. This is a dummy thing to overwrite the old thing, kay27 01/25/22
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
-- Check: v7 apple -21539,27,2404
|
||||
|
||||
local chance_per_chunk = 32
|
||||
local noise_multiplier = 0.9
|
||||
local random_offset = 999
|
||||
local scanning_ratio = 0.0003
|
||||
local struct_threshold = chance_per_chunk - 1
|
||||
|
||||
local mcl_structures_get_perlin_noise_level = mcl_structures.get_perlin_noise_level
|
||||
|
||||
local node_list = {"mcl_core:sand", "mcl_core:sandstone", "mcl_core:redsand", "mcl_colorblocks:hardened_clay_orange"}
|
||||
|
||||
local schematic_file = modpath .. "/schematics/mcl_structures_desert_temple.mts"
|
||||
|
||||
local temple_schematic_lua = minetest.serialize_schematic(schematic_file, "lua", {lua_use_comments = false, lua_num_indent_spaces = 0}) .. " return schematic"
|
||||
local temple_schematic = loadstring(temple_schematic_lua)()
|
||||
|
||||
local red_temple_schematic_lua = minetest.serialize_schematic(schematic_file, "lua", {lua_use_comments = false, lua_num_indent_spaces = 0}) .. " return schematic"
|
||||
red_temple_schematic_lua = red_temple_schematic_lua:gsub("mcl_colorblocks:hardened_clay_orange", "mcl_colorblocks:hardened_clay_red")
|
||||
red_temple_schematic_lua = red_temple_schematic_lua:gsub("mcl_core:sand_stone", "mcl_colorblocks:hardened_clay_orange")
|
||||
red_temple_schematic_lua = red_temple_schematic_lua:gsub("mcl_core:sand", "mcl_core:redsand")
|
||||
red_temple_schematic_lua = red_temple_schematic_lua:gsub("mcl_stairs:stair_sandstone", "mcl_stairs:stair_redsandstone")
|
||||
red_temple_schematic_lua = red_temple_schematic_lua:gsub("mcl_stairs:slab_sandstone", "mcl_stairs:slab_redsandstone")
|
||||
red_temple_schematic_lua = red_temple_schematic_lua:gsub("mcl_colorblocks:hardened_clay_yellow", "mcl_colorblocks:hardened_clay_pink")
|
||||
local red_temple_schematic = loadstring(red_temple_schematic_lua)()
|
||||
|
||||
local function on_placed(p1, rotation, pr, size)
|
||||
local p2 = {x = p1.x + size.x - 1, y = p1.y + size.y - 1, z = p1.z + size.z - 1}
|
||||
-- Delete cacti leftovers:
|
||||
local cactus_nodes = minetest.find_nodes_in_area_under_air({x = p1.x, y = p1.y + 11, z = p1.z}, {x = p2.x, y = p2.y - 2, z = p2.z}, "mcl_core:cactus", false)
|
||||
for _, pos in pairs(cactus_nodes) do
|
||||
local node_below = minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z})
|
||||
local nn = node_below.name
|
||||
if nn == "mcl_core:sandstone" then
|
||||
minetest.swap_node(pos, {name="air"})
|
||||
end
|
||||
end
|
||||
|
||||
-- Find chests.
|
||||
local chests = minetest.find_nodes_in_area(p1, {x = p2.x, y = p1.y + 5, z = p2.z}, "mcl_chests:chest")
|
||||
|
||||
-- Add desert temple loot into chests
|
||||
for c=1, #chests do
|
||||
local lootitems = mcl_loot.get_multi_loot({
|
||||
{
|
||||
stacks_min = 2,
|
||||
stacks_max = 4,
|
||||
items = {
|
||||
{ itemstring = "mcl_mobitems:bone", weight = 25, amount_min = 4, amount_max=6 },
|
||||
{ itemstring = "mcl_mobitems:rotten_flesh", weight = 25, amount_min = 3, amount_max=7 },
|
||||
{ itemstring = "mcl_mobitems:spider_eye", weight = 25, amount_min = 1, amount_max=3 },
|
||||
{ itemstring = "mcl_books:book", weight = 20, func = function(stack, pr)
|
||||
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}, pr)
|
||||
end },
|
||||
{ itemstring = "mcl_mobitems:saddle", weight = 20, },
|
||||
{ itemstring = "mcl_core:apple_gold", weight = 20, },
|
||||
{ itemstring = "mcl_core:gold_ingot", weight = 15, amount_min = 2, amount_max = 7 },
|
||||
{ itemstring = "mcl_core:iron_ingot", weight = 15, amount_min = 1, amount_max = 5 },
|
||||
{ itemstring = "mcl_core:emerald", weight = 15, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "", weight = 15, },
|
||||
{ itemstring = "mobs_mc:iron_horse_armor", weight = 15, },
|
||||
{ itemstring = "mobs_mc:gold_horse_armor", weight = 10, },
|
||||
{ itemstring = "mobs_mc:diamond_horse_armor", weight = 5, },
|
||||
{ itemstring = "mcl_core:diamond", weight = 5, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_core:apple_gold_enchanted", weight = 2, },
|
||||
}
|
||||
},
|
||||
{
|
||||
stacks_min = 4,
|
||||
stacks_max = 4,
|
||||
items = {
|
||||
{ itemstring = "mcl_mobitems:bone", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_mobitems:rotten_flesh", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_mobitems:gunpowder", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_core:sand", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_mobitems:string", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
}
|
||||
}}, pr)
|
||||
mcl_structures.init_node_construct(chests[c])
|
||||
local meta = minetest.get_meta(chests[c])
|
||||
local inv = meta:get_inventory()
|
||||
mcl_loot.fill_inventory(inv, "main", lootitems, pr)
|
||||
end
|
||||
|
||||
-- Initialize pressure plates and randomly remove up to 5 plates
|
||||
local pplates = minetest.find_nodes_in_area(p1, {x = p2.x, y = p1.y + 5, z = p2.z}, "mesecons_pressureplates:pressure_plate_stone_off")
|
||||
local pplates_remove = 5
|
||||
for p=1, #pplates do
|
||||
if pplates_remove > 0 and pr:next(1, 100) >= 50 then
|
||||
-- Remove plate
|
||||
minetest.remove_node(pplates[p])
|
||||
pplates_remove = pplates_remove - 1
|
||||
else
|
||||
-- Initialize plate
|
||||
minetest.registered_nodes["mesecons_pressureplates:pressure_plate_stone_off"].on_construct(pplates[p])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function place(pos, rotation, pr)
|
||||
local pos_below = {x = pos.x, y = pos.y - 1, z = pos.z}
|
||||
local pos_temple = {x = pos.x - 10, y = pos.y - 12, z = pos.z - 10}
|
||||
local node_below = minetest.get_node(pos_below)
|
||||
local nn = node_below.name
|
||||
if string.find(nn, "red") then
|
||||
mcl_structures.place_schematic({pos = pos_temple, schematic = red_temple_schematic, pr = pr, on_placed = on_placed})
|
||||
else
|
||||
mcl_structures.place_schematic({pos = pos_temple, schematic = temple_schematic, pr = pr, on_placed = on_placed})
|
||||
end
|
||||
end
|
||||
|
||||
local function get_place_rank(pos)
|
||||
local x, y, z = pos.x, pos.y - 1, pos.z
|
||||
local p1 = {x = x - 8, y = y, z = z - 8}
|
||||
local p2 = {x = x + 8, y = y, z = z + 8}
|
||||
local best_pos_list_surface = minetest.find_nodes_in_area(p1, p2, node_list, false)
|
||||
local other_pos_list_surface = minetest.find_nodes_in_area(p1, p2, "group:opaque", false)
|
||||
p1 = {x = x - 4, y = y - 7, z = z - 4}
|
||||
p2 = {x = x + 4, y = y - 3, z = z + 4}
|
||||
local best_pos_list_underground = minetest.find_nodes_in_area(p1, p2, node_list, false)
|
||||
local other_pos_list_underground = minetest.find_nodes_in_area(p1, p2, "group:opaque", false)
|
||||
return 10 * (#best_pos_list_surface) + 2 * (#other_pos_list_surface) + 5 * (#best_pos_list_underground) + #other_pos_list_underground
|
||||
end
|
||||
|
||||
mcl_structures.register_structure({
|
||||
name = "desert_temple",
|
||||
decoration = {
|
||||
deco_type = "simple",
|
||||
place_on = node_list,
|
||||
flags = "all_floors",
|
||||
fill_ratio = scanning_ratio,
|
||||
y_min = 1,
|
||||
y_max = mcl_mapgen.overworld.max,
|
||||
height = 1,
|
||||
biomes = not mcl_mapgen.v6 and {
|
||||
"ColdTaiga_beach",
|
||||
"ColdTaiga_beach_water",
|
||||
"Desert",
|
||||
"Desert_ocean",
|
||||
"ExtremeHills_beach",
|
||||
"FlowerForest_beach",
|
||||
"Forest_beach",
|
||||
"MesaBryce_sandlevel",
|
||||
"MesaPlateauF_sandlevel",
|
||||
"MesaPlateauFM_sandlevel",
|
||||
"Savanna",
|
||||
"Savanna_beach",
|
||||
"StoneBeach",
|
||||
"StoneBeach_ocean",
|
||||
"Taiga_beach",
|
||||
},
|
||||
},
|
||||
on_finished_chunk = function(minp, maxp, seed, vm_context, pos_list)
|
||||
local pr = PseudoRandom(seed + random_offset)
|
||||
local random_number = pr:next(1, chance_per_chunk)
|
||||
local noise = mcl_structures_get_perlin_noise_level(minp) * noise_multiplier
|
||||
if (random_number + noise) < struct_threshold then return end
|
||||
local pos = pos_list[1]
|
||||
if #pos_list > 1 then
|
||||
local count = get_place_rank(pos)
|
||||
for i = 2, #pos_list do
|
||||
local pos_i = pos_list[i]
|
||||
local count_i = get_place_rank(pos_i)
|
||||
if count_i > count then
|
||||
count = count_i
|
||||
pos = pos_i
|
||||
end
|
||||
end
|
||||
end
|
||||
place(pos, nil, pr)
|
||||
end,
|
||||
place_function = place,
|
||||
})
|
|
@ -0,0 +1,93 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
local chance_per_chunk = 40
|
||||
local noise_multiplier = 1
|
||||
local random_offset = 999
|
||||
local scanning_ratio = 0.0002
|
||||
local struct_threshold = chance_per_chunk - 1
|
||||
|
||||
local mcl_structures_get_perlin_noise_level = mcl_structures.get_perlin_noise_level
|
||||
|
||||
local node_list = {"mcl_core:sand", "mcl_core:sandstone", "mcl_core:redsand", "mcl_colorblocks:hardened_clay_orange"}
|
||||
|
||||
local schematic_file = modpath .. "/schematics/mcl_structures_desert_well.mts"
|
||||
|
||||
local well_schematic_lua = minetest.serialize_schematic(schematic_file, "lua", {lua_use_comments = false, lua_num_indent_spaces = 0}) .. " return schematic"
|
||||
local well_schematic = loadstring(well_schematic_lua)()
|
||||
|
||||
local red_well_schematic_lua = minetest.serialize_schematic(schematic_file, "lua", {lua_use_comments = false, lua_num_indent_spaces = 0}) .. " return schematic"
|
||||
red_well_schematic_lua = red_well_schematic_lua:gsub("mcl_core:sand", "mcl_core:redsand")
|
||||
red_well_schematic_lua = red_well_schematic_lua:gsub("mcl_stairs:slab_sandstone", "mcl_stairs:slab_redsandstone")
|
||||
local red_well_schematic = loadstring(red_well_schematic_lua)()
|
||||
|
||||
local function place(pos, rotation, pr)
|
||||
local pos_below = {x = pos.x, y = pos.y - 1, z = pos.z}
|
||||
local pos_well = {x = pos.x, y = pos.y - 2, z = pos.z}
|
||||
local node_below = minetest.get_node(pos_below)
|
||||
local nn = node_below.name
|
||||
if string.find(nn, "red") then
|
||||
mcl_structures.place_schematic({pos = pos_well, rotaton = rotation, schematic = red_well_schematic, pr = pr})
|
||||
else
|
||||
mcl_structures.place_schematic({pos = pos_well, rotaton = rotation, schematic = well_schematic, pr = pr})
|
||||
end
|
||||
end
|
||||
|
||||
local function get_place_rank(pos)
|
||||
local x, y, z = pos.x, pos.y - 1, pos.z
|
||||
local p1 = {x = x , y = y, z = z }
|
||||
local p2 = {x = x + 5, y = y, z = z + 5}
|
||||
local post_pos_list_surface = #minetest.find_nodes_in_area(p1, p2, node_list, false)
|
||||
local other_pos_list_surface = #minetest.find_nodes_in_area(p1, p2, "group:opaque", false)
|
||||
return post_pos_list_surface * 5 + other_pos_list_surface
|
||||
end
|
||||
|
||||
mcl_structures.register_structure({
|
||||
name = "desert_well",
|
||||
decoration = {
|
||||
deco_type = "simple",
|
||||
place_on = node_list,
|
||||
flags = "all_floors",
|
||||
fill_ratio = scanning_ratio,
|
||||
y_min = -5,
|
||||
y_max = mcl_mapgen.overworld.max,
|
||||
height = 1,
|
||||
biomes = not mcl_mapgen.v6 and {
|
||||
"ColdTaiga_beach",
|
||||
"ColdTaiga_beach_water",
|
||||
"Desert",
|
||||
"Desert_ocean",
|
||||
"ExtremeHills_beach",
|
||||
"FlowerForest_beach",
|
||||
"Forest_beach",
|
||||
"MesaBryce_sandlevel",
|
||||
"MesaPlateauF_sandlevel",
|
||||
"MesaPlateauFM_sandlevel",
|
||||
"Savanna",
|
||||
"Savanna_beach",
|
||||
"StoneBeach",
|
||||
"StoneBeach_ocean",
|
||||
"Taiga_beach",
|
||||
},
|
||||
},
|
||||
on_finished_chunk = function(minp, maxp, seed, vm_context, pos_list)
|
||||
local pr = PseudoRandom(seed + random_offset)
|
||||
local random_number = pr:next(1, chance_per_chunk)
|
||||
local noise = mcl_structures_get_perlin_noise_level(minp) * noise_multiplier
|
||||
if (random_number + noise) < struct_threshold then return end
|
||||
local pos = pos_list[1]
|
||||
if #pos_list > 1 then
|
||||
local count = get_place_rank(pos)
|
||||
for i = 2, #pos_list do
|
||||
local pos_i = pos_list[i]
|
||||
local count_i = get_place_rank(pos_i)
|
||||
if count_i > count then
|
||||
count = count_i
|
||||
pos = pos_i
|
||||
end
|
||||
end
|
||||
end
|
||||
place(pos, nil, pr)
|
||||
end,
|
||||
place_function = place,
|
||||
})
|
|
@ -0,0 +1,81 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
local END_EXIT_PORTAL_POS_X = -3
|
||||
local END_EXIT_PORTAL_POS_Y = -27003
|
||||
local END_EXIT_PORTAL_POS_Z = -3
|
||||
local p0 = {
|
||||
x = END_EXIT_PORTAL_POS_X,
|
||||
y = END_EXIT_PORTAL_POS_Y,
|
||||
z = END_EXIT_PORTAL_POS_Z,
|
||||
}
|
||||
|
||||
local schematic = modpath .. "/schematics/mcl_structures_end_exit_portal.mts"
|
||||
|
||||
local dragon_spawn_pos = false
|
||||
local dragon_spawned, portal_generated = false, false
|
||||
|
||||
local function spawn_ender_dragon()
|
||||
local obj = minetest.add_entity(dragon_spawn_pos, "mobs_mc:enderdragon")
|
||||
if not obj then return false end
|
||||
local dragon_entity = obj:get_luaentity()
|
||||
dragon_entity._initial = true
|
||||
dragon_entity._portal_pos = p0
|
||||
return obj
|
||||
end
|
||||
|
||||
local function try_to_spawn_ender_dragon()
|
||||
if spawn_ender_dragon() then
|
||||
dragon_spawned = true
|
||||
return
|
||||
end
|
||||
minetest.after(2, try_to_spawn_ender_dragon)
|
||||
minetest.log("warning", "Ender dragon doesn't want to spawn at "..minetest.pos_to_string(dragon_spawn_pos))
|
||||
end
|
||||
|
||||
if portal_generated and not dragon_spawned then
|
||||
minetest.after(10, try_to_spawn_ender_dragon)
|
||||
end
|
||||
|
||||
local function place(pos, rotation, pr)
|
||||
mcl_structures.place_schematic({pos = pos, schematic = schematic, rotation = rotation, pr = pr})
|
||||
end
|
||||
|
||||
mcl_mapgen.register_mapgen(function(minp, maxp, seed, vm_context)
|
||||
local minp = minp
|
||||
local y1 = minp.y
|
||||
if y1 > END_EXIT_PORTAL_POS_Y then return end
|
||||
local maxp = maxp
|
||||
local y2 = maxp.y
|
||||
if y2 < END_EXIT_PORTAL_POS_Y then return end
|
||||
if minp.x > END_EXIT_PORTAL_POS_X then return end
|
||||
if maxp.x < END_EXIT_PORTAL_POS_X then return end
|
||||
if minp.z > END_EXIT_PORTAL_POS_Z then return end
|
||||
if maxp.z < END_EXIT_PORTAL_POS_Z then return end
|
||||
|
||||
dragon_spawn_pos = vector.add(p0, vector.new(3, 11, 3))
|
||||
portal_generated = true
|
||||
try_to_spawn_ender_dragon()
|
||||
|
||||
local p = table.copy(p0)
|
||||
|
||||
for y = y2, y1, -1 do
|
||||
p.y = y
|
||||
if minetest.get_node(p).name == "mcl_end:end_stone" then
|
||||
place(p, "0", PseudoRandom(vm_context.chunkseed))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
for y = y2, y1, -1 do
|
||||
p.y = y
|
||||
if minetest.get_node(p).name ~= "air" then
|
||||
place(p, "0", PseudoRandom(vm_context.chunkseed))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
place(p0, "0", PseudoRandom(vm_context.chunkseed))
|
||||
end)
|
||||
|
||||
mcl_structures.register_structure({name = "end_exit_portal", place_function = place})
|
|
@ -0,0 +1,53 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
local chance_per_block = mcl_structures.from_16x16_to_block_inverted_chance(64)
|
||||
local noise_multiplier = 2
|
||||
local random_offset = 5
|
||||
local struct_threshold = chance_per_block
|
||||
local mcl_structures_get_perlin_noise_level = mcl_structures.get_perlin_noise_level
|
||||
local minetest_find_nodes_in_area = minetest.find_nodes_in_area
|
||||
local min_y = mcl_worlds.layer_to_y(40)
|
||||
local max_y = mcl_worlds.layer_to_y(49)
|
||||
local fossils = {
|
||||
"mcl_structures_fossil_skull_1.mts", -- 4×5×5
|
||||
"mcl_structures_fossil_skull_2.mts", -- 5×5×5
|
||||
"mcl_structures_fossil_skull_3.mts", -- 5×5×7
|
||||
"mcl_structures_fossil_skull_4.mts", -- 7×5×5
|
||||
"mcl_structures_fossil_spine_1.mts", -- 3×3×13
|
||||
"mcl_structures_fossil_spine_2.mts", -- 5×4×13
|
||||
"mcl_structures_fossil_spine_3.mts", -- 7×4×13
|
||||
"mcl_structures_fossil_spine_4.mts", -- 8×5×13
|
||||
}
|
||||
local nodes_for_fossil = {"mcl_core:sandstone", "mcl_core:stone", "mcl_core:diorite", "mcl_core:andesite", "mcl_core:granite", "mcl_core:stone_with_coal", "mcl_core:dirt", "mcl_core:gravel"}
|
||||
|
||||
function spawn_fossil(pos, rotation, pr, placer)
|
||||
-- Generates one out of 8 possible fossil pieces
|
||||
local def = {
|
||||
pos = {x = pos.x, y = pos.y - 1, z = pos.z},
|
||||
schematic = modpath .. "/schematics/" .. fossils[pr:next(1, #fossils)],
|
||||
rotation = rotation,
|
||||
pr = pr,
|
||||
}
|
||||
mcl_structures.place_schematic(def)
|
||||
end
|
||||
|
||||
mcl_mapgen.register_mapgen_block(function(minp, maxp, seed)
|
||||
local p1 = table.copy(minp)
|
||||
local y1 = p1.y
|
||||
if y1 > max_y then return end
|
||||
local p2 = table.copy(maxp)
|
||||
local y2 = p2.y
|
||||
if y2 < min_y then return end
|
||||
local pr = PseudoRandom(seed + random_offset)
|
||||
local random_number = pr:next(1, chance_per_block)
|
||||
p1.y = math.max(y1, min_y)
|
||||
local noise = mcl_structures_get_perlin_noise_level(p1) * noise_multiplier
|
||||
if (random_number + noise) < struct_threshold then return end
|
||||
p2.y = math.min(y2, max_y)
|
||||
local nodes = minetest_find_nodes_in_area(p1, p2, nodes_for_fossil, false)
|
||||
if #nodes < 100 then return end
|
||||
spawn_fossil(p1, nil, pr)
|
||||
end, 1000)
|
||||
|
||||
mcl_structures.register_structure({name = 'fossil', place_function = spawn_fossil})
|
|
@ -0,0 +1,66 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
local chance_per_chunk = 5
|
||||
local random_offset = 24435
|
||||
local struct_threshold = chance_per_chunk - 1
|
||||
local noise_params = {
|
||||
offset = 0,
|
||||
scale = 1,
|
||||
spread = {
|
||||
x = 1000,
|
||||
y = 1000,
|
||||
z = 1000,
|
||||
},
|
||||
scale = 0.01,
|
||||
seed = 29313,
|
||||
octaves = 2,
|
||||
persistence = 0.7,
|
||||
}
|
||||
|
||||
local node_list = {"mcl_core:snowblock", "mcl_core:dirt_with_grass_snow"}
|
||||
local schematic = modpath.."/schematics/mcl_structures_ice_spike_large.mts"
|
||||
|
||||
minetest_find_nodes_in_area = minetest.find_nodes_in_area
|
||||
|
||||
local function place(pos, rotation, pr)
|
||||
mcl_structures.place_schematic({pos = pos, schematic = schematic, rotation = rotation, pr = pr})
|
||||
end
|
||||
|
||||
local function is_place_ok(p)
|
||||
-- Check surface
|
||||
local floor = {x=p.x+4, y=p.y-1, z=p.z+4}
|
||||
local surface = #minetest_find_nodes_in_area({x=p.x+1,y=p.y-1,z=p.z+1}, floor, node_list, false)
|
||||
if surface < 9 then return end
|
||||
|
||||
-- Check for collision with spruce
|
||||
local spruce_collisions = #minetest_find_nodes_in_area({x=p.x+1,y=p.y+2,z=p.z+1}, {x=p.x+4, y=p.y+6, z=p.z+4}, {"group:tree"}, false)
|
||||
if spruce_collisions > 0 then return end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local def = mcl_mapgen.v6 and {
|
||||
decoration = {
|
||||
deco_type = "simple",
|
||||
place_on = node_list,
|
||||
noise_params = noise_params,
|
||||
y_min = mcl_mapgen.overworld.min,
|
||||
y_max = mcl_mapgen.overworld.max,
|
||||
height = 1,
|
||||
},
|
||||
on_finished_chunk = mcl_mapgen.v6 and function(minp, maxp, seed, vm_context, pos_list)
|
||||
local pr = PseudoRandom(seed + random_offset)
|
||||
local random_number = pr:next(1, chance_per_chunk)
|
||||
if random_number < struct_threshold then return end
|
||||
for i = 1, #pos_list do
|
||||
local pos = pos_list[i]
|
||||
if is_place_ok(pos) then
|
||||
place(pos, nil, pr)
|
||||
end
|
||||
end
|
||||
end,
|
||||
} or {}
|
||||
def.name = "ice_spike_large"
|
||||
def.place_function = place
|
||||
mcl_structures.register_structure(def)
|
|
@ -0,0 +1,65 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
local chance_per_chunk = 3
|
||||
local random_offset = 1264
|
||||
local struct_threshold = chance_per_chunk
|
||||
local noise_params = {
|
||||
offset = 0,
|
||||
scale = 1,
|
||||
spread = {
|
||||
x = mcl_mapgen.CS,
|
||||
y = mcl_mapgen.CS,
|
||||
z = mcl_mapgen.CS,
|
||||
},
|
||||
scale = 0.3,
|
||||
seed = 32931,
|
||||
octaves = 2,
|
||||
persistence = 0.7,
|
||||
}
|
||||
|
||||
local node_list = {"mcl_core:snowblock", "mcl_core:dirt_with_grass_snow"}
|
||||
local schematic = modpath.."/schematics/mcl_structures_ice_spike_small.mts"
|
||||
|
||||
minetest_find_nodes_in_area = minetest.find_nodes_in_area
|
||||
|
||||
local function place(pos, rotation, pr)
|
||||
mcl_structures.place_schematic({pos = pos, schematic = schematic, rotation = rotation, pr = pr})
|
||||
end
|
||||
|
||||
local function is_place_ok(p)
|
||||
local floor = {x=p.x+6, y=p.y-1, z=p.z+6}
|
||||
local surface = #minetest_find_nodes_in_area({x=p.x+1,y=p.y-1,z=p.z+1}, floor, node_list, false)
|
||||
if surface < 25 then return end
|
||||
|
||||
-- Check for collision with spruce
|
||||
local spruce_collisions = #minetest_find_nodes_in_area({x=p.x+1,y=p.y+1,z=p.z+1}, {x=p.x+6, y=p.y+6, z=p.z+6}, {"group:tree"}, false)
|
||||
if spruce_collisions > 0 then return end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local def = mcl_mapgen.v6 and {
|
||||
decoration = {
|
||||
deco_type = "simple",
|
||||
place_on = node_list,
|
||||
noise_params = noise_params,
|
||||
y_min = mcl_mapgen.overworld.min,
|
||||
y_max = mcl_mapgen.overworld.max,
|
||||
height = 1,
|
||||
},
|
||||
on_finished_chunk = mcl_mapgen.v6 and function(minp, maxp, seed, vm_context, pos_list)
|
||||
local pr = PseudoRandom(seed + random_offset)
|
||||
local random_number = pr:next(1, chance_per_chunk)
|
||||
if random_number < struct_threshold then return end
|
||||
for i = 1, #pos_list do
|
||||
local pos = pos_list[i]
|
||||
if is_place_ok(pos) then
|
||||
place(pos, nil, pr)
|
||||
end
|
||||
end
|
||||
end,
|
||||
} or {}
|
||||
def.name = "ice_spike_small"
|
||||
def.place_function = place
|
||||
mcl_structures.register_structure(def)
|
|
@ -0,0 +1,196 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
-- Check: v7 apple -27787,31,3115
|
||||
|
||||
local chance_per_chunk = 39
|
||||
local noise_multiplier = 1.3
|
||||
local random_offset = 555
|
||||
local struct_threshold = chance_per_chunk - 1
|
||||
local scanning_ratio = 0.0003
|
||||
|
||||
local mcl_structures_get_perlin_noise_level = mcl_structures.get_perlin_noise_level
|
||||
|
||||
local node_list = {"mcl_core:snowblock", "mcl_core:snow", "group:grass_block_snow"}
|
||||
|
||||
local schematic_top = modpath.."/schematics/mcl_structures_igloo_top.mts"
|
||||
local schematic_basement = modpath.."/schematics/mcl_structures_igloo_basement.mts"
|
||||
|
||||
local brick = {
|
||||
-- monster egg:
|
||||
[false] = {
|
||||
-- cracked:
|
||||
[false] = "mcl_core:stonebrick",
|
||||
[true ] = "mcl_core:stonebrickcracked",
|
||||
},
|
||||
[true] = {
|
||||
[false] = "mcl_monster_eggs:monster_egg_stonebrick",
|
||||
[true ] = "mcl_monster_eggs:monster_egg_stonebrickcracked",
|
||||
},
|
||||
}
|
||||
local dirs = {
|
||||
["0"] = {x=-1, y=0, z= 0},
|
||||
["90"] = {x= 0, y=0, z=-1},
|
||||
["180"] = {x= 1, y=0, z= 0},
|
||||
["270"] = {x= 0, y=0, z= 1},
|
||||
}
|
||||
local tdirs = {
|
||||
["0"] = {x= 1, y=0, z= 0},
|
||||
["90"] = {x= 0, y=0, z=-1},
|
||||
["180"] = {x=-1, y=0, z= 0},
|
||||
["270"] = {x= 0, y=0, z= 1}
|
||||
}
|
||||
local tposes = {
|
||||
["0"] = {x=7, y=-1, z=3},
|
||||
["90"] = {x=3, y=-1, z=1},
|
||||
["180"] = {x=1, y=-1, z=3},
|
||||
["270"] = {x=3, y=-1, z=7},
|
||||
}
|
||||
local chest_offsets = {
|
||||
["0"] = {x=5, y=1, z=5},
|
||||
["90"] = {x=5, y=1, z=3},
|
||||
["180"] = {x=3, y=1, z=1},
|
||||
["270"] = {x=1, y=1, z=5},
|
||||
}
|
||||
|
||||
local function on_placed(pos, rotation, pr, size)
|
||||
local chest_offset = chest_offsets[rotation]
|
||||
if not chest_offset then return end
|
||||
local lootitems = mcl_loot.get_multi_loot({
|
||||
{
|
||||
stacks_min = 1,
|
||||
stacks_max = 1,
|
||||
items = {
|
||||
{ itemstring = "mcl_core:apple_gold", weight = 1 },
|
||||
}
|
||||
},
|
||||
{
|
||||
stacks_min = 2,
|
||||
stacks_max = 8,
|
||||
items = {
|
||||
{ itemstring = "mcl_core:coal_lump", weight = 15, amount_min = 1, amount_max = 4 },
|
||||
{ itemstring = "mcl_core:apple", weight = 15, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_farming:wheat_item", weight = 10, amount_min = 2, amount_max = 3 },
|
||||
{ itemstring = "mcl_core:gold_nugget", weight = 10, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_mobitems:rotten_flesh", weight = 10 },
|
||||
{ itemstring = "mcl_tools:axe_stone", weight = 2 },
|
||||
{ itemstring = "mcl_core:emerald", weight = 1 },
|
||||
}
|
||||
}}, pr)
|
||||
|
||||
local chest_pos = vector.add(pos, chest_offset)
|
||||
mcl_structures.init_node_construct(chest_pos)
|
||||
local meta = minetest.get_meta(chest_pos)
|
||||
local inv = meta:get_inventory()
|
||||
mcl_loot.fill_inventory(inv, "main", lootitems, pr)
|
||||
end
|
||||
|
||||
local function on_placed_top(p1, rotation, pr, size)
|
||||
local y = p1.y + 1
|
||||
local pos = {x = p1.x, y = y, z = p1.z}
|
||||
local dim = mcl_mapgen[mcl_worlds.pos_to_dimension(pos)]
|
||||
local bottom_of_dimension = (dim and dim.min or mcl_mapgen.EDGE_MIN) + 10
|
||||
local bottom_of_chunk = mcl_mapgen.get_chunk_beginning(y)
|
||||
local buffer = y - math.max(bottom_of_chunk, bottom_of_dimension)
|
||||
if buffer < 20 then return end
|
||||
|
||||
local depth = pr:next(19, buffer)
|
||||
local bpos = {x=pos.x, y=pos.y-depth, z=pos.z}
|
||||
local dir = dirs[rotation]
|
||||
if not dir then return end
|
||||
local tdir = tdirs[rotation]
|
||||
|
||||
-- Trapdoor position
|
||||
local tpos = vector.add(pos, tposes[rotation])
|
||||
local ladder_param2 = minetest.dir_to_wallmounted(tdir)
|
||||
|
||||
-- Check how deep we can actuall dig
|
||||
local real_depth = 0
|
||||
for y = 1, depth - 5 do
|
||||
local node = minetest.get_node({x=tpos.x,y=tpos.y-y,z=tpos.z})
|
||||
local def = minetest.registered_nodes[node.name]
|
||||
if (not def) or (not def.walkable) or (def.liquidtype ~= "none") then
|
||||
bpos.y = tpos.y-y+1
|
||||
break
|
||||
end
|
||||
real_depth = real_depth + 1
|
||||
end
|
||||
if real_depth < 6 then return end
|
||||
|
||||
-- Generate ladder to basement
|
||||
for y=1, real_depth-1 do
|
||||
minetest.set_node({x=tpos.x-1,y=tpos.y-y,z=tpos.z }, {name = brick[pr:next(1, 10) == 1][pr:next(1, 3) == 1]})
|
||||
minetest.set_node({x=tpos.x+1,y=tpos.y-y,z=tpos.z }, {name = brick[pr:next(1, 10) == 1][pr:next(1, 3) == 1]})
|
||||
minetest.set_node({x=tpos.x ,y=tpos.y-y,z=tpos.z-1}, {name = brick[pr:next(1, 10) == 1][pr:next(1, 3) == 1]})
|
||||
minetest.set_node({x=tpos.x ,y=tpos.y-y,z=tpos.z+1}, {name = brick[pr:next(1, 10) == 1][pr:next(1, 3) == 1]})
|
||||
minetest.set_node({x=tpos.x ,y=tpos.y-y,z=tpos.z }, {name="mcl_core:ladder", param2=ladder_param2})
|
||||
end
|
||||
|
||||
-- Place basement
|
||||
local def = {
|
||||
pos = bpos,
|
||||
schematic = schematic_basement,
|
||||
rotation = rotation,
|
||||
pr = pr,
|
||||
on_placed = on_placed,
|
||||
}
|
||||
mcl_structures.place_schematic(def)
|
||||
|
||||
minetest.after(5, function(tpos, dir)
|
||||
minetest.swap_node(tpos, {name="mcl_doors:trapdoor", param2=20+minetest.dir_to_facedir(dir)}) -- TODO: more reliable param2
|
||||
end, tpos, dir)
|
||||
end
|
||||
|
||||
local function place(pos, rotation, pr)
|
||||
local def = {
|
||||
pos = {x = pos.x, y = pos.y - 1, z = pos.z},
|
||||
schematic = schematic_top,
|
||||
rotation = rotation or tostring(pr:next(0,3)*90),
|
||||
pr = pr,
|
||||
on_placed = on_placed_top,
|
||||
}
|
||||
-- FIXME: This spawns bookshelf instead of furnace. Fix this!
|
||||
-- Furnace does not work atm because apparently meta is not set. :-(
|
||||
mcl_structures.place_schematic(def)
|
||||
end
|
||||
|
||||
local function get_place_rank(pos)
|
||||
local x, y, z = pos.x, pos.y, pos.z
|
||||
local p1 = {x = x , y = y, z = z }
|
||||
local p2 = {x = x + 9, y = y, z = z + 9}
|
||||
local best_pos_list_surface = #minetest.find_nodes_in_area(p1, p2, node_list, false)
|
||||
local other_pos_list_surface = #minetest.find_nodes_in_area(p1, p2, "group:opaque", false)
|
||||
return 10 * (best_pos_list_surface) + other_pos_list_surface - 640
|
||||
end
|
||||
|
||||
mcl_structures.register_structure({
|
||||
name = "igloo",
|
||||
decoration = {
|
||||
deco_type = "simple",
|
||||
place_on = node_list,
|
||||
flags = "all_floors",
|
||||
fill_ratio = scanning_ratio,
|
||||
y_min = -33,
|
||||
y_max = mcl_mapgen.overworld.max,
|
||||
height = 1,
|
||||
},
|
||||
on_finished_chunk = function(minp, maxp, seed, vm_context, pos_list)
|
||||
local pr = PseudoRandom(seed + random_offset)
|
||||
local random_number = pr:next(1, chance_per_chunk)
|
||||
local noise = mcl_structures_get_perlin_noise_level(minp) * noise_multiplier
|
||||
if (random_number + noise) < struct_threshold then return end
|
||||
local pos
|
||||
local count = -1
|
||||
for i = 1, #pos_list do
|
||||
local pos_i = vector.subtract(pos_list[i], {x = 4, y = 1, z = 4})
|
||||
local count_i = get_place_rank(pos_i)
|
||||
if count_i > count then
|
||||
count = count_i
|
||||
pos = pos_i
|
||||
end
|
||||
end
|
||||
if count < 0 then return end
|
||||
place(pos, nil, pr)
|
||||
end,
|
||||
place_function = place,
|
||||
})
|
|
@ -2,44 +2,307 @@ local modname = minetest.get_current_modname()
|
|||
local S = minetest.get_translator(modname)
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
mcl_structures = {}
|
||||
local name_prefix = "mcl_structures:"
|
||||
|
||||
mcl_structures = {}
|
||||
local rotations = {
|
||||
"0",
|
||||
"90",
|
||||
"180",
|
||||
"270"
|
||||
}
|
||||
local registered_structures = {}
|
||||
local use_process_mapgen_block_lvm = false
|
||||
local use_process_mapgen_chunk = false
|
||||
local on_finished_block_callbacks = {}
|
||||
local on_finished_chunk_callbacks = {}
|
||||
|
||||
local noise_params = {
|
||||
offset = 0,
|
||||
scale = 1,
|
||||
spread = {
|
||||
x = mcl_mapgen.CS_NODES,
|
||||
y = mcl_mapgen.CS_NODES,
|
||||
z = mcl_mapgen.CS_NODES,
|
||||
},
|
||||
seed = 329,
|
||||
octaves = 1,
|
||||
persistence = 0.6,
|
||||
}
|
||||
|
||||
local perlin_noise
|
||||
local get_perlin_noise_level = function(minp)
|
||||
perlin_noise = perlin_noise or minetest.get_perlin(noise_params)
|
||||
return perlin_noise:get_3d(minp)
|
||||
end
|
||||
mcl_structures.get_perlin_noise_level = get_perlin_noise_level
|
||||
|
||||
local spawnstruct_hint = S("Use /help spawnstruct to see a list of avaiable types.")
|
||||
|
||||
local function dir_to_rotation(dir)
|
||||
local ax, az = math.abs(dir.x), math.abs(dir.z)
|
||||
if ax > az then
|
||||
if dir.x < 0 then
|
||||
return "270"
|
||||
end
|
||||
return "90"
|
||||
end
|
||||
if dir.z < 0 then
|
||||
return "180"
|
||||
end
|
||||
return "0"
|
||||
end
|
||||
|
||||
local function spawnstruct_function(name, param)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then return end
|
||||
if param == "" then
|
||||
minetest.chat_send_player(name, S("Error: No structure type given. Please use “/spawnstruct <type>”."))
|
||||
minetest.chat_send_player(name, spawnstruct_hint)
|
||||
return
|
||||
end
|
||||
local struct = registered_structures[param]
|
||||
if not struct then
|
||||
struct = registered_structures[name_prefix .. param]
|
||||
end
|
||||
if not struct then
|
||||
minetest.chat_send_player(name, S("Error: Unknown structure type. Please use “/spawnstruct <type>”."))
|
||||
minetest.chat_send_player(name, spawnstruct_hint)
|
||||
return
|
||||
end
|
||||
local place = struct.place_function
|
||||
if not place then return end
|
||||
|
||||
local pos = player:get_pos()
|
||||
if not pos then return end
|
||||
local pr = PseudoRandom(math.floor(pos.x * 333 + pos.y * 19 - pos.z + 4))
|
||||
pos = vector.round(pos)
|
||||
local dir = minetest.yaw_to_dir(player:get_look_horizontal())
|
||||
local rot = dir_to_rotation(dir)
|
||||
place(pos, rot, pr, player)
|
||||
minetest.chat_send_player(name, S("Structure placed."))
|
||||
end
|
||||
|
||||
local function update_spawnstruct_chatcommand()
|
||||
local spawnstruct_params = ""
|
||||
for _, registered_structure in pairs(registered_structures) do
|
||||
if spawnstruct_params ~= "" then
|
||||
spawnstruct_params = spawnstruct_params .. " | "
|
||||
end
|
||||
spawnstruct_params = spawnstruct_params .. registered_structure.short_name
|
||||
end
|
||||
local def = {
|
||||
params = spawnstruct_params,
|
||||
description = S("Generate a pre-defined structure near your position."),
|
||||
privs = {debug = true},
|
||||
func = spawnstruct_function,
|
||||
}
|
||||
local registered_chatcommands = minetest.registered_chatcommands
|
||||
if registered_chatcommands["spawnstruct"] then
|
||||
minetest.override_chatcommand("spawnstruct", def)
|
||||
else
|
||||
minetest.register_chatcommand("spawnstruct", def)
|
||||
end
|
||||
end
|
||||
|
||||
function process_mapgen_block_lvm(vm_context)
|
||||
local nodes = minetest.find_nodes_in_area(vm_context.minp, vm_context.maxp, {"group:struct"}, true)
|
||||
for node_name, pos_list in pairs(nodes) do
|
||||
local lvm_callback = on_finished_block_callbacks[node_name]
|
||||
if lvm_callback then
|
||||
lvm_callback(vm_context, pos_list)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function process_mapgen_chunk(minp, maxp, seed, vm_context)
|
||||
local nodes = minetest.find_nodes_in_area(minp, maxp, {"group:struct"}, true)
|
||||
for node_name, pos_list in pairs(nodes) do
|
||||
local chunk_callback = on_finished_chunk_callbacks[node_name]
|
||||
if chunk_callback then
|
||||
chunk_callback(minp, maxp, seed, vm_context, pos_list)
|
||||
end
|
||||
end
|
||||
for node_name, pos_list in pairs(nodes) do
|
||||
for _, pos in pairs(pos_list) do
|
||||
local node = minetest.get_node(pos)
|
||||
if string.sub(node.name, 1, 15) == 'mcl_structures:' then
|
||||
minetest.swap_node(pos, {name = 'air'})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------------
|
||||
-- mcl_structures.register_structure(struct_def)
|
||||
-- struct_def:
|
||||
-- name - name, like 'desert_temple'
|
||||
-- decoration - decoration definition, to use as structure seed (thanks cora for the idea)
|
||||
-- on_finished_block - callback, if needed, to use with decorations: funcion(vm_context, pos_list)
|
||||
-- on_finished_chunk - next callback if needed: funcion(minp, maxp, seed, vm_context, pos_list)
|
||||
-- place_function - callback to place schematic by /spawnstruct debug command: function(pos, rotation, pr, placer)
|
||||
-- on_placed - useful when you want to process the area after placement: function(pos, rotation, pr, size)
|
||||
function mcl_structures.register_structure(def)
|
||||
local short_name = def.name
|
||||
local name = "mcl_structures:" .. short_name
|
||||
local decoration = def.decoration
|
||||
local on_finished_block = def.on_finished_block
|
||||
local on_finished_chunk = def.on_finished_chunk
|
||||
local place_function = def.place_function
|
||||
if not name then
|
||||
minetest.log('warning', 'Structure name is not passed for registration - ignoring')
|
||||
return
|
||||
end
|
||||
if registered_structures[name] then
|
||||
minetest.log('warning', 'Structure '..name..' is already registered - owerwriting')
|
||||
end
|
||||
local decoration_id
|
||||
if decoration then
|
||||
minetest.register_node(':' .. name, {
|
||||
drawtype = "airlike",
|
||||
sunlight_propagates = true,
|
||||
pointable = false,
|
||||
walkable = false,
|
||||
diggable = false,
|
||||
buildable_to = true,
|
||||
groups = {
|
||||
struct = 1,
|
||||
not_in_creative_inventory = 1,
|
||||
},
|
||||
})
|
||||
decoration_id = minetest.register_decoration({
|
||||
deco_type = decoration.deco_type,
|
||||
place_on = decoration.place_on,
|
||||
sidelen = decoration.sidelen,
|
||||
fill_ratio = decoration.fill_ratio,
|
||||
noise_params = decoration.noise_params,
|
||||
biomes = decoration.biomes,
|
||||
y_min = decoration.y_min,
|
||||
y_max = decoration.y_max,
|
||||
spawn_by = decoration.spawn_by,
|
||||
num_spawn_by = decoration.num_spawn_by,
|
||||
flags = decoration.flags,
|
||||
decoration = name,
|
||||
height = decoration.height,
|
||||
height_max = decoration.height_max,
|
||||
param2 = decoration.param2,
|
||||
param2_max = decoration.param2_max,
|
||||
place_offset_y = decoration.place_offset_y,
|
||||
schematic = decoration.schematic,
|
||||
replacements = decoration.replacements,
|
||||
flags = decoration.flags,
|
||||
rotation = decoration.rotation,
|
||||
})
|
||||
end
|
||||
registered_structures[name] = {
|
||||
place_function = place_function,
|
||||
on_finished_block = on_finished_block,
|
||||
on_finished_chunk = on_finished_chunk,
|
||||
decoration_id = decoration_id,
|
||||
short_name = short_name,
|
||||
}
|
||||
update_spawnstruct_chatcommand()
|
||||
if on_finished_block then
|
||||
on_finished_block_callbacks[name] = on_finished_block
|
||||
if not use_process_mapgen_block_lvm then
|
||||
use_process_mapgen_block_lvm = true
|
||||
mcl_mapgen.register_mapgen_block_lvm(process_mapgen_block_lvm, mcl_mapgen.order.BUILDINGS)
|
||||
end
|
||||
end
|
||||
if on_finished_chunk then
|
||||
on_finished_chunk_callbacks[name] = on_finished_chunk
|
||||
if not use_process_mapgen_chunk then
|
||||
use_process_mapgen_chunk = true
|
||||
mcl_mapgen.register_mapgen(process_mapgen_chunk, mcl_mapgen.order.BUILDINGS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- It doesN'T remove registered node and decoration!
|
||||
function mcl_structures.unregister_structure(name)
|
||||
if not registered_structures[name] then
|
||||
minetest.log('warning','Structure '..name..' is not registered - skipping')
|
||||
return
|
||||
end
|
||||
registered_structures[name] = nil
|
||||
end
|
||||
|
||||
local function ecb_place(blockpos, action, calls_remaining, param)
|
||||
if calls_remaining >= 1 then return end
|
||||
minetest.place_schematic(param.pos, param.schematic, param.rotation, param.replacements, param.force_placement, param.flags)
|
||||
if param.after_placement_callback and param.p1 and param.p2 then
|
||||
param.after_placement_callback(param.p1, param.p2, param.size, param.rotation, param.pr, param.callback_param)
|
||||
local pos = param.pos
|
||||
local rotation = param.rotation
|
||||
minetest.place_schematic(pos, param.schematic, rotation, param.replacements, param.force_placement, param.flags)
|
||||
local on_placed = param.on_placed
|
||||
if not on_placed then
|
||||
return
|
||||
end
|
||||
on_placed(pos, rotation, param.pr, param.size)
|
||||
end
|
||||
|
||||
function mcl_structures.place_schematic(def)
|
||||
local pos = def.pos
|
||||
local schematic = def.schematic
|
||||
local rotation = def.rotation
|
||||
local pr = def.pr
|
||||
local on_placed = def.on_placed -- on_placed(pos, rotation, pr, size)
|
||||
local emerge = def.emerge
|
||||
if not pos then
|
||||
minetest.log('warning', '[mcl_structures] No pos. specified to place schematic')
|
||||
return
|
||||
end
|
||||
if not schematic then
|
||||
minetest.log('warning', '[mcl_structures] No schematic specified to place at ' .. minetest.pos_to_string(pos))
|
||||
return
|
||||
end
|
||||
if not rotation or rotation == 'random' then
|
||||
if pr then
|
||||
rotation = rotations[pr:next(1,#rotations)]
|
||||
else
|
||||
rotation = rotations[math.random(1,#rotations)]
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_structures.place_schematic(pos, schematic, rotation, replacements, force_placement, flags, after_placement_callback, pr, callback_param)
|
||||
local s = loadstring(minetest.serialize_schematic(schematic, "lua", {lua_use_comments = false, lua_num_indent_spaces = 0}) .. " return schematic")()
|
||||
if s and s.size then
|
||||
local x, z = s.size.x, s.size.z
|
||||
if rotation then
|
||||
if rotation == "random" and pr then
|
||||
rotation = rotations[pr:next(1,#rotations)]
|
||||
if not emerge and not on_placed then
|
||||
minetest.place_schematic(pos, schematic, rotation, def.replacements, def.force_placement, def.flags)
|
||||
return
|
||||
end
|
||||
if rotation == "random" then
|
||||
x = math.max(x, z)
|
||||
z = x
|
||||
elseif rotation == "90" or rotation == "270" then
|
||||
x, z = z, x
|
||||
|
||||
local serialized_schematic = minetest.serialize_schematic(schematic, "lua", {lua_use_comments = false, lua_num_indent_spaces = 0}) .. " return schematic"
|
||||
local loaded_schematic = loadstring(serialized_schematic)()
|
||||
if not loaded_schematic then
|
||||
minetest.log('warning', '[mcl_structures] Schematic ' .. schematic .. ' load serialized string problem at ' .. minetest.pos_to_string(pos))
|
||||
return
|
||||
end
|
||||
local size = loaded_schematic.size
|
||||
if not size then
|
||||
minetest.log('warning', '[mcl_structures] Schematic ' .. schematic .. ' has no size at ' .. minetest.pos_to_string(pos))
|
||||
return
|
||||
end
|
||||
local p1 = {x=pos.x , y=pos.y , z=pos.z }
|
||||
local p2 = {x=pos.x+x-1, y=pos.y+s.size.y-1, z=pos.z+z-1}
|
||||
minetest.log("verbose", "[mcl_structures] size=" ..minetest.pos_to_string(s.size) .. ", rotation=" .. tostring(rotation) .. ", emerge from "..minetest.pos_to_string(p1) .. " to " .. minetest.pos_to_string(p2))
|
||||
local param = {pos=vector.new(pos), schematic=s, rotation=rotation, replacements=replacements, force_placement=force_placement, flags=flags, p1=p1, p2=p2, after_placement_callback = after_placement_callback, size=vector.new(s.size), pr=pr, callback_param=callback_param}
|
||||
minetest.emerge_area(p1, p2, ecb_place, param)
|
||||
local size_x, size_y, size_z = size.x, size.y, size.z
|
||||
if rotation == "90" or rotation == "270" then
|
||||
size_x, size_z = size_z, size_x
|
||||
end
|
||||
local x, y, z = pos.x, pos.y, pos.z
|
||||
local p1 = {x = x, y = y, z = z}
|
||||
local p2 = {x = x + size_x - 1, y = y + size_y - 1, z = size_z - 1}
|
||||
local ecb_param = {
|
||||
pos = vector.new(pos),
|
||||
schematic = loaded_schematic,
|
||||
rotation = rotation,
|
||||
replacements = replacements,
|
||||
force_placement = force_placement,
|
||||
flags = flags,
|
||||
size = vector.new(size),
|
||||
pr = pr,
|
||||
on_placed = on_placed,
|
||||
}
|
||||
if not emerge then
|
||||
ecb_place(p1, nil, 0, ecb_param)
|
||||
return
|
||||
end
|
||||
minetest.log("verbose", "[mcl_structures] Emerge area " .. minetest.pos_to_string(p1) .. " - " .. minetest.pos_to_string(p2)
|
||||
.. " of size " ..minetest.pos_to_string(size) .. " to place " .. schematic .. ", rotation " .. tostring(rotation))
|
||||
minetest.emerge_area(p1, p2, ecb_place, ecb_param)
|
||||
end
|
||||
|
||||
function mcl_structures.get_struct(file)
|
||||
|
@ -58,7 +321,7 @@ end
|
|||
|
||||
-- Call on_construct on pos.
|
||||
-- Useful to init chests from formspec.
|
||||
local function init_node_construct(pos)
|
||||
function mcl_structures.init_node_construct(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
local def = minetest.registered_nodes[node.name]
|
||||
if def and def.on_construct then
|
||||
|
@ -69,200 +332,40 @@ local function init_node_construct(pos)
|
|||
end
|
||||
|
||||
-- The call of Struct
|
||||
function mcl_structures.call_struct(pos, struct_style, rotation, pr)
|
||||
function mcl_structures.call_struct(pos, struct_style, rotation, pr, callback)
|
||||
minetest.log("action","[mcl_structures] call_struct " .. struct_style.." at "..minetest.pos_to_string(pos))
|
||||
if not rotation then
|
||||
rotation = "random"
|
||||
end
|
||||
if struct_style == "desert_temple" then
|
||||
return mcl_structures.generate_desert_temple(pos, rotation, pr)
|
||||
elseif struct_style == "desert_well" then
|
||||
return mcl_structures.generate_desert_well(pos, rotation)
|
||||
elseif struct_style == "igloo" then
|
||||
return mcl_structures.generate_igloo(pos, rotation, pr)
|
||||
elseif struct_style == "witch_hut" then
|
||||
return mcl_structures.generate_witch_hut(pos, rotation)
|
||||
elseif struct_style == "ice_spike_small" then
|
||||
return mcl_structures.generate_ice_spike_small(pos, rotation)
|
||||
elseif struct_style == "ice_spike_large" then
|
||||
return mcl_structures.generate_ice_spike_large(pos, rotation)
|
||||
elseif struct_style == "boulder" then
|
||||
if struct_style == "boulder" then
|
||||
return mcl_structures.generate_boulder(pos, rotation, pr)
|
||||
elseif struct_style == "fossil" then
|
||||
return mcl_structures.generate_fossil(pos, rotation, pr)
|
||||
elseif struct_style == "end_exit_portal" then
|
||||
return mcl_structures.generate_end_exit_portal(pos, rotation)
|
||||
return mcl_structures.generate_end_exit_portal(pos, rotation, pr, callback)
|
||||
elseif struct_style == "end_exit_portal_open" then
|
||||
return mcl_structures.generate_end_exit_portal_open(pos, rotation)
|
||||
elseif struct_style == "end_gateway_portal" then
|
||||
return mcl_structures.generate_end_gateway_portal(pos, rotation)
|
||||
elseif struct_style == "end_portal_shrine" then
|
||||
return mcl_structures.generate_end_portal_shrine(pos, rotation, pr)
|
||||
elseif struct_style == "end_portal" then
|
||||
return mcl_structures.generate_end_portal(pos, rotation, pr)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_structures.generate_desert_well(pos, rot)
|
||||
local newpos = {x=pos.x,y=pos.y-2,z=pos.z}
|
||||
local path = modpath.."/schematics/mcl_structures_desert_well.mts"
|
||||
return mcl_structures.place_schematic(newpos, path, rot or "0", nil, true)
|
||||
end
|
||||
|
||||
function mcl_structures.generate_igloo(pos, rotation, pr)
|
||||
-- Place igloo
|
||||
local success, rotation = mcl_structures.generate_igloo_top(pos, pr)
|
||||
-- Place igloo basement with 50% chance
|
||||
local r = pr:next(1,2)
|
||||
if r == 1 then
|
||||
-- Select basement depth
|
||||
local dim = mcl_worlds.pos_to_dimension(pos)
|
||||
--local buffer = pos.y - (mcl_vars.mg_lava_overworld_max + 10)
|
||||
local buffer
|
||||
if dim == "nether" then
|
||||
buffer = pos.y - (mcl_vars.mg_lava_nether_max + 10)
|
||||
elseif dim == "end" then
|
||||
buffer = pos.y - (mcl_vars.mg_end_min + 1)
|
||||
elseif dim == "overworld" then
|
||||
buffer = pos.y - (mcl_vars.mg_lava_overworld_max + 10)
|
||||
else
|
||||
return success
|
||||
end
|
||||
if buffer <= 19 then
|
||||
return success
|
||||
end
|
||||
local depth = pr:next(19, buffer)
|
||||
local bpos = {x=pos.x, y=pos.y-depth, z=pos.z}
|
||||
-- trapdoor position
|
||||
local tpos
|
||||
local dir, tdir
|
||||
if rotation == "0" then
|
||||
dir = {x=-1, y=0, z=0}
|
||||
tdir = {x=1, y=0, z=0}
|
||||
tpos = {x=pos.x+7, y=pos.y-1, z=pos.z+3}
|
||||
elseif rotation == "90" then
|
||||
dir = {x=0, y=0, z=-1}
|
||||
tdir = {x=0, y=0, z=-1}
|
||||
tpos = {x=pos.x+3, y=pos.y-1, z=pos.z+1}
|
||||
elseif rotation == "180" then
|
||||
dir = {x=1, y=0, z=0}
|
||||
tdir = {x=-1, y=0, z=0}
|
||||
tpos = {x=pos.x+1, y=pos.y-1, z=pos.z+3}
|
||||
elseif rotation == "270" then
|
||||
dir = {x=0, y=0, z=1}
|
||||
tdir = {x=0, y=0, z=1}
|
||||
tpos = {x=pos.x+3, y=pos.y-1, z=pos.z+7}
|
||||
else
|
||||
return success
|
||||
end
|
||||
local function set_brick(pos)
|
||||
local c = pr:next(1, 3) -- cracked chance
|
||||
local m = pr:next(1, 10) -- chance for monster egg
|
||||
local brick
|
||||
if m == 1 then
|
||||
if c == 1 then
|
||||
brick = "mcl_monster_eggs:monster_egg_stonebrickcracked"
|
||||
else
|
||||
brick = "mcl_monster_eggs:monster_egg_stonebrick"
|
||||
function mcl_structures.generate_end_portal(pos, rotation, pr)
|
||||
-- todo: proper facedir
|
||||
local x0, y0, z0 = pos.x - 2, pos.y, pos.z - 2
|
||||
for x = 0, 4 do
|
||||
for z = 0, 4 do
|
||||
if x % 4 == 0 or z % 4 == 0 then
|
||||
if x % 4 ~= 0 or z % 4 ~= 0 then
|
||||
minetest.swap_node({x = x0 + x, y = y0, z = z0 + z}, {name = "mcl_portals:end_portal_frame_eye"})
|
||||
end
|
||||
else
|
||||
if c == 1 then
|
||||
brick = "mcl_core:stonebrickcracked"
|
||||
else
|
||||
brick = "mcl_core:stonebrick"
|
||||
minetest.swap_node({x = x0 + x, y = y0, z = z0 + z}, {name = "mcl_portals:portal_end"})
|
||||
end
|
||||
end
|
||||
minetest.set_node(pos, {name=brick})
|
||||
end
|
||||
local ladder_param2 = minetest.dir_to_wallmounted(tdir)
|
||||
local real_depth = 0
|
||||
-- Check how deep we can actuall dig
|
||||
for y=1, depth-5 do
|
||||
real_depth = real_depth + 1
|
||||
local node = minetest.get_node({x=tpos.x,y=tpos.y-y,z=tpos.z})
|
||||
local def = minetest.registered_nodes[node.name]
|
||||
if not (def and def.walkable and def.liquidtype == "none" and def.is_ground_content) then
|
||||
bpos.y = tpos.y-y+1
|
||||
break
|
||||
end
|
||||
end
|
||||
if real_depth <= 6 then
|
||||
return success
|
||||
end
|
||||
-- Generate ladder to basement
|
||||
for y=1, real_depth-1 do
|
||||
set_brick({x=tpos.x-1,y=tpos.y-y,z=tpos.z })
|
||||
set_brick({x=tpos.x+1,y=tpos.y-y,z=tpos.z })
|
||||
set_brick({x=tpos.x ,y=tpos.y-y,z=tpos.z-1})
|
||||
set_brick({x=tpos.x ,y=tpos.y-y,z=tpos.z+1})
|
||||
minetest.set_node({x=tpos.x,y=tpos.y-y,z=tpos.z}, {name="mcl_core:ladder", param2=ladder_param2})
|
||||
end
|
||||
-- Place basement
|
||||
mcl_structures.generate_igloo_basement(bpos, rotation, pr)
|
||||
-- Place hidden trapdoor
|
||||
minetest.after(5, function(tpos, dir)
|
||||
minetest.set_node(tpos, {name="mcl_doors:trapdoor", param2=20+minetest.dir_to_facedir(dir)}) -- TODO: more reliable param2
|
||||
end, tpos, dir)
|
||||
end
|
||||
return success
|
||||
end
|
||||
|
||||
function mcl_structures.generate_igloo_top(pos, pr)
|
||||
-- FIXME: This spawns bookshelf instead of furnace. Fix this!
|
||||
-- Furnace does ot work atm because apparently meta is not set. :-(
|
||||
local newpos = {x=pos.x,y=pos.y-1,z=pos.z}
|
||||
local path = modpath.."/schematics/mcl_structures_igloo_top.mts"
|
||||
local rotation = tostring(pr:next(0,3)*90)
|
||||
return mcl_structures.place_schematic(newpos, path, rotation, nil, true), rotation
|
||||
end
|
||||
|
||||
local function igloo_placement_callback(p1, p2, size, orientation, pr)
|
||||
local chest_offset
|
||||
if orientation == "0" then
|
||||
chest_offset = {x=5, y=1, z=5}
|
||||
elseif orientation == "90" then
|
||||
chest_offset = {x=5, y=1, z=3}
|
||||
elseif orientation == "180" then
|
||||
chest_offset = {x=3, y=1, z=1}
|
||||
elseif orientation == "270" then
|
||||
chest_offset = {x=1, y=1, z=5}
|
||||
else
|
||||
return
|
||||
end
|
||||
--local size = {x=9,y=5,z=7}
|
||||
local lootitems = mcl_loot.get_multi_loot({
|
||||
{
|
||||
stacks_min = 1,
|
||||
stacks_max = 1,
|
||||
items = {
|
||||
{ itemstring = "mcl_core:apple_gold", weight = 1 },
|
||||
}
|
||||
},
|
||||
{
|
||||
stacks_min = 2,
|
||||
stacks_max = 8,
|
||||
items = {
|
||||
{ itemstring = "mcl_core:coal_lump", weight = 15, amount_min = 1, amount_max = 4 },
|
||||
{ itemstring = "mcl_core:apple", weight = 15, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_farming:wheat_item", weight = 10, amount_min = 2, amount_max = 3 },
|
||||
{ itemstring = "mcl_core:gold_nugget", weight = 10, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_mobitems:rotten_flesh", weight = 10 },
|
||||
{ itemstring = "mcl_tools:axe_stone", weight = 2 },
|
||||
{ itemstring = "mcl_core:emerald", weight = 1 },
|
||||
}
|
||||
}}, pr)
|
||||
|
||||
local chest_pos = vector.add(p1, chest_offset)
|
||||
init_node_construct(chest_pos)
|
||||
local meta = minetest.get_meta(chest_pos)
|
||||
local inv = meta:get_inventory()
|
||||
mcl_loot.fill_inventory(inv, "main", lootitems, pr)
|
||||
end
|
||||
|
||||
function mcl_structures.generate_igloo_basement(pos, orientation, pr)
|
||||
-- TODO: Add brewing stand
|
||||
-- TODO: Add monster eggs
|
||||
-- TODO: Spawn villager and zombie villager
|
||||
local path = modpath.."/schematics/mcl_structures_igloo_basement.mts"
|
||||
mcl_structures.place_schematic(pos, path, orientation, nil, true, nil, igloo_placement_callback, pr)
|
||||
end
|
||||
|
||||
function mcl_structures.generate_boulder(pos, rotation, pr)
|
||||
|
@ -280,53 +383,9 @@ function mcl_structures.generate_boulder(pos, rotation, pr)
|
|||
return minetest.place_schematic(newpos, path, rotation) -- don't serialize schematics for registered biome decorations, for MT 5.4.0, https://github.com/minetest/minetest/issues/10995
|
||||
end
|
||||
|
||||
local function hut_placement_callback(p1, p2, size, orientation, pr)
|
||||
if not p1 or not p2 then return end
|
||||
local legs = minetest.find_nodes_in_area(p1, p2, "mcl_core:tree")
|
||||
for i = 1, #legs do
|
||||
while minetest.get_item_group(mcl_vars.get_node({x=legs[i].x, y=legs[i].y-1, z=legs[i].z}, true, 333333).name, "water") ~= 0 do
|
||||
legs[i].y = legs[i].y - 1
|
||||
minetest.swap_node(legs[i], {name = "mcl_core:tree", param2 = 2})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_structures.generate_witch_hut(pos, rotation, pr)
|
||||
local path = modpath.."/schematics/mcl_structures_witch_hut.mts"
|
||||
mcl_structures.place_schematic(pos, path, rotation, nil, true, nil, hut_placement_callback, pr)
|
||||
end
|
||||
|
||||
function mcl_structures.generate_ice_spike_small(pos, rotation)
|
||||
local path = modpath.."/schematics/mcl_structures_ice_spike_small.mts"
|
||||
return minetest.place_schematic(pos, path, rotation or "random", nil, false) -- don't serialize schematics for registered biome decorations, for MT 5.4.0
|
||||
end
|
||||
|
||||
function mcl_structures.generate_ice_spike_large(pos, rotation)
|
||||
local path = modpath.."/schematics/mcl_structures_ice_spike_large.mts"
|
||||
return minetest.place_schematic(pos, path, rotation or "random", nil, false) -- don't serialize schematics for registered biome decorations, for MT 5.4.0
|
||||
end
|
||||
|
||||
function mcl_structures.generate_fossil(pos, rotation, pr)
|
||||
-- Generates one out of 8 possible fossil pieces
|
||||
local newpos = {x=pos.x,y=pos.y-1,z=pos.z}
|
||||
local fossils = {
|
||||
"mcl_structures_fossil_skull_1.mts", -- 4×5×5
|
||||
"mcl_structures_fossil_skull_2.mts", -- 5×5×5
|
||||
"mcl_structures_fossil_skull_3.mts", -- 5×5×7
|
||||
"mcl_structures_fossil_skull_4.mts", -- 7×5×5
|
||||
"mcl_structures_fossil_spine_1.mts", -- 3×3×13
|
||||
"mcl_structures_fossil_spine_2.mts", -- 5×4×13
|
||||
"mcl_structures_fossil_spine_3.mts", -- 7×4×13
|
||||
"mcl_structures_fossil_spine_4.mts", -- 8×5×13
|
||||
}
|
||||
local r = pr:next(1, #fossils)
|
||||
local path = modpath.."/schematics/"..fossils[r]
|
||||
return mcl_structures.place_schematic(newpos, path, rotation or "random", nil, true)
|
||||
end
|
||||
|
||||
function mcl_structures.generate_end_exit_portal(pos, rot)
|
||||
function mcl_structures.generate_end_exit_portal(pos, rot, pr, callback)
|
||||
local path = modpath.."/schematics/mcl_structures_end_exit_portal.mts"
|
||||
return mcl_structures.place_schematic(pos, path, rot or "0", {["mcl_portals:portal_end"] = "air"}, true)
|
||||
return mcl_structures.place_schematic(pos, path, rot or "0", {["mcl_portals:portal_end"] = "air"}, true, nil, callback)
|
||||
end
|
||||
|
||||
function mcl_structures.generate_end_exit_portal_open(pos, rot)
|
||||
|
@ -339,275 +398,15 @@ function mcl_structures.generate_end_gateway_portal(pos, rot)
|
|||
return mcl_structures.place_schematic(pos, path, rot or "0", nil, true)
|
||||
end
|
||||
|
||||
local function shrine_placement_callback(p1, p2, size, rotation, pr)
|
||||
-- Find and setup spawner with silverfish
|
||||
local spawners = minetest.find_nodes_in_area(p1, p2, "mcl_mobspawners:spawner")
|
||||
for s=1, #spawners do
|
||||
--local meta = minetest.get_meta(spawners[s])
|
||||
mcl_mobspawners.setup_spawner(spawners[s], "mobs_mc:silverfish")
|
||||
local chunk_square = mcl_mapgen.CS_NODES * mcl_mapgen.CS_NODES
|
||||
local block_square = mcl_mapgen.BS * mcl_mapgen.BS
|
||||
|
||||
function mcl_structures.from_16x16_to_chunk_inverted_chance(x)
|
||||
return math.floor(x * 256 / chunk_square + 0.5)
|
||||
end
|
||||
|
||||
-- Shuffle stone brick types
|
||||
local bricks = minetest.find_nodes_in_area(p1, p2, "mcl_core:stonebrick")
|
||||
for b=1, #bricks do
|
||||
local r_bricktype = pr:next(1, 100)
|
||||
local r_infested = pr:next(1, 100)
|
||||
local bricktype
|
||||
if r_infested <= 5 then
|
||||
if r_bricktype <= 30 then -- 30%
|
||||
bricktype = "mcl_monster_eggs:monster_egg_stonebrickmossy"
|
||||
elseif r_bricktype <= 50 then -- 20%
|
||||
bricktype = "mcl_monster_eggs:monster_egg_stonebrickcracked"
|
||||
else -- 50%
|
||||
bricktype = "mcl_monster_eggs:monster_egg_stonebrick"
|
||||
end
|
||||
else
|
||||
if r_bricktype <= 30 then -- 30%
|
||||
bricktype = "mcl_core:stonebrickmossy"
|
||||
elseif r_bricktype <= 50 then -- 20%
|
||||
bricktype = "mcl_core:stonebrickcracked"
|
||||
end
|
||||
-- 50% stonebrick (no change necessary)
|
||||
end
|
||||
if bricktype then
|
||||
minetest.set_node(bricks[b], { name = bricktype })
|
||||
end
|
||||
function mcl_structures.from_16x16_to_block_inverted_chance(x)
|
||||
return math.floor(x * 256 / block_square + 0.5)
|
||||
end
|
||||
|
||||
-- Also replace stairs
|
||||
local stairs = minetest.find_nodes_in_area(p1, p2, {"mcl_stairs:stair_stonebrick", "mcl_stairs:stair_stonebrick_outer", "mcl_stairs:stair_stonebrick_inner"})
|
||||
for s=1, #stairs do
|
||||
local stair = minetest.get_node(stairs[s])
|
||||
local r_type = pr:next(1, 100)
|
||||
if r_type <= 30 then -- 30% mossy
|
||||
if stair.name == "mcl_stairs:stair_stonebrick" then
|
||||
stair.name = "mcl_stairs:stair_stonebrickmossy"
|
||||
elseif stair.name == "mcl_stairs:stair_stonebrick_outer" then
|
||||
stair.name = "mcl_stairs:stair_stonebrickmossy_outer"
|
||||
elseif stair.name == "mcl_stairs:stair_stonebrick_inner" then
|
||||
stair.name = "mcl_stairs:stair_stonebrickmossy_inner"
|
||||
end
|
||||
minetest.set_node(stairs[s], stair)
|
||||
elseif r_type <= 50 then -- 20% cracky
|
||||
if stair.name == "mcl_stairs:stair_stonebrick" then
|
||||
stair.name = "mcl_stairs:stair_stonebrickcracked"
|
||||
elseif stair.name == "mcl_stairs:stair_stonebrick_outer" then
|
||||
stair.name = "mcl_stairs:stair_stonebrickcracked_outer"
|
||||
elseif stair.name == "mcl_stairs:stair_stonebrick_inner" then
|
||||
stair.name = "mcl_stairs:stair_stonebrickcracked_inner"
|
||||
end
|
||||
minetest.set_node(stairs[s], stair)
|
||||
end
|
||||
-- 50% no change
|
||||
end
|
||||
|
||||
-- Randomly add ender eyes into end portal frames, but never fill the entire frame
|
||||
local frames = minetest.find_nodes_in_area(p1, p2, "mcl_portals:end_portal_frame")
|
||||
local eyes = 0
|
||||
for f=1, #frames do
|
||||
local r_eye = pr:next(1, 10)
|
||||
if r_eye == 1 then
|
||||
eyes = eyes + 1
|
||||
if eyes < #frames then
|
||||
local frame_node = minetest.get_node(frames[f])
|
||||
frame_node.name = "mcl_portals:end_portal_frame_eye"
|
||||
minetest.set_node(frames[f], frame_node)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_structures.generate_end_portal_shrine(pos, rotation, pr)
|
||||
local offset = {x=6, y=4, z=6}
|
||||
--local size = {x=13, y=8, z=13}
|
||||
local newpos = { x = pos.x - offset.x, y = pos.y, z = pos.z - offset.z }
|
||||
|
||||
local path = modpath.."/schematics/mcl_structures_end_portal_room_simple.mts"
|
||||
mcl_structures.place_schematic(newpos, path, rotation or "0", nil, true, nil, shrine_placement_callback, pr)
|
||||
end
|
||||
|
||||
local function temple_placement_callback(p1, p2, size, rotation, pr)
|
||||
|
||||
-- Delete cacti leftovers:
|
||||
local cactus_nodes = minetest.find_nodes_in_area_under_air(p1, p2, "mcl_core:cactus")
|
||||
if cactus_nodes and #cactus_nodes > 0 then
|
||||
for _, pos in pairs(cactus_nodes) do
|
||||
local node_below = minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z})
|
||||
if node_below and node_below.name == "mcl_core:sandstone" then
|
||||
minetest.swap_node(pos, {name="air"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Find chests.
|
||||
-- FIXME: Searching this large area just for the chets is not efficient. Need a better way to find the chests;
|
||||
-- probably let's just infer it from newpos because the schematic always the same.
|
||||
local chests = minetest.find_nodes_in_area(p1, p2, "mcl_chests:chest")
|
||||
|
||||
-- Add desert temple loot into chests
|
||||
for c=1, #chests do
|
||||
local lootitems = mcl_loot.get_multi_loot({
|
||||
{
|
||||
stacks_min = 2,
|
||||
stacks_max = 4,
|
||||
items = {
|
||||
{ itemstring = "mcl_mobitems:bone", weight = 25, amount_min = 4, amount_max=6 },
|
||||
{ itemstring = "mcl_mobitems:rotten_flesh", weight = 25, amount_min = 3, amount_max=7 },
|
||||
{ itemstring = "mcl_mobitems:spider_eye", weight = 25, amount_min = 1, amount_max=3 },
|
||||
{ itemstring = "mcl_books:book", weight = 20, func = function(stack, pr)
|
||||
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}, pr)
|
||||
end },
|
||||
{ itemstring = "mcl_mobitems:saddle", weight = 20, },
|
||||
{ itemstring = "mcl_core:apple_gold", weight = 20, },
|
||||
{ itemstring = "mcl_core:gold_ingot", weight = 15, amount_min = 2, amount_max = 7 },
|
||||
{ itemstring = "mcl_core:iron_ingot", weight = 15, amount_min = 1, amount_max = 5 },
|
||||
{ itemstring = "mcl_core:emerald", weight = 15, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "", weight = 15, },
|
||||
{ itemstring = "mobs_mc:iron_horse_armor", weight = 15, },
|
||||
{ itemstring = "mobs_mc:gold_horse_armor", weight = 10, },
|
||||
{ itemstring = "mobs_mc:diamond_horse_armor", weight = 5, },
|
||||
{ itemstring = "mcl_core:diamond", weight = 5, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_core:apple_gold_enchanted", weight = 2, },
|
||||
}
|
||||
},
|
||||
{
|
||||
stacks_min = 4,
|
||||
stacks_max = 4,
|
||||
items = {
|
||||
{ itemstring = "mcl_mobitems:bone", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_mobitems:rotten_flesh", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_mobitems:gunpowder", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_core:sand", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_mobitems:string", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
}
|
||||
}}, pr)
|
||||
init_node_construct(chests[c])
|
||||
local meta = minetest.get_meta(chests[c])
|
||||
local inv = meta:get_inventory()
|
||||
mcl_loot.fill_inventory(inv, "main", lootitems, pr)
|
||||
end
|
||||
|
||||
-- Initialize pressure plates and randomly remove up to 5 plates
|
||||
local pplates = minetest.find_nodes_in_area(p1, p2, "mesecons_pressureplates:pressure_plate_stone_off")
|
||||
local pplates_remove = 5
|
||||
for p=1, #pplates do
|
||||
if pplates_remove > 0 and pr:next(1, 100) >= 50 then
|
||||
-- Remove plate
|
||||
minetest.remove_node(pplates[p])
|
||||
pplates_remove = pplates_remove - 1
|
||||
else
|
||||
-- Initialize plate
|
||||
minetest.registered_nodes["mesecons_pressureplates:pressure_plate_stone_off"].on_construct(pplates[p])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_structures.generate_desert_temple(pos, rotation, pr)
|
||||
-- No Generating for the temple ... Why using it ? No Change
|
||||
local path = modpath.."/schematics/mcl_structures_desert_temple.mts"
|
||||
local newpos = {x=pos.x,y=pos.y-12,z=pos.z}
|
||||
--local size = {x=22, y=24, z=22}
|
||||
if newpos == nil then
|
||||
return
|
||||
end
|
||||
mcl_structures.place_schematic(newpos, path, rotation or "random", nil, true, nil, temple_placement_callback, pr)
|
||||
end
|
||||
|
||||
local registered_structures = {}
|
||||
|
||||
--[[ Returns a table of structure of the specified type.
|
||||
Currently the only valid parameter is "stronghold".
|
||||
Format of return value:
|
||||
{
|
||||
{ pos = <position>, generated=<true/false> }, -- first structure
|
||||
{ pos = <position>, generated=<true/false> }, -- second structure
|
||||
-- and so on
|
||||
}
|
||||
|
||||
TODO: Implement this function for all other structure types as well.
|
||||
]]
|
||||
function mcl_structures.get_registered_structures(structure_type)
|
||||
if registered_structures[structure_type] then
|
||||
return table.copy(registered_structures[structure_type])
|
||||
else
|
||||
return {}
|
||||
end
|
||||
end
|
||||
|
||||
-- Register a structures table for the given type. The table format is the same as for
|
||||
-- mcl_structures.get_registered_structures.
|
||||
function mcl_structures.register_structures(structure_type, structures)
|
||||
registered_structures[structure_type] = structures
|
||||
end
|
||||
|
||||
local function dir_to_rotation(dir)
|
||||
local ax, az = math.abs(dir.x), math.abs(dir.z)
|
||||
if ax > az then
|
||||
if dir.x < 0 then
|
||||
return "270"
|
||||
end
|
||||
return "90"
|
||||
end
|
||||
if dir.z < 0 then
|
||||
return "180"
|
||||
end
|
||||
return "0"
|
||||
end
|
||||
|
||||
-- Debug command
|
||||
minetest.register_chatcommand("spawnstruct", {
|
||||
params = "desert_temple | desert_well | igloo | witch_hut | boulder | ice_spike_small | ice_spike_large | fossil | end_exit_portal | end_exit_portal_open | end_gateway_portal | end_portal_shrine | nether_portal | dungeon",
|
||||
description = S("Generate a pre-defined 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)
|
||||
local dir = minetest.yaw_to_dir(player:get_look_horizontal())
|
||||
local rot = dir_to_rotation(dir)
|
||||
local pr = PseudoRandom(pos.x+pos.y+pos.z)
|
||||
local errord = false
|
||||
local message = S("Structure placed.")
|
||||
if param == "desert_temple" then
|
||||
mcl_structures.generate_desert_temple(pos, rot, pr)
|
||||
elseif param == "desert_well" then
|
||||
mcl_structures.generate_desert_well(pos, rot)
|
||||
elseif param == "igloo" then
|
||||
mcl_structures.generate_igloo(pos, rot, pr)
|
||||
elseif param == "witch_hut" then
|
||||
mcl_structures.generate_witch_hut(pos, rot, pr)
|
||||
elseif param == "boulder" then
|
||||
mcl_structures.generate_boulder(pos, rot, pr)
|
||||
elseif param == "fossil" then
|
||||
mcl_structures.generate_fossil(pos, rot, pr)
|
||||
elseif param == "ice_spike_small" then
|
||||
mcl_structures.generate_ice_spike_small(pos, rot, pr)
|
||||
elseif param == "ice_spike_large" then
|
||||
mcl_structures.generate_ice_spike_large(pos, rot, pr)
|
||||
elseif param == "end_exit_portal" then
|
||||
mcl_structures.generate_end_exit_portal(pos, rot, pr)
|
||||
elseif param == "end_exit_portal_open" then
|
||||
mcl_structures.generate_end_exit_portal_open(pos, rot, pr)
|
||||
elseif param == "end_gateway_portal" then
|
||||
mcl_structures.generate_end_gateway_portal(pos, rot, pr)
|
||||
elseif param == "end_portal_shrine" then
|
||||
mcl_structures.generate_end_portal_shrine(pos, rot, pr)
|
||||
elseif param == "dungeon" and mcl_dungeons and mcl_dungeons.spawn_dungeon then
|
||||
mcl_dungeons.spawn_dungeon(pos, rot, pr)
|
||||
elseif param == "nether_portal" and mcl_portals and mcl_portals.spawn_nether_portal then
|
||||
mcl_portals.spawn_nether_portal(pos, rot, pr, name)
|
||||
elseif param == "" then
|
||||
message = S("Error: No structure type given. Please use “/spawnstruct <type>”.")
|
||||
errord = true
|
||||
else
|
||||
message = S("Error: Unknown structure type. Please use “/spawnstruct <type>”.")
|
||||
errord = true
|
||||
end
|
||||
minetest.chat_send_player(name, message)
|
||||
if errord then
|
||||
minetest.chat_send_player(name, S("Use /help spawnstruct to see a list of avaiable types."))
|
||||
end
|
||||
end
|
||||
})
|
||||
dofile(modpath .. "/structures.lua")
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
-- Check: v7 apple 28530,6,28070
|
||||
-- Check: v7 apple -16343,24,5330
|
||||
|
||||
local chance_per_chunk = 50
|
||||
local noise_multiplier = 1.3
|
||||
local random_offset = 132
|
||||
local struct_threshold = chance_per_chunk - 1
|
||||
local scanning_ratio = 0.0003
|
||||
|
||||
local mcl_structures_get_perlin_noise_level = mcl_structures.get_perlin_noise_level
|
||||
|
||||
local node_list = {"mcl_core:dirt_with_grass", "mcl_core:dirt", "mcl_core:stone", "mcl_core:granite", "mcl_core:gravel", "mcl_core:diorite"}
|
||||
|
||||
local schematic_file = modpath .. "/schematics/mcl_structures_jungle_temple.mts"
|
||||
|
||||
local temple_schematic_lua = minetest.serialize_schematic(schematic_file, "lua", {lua_use_comments = false, lua_num_indent_spaces = 0}) .. " return schematic"
|
||||
local temple_schematic = loadstring(temple_schematic_lua)()
|
||||
local size = temple_schematic.size
|
||||
local sx = size.x
|
||||
local sy = size.y
|
||||
local sz = size.z
|
||||
local offset = vector.round(vector.divide(size, 2))
|
||||
offset.y = 5
|
||||
|
||||
local ox = offset.x
|
||||
local oy = offset.y
|
||||
local oz = offset.z
|
||||
local corner_x = sx - 3
|
||||
local corner_z = sz - 3
|
||||
local air_offset_x = ox - 6
|
||||
local air_offset_z = oz - 6
|
||||
|
||||
local function is_air(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
return node.name == "air"
|
||||
end
|
||||
|
||||
local stair_support_node = {
|
||||
{name = "mcl_core:cobble"},
|
||||
{name = "mcl_core:mossycobble"},
|
||||
{name = "mcl_core:stonebrick"},
|
||||
{name = "mcl_core:stonebrickmossy"},
|
||||
{name = "mcl_core:stonebrickcracked"},
|
||||
}
|
||||
|
||||
local function on_placed(p1, rotation, pr, size)
|
||||
local p2
|
||||
if rotation == "90" or rotation == "270" then
|
||||
p2 = {x = p1.x + sz - 1, y = p1.y + sy - 1, z = p1.z + sx - 1}
|
||||
else
|
||||
p2 = {x = p1.x + sx - 1, y = p1.y + sy - 1, z = p1.z + sz - 1}
|
||||
end
|
||||
|
||||
-- Support stairs
|
||||
local y = p1.y + 5
|
||||
local bottom = mcl_mapgen.get_chunk_beginning(y)
|
||||
local stair_list = minetest.find_nodes_in_area({x = p1.x, y = y, z = p1.z}, {x = p2.x, y = y, z = p2.z}, {"mcl_stairs:stair_cobble"}, false)
|
||||
for i = 1, #stair_list do
|
||||
local pos = stair_list[i]
|
||||
pos.y = y - 1
|
||||
while is_air(pos) and pos.y > bottom do
|
||||
minetest.swap_node(pos, stair_support_node[pr:next(1, #stair_support_node)])
|
||||
pos.y = pos.y - 1
|
||||
end
|
||||
end
|
||||
|
||||
-- Initialize some nodes
|
||||
local chest_node = "mcl_chests:trapped_chest_small"
|
||||
local lever_node = "mesecons_walllever:wall_lever_off"
|
||||
local nodes = minetest.find_nodes_in_area(p1, {x = p2.x, y = p1.y + 5, z = p2.z}, {chest_node, lever_node}, true)
|
||||
|
||||
local levers = nodes[lever_node]
|
||||
for _, pos in pairs(levers) do
|
||||
mcl_structures.init_node_construct(pos)
|
||||
end
|
||||
|
||||
-- Add loot into chests TODO: fix items
|
||||
local chests = nodes[chest_node]
|
||||
for c=1, #chests do
|
||||
local lootitems = mcl_loot.get_multi_loot({
|
||||
{
|
||||
stacks_min = 2,
|
||||
stacks_max = 4,
|
||||
items = {
|
||||
{ itemstring = "mcl_mobitems:bone", weight = 25, amount_min = 4, amount_max=6 },
|
||||
{ itemstring = "mcl_mobitems:rotten_flesh", weight = 25, amount_min = 3, amount_max=7 },
|
||||
{ itemstring = "mcl_mobitems:spider_eye", weight = 25, amount_min = 1, amount_max=3 },
|
||||
{ itemstring = "mcl_books:book", weight = 20, func = function(stack, pr)
|
||||
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}, pr)
|
||||
end },
|
||||
{ itemstring = "mcl_mobitems:saddle", weight = 20, },
|
||||
{ itemstring = "mcl_core:apple_gold", weight = 20, },
|
||||
{ itemstring = "mcl_core:gold_ingot", weight = 15, amount_min = 2, amount_max = 7 },
|
||||
{ itemstring = "mcl_core:iron_ingot", weight = 15, amount_min = 1, amount_max = 5 },
|
||||
{ itemstring = "mcl_core:emerald", weight = 15, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "", weight = 15, },
|
||||
{ itemstring = "mobs_mc:iron_horse_armor", weight = 15, },
|
||||
{ itemstring = "mobs_mc:gold_horse_armor", weight = 10, },
|
||||
{ itemstring = "mobs_mc:diamond_horse_armor", weight = 5, },
|
||||
{ itemstring = "mcl_core:diamond", weight = 5, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_core:apple_gold_enchanted", weight = 2, },
|
||||
}
|
||||
},
|
||||
{
|
||||
stacks_min = 4,
|
||||
stacks_max = 4,
|
||||
items = {
|
||||
{ itemstring = "mcl_mobitems:bone", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_mobitems:rotten_flesh", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_mobitems:gunpowder", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_core:sand", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_mobitems:string", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
}
|
||||
}}, pr)
|
||||
mcl_structures.init_node_construct(chests[c])
|
||||
local meta = minetest.get_meta(chests[c])
|
||||
local inv = meta:get_inventory()
|
||||
mcl_loot.fill_inventory(inv, "main", lootitems, pr)
|
||||
end
|
||||
end
|
||||
|
||||
local function place(pos, rotation, pr)
|
||||
mcl_structures.place_schematic({pos = pos, schematic = temple_schematic, pr = pr, on_placed = on_placed})
|
||||
end
|
||||
|
||||
local mcl_mapgen_clamp_to_chunk = mcl_mapgen.clamp_to_chunk
|
||||
local function process_pos(pos)
|
||||
return {
|
||||
x = mcl_mapgen_clamp_to_chunk(pos.x - ox, sx),
|
||||
y = mcl_mapgen_clamp_to_chunk(pos.y - oy, sy),
|
||||
z = mcl_mapgen_clamp_to_chunk(pos.z - oz, sz),
|
||||
}
|
||||
end
|
||||
|
||||
local function get_place_rank(pos)
|
||||
local x1 = pos.x + 1
|
||||
local x2 = x1 + corner_x
|
||||
local z1 = pos.z + 1
|
||||
local z2 = z1 + corner_z
|
||||
local y2 = pos.y + 1
|
||||
local y1 = y2 - 2
|
||||
if is_air({x = x1, y = y1, z = z1}) then return -1 end
|
||||
if is_air({x = x2, y = y1, z = z1}) then return -1 end
|
||||
if is_air({x = x1, y = y1, z = z2}) then return -1 end
|
||||
if is_air({x = x2, y = y1, z = z2}) then return -1 end
|
||||
|
||||
local p1 = {x = x1 + air_offset_x, y = y2, z = z1 + air_offset_z}
|
||||
local p2 = {x = x2 - air_offset_x, y = y2, z = z2 + air_offset_z}
|
||||
local pos_counter_air = #minetest.find_nodes_in_area(p1, p2, {"air", "group:buildable_to", "group:deco_block"}, false)
|
||||
local pos_counter_air = pos_counter_air - 2 * (#minetest.find_nodes_in_area(p1, p2, {"group:tree"}, false))
|
||||
|
||||
local p1 = {x = x1 + 1, y = y1, z = z1 + 1}
|
||||
local p2 = {x = x2 - 1, y = y1, z = z2 - 1}
|
||||
local pos_counter_ground = #minetest.find_nodes_in_area(p1, p2, node_list, false)
|
||||
return pos_counter_ground + pos_counter_air
|
||||
end
|
||||
|
||||
mcl_structures.register_structure({
|
||||
name = "jungle_temple",
|
||||
decoration = {
|
||||
deco_type = "simple",
|
||||
place_on = node_list,
|
||||
flags = "all_floors",
|
||||
fill_ratio = scanning_ratio,
|
||||
y_min = -13,
|
||||
y_max = mcl_mapgen.overworld.max,
|
||||
height = 1,
|
||||
biomes =
|
||||
mcl_mapgen.v6 and {
|
||||
"Jungle"
|
||||
} or {
|
||||
"Jungle",
|
||||
"JungleEdge",
|
||||
"JungleEdgeM",
|
||||
"JungleEdgeM_ocean",
|
||||
"JungleEdge_ocean",
|
||||
"JungleM",
|
||||
"JungleM_ocean",
|
||||
"JungleM_shore",
|
||||
"Jungle_ocean",
|
||||
"Jungle_shore",
|
||||
},
|
||||
},
|
||||
on_finished_chunk = function(minp, maxp, seed, vm_context, pos_list)
|
||||
local pr = PseudoRandom(seed + random_offset)
|
||||
local random_number = pr:next(1, chance_per_chunk)
|
||||
local noise = mcl_structures_get_perlin_noise_level(minp) * noise_multiplier
|
||||
if (random_number + noise) < struct_threshold then return end
|
||||
local pos
|
||||
local count = -1
|
||||
for i = 1, #pos_list do
|
||||
local pos_i = process_pos(pos_list[i])
|
||||
local count_i = get_place_rank(pos_i)
|
||||
if count_i > count then
|
||||
count = count_i
|
||||
pos = pos_i
|
||||
end
|
||||
end
|
||||
if count < 0 then return end
|
||||
place(pos, nil, pr)
|
||||
end,
|
||||
place_function = place,
|
||||
})
|
|
@ -1,4 +1,4 @@
|
|||
name = mcl_structures
|
||||
author = Wuzzy
|
||||
description = Structures for MCL2
|
||||
depends = mcl_loot
|
||||
author = Wuzzy, kay27, cora
|
||||
description = Structures for MineClone 2/5
|
||||
depends = mcl_loot, mcl_mapgen, mcl_worlds
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
-- Check: v7 apple 27576,14,28368
|
||||
-- Check: v7 apple 29570,10,29266
|
||||
|
||||
local chance_per_chunk = 70
|
||||
local noise_multiplier = 1
|
||||
local random_offset = 133
|
||||
local struct_threshold = chance_per_chunk - 1
|
||||
local scanning_ratio = 0.00021
|
||||
local mcl_structures_get_perlin_noise_level = mcl_structures.get_perlin_noise_level
|
||||
|
||||
local node_list = {"mcl_core:dirt_with_grass", "mcl_core:dirt", "mcl_core:stone", "mcl_core:granite", "mcl_core:gravel", "mcl_core:diorite"}
|
||||
|
||||
local schematic_file = modpath .. "/schematics/mcl_structures_nice_jungle_temple.mts"
|
||||
|
||||
local temple_schematic_lua = minetest.serialize_schematic(schematic_file, "lua", {lua_use_comments = false, lua_num_indent_spaces = 0}) .. " return schematic"
|
||||
local temple_schematic = loadstring(temple_schematic_lua)()
|
||||
local size = temple_schematic.size
|
||||
local sx = size.x
|
||||
local sy = size.y
|
||||
local sz = size.z
|
||||
local offset = vector.round(vector.divide(size, 2))
|
||||
offset.y = 5
|
||||
|
||||
local ox = offset.x
|
||||
local oy = offset.y
|
||||
local oz = offset.z
|
||||
local corner_x = sx - 3
|
||||
local corner_z = sz - 3
|
||||
local air_offset_x = ox - 6
|
||||
local air_offset_z = oz - 6
|
||||
|
||||
local function is_air(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
return node.name == "air"
|
||||
end
|
||||
|
||||
local stair_support_node = {
|
||||
{name = "mcl_core:cobble"},
|
||||
{name = "mcl_core:mossycobble"},
|
||||
{name = "mcl_core:stonebrick"},
|
||||
{name = "mcl_core:stonebrickmossy"},
|
||||
{name = "mcl_core:stonebrickcracked"},
|
||||
}
|
||||
|
||||
local nodes_to_be_supported = {
|
||||
"mcl_stairs:stair_cobble",
|
||||
"mcl_stairs:stair_stonebrickmossy",
|
||||
"mcl_stairs:stair_stonebrickcracked",
|
||||
}
|
||||
|
||||
local function on_placed(p1, rotation, pr, size)
|
||||
local p2
|
||||
if rotation == "90" or rotation == "270" then
|
||||
p2 = {x = p1.x + sz - 1, y = p1.y + sy - 1, z = p1.z + sx - 1}
|
||||
else
|
||||
p2 = {x = p1.x + sx - 1, y = p1.y + sy - 1, z = p1.z + sz - 1}
|
||||
end
|
||||
|
||||
-- Support stairs
|
||||
local y = p1.y + 5
|
||||
local bottom = mcl_mapgen.get_chunk_beginning(y)
|
||||
local stair_list = minetest.find_nodes_in_area({x = p1.x, y = y, z = p1.z}, {x = p2.x, y = y, z = p2.z}, nodes_to_be_supported, false)
|
||||
for i = 1, #stair_list do
|
||||
local pos = stair_list[i]
|
||||
pos.y = y - 1
|
||||
while is_air(pos) and pos.y > bottom do
|
||||
minetest.swap_node(pos, stair_support_node[pr:next(1, #stair_support_node)])
|
||||
pos.y = pos.y - 1
|
||||
end
|
||||
end
|
||||
|
||||
-- Initialize some nodes
|
||||
local chest_node = "mcl_chests:trapped_chest_small"
|
||||
local lever_node = "mesecons_walllever:wall_lever_off"
|
||||
local nodes = minetest.find_nodes_in_area(p1, {x = p2.x, y = p1.y + 5, z = p2.z}, {chest_node, lever_node}, true)
|
||||
|
||||
local levers = nodes[lever_node]
|
||||
for _, pos in pairs(levers) do
|
||||
mcl_structures.init_node_construct(pos)
|
||||
end
|
||||
|
||||
-- Add loot into chests TODO: fix items
|
||||
local chests = nodes[chest_node]
|
||||
for c=1, #chests do
|
||||
local lootitems = mcl_loot.get_multi_loot({
|
||||
{
|
||||
stacks_min = 2,
|
||||
stacks_max = 4,
|
||||
items = {
|
||||
{ itemstring = "mcl_mobitems:bone", weight = 25, amount_min = 4, amount_max=6 },
|
||||
{ itemstring = "mcl_mobitems:rotten_flesh", weight = 25, amount_min = 3, amount_max=7 },
|
||||
{ itemstring = "mcl_mobitems:spider_eye", weight = 25, amount_min = 1, amount_max=3 },
|
||||
{ itemstring = "mcl_books:book", weight = 20, func = function(stack, pr)
|
||||
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}, pr)
|
||||
end },
|
||||
{ itemstring = "mcl_mobitems:saddle", weight = 20, },
|
||||
{ itemstring = "mcl_core:apple_gold", weight = 20, },
|
||||
{ itemstring = "mcl_core:gold_ingot", weight = 15, amount_min = 2, amount_max = 7 },
|
||||
{ itemstring = "mcl_core:iron_ingot", weight = 15, amount_min = 1, amount_max = 5 },
|
||||
{ itemstring = "mcl_core:emerald", weight = 15, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "", weight = 15, },
|
||||
{ itemstring = "mobs_mc:iron_horse_armor", weight = 15, },
|
||||
{ itemstring = "mobs_mc:gold_horse_armor", weight = 10, },
|
||||
{ itemstring = "mobs_mc:diamond_horse_armor", weight = 5, },
|
||||
{ itemstring = "mcl_core:diamond", weight = 5, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_core:apple_gold_enchanted", weight = 2, },
|
||||
}
|
||||
},
|
||||
{
|
||||
stacks_min = 4,
|
||||
stacks_max = 4,
|
||||
items = {
|
||||
{ itemstring = "mcl_mobitems:bone", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_mobitems:rotten_flesh", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_mobitems:gunpowder", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_core:sand", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
{ itemstring = "mcl_mobitems:string", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
}
|
||||
}}, pr)
|
||||
mcl_structures.init_node_construct(chests[c])
|
||||
local meta = minetest.get_meta(chests[c])
|
||||
local inv = meta:get_inventory()
|
||||
mcl_loot.fill_inventory(inv, "main", lootitems, pr)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function place(pos, rotation, pr)
|
||||
mcl_structures.place_schematic({pos = pos, schematic = temple_schematic, pr = pr, on_placed = on_placed})
|
||||
end
|
||||
|
||||
local mcl_mapgen_clamp_to_chunk = mcl_mapgen.clamp_to_chunk
|
||||
local function process_pos(pos)
|
||||
return {
|
||||
x = mcl_mapgen_clamp_to_chunk(pos.x - ox, sx),
|
||||
y = mcl_mapgen_clamp_to_chunk(pos.y - oy, sy),
|
||||
z = mcl_mapgen_clamp_to_chunk(pos.z - oz, sz),
|
||||
}
|
||||
end
|
||||
|
||||
local function get_place_rank(pos)
|
||||
local x1 = pos.x + 1
|
||||
local x2 = x1 + corner_x
|
||||
local z1 = pos.z + 1
|
||||
local z2 = z1 + corner_z
|
||||
local y2 = pos.y + 1
|
||||
local y1 = y2 - 2
|
||||
if is_air({x = x1, y = y1, z = z1}) then return -1 end
|
||||
if is_air({x = x2, y = y1, z = z1}) then return -1 end
|
||||
if is_air({x = x1, y = y1, z = z2}) then return -1 end
|
||||
if is_air({x = x2, y = y1, z = z2}) then return -1 end
|
||||
|
||||
local p1 = {x = x1 + air_offset_x, y = y2, z = z1 + air_offset_z}
|
||||
local p2 = {x = x2 - air_offset_x, y = y2, z = z2 + air_offset_z}
|
||||
local pos_counter_air = #minetest.find_nodes_in_area(p1, p2, {"air", "group:buildable_to", "group:deco_block"}, false)
|
||||
local pos_counter_air = pos_counter_air - 2 * (#minetest.find_nodes_in_area(p1, p2, {"group:tree"}, false))
|
||||
|
||||
local p1 = {x = x1 + 1, y = y1, z = z1 + 1}
|
||||
local p2 = {x = x2 - 1, y = y1, z = z2 - 1}
|
||||
local pos_counter_ground = #minetest.find_nodes_in_area(p1, p2, node_list, false)
|
||||
return pos_counter_ground + pos_counter_air
|
||||
end
|
||||
|
||||
mcl_structures.register_structure({
|
||||
name = "nice_jungle_temple",
|
||||
decoration = {
|
||||
deco_type = "simple",
|
||||
place_on = node_list,
|
||||
flags = "all_floors",
|
||||
fill_ratio = scanning_ratio,
|
||||
y_min = -20,
|
||||
y_max = mcl_mapgen.overworld.max,
|
||||
height = 1,
|
||||
biomes =
|
||||
mcl_mapgen.v6 and {
|
||||
"Jungle"
|
||||
} or {
|
||||
"Jungle",
|
||||
"JungleEdge",
|
||||
"JungleEdgeM",
|
||||
"JungleEdgeM_ocean",
|
||||
"JungleEdge_ocean",
|
||||
"JungleM",
|
||||
"JungleM_ocean",
|
||||
"JungleM_shore",
|
||||
"Jungle_ocean",
|
||||
"Jungle_shore",
|
||||
},
|
||||
},
|
||||
on_finished_chunk = function(minp, maxp, seed, vm_context, pos_list)
|
||||
local pr = PseudoRandom(seed + random_offset)
|
||||
local random_number = pr:next(1, chance_per_chunk)
|
||||
local noise = mcl_structures_get_perlin_noise_level(minp) * noise_multiplier
|
||||
if (random_number + noise) < struct_threshold then return end
|
||||
local pos
|
||||
local count = -1
|
||||
for i = 1, #pos_list do
|
||||
local pos_i = process_pos(pos_list[i])
|
||||
local count_i = get_place_rank(pos_i)
|
||||
if count_i > count then
|
||||
count = count_i
|
||||
pos = pos_i
|
||||
end
|
||||
end
|
||||
if count < 0 then return end
|
||||
place(pos, nil, pr)
|
||||
end,
|
||||
place_function = place,
|
||||
})
|
|
@ -0,0 +1,69 @@
|
|||
local step = 1
|
||||
|
||||
local levels = {
|
||||
[-9] = "black",
|
||||
[-8] = "brown",
|
||||
[-7] = "brown",
|
||||
[-6] = "gray",
|
||||
[-5] = "gray",
|
||||
[-4] = "red",
|
||||
[-3] = "orange",
|
||||
[-2] = "purple",
|
||||
[-1] = "magenta",
|
||||
[0] = "pink",
|
||||
[1] = "yellow",
|
||||
[2] = "green",
|
||||
[3] = "lime",
|
||||
[4] = "blue",
|
||||
[5] = "cyan",
|
||||
[6] = "light_blue",
|
||||
[7] = "silver",
|
||||
[8] = "silver",
|
||||
[9] = "white",
|
||||
}
|
||||
|
||||
local math_min, math_max = math.min, math.max
|
||||
local math_floor, math_ceil = math.floor, math.ceil
|
||||
|
||||
local mcl_structures_get_perlin_noise_level = mcl_structures.get_perlin_noise_level
|
||||
|
||||
local noise_offset_x_and_z = math_floor(mcl_mapgen.CS_NODES/2)
|
||||
|
||||
mcl_mapgen.register_mapgen(function(minp, maxp, seed, vm_context)
|
||||
if minetest.settings:get_bool("mcl_debug_struct_noise", false) then
|
||||
local y0 = minp.y
|
||||
for x0 = minp.x, maxp.x, step do
|
||||
for z0 = minp.z, maxp.z, step do
|
||||
local current_noise_level = mcl_structures_get_perlin_noise_level({x = x0 - noise_offset_x_and_z, y = y0, z = z0 - noise_offset_x_and_z})
|
||||
local amount
|
||||
if current_noise_level < 0 then
|
||||
amount = math_max(math_ceil(current_noise_level * 9), -9)
|
||||
else
|
||||
amount = math_min(math_floor(current_noise_level * 9), 9)
|
||||
end
|
||||
local y0 = maxp.y - 9 + amount
|
||||
minetest.set_node({x=x0, y=y0, z=z0}, {name = "mcl_core:glass_"..levels[amount]})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if minetest.settings:get_bool("mcl_debug_chunk_borders", false) then
|
||||
for x0 = minp.x, maxp.x, step do
|
||||
for y0 = minp.y, maxp.y, step do
|
||||
minetest.set_node({x=x0, y=y0, z=maxp.z}, {name = "mcl_core:glass"})
|
||||
end
|
||||
end
|
||||
for z0 = minp.z, maxp.z, step do
|
||||
for y0 = minp.y, maxp.y, step do
|
||||
minetest.set_node({x=maxp.x, y=y0, z=z0}, {name = "mcl_core:glass"})
|
||||
end
|
||||
end
|
||||
for z0 = minp.z, maxp.z, step do
|
||||
for x0 = minp.x, maxp.x, step do
|
||||
minetest.set_node({x=x0, y=maxp.y, z=z0}, {name = "mcl_core:glass"})
|
||||
end
|
||||
end
|
||||
if not minetest.settings:get_bool("mcl_debug_struct_noise", false) then
|
||||
end
|
||||
end
|
||||
end, 999999999999)
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,184 @@
|
|||
-- Generate strongholds.
|
||||
|
||||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
-- A total of 128 strongholds are generated in rings around the world origin.
|
||||
-- This is the list of rings, starting with the innermost ring first.
|
||||
local stronghold_rings = {
|
||||
-- amount: Number of strongholds in ring.
|
||||
-- min, max: Minimum and maximum distance from (X=0, Z=0).
|
||||
{ amount = 3, min = 1408, max = 2688 },
|
||||
{ amount = 6, min = 4480, max = 5760 },
|
||||
{ amount = 10, min = 7552, max = 8832 },
|
||||
{ amount = 15, min = 10624, max = 11904 },
|
||||
{ amount = 21, min = 13696, max = 14976 },
|
||||
{ amount = 28, min = 16768, max = 18048 },
|
||||
{ amount = 36, min = 19840, max = 21120 },
|
||||
{ amount = 9, min = 22912, max = 24192 },
|
||||
}
|
||||
|
||||
local strongholds = {}
|
||||
local strongholds_inited = false
|
||||
|
||||
local superflat = mcl_mapgen.superflat
|
||||
|
||||
local size = {x = 13, y = 8, z = 13}
|
||||
local offset = vector.round(vector.divide(size, 2))
|
||||
|
||||
local function place(pos, rotation, pr)
|
||||
local p1 = { x = pos.x - offset.x, y = pos.y - offset.y, z = pos.z - offset.z }
|
||||
local p2 = vector.add(p1, vector.subtract(size, 1))
|
||||
|
||||
local path = modpath.."/schematics/mcl_structures_end_portal_room_simple.mts"
|
||||
|
||||
mcl_structures.place_schematic({
|
||||
pos = p1,
|
||||
schematic = path,
|
||||
rotation = rotation or "0",
|
||||
pr = pr,
|
||||
})
|
||||
-- Find and setup spawner with silverfish
|
||||
local spawners = minetest.find_nodes_in_area(p1, p2, "mcl_mobspawners:spawner")
|
||||
for s=1, #spawners do
|
||||
mcl_mobspawners.setup_spawner(spawners[s], "mobs_mc:silverfish")
|
||||
end
|
||||
|
||||
-- Shuffle stone brick types
|
||||
local bricks = minetest.find_nodes_in_area(p1, p2, "mcl_core:stonebrick")
|
||||
for b=1, #bricks do
|
||||
local r_bricktype = pr:next(1, 100)
|
||||
local r_infested = pr:next(1, 100)
|
||||
local bricktype
|
||||
if r_infested <= 5 then
|
||||
if r_bricktype <= 30 then -- 30%
|
||||
bricktype = "mcl_monster_eggs:monster_egg_stonebrickmossy"
|
||||
elseif r_bricktype <= 50 then -- 20%
|
||||
bricktype = "mcl_monster_eggs:monster_egg_stonebrickcracked"
|
||||
else -- 50%
|
||||
bricktype = "mcl_monster_eggs:monster_egg_stonebrick"
|
||||
end
|
||||
else
|
||||
if r_bricktype <= 30 then -- 30%
|
||||
bricktype = "mcl_core:stonebrickmossy"
|
||||
elseif r_bricktype <= 50 then -- 20%
|
||||
bricktype = "mcl_core:stonebrickcracked"
|
||||
end
|
||||
-- 50% stonebrick (no change necessary)
|
||||
end
|
||||
if bricktype then
|
||||
minetest.set_node(bricks[b], { name = bricktype })
|
||||
end
|
||||
end
|
||||
|
||||
-- Also replace stairs
|
||||
local stairs = minetest.find_nodes_in_area(p1, p2, {"mcl_stairs:stair_stonebrick", "mcl_stairs:stair_stonebrick_outer", "mcl_stairs:stair_stonebrick_inner"})
|
||||
for s=1, #stairs do
|
||||
local stair = minetest.get_node(stairs[s])
|
||||
local r_type = pr:next(1, 100)
|
||||
if r_type <= 30 then -- 30% mossy
|
||||
if stair.name == "mcl_stairs:stair_stonebrick" then
|
||||
stair.name = "mcl_stairs:stair_stonebrickmossy"
|
||||
elseif stair.name == "mcl_stairs:stair_stonebrick_outer" then
|
||||
stair.name = "mcl_stairs:stair_stonebrickmossy_outer"
|
||||
elseif stair.name == "mcl_stairs:stair_stonebrick_inner" then
|
||||
stair.name = "mcl_stairs:stair_stonebrickmossy_inner"
|
||||
end
|
||||
minetest.set_node(stairs[s], stair)
|
||||
elseif r_type <= 50 then -- 20% cracky
|
||||
if stair.name == "mcl_stairs:stair_stonebrick" then
|
||||
stair.name = "mcl_stairs:stair_stonebrickcracked"
|
||||
elseif stair.name == "mcl_stairs:stair_stonebrick_outer" then
|
||||
stair.name = "mcl_stairs:stair_stonebrickcracked_outer"
|
||||
elseif stair.name == "mcl_stairs:stair_stonebrick_inner" then
|
||||
stair.name = "mcl_stairs:stair_stonebrickcracked_inner"
|
||||
end
|
||||
minetest.set_node(stairs[s], stair)
|
||||
end
|
||||
-- 50% no change
|
||||
end
|
||||
|
||||
-- Randomly add ender eyes into end portal frames, but never fill the entire frame
|
||||
local frames = minetest.find_nodes_in_area(p1, p2, "mcl_portals:end_portal_frame")
|
||||
local eyes = 0
|
||||
for f=1, #frames do
|
||||
local r_eye = pr:next(1, 10)
|
||||
if r_eye == 1 then
|
||||
eyes = eyes + 1
|
||||
if eyes < #frames then
|
||||
local frame_node = minetest.get_node(frames[f])
|
||||
frame_node.name = "mcl_portals:end_portal_frame_eye"
|
||||
minetest.set_node(frames[f], frame_node)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Determine the stronghold positions and store them into the strongholds table.
|
||||
-- The stronghold positions are based on the world seed.
|
||||
-- The actual position might be offset by a few blocks because it might be shifted
|
||||
-- to make sure the end portal room is completely within the boundaries of a mapchunk.
|
||||
local function init_strongholds()
|
||||
if strongholds_inited then
|
||||
return
|
||||
end
|
||||
-- Don't generate strongholds in singlenode
|
||||
if mcl_mapgen.singlenode then
|
||||
strongholds_inited = true
|
||||
return
|
||||
end
|
||||
local pr = PseudoRandom(mcl_mapgen.seed)
|
||||
for s=1, #stronghold_rings do
|
||||
local ring = stronghold_rings[s]
|
||||
|
||||
-- Get random angle
|
||||
local angle = pr:next()
|
||||
-- Scale angle to 0 .. 2*math.pi
|
||||
angle = (angle / 32767) * (math.pi*2)
|
||||
for a=1, ring.amount do
|
||||
local dist = pr:next(ring.min, ring.max)
|
||||
local y
|
||||
if superflat then
|
||||
y = mcl_mapgen.overworld.bedrock_max + offset.y
|
||||
else
|
||||
y = pr:next(mcl_mapgen.overworld.bedrock_max+1+offset.y, mcl_mapgen.overworld.bedrock_min+48+offset.y)
|
||||
end
|
||||
local pos = {
|
||||
x = mcl_mapgen.clamp_to_chunk(math.floor(math.cos(angle) * dist) - offset.x, size.x) + offset.x,
|
||||
y = mcl_mapgen.clamp_to_chunk(y - offset.y, size.y) + offset.y,
|
||||
z = mcl_mapgen.clamp_to_chunk(math.floor(math.sin(angle) * dist) - offset.z, size.z) + offset.z,
|
||||
}
|
||||
table.insert(strongholds, { pos = pos, generated = false })
|
||||
|
||||
-- Rotate angle by (360 / amount) degrees.
|
||||
-- This will cause the angles to be evenly distributed in the stronghold ring
|
||||
angle = math.fmod(angle + ((math.pi*2) / ring.amount), math.pi*2)
|
||||
end
|
||||
end
|
||||
|
||||
mcl_structures.strongholds = strongholds
|
||||
|
||||
mcl_structures.register_structure({
|
||||
name = "stronghold",
|
||||
place_function = place,
|
||||
})
|
||||
|
||||
strongholds_inited = true
|
||||
end
|
||||
|
||||
init_strongholds()
|
||||
|
||||
-- Stronghold generation for register_on_generated.
|
||||
mcl_mapgen.register_mapgen(function(minp, maxp, blockseed)
|
||||
local pr = PseudoRandom(blockseed)
|
||||
for s=1, #strongholds do
|
||||
if not strongholds[s].generated then
|
||||
local pos = strongholds[s].pos
|
||||
if minp.x <= pos.x and maxp.x >= pos.x and minp.z <= pos.z and maxp.z >= pos.z and minp.y <= pos.y and maxp.y >= pos.y then
|
||||
place(pos, nil, pr)
|
||||
strongholds[s].generated = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end, mcl_mapgen.order.STRONGHOLDS)
|
|
@ -0,0 +1,17 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
if not mcl_mapgen.singlenode then
|
||||
dofile(modpath .. "/desert_temple.lua")
|
||||
dofile(modpath .. "/desert_well.lua")
|
||||
dofile(modpath .. "/end_exit_portal.lua")
|
||||
dofile(modpath .. "/fossil.lua")
|
||||
dofile(modpath .. "/igloo.lua")
|
||||
dofile(modpath .. "/ice_spike_small.lua")
|
||||
dofile(modpath .. "/ice_spike_large.lua")
|
||||
dofile(modpath .. "/jungle_temple.lua")
|
||||
dofile(modpath .. "/nice_jungle_temple.lua")
|
||||
dofile(modpath .. "/noise_indicator.lua")
|
||||
dofile(modpath .. "/stronghold.lua")
|
||||
dofile(modpath .. "/witch_hut.lua")
|
||||
end
|
|
@ -0,0 +1,140 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
-- Check: v7 apple 30584,5,30356
|
||||
-- Check: v7 apple 2637,6,-12031
|
||||
-- Check: v7 apple 2644,6,-17968
|
||||
|
||||
local chance_per_chunk = 34
|
||||
local noise_multiplier = -0.9
|
||||
local random_offset = 8
|
||||
local scanning_ratio = 0.01
|
||||
local struct_threshold = chance_per_chunk - 1
|
||||
|
||||
local mcl_structures_get_perlin_noise_level = mcl_structures.get_perlin_noise_level
|
||||
|
||||
local schematic_file = modpath .. "/schematics/mcl_structures_witch_hut.mts"
|
||||
|
||||
local witch_hut_schematic_lua = minetest.serialize_schematic(schematic_file, "lua", {lua_use_comments = false, lua_num_indent_spaces = 0}) .. " return schematic"
|
||||
local witch_hut_schematic = loadstring(witch_hut_schematic_lua)()
|
||||
|
||||
local node_list = {"mcl_core:dirt_with_grass", "mcl_core:dirt"}
|
||||
|
||||
local WITCH_HUT_HEIGHT = 2 -- Exact Y level to spawn witch huts at. This height refers to the height of the floor
|
||||
|
||||
local witch_hut_offsets = {
|
||||
["0"] = {
|
||||
{x=1, y=0, z=1}, {x=1, y=0, z=5}, {x=6, y=0, z=1}, {x=6, y=0, z=5},
|
||||
},
|
||||
["180"] = {
|
||||
{x=2, y=0, z=1}, {x=2, y=0, z=5}, {x=7, y=0, z=1}, {x=7, y=0, z=5},
|
||||
},
|
||||
["270"] = {
|
||||
{x=1, y=0, z=1}, {x=5, y=0, z=1}, {x=1, y=0, z=6}, {x=5, y=0, z=6},
|
||||
},
|
||||
["90"] = {
|
||||
{x=1, y=0, z=2}, {x=5, y=0, z=2}, {x=1, y=0, z=7}, {x=5, y=0, z=7},
|
||||
},
|
||||
}
|
||||
|
||||
local function on_placed(place, rotation, pr, size)
|
||||
local offsets = witch_hut_offsets[rotation]
|
||||
if not offsets then return end
|
||||
for _, offset in pairs(offsets) do
|
||||
local tpos = vector.add(place, offset)
|
||||
for y = place.y - 1, mcl_mapgen.get_chunk_beginning(place.y - 1), -1 do
|
||||
tpos.y = y
|
||||
local nn = minetest.get_node(tpos).name
|
||||
if not nn then break end
|
||||
local node = minetest.registered_nodes[nn]
|
||||
local groups = node.groups
|
||||
if nn == "mcl_flowers:waterlily" or nn == "mcl_core:river_water_source" or nn == "mcl_core:water_source" or nn == "mcl_core:water_flowing" or nn == "air" or groups.deco_block then
|
||||
minetest.swap_node(tpos, {name="mcl_core:tree"})
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function place(pos, rotation, pr)
|
||||
mcl_structures.place_schematic({pos = pos, rotaton = rotation, schematic = witch_hut_schematic, pr = pr, on_placed = on_placed})
|
||||
end
|
||||
|
||||
local function get_place_rank(pos)
|
||||
local x, y, z = pos.x, pos.y, pos.z
|
||||
local p1 = {x = x + 1, y = y + 1, z = z + 1}
|
||||
local p2 = {x = x + 4, y = y + 4, z = z + 4}
|
||||
local counter = #minetest.find_nodes_in_area(p1, p2, {"air", "group:buildable_to", "group:deco_block"}, false)
|
||||
return counter
|
||||
end
|
||||
|
||||
local function tune_pos(pos)
|
||||
local pos = table.copy(pos)
|
||||
local y = pos.y - 1
|
||||
if y >= WITCH_HUT_HEIGHT - 5 and y <= WITCH_HUT_HEIGHT + 5 then
|
||||
pos.y = WITCH_HUT_HEIGHT
|
||||
return pos
|
||||
end
|
||||
local x = pos.x
|
||||
local z = pos.z
|
||||
local p1 = {x = x - 3, y = y , z = z - 3}
|
||||
local p2 = {x = x + 3, y = y + 2, z = z + 3}
|
||||
local water_list = minetest.find_nodes_in_area(p1, p2, {"group:water"}, false)
|
||||
if not water_list or #water_list < 1 then
|
||||
pos.y = y
|
||||
return pos
|
||||
end
|
||||
local top = -1
|
||||
for _, pos in pairs(water_list) do
|
||||
if pos.y > top then
|
||||
top = pos.y
|
||||
end
|
||||
end
|
||||
pos.y = top
|
||||
return pos
|
||||
end
|
||||
|
||||
mcl_structures.register_structure({
|
||||
name = "witch_hut",
|
||||
decoration = {
|
||||
deco_type = "simple",
|
||||
place_on = node_list,
|
||||
spawn_by = {"mcl_core:river_water_source", "mcl_core:water_source", "group:frosted_ice"},
|
||||
num_spawn_by = 1,
|
||||
-- flags = "all_floors",
|
||||
fill_ratio = scanning_ratio,
|
||||
y_min = mcl_mapgen.overworld.min,
|
||||
y_max = mcl_mapgen.overworld.max,
|
||||
height = 1,
|
||||
biomes = mcl_mapgen.v6 and {
|
||||
"Normal",
|
||||
} or {
|
||||
"Swampland",
|
||||
"Swampland_shore",
|
||||
"Swampland_ocean",
|
||||
"Swampland_deep_ocean",
|
||||
},
|
||||
},
|
||||
on_finished_chunk = function(minp, maxp, seed, vm_context, pos_list)
|
||||
local pr = PseudoRandom(seed + random_offset)
|
||||
local random_number = pr:next(1, chance_per_chunk)
|
||||
local noise = mcl_structures_get_perlin_noise_level(minp) * noise_multiplier
|
||||
if (random_number + noise) < struct_threshold then return end
|
||||
local pos = tune_pos(pos_list[1])
|
||||
if #pos_list > 1 then
|
||||
local count = get_place_rank(pos)
|
||||
for i = 2, #pos_list do
|
||||
local pos_i = pos_list[i]
|
||||
local count_i = get_place_rank(pos_i)
|
||||
if count_i > count then
|
||||
count = count_i
|
||||
pos = pos_i
|
||||
end
|
||||
end
|
||||
end
|
||||
place(pos, nil, pr)
|
||||
end,
|
||||
place_function = place,
|
||||
})
|
|
@ -0,0 +1,22 @@
|
|||
# MCL_Villages version 1.0
|
||||
--------------------------
|
||||
Originally a fork of Rochambeau's "Settlements", fully rewritten for MineClone 5.
|
||||
|
||||
## Using the mod
|
||||
----------------
|
||||
This mod adds villages on world generation.
|
||||
|
||||
## Credits
|
||||
----------
|
||||
* This mod is originally based on "ruins" by BlockMen
|
||||
|
||||
* Completely new schematics for MineClone2:
|
||||
* MysticTempest - CC-BY-SA 4.0
|
||||
|
||||
* Basic conversion of Settlements mod for compatibility with MineClone2: MysticTempest
|
||||
|
||||
* Reimplemention: kay27
|
||||
|
||||
## License
|
||||
----------
|
||||
* License of source code: WTFPL
|
|
@ -1,45 +0,0 @@
|
|||
MCL_Villages:
|
||||
============================
|
||||
A fork of Rochambeau's "Settlements" mod converted for use in MineClone2.
|
||||
|
||||
--------------
|
||||
Using the mod:
|
||||
--------------
|
||||
This mod adds settlements on world generation.
|
||||
|
||||
And, in Creative Mode; also comes with a debug tool for spawning in villages.
|
||||
|
||||
|
||||
-------------
|
||||
MCL2 Credits:
|
||||
-------------
|
||||
Code forked from: https://github.com/MysticTempest/settlements/tree/mcl_villages
|
||||
Commit: e24b4be
|
||||
================================================================================
|
||||
Basic conversion of Settlements mod for compatibility with MineClone2, plus new schematics: MysticTempest
|
||||
|
||||
Seed-based Village Generation, multi-threading, bugfixes: kay27
|
||||
|
||||
|
||||
|
||||
=========================
|
||||
version: 0.1 alpha
|
||||
|
||||
License of source code: WTFPL
|
||||
-----------------------------
|
||||
(c) Copyright Rochambeau (2018)
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
|
||||
Credits:
|
||||
--------------
|
||||
This mod is based on "ruins" by BlockMen
|
||||
|
||||
Completely new schematics for MineClone2:
|
||||
MysticTempest - CC-BY-SA 4.0
|
||||
|
|
@ -1,282 +0,0 @@
|
|||
--[[
|
||||
-------------------------------------------------------------------------------
|
||||
-- build schematic, replace material, rotation
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.build_schematic(vm, data, va, pos, building, replace_wall, name)
|
||||
-- get building node material for better integration to surrounding
|
||||
local platform_material = mcl_vars.get_node(pos)
|
||||
if not platform_material or (platform_material.name == "air" or platform_material.name == "ignore") then
|
||||
return
|
||||
end
|
||||
platform_material = platform_material.name
|
||||
-- pick random material
|
||||
local material = wallmaterial[math.random(1,#wallmaterial)]
|
||||
-- schematic conversion to lua
|
||||
local schem_lua = minetest.serialize_schematic(building,
|
||||
"lua",
|
||||
{lua_use_comments = false, lua_num_indent_spaces = 0}).." return schematic"
|
||||
-- replace material
|
||||
if replace_wall == "y" then
|
||||
schem_lua = schem_lua:gsub("mcl_core:cobble", material)
|
||||
end
|
||||
schem_lua = schem_lua:gsub("mcl_core:dirt_with_grass",
|
||||
platform_material)
|
||||
|
||||
-- Disable special junglewood for now.
|
||||
-- special material for spawning npcs
|
||||
-- schem_lua = schem_lua:gsub("mcl_core:junglewood",
|
||||
-- "settlements:junglewood")
|
||||
--
|
||||
|
||||
-- format schematic string
|
||||
local schematic = loadstring(schem_lua)()
|
||||
-- build foundation for the building an make room above
|
||||
local width = schematic["size"]["x"]
|
||||
local depth = schematic["size"]["z"]
|
||||
local height = schematic["size"]["y"]
|
||||
local possible_rotations = {"0", "90", "180", "270"}
|
||||
local rotation = possible_rotations[ math.random( #possible_rotations ) ]
|
||||
settlements.foundation(
|
||||
pos,
|
||||
width,
|
||||
depth,
|
||||
height,
|
||||
rotation)
|
||||
vm:set_data(data)
|
||||
-- place schematic
|
||||
|
||||
minetest.place_schematic_on_vmanip(
|
||||
vm,
|
||||
pos,
|
||||
schematic,
|
||||
rotation,
|
||||
nil,
|
||||
true)
|
||||
vm:write_to_map(true)
|
||||
end]]
|
||||
-------------------------------------------------------------------------------
|
||||
-- initialize settlement_info
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.initialize_settlement_info(pr)
|
||||
local count_buildings = {}
|
||||
|
||||
-- count_buildings table reset
|
||||
for k,v in pairs(settlements.schematic_table) do
|
||||
count_buildings[v["name"]] = 0
|
||||
end
|
||||
|
||||
-- randomize number of buildings
|
||||
local number_of_buildings = pr:next(10, 25)
|
||||
local number_built = 1
|
||||
settlements.debug("Village ".. number_of_buildings)
|
||||
|
||||
return count_buildings, number_of_buildings, number_built
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- fill settlement_info
|
||||
--------------------------------------------------------------------------------
|
||||
function settlements.create_site_plan(maxp, minp, pr)
|
||||
local settlement_info = {}
|
||||
local building_all_info
|
||||
local possible_rotations = {"0", "90", "180", "270"}
|
||||
-- find center of chunk
|
||||
local center = {
|
||||
x=math.floor((minp.x+maxp.x)/2),
|
||||
y=maxp.y,
|
||||
z=math.floor((minp.z+maxp.z)/2)
|
||||
}
|
||||
-- find center_surface of chunk
|
||||
local center_surface , surface_material = settlements.find_surface(center, true)
|
||||
local chunks = {}
|
||||
chunks[mcl_vars.get_chunk_number(center)] = true
|
||||
|
||||
-- go build settlement around center
|
||||
if not center_surface then return false end
|
||||
|
||||
-- add settlement to list
|
||||
table.insert(settlements_in_world, center_surface)
|
||||
-- save list to file
|
||||
settlements.save()
|
||||
-- initialize all settlement_info table
|
||||
local count_buildings, number_of_buildings, number_built = settlements.initialize_settlement_info(pr)
|
||||
-- first building is townhall in the center
|
||||
building_all_info = settlements.schematic_table[1]
|
||||
local rotation = possible_rotations[ pr:next(1, #possible_rotations ) ]
|
||||
-- add to settlement info table
|
||||
local index = 1
|
||||
settlement_info[index] = {
|
||||
pos = center_surface,
|
||||
name = building_all_info["name"],
|
||||
hsize = building_all_info["hsize"],
|
||||
rotat = rotation,
|
||||
surface_mat = surface_material
|
||||
}
|
||||
--increase index for following buildings
|
||||
index = index + 1
|
||||
-- now some buildings around in a circle, radius = size of town center
|
||||
local x, z, r = center_surface.x, center_surface.z, building_all_info["hsize"]
|
||||
-- draw j circles around center and increase radius by math.random(2,5)
|
||||
for j = 1,20 do
|
||||
-- set position on imaginary circle
|
||||
for j = 0, 360, 15 do
|
||||
local angle = j * math.pi / 180
|
||||
local ptx, ptz = x + r * math.cos( angle ), z + r * math.sin( angle )
|
||||
ptx = settlements.round(ptx, 0)
|
||||
ptz = settlements.round(ptz, 0)
|
||||
local pos1 = { x=ptx, y=center_surface.y+50, z=ptz}
|
||||
local chunk_number = mcl_vars.get_chunk_number(pos1)
|
||||
local pos_surface, surface_material
|
||||
if chunks[chunk_number] then
|
||||
pos_surface, surface_material = settlements.find_surface(pos1)
|
||||
else
|
||||
chunks[chunk_number] = true
|
||||
pos_surface, surface_material = settlements.find_surface(pos1, true)
|
||||
end
|
||||
if not pos_surface then break end
|
||||
|
||||
local randomized_schematic_table = shuffle(settlements.schematic_table, pr)
|
||||
-- pick schematic
|
||||
local size = #randomized_schematic_table
|
||||
for i = size, 1, -1 do
|
||||
-- already enough buildings of that type?
|
||||
if count_buildings[randomized_schematic_table[i]["name"]] < randomized_schematic_table[i]["max_num"]*number_of_buildings then
|
||||
building_all_info = randomized_schematic_table[i]
|
||||
-- check distance to other buildings
|
||||
local distance_to_other_buildings_ok = settlements.check_distance(settlement_info, pos_surface, building_all_info["hsize"])
|
||||
if distance_to_other_buildings_ok then
|
||||
-- count built houses
|
||||
count_buildings[building_all_info["name"]] = count_buildings[building_all_info["name"]] +1
|
||||
rotation = possible_rotations[ pr:next(1, #possible_rotations ) ]
|
||||
number_built = number_built + 1
|
||||
settlement_info[index] = {
|
||||
pos = pos_surface,
|
||||
name = building_all_info["name"],
|
||||
hsize = building_all_info["hsize"],
|
||||
rotat = rotation,
|
||||
surface_mat = surface_material
|
||||
}
|
||||
index = index + 1
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if number_of_buildings == number_built then
|
||||
break
|
||||
end
|
||||
end
|
||||
if number_built >= number_of_buildings then
|
||||
break
|
||||
end
|
||||
r = r + pr:next(2,5)
|
||||
end
|
||||
settlements.debug("really ".. number_built)
|
||||
return settlement_info
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- evaluate settlement_info and place schematics
|
||||
-------------------------------------------------------------------------------
|
||||
-- Initialize node
|
||||
local function construct_node(p1, p2, name)
|
||||
local r = minetest.registered_nodes[name]
|
||||
if r then
|
||||
if r.on_construct then
|
||||
local nodes = minetest.find_nodes_in_area(p1, p2, name)
|
||||
for p=1, #nodes do
|
||||
local pos = nodes[p]
|
||||
r.on_construct(pos)
|
||||
end
|
||||
return nodes
|
||||
end
|
||||
minetest.log("warning", "[mcl_villages] No on_construct defined for node name " .. name)
|
||||
return
|
||||
end
|
||||
minetest.log("warning", "[mcl_villages] Attempt to 'construct' inexistant nodes: " .. name)
|
||||
end
|
||||
local function init_nodes(p1, p2, size, rotation, pr)
|
||||
construct_node(p1, p2, "mcl_itemframes:item_frame")
|
||||
construct_node(p1, p2, "mcl_furnaces:furnace")
|
||||
construct_node(p1, p2, "mcl_anvils:anvil")
|
||||
|
||||
local nodes = construct_node(p1, p2, "mcl_chests:chest")
|
||||
if nodes and #nodes > 0 then
|
||||
for p=1, #nodes do
|
||||
local pos = nodes[p]
|
||||
settlements.fill_chest(pos, pr)
|
||||
end
|
||||
end
|
||||
end
|
||||
function settlements.place_schematics(settlement_info, pr)
|
||||
local building_all_info
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
for j, schem in ipairs(settlements.schematic_table) do
|
||||
if settlement_info[i]["name"] == schem["name"] then
|
||||
building_all_info = schem
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local pos = settlement_info[i]["pos"]
|
||||
local rotation = settlement_info[i]["rotat"]
|
||||
-- get building node material for better integration to surrounding
|
||||
local platform_material = settlement_info[i]["surface_mat"]
|
||||
--platform_material_name = minetest.get_name_from_content_id(platform_material)
|
||||
-- pick random material
|
||||
--local material = wallmaterial[pr:next(1,#wallmaterial)]
|
||||
--
|
||||
local building = building_all_info["mts"]
|
||||
local replace_wall = building_all_info["rplc"]
|
||||
-- schematic conversion to lua
|
||||
local schem_lua = minetest.serialize_schematic(building,
|
||||
"lua",
|
||||
{lua_use_comments = false, lua_num_indent_spaces = 0}).." return schematic"
|
||||
schem_lua = schem_lua:gsub("mcl_core:stonebrickcarved", "mcl_villages:stonebrickcarved")
|
||||
-- replace material
|
||||
if replace_wall then
|
||||
--Note, block substitution isn't matching node names exactly; so nodes that are to be substituted that have the same prefixes cause bugs.
|
||||
-- Example: Attempting to swap out 'mcl_core:stonebrick'; which has multiple, additional sub-variants: (carved, cracked, mossy). Will currently cause issues, so leaving disabled.
|
||||
if platform_material == "mcl_core:snow" or platform_material == "mcl_core:dirt_with_grass_snow" or platform_material == "mcl_core:podzol" then
|
||||
schem_lua = schem_lua:gsub("mcl_core:tree", "mcl_core:sprucetree")
|
||||
schem_lua = schem_lua:gsub("mcl_core:wood", "mcl_core:sprucewood")
|
||||
--schem_lua = schem_lua:gsub("mcl_fences:fence", "mcl_fences:spruce_fence")
|
||||
--schem_lua = schem_lua:gsub("mcl_stairs:slab_wood_top", "mcl_stairs:slab_sprucewood_top")
|
||||
--schem_lua = schem_lua:gsub("mcl_stairs:stair_wood", "mcl_stairs:stair_sprucewood")
|
||||
--schem_lua = schem_lua:gsub("mesecons_pressureplates:pressure_plate_wood_off", "mesecons_pressureplates:pressure_plate_sprucewood_off")
|
||||
elseif platform_material == "mcl_core:sand" or platform_material == "mcl_core:redsand" then
|
||||
schem_lua = schem_lua:gsub("mcl_core:tree", "mcl_core:sandstonecarved")
|
||||
schem_lua = schem_lua:gsub("mcl_core:cobble", "mcl_core:sandstone")
|
||||
schem_lua = schem_lua:gsub("mcl_core:wood", "mcl_core:sandstonesmooth")
|
||||
--schem_lua = schem_lua:gsub("mcl_fences:fence", "mcl_fences:birch_fence")
|
||||
--schem_lua = schem_lua:gsub("mcl_stairs:slab_wood_top", "mcl_stairs:slab_birchwood_top")
|
||||
--schem_lua = schem_lua:gsub("mcl_stairs:stair_wood", "mcl_stairs:stair_birchwood")
|
||||
--schem_lua = schem_lua:gsub("mesecons_pressureplates:pressure_plate_wood_off", "mesecons_pressureplates:pressure_plate_birchwood_off")
|
||||
--schem_lua = schem_lua:gsub("mcl_stairs:stair_stonebrick", "mcl_stairs:stair_redsandstone")
|
||||
--schem_lua = schem_lua:gsub("mcl_core:stonebrick", "mcl_core:redsandstonesmooth")
|
||||
schem_lua = schem_lua:gsub("mcl_core:brick_block", "mcl_core:redsandstone")
|
||||
end
|
||||
end
|
||||
schem_lua = schem_lua:gsub("mcl_core:dirt_with_grass", platform_material)
|
||||
|
||||
--[[ Disable special junglewood for now.
|
||||
-- special material for spawning npcs
|
||||
schem_lua = schem_lua:gsub("mcl_core:junglewood", "settlements:junglewood")
|
||||
--]]
|
||||
|
||||
schem_lua = schem_lua:gsub("mcl_stairs:stair_wood_outer", "mcl_stairs:slab_wood")
|
||||
schem_lua = schem_lua:gsub("mcl_stairs:stair_stone_rough_outer", "air")
|
||||
|
||||
-- format schematic string
|
||||
local schematic = loadstring(schem_lua)()
|
||||
-- build foundation for the building an make room above
|
||||
-- place schematic
|
||||
mcl_structures.place_schematic(
|
||||
pos,
|
||||
schematic,
|
||||
rotation,
|
||||
nil,
|
||||
true,
|
||||
nil,
|
||||
init_nodes,
|
||||
pr
|
||||
)
|
||||
end
|
||||
end
|
|
@ -1,81 +0,0 @@
|
|||
-- switch for debugging
|
||||
function settlements.debug(message)
|
||||
-- minetest.chat_send_all(message)
|
||||
-- minetest.log("warning", "[mcl_villages] "..message)
|
||||
minetest.log("verbose", "[mcl_villages] "..message)
|
||||
end
|
||||
|
||||
--[[ Manually set in 'buildings.lua'
|
||||
-- material to replace cobblestone with
|
||||
local wallmaterial = {
|
||||
"mcl_core:junglewood",
|
||||
"mcl_core:sprucewood",
|
||||
"mcl_core:wood",
|
||||
"mcl_core:birchwood",
|
||||
"mcl_core:acaciawood",
|
||||
"mcl_core:stonebrick",
|
||||
"mcl_core:cobble",
|
||||
"mcl_core:sandstonecarved",
|
||||
"mcl_core:sandstone",
|
||||
"mcl_core:sandstonesmooth2"
|
||||
}
|
||||
--]]
|
||||
settlements.surface_mat = {}
|
||||
-------------------------------------------------------------------------------
|
||||
-- Set array to list
|
||||
-- https://stackoverflow.com/questions/656199/search-for-an-item-in-a-lua-list
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.grundstellungen()
|
||||
settlements.surface_mat = settlements.Set {
|
||||
"mcl_core:dirt_with_grass",
|
||||
--"mcl_core:dry_dirt_with_grass",
|
||||
"mcl_core:dirt_with_grass_snow",
|
||||
--"mcl_core:dirt_with_dry_grass",
|
||||
"mcl_core:podzol",
|
||||
"mcl_core:sand",
|
||||
"mcl_core:redsand",
|
||||
--"mcl_core:silver_sand",
|
||||
"mcl_core:snow"
|
||||
}
|
||||
end
|
||||
--
|
||||
-- possible surfaces where buildings can be built
|
||||
--
|
||||
|
||||
--
|
||||
-- path to schematics
|
||||
--
|
||||
schem_path = settlements.modpath.."/schematics/"
|
||||
--
|
||||
-- list of schematics
|
||||
--
|
||||
local basic_pseudobiome_villages = minetest.settings:get_bool("basic_pseudobiome_villages", true)
|
||||
|
||||
settlements.schematic_table = {
|
||||
{name = "large_house", mts = schem_path.."large_house.mts", hwidth = 11, hdepth = 12, hheight = 9, hsize = 14, max_num = 0.08 , rplc = basic_pseudobiome_villages },
|
||||
{name = "blacksmith", mts = schem_path.."blacksmith.mts", hwidth = 7, hdepth = 7, hheight = 13, hsize = 13, max_num = 0.055, rplc = basic_pseudobiome_villages },
|
||||
{name = "butcher", mts = schem_path.."butcher.mts", hwidth = 11, hdepth = 8, hheight = 10, hsize = 14, max_num = 0.03 , rplc = basic_pseudobiome_villages },
|
||||
{name = "church", mts = schem_path.."church.mts", hwidth = 13, hdepth = 13, hheight = 14, hsize = 15, max_num = 0.04 , rplc = basic_pseudobiome_villages },
|
||||
{name = "farm", mts = schem_path.."farm.mts", hwidth = 7, hdepth = 7, hheight = 13, hsize = 13, max_num = 0.1 , rplc = basic_pseudobiome_villages },
|
||||
{name = "lamp", mts = schem_path.."lamp.mts", hwidth = 3, hdepth = 3, hheight = 13, hsize = 10, max_num = 0.1 , rplc = false },
|
||||
{name = "library", mts = schem_path.."library.mts", hwidth = 12, hdepth = 12, hheight = 8, hsize = 13, max_num = 0.04 , rplc = basic_pseudobiome_villages },
|
||||
{name = "medium_house", mts = schem_path.."medium_house.mts", hwidth = 8, hdepth = 12, hheight = 8, hsize = 14, max_num = 0.08 , rplc = basic_pseudobiome_villages },
|
||||
{name = "small_house", mts = schem_path.."small_house.mts", hwidth = 9, hdepth = 7, hheight = 8, hsize = 13, max_num = 0.7 , rplc = basic_pseudobiome_villages },
|
||||
{name = "tavern", mts = schem_path.."tavern.mts", hwidth = 11, hdepth = 10, hheight = 10, hsize = 13, max_num = 0.050, rplc = basic_pseudobiome_villages },
|
||||
{name = "well", mts = schem_path.."well.mts", hwidth = 6, hdepth = 8, hheight = 6, hsize = 10, max_num = 0.045, rplc = basic_pseudobiome_villages },
|
||||
}
|
||||
|
||||
--
|
||||
-- list of settlements, load on server start up
|
||||
--
|
||||
settlements_in_world = {}
|
||||
--
|
||||
--
|
||||
-- maximum allowed difference in height for building a sttlement
|
||||
--
|
||||
max_height_difference = 56
|
||||
--
|
||||
--
|
||||
--
|
||||
half_map_chunk_size = 40
|
||||
--quarter_map_chunk_size = 20
|
|
@ -1,65 +0,0 @@
|
|||
-------------------------------------------------------------------------------
|
||||
-- function to fill empty space below baseplate when building on a hill
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.ground(pos, pr) -- role model: Wendelsteinkircherl, Brannenburg
|
||||
local p2 = vector.new(pos)
|
||||
local cnt = 0
|
||||
local mat = "mcl_core:dirt"
|
||||
p2.y = p2.y-1
|
||||
while true do
|
||||
cnt = cnt+1
|
||||
if cnt > 20 then break end
|
||||
if cnt>pr:next(2,4) then
|
||||
mat = "mcl_core:stone"
|
||||
end
|
||||
minetest.swap_node(p2, {name=mat})
|
||||
p2.y = p2.y-1
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- function clear space above baseplate
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.terraform(settlement_info, pr)
|
||||
local fheight, fwidth, fdepth, schematic_data
|
||||
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
-- pick right schematic_info to current built_house
|
||||
for j, schem in ipairs(settlements.schematic_table) do
|
||||
if settlement_info[i]["name"] == schem["name"] then
|
||||
schematic_data = schem
|
||||
break
|
||||
end
|
||||
end
|
||||
local pos = settlement_info[i]["pos"]
|
||||
if settlement_info[i]["rotat"] == "0" or settlement_info[i]["rotat"] == "180" then
|
||||
fwidth = schematic_data["hwidth"]
|
||||
fdepth = schematic_data["hdepth"]
|
||||
else
|
||||
fwidth = schematic_data["hdepth"]
|
||||
fdepth = schematic_data["hwidth"]
|
||||
end
|
||||
--fheight = schematic_data["hheight"] * 3 -- remove trees and leaves above
|
||||
fheight = schematic_data["hheight"] -- remove trees and leaves above
|
||||
--
|
||||
-- now that every info is available -> create platform and clear space above
|
||||
--
|
||||
for xi = 0,fwidth-1 do
|
||||
for zi = 0,fdepth-1 do
|
||||
for yi = 0,fheight *3 do
|
||||
if yi == 0 then
|
||||
local p = {x=pos.x+xi, y=pos.y, z=pos.z+zi}
|
||||
settlements.ground(p, pr)
|
||||
else
|
||||
-- write ground
|
||||
-- local p = {x=pos.x+xi, y=pos.y+yi, z=pos.z+zi}
|
||||
-- local node = mcl_vars.get_node(p)
|
||||
-- if node and node.name ~= "air" then
|
||||
-- minetest.swap_node(p,{name="air"})
|
||||
-- end
|
||||
minetest.swap_node({x=pos.x+xi, y=pos.y+yi, z=pos.z+zi},{name="air"})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,24 +1,379 @@
|
|||
settlements = {}
|
||||
settlements.modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
mcl_villages = {}
|
||||
local chance_per_chunk = 100
|
||||
local chunk_offset_top = 16
|
||||
local chunk_offset_bottom = 3
|
||||
local max_height_difference = 12
|
||||
local minp_min = -64
|
||||
local noise_multiplier = 1
|
||||
local random_offset = 1
|
||||
local random_multiply = 19
|
||||
local struct_threshold = chance_per_chunk
|
||||
local noise_params = {
|
||||
offset = 0,
|
||||
scale = 2,
|
||||
spread = {
|
||||
x = mcl_mapgen.CS_NODES * chance_per_chunk,
|
||||
y = mcl_mapgen.CS_NODES * chance_per_chunk,
|
||||
z = mcl_mapgen.CS_NODES * chance_per_chunk,
|
||||
},
|
||||
seed = 842458,
|
||||
octaves = 2,
|
||||
persistence = 0.5,
|
||||
}
|
||||
local perlin_noise
|
||||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
local S = minetest.get_translator(modname)
|
||||
local basic_pseudobiome_villages = minetest.settings:get_bool("basic_pseudobiome_villages", true)
|
||||
local schem_path = modpath .. "/schematics/"
|
||||
local schematic_table = {
|
||||
{name = "large_house", mts = schem_path.."large_house.mts", max_num = 0.08 , rplc = basic_pseudobiome_villages },
|
||||
{name = "blacksmith", mts = schem_path.."blacksmith.mts", max_num = 0.055, rplc = basic_pseudobiome_villages },
|
||||
{name = "butcher", mts = schem_path.."butcher.mts", max_num = 0.03 , rplc = basic_pseudobiome_villages },
|
||||
{name = "church", mts = schem_path.."church.mts", max_num = 0.04 , rplc = basic_pseudobiome_villages },
|
||||
{name = "farm", mts = schem_path.."farm.mts", max_num = 0.1 , rplc = basic_pseudobiome_villages },
|
||||
{name = "lamp", mts = schem_path.."lamp.mts", max_num = 0.1 , rplc = false },
|
||||
{name = "library", mts = schem_path.."library.mts", max_num = 0.04 , rplc = basic_pseudobiome_villages },
|
||||
{name = "medium_house", mts = schem_path.."medium_house.mts", max_num = 0.08 , rplc = basic_pseudobiome_villages },
|
||||
{name = "small_house", mts = schem_path.."small_house.mts", max_num = 0.7 , rplc = basic_pseudobiome_villages },
|
||||
{name = "tavern", mts = schem_path.."tavern.mts", max_num = 0.050, rplc = basic_pseudobiome_villages },
|
||||
{name = "well", mts = schem_path.."well.mts", max_num = 0.045, rplc = basic_pseudobiome_villages },
|
||||
}
|
||||
local surface_mat = {
|
||||
["mcl_core:dirt_with_dry_grass"] = { top = "mcl_core:dirt", bottom = "mcl_core:stone" },
|
||||
["mcl_core:dirt_with_grass"] = { top = "mcl_core:dirt", bottom = "mcl_core:stone" },
|
||||
["mcl_core:dirt_with_grass_snow"] = { top = "mcl_core:dirt", bottom = "mcl_core:stone" },
|
||||
["mcl_core:podzol"] = { top = "mcl_core:podzol", bottom = "mcl_core:stone" },
|
||||
["mcl_core:redsand"] = { top = "mcl_core:redsand", bottom = "mcl_core:redsandstone" },
|
||||
["mcl_core:sand"] = { top = "mcl_core:sand", bottom = "mcl_core:sandstone" },
|
||||
["mcl_core:snow"] = { top = "mcl_core:dirt", bottom = "mcl_core:stone" },
|
||||
}
|
||||
local storage = minetest.get_mod_storage()
|
||||
local villages = minetest.deserialize(storage:get_string("villages") or "return {}") or {}
|
||||
local minetest_get_spawn_level = minetest.get_spawn_level
|
||||
local minetest_get_node = minetest.get_node
|
||||
local minetest_find_nodes_in_area = minetest.find_nodes_in_area
|
||||
local minetest_get_perlin = minetest.get_perlin
|
||||
local math_pi = math.pi
|
||||
local math_cos = math.cos
|
||||
local math_sin = math.sin
|
||||
local math_min = math.min
|
||||
local math_max = math.max
|
||||
local math_floor = math.floor
|
||||
local math_ceil = math.ceil
|
||||
local string_find = string.find
|
||||
local minetest_swap_node = minetest.swap_node
|
||||
local minetest_registered_nodes = minetest.registered_nodes
|
||||
local minetest_bulk_set_node = minetest.bulk_set_node
|
||||
local air_offset = chunk_offset_top - 1
|
||||
local ground_offset = chunk_offset_bottom + 1
|
||||
local surface_search_list = {}
|
||||
for k, _ in pairs(surface_mat) do
|
||||
table.insert(surface_search_list, k)
|
||||
end
|
||||
|
||||
dofile(settlements.modpath.."/const.lua")
|
||||
dofile(settlements.modpath.."/utils.lua")
|
||||
dofile(settlements.modpath.."/foundation.lua")
|
||||
dofile(settlements.modpath.."/buildings.lua")
|
||||
dofile(settlements.modpath.."/paths.lua")
|
||||
--dofile(settlements.modpath.."/convert_lua_mts.lua")
|
||||
--
|
||||
-- load settlements on server
|
||||
--
|
||||
settlements_in_world = settlements.load()
|
||||
settlements.grundstellungen()
|
||||
local function math_round(x)
|
||||
return (x < 0) and math_ceil(x - 0.5) or math_floor(x + 0.5)
|
||||
end
|
||||
|
||||
local function find_surface(pos, minp, maxp)
|
||||
local x, z = pos.x, pos.z
|
||||
local y_top = maxp.y
|
||||
local y_max = y_top - air_offset
|
||||
if #minetest_find_nodes_in_area({x=x, y=y_max, z=z}, {x=x, y=y_top, z=z}, "air") < chunk_offset_top then return end
|
||||
y_max = y_max - 1
|
||||
local y_bottom = minp.y
|
||||
local y_min = y_bottom + chunk_offset_bottom
|
||||
local nodes = minetest_find_nodes_in_area({x=x, y=y_min, z=z}, {x=x, y=y_max, z=z}, surface_search_list)
|
||||
for _, surface_pos in pairs(nodes) do
|
||||
local node_name_from_above = minetest_get_node({x=surface_pos.x, y=surface_pos.y+1, z=surface_pos.z}).name
|
||||
if string_find(node_name_from_above, "air" )
|
||||
or string_find(node_name_from_above, "snow" )
|
||||
or string_find(node_name_from_above, "fern" )
|
||||
or string_find(node_name_from_above, "flower")
|
||||
or string_find(node_name_from_above, "bush" )
|
||||
or string_find(node_name_from_above, "tree" )
|
||||
or string_find(node_name_from_above, "grass" )
|
||||
then
|
||||
return surface_pos, minetest_get_node(surface_pos).name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function get_treasures(pr)
|
||||
local loottable = {{
|
||||
stacks_min = 3,
|
||||
stacks_max = 8,
|
||||
items = {
|
||||
{ itemstring = "mcl_core:diamond" , weight = 3, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_core:iron_ingot" , weight = 10, amount_min = 1, amount_max = 5 },
|
||||
{ itemstring = "mcl_core:gold_ingot" , weight = 5, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_farming:bread" , weight = 15, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_core:apple" , weight = 15, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_tools:pick_iron" , weight = 5, },
|
||||
{ itemstring = "mcl_tools:sword_iron" , weight = 5, },
|
||||
{ itemstring = "mcl_armor:chestplate_iron" , weight = 5, },
|
||||
{ itemstring = "mcl_armor:helmet_iron" , weight = 5, },
|
||||
{ itemstring = "mcl_armor:leggings_iron" , weight = 5, },
|
||||
{ itemstring = "mcl_armor:boots_iron" , weight = 5, },
|
||||
{ itemstring = "mcl_core:obsidian" , weight = 5, amount_min = 3, amount_max = 7 },
|
||||
{ itemstring = "mcl_core:sapling" , weight = 5, amount_min = 3, amount_max = 7 },
|
||||
{ itemstring = "mcl_mobitems:saddle" , weight = 3, },
|
||||
{ itemstring = "mobs_mc:iron_horse_armor" , weight = 1, },
|
||||
{ itemstring = "mobs_mc:gold_horse_armor" , weight = 1, },
|
||||
{ itemstring = "mobs_mc:diamond_horse_armor", weight = 1, },
|
||||
}
|
||||
}}
|
||||
local items = mcl_loot.get_multi_loot(loottable, pr)
|
||||
return items
|
||||
end
|
||||
|
||||
local function fill_chest(pos, pr)
|
||||
local meta = minetest.get_meta(pos)
|
||||
minetest.registered_nodes["mcl_chests:chest_small"].on_construct(pos)
|
||||
local inv = minetest.get_inventory( {type="node", pos=pos} )
|
||||
local items = get_treasures(pr)
|
||||
mcl_loot.fill_inventory(inv, "main", items, pr)
|
||||
end
|
||||
|
||||
local possible_rotations = {"0", "90", "180", "270"}
|
||||
|
||||
local function get_random_rotation(pr)
|
||||
return possible_rotations[pr:next(1, #possible_rotations)]
|
||||
end
|
||||
|
||||
local function create_site_plan(minp, maxp, pr)
|
||||
local plan = {}
|
||||
local building_all_info
|
||||
local center = vector.add(minp, mcl_mapgen.HALF_CS_NODES)
|
||||
local center_surface, surface_material = find_surface(center, minp, maxp)
|
||||
if not center_surface then return end
|
||||
|
||||
local number_of_buildings = pr:next(10, 25)
|
||||
local shuffle = {}
|
||||
local count_buildings = {}
|
||||
for i = 1, #schematic_table do
|
||||
shuffle[i] = i
|
||||
count_buildings[i] = 0
|
||||
end
|
||||
for i = #shuffle, 2, -1 do
|
||||
local j = pr:next(1, i)
|
||||
shuffle[i], shuffle[j] = shuffle[j], shuffle[i]
|
||||
end
|
||||
local number_built = 1
|
||||
local shuffle_index = pr:next(1, #schematic_table)
|
||||
|
||||
-- first building is townhall in the center
|
||||
plan[#plan + 1] = {
|
||||
pos = center_surface,
|
||||
building = schematic_table[shuffle_index],
|
||||
rotation = get_random_rotation(pr),
|
||||
surface_mat = surface_material,
|
||||
}
|
||||
count_buildings[1] = count_buildings[1] + 1
|
||||
-- now some buildings around in a circle, radius = size of town center
|
||||
local x, z, r = center_surface.x, center_surface.z, schematic_table[1].hsize
|
||||
-- draw j circles around center and increase radius by random(2, 5)
|
||||
for k = 1, 20 do
|
||||
-- set position on imaginary circle
|
||||
for j = 0, 360, 15 do
|
||||
local angle = j * math_pi / 180
|
||||
local pos_surface, surface_material = find_surface(
|
||||
{
|
||||
x = math_round(x + r * math_cos(angle)),
|
||||
z = math_round(z + r * math_sin(angle))
|
||||
},
|
||||
minp,
|
||||
maxp
|
||||
)
|
||||
if pos_surface then
|
||||
shuffle_index = (shuffle_index % (#schematic_table)) + 1
|
||||
local schematic_index = shuffle[shuffle_index]
|
||||
local schematic = schematic_table[schematic_index]
|
||||
if count_buildings[schematic_index] < schematic.max_num * number_of_buildings then
|
||||
local hsize2 = schematic.hsize^2
|
||||
local is_distance_ok = true
|
||||
for _, built_house in pairs(plan) do
|
||||
local pos = built_house.pos
|
||||
local building = built_house.building
|
||||
local distance2 = (pos_surface.x - pos.x)^2 + (pos_surface.z - pos.z)^2
|
||||
if distance2 < building.hsize^2 or distance2 < hsize2 then
|
||||
is_distance_ok = false
|
||||
break
|
||||
end
|
||||
end
|
||||
if is_distance_ok then
|
||||
plan[#plan + 1] = {
|
||||
pos = pos_surface,
|
||||
building = schematic,
|
||||
rotation = get_random_rotation(pr),
|
||||
surface_mat = surface_material,
|
||||
}
|
||||
count_buildings[schematic_index] = count_buildings[schematic_index] + 1
|
||||
number_built = number_built + 1
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if number_built >= number_of_buildings then
|
||||
break
|
||||
end
|
||||
end
|
||||
if number_built >= number_of_buildings then
|
||||
break
|
||||
end
|
||||
r = r + pr:next(2, 5)
|
||||
end
|
||||
return plan
|
||||
end
|
||||
|
||||
local function ground(pos1, pos2, minp, maxp, pr, mat)
|
||||
local pos1, pos2 = pos1, pos2
|
||||
local x1, x2, z1, z2, y = pos1.x, pos2.x, pos1.z, pos2.z, pos1.y - 1
|
||||
local pos_list_dirt = {}
|
||||
local pos_list_stone = {}
|
||||
for x0 = x1, x2 do
|
||||
for z0 = z1, z2 do
|
||||
local finish = false
|
||||
local y1 = y - pr:next(2, 4)
|
||||
for y0 = y, y1, -1 do
|
||||
local p0 = {x = x0, y = y0, z = z0}
|
||||
local node = minetest_get_node(p0)
|
||||
local node_name = node.name
|
||||
if node_name ~= "air" and not string_find(node_name, "water") and not string_find(node_name, "flower") then
|
||||
finish = true
|
||||
break
|
||||
end
|
||||
pos_list_dirt[#pos_list_dirt + 1] = p0
|
||||
end
|
||||
if not finish then
|
||||
for y0 = y1 - 1, math_max(minp.y, y - pr:next(17, 27)), -1 do
|
||||
local p0 = {x = x0, y = y0, z = z0}
|
||||
local node = minetest_get_node(p0)
|
||||
local node_name = node.name
|
||||
if node_name ~= "air" and not string_find(node_name, "water") and not string_find(node_name, "flower") then
|
||||
break
|
||||
end
|
||||
pos_list_stone[#pos_list_stone + 1] = p0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
minetest_bulk_set_node(pos_list_dirt, {name = surface_mat[mat].top})
|
||||
minetest_bulk_set_node(pos_list_stone, {name = surface_mat[mat].bottom})
|
||||
end
|
||||
|
||||
local function terraform(plan, minp, maxp, pr)
|
||||
local fheight, fwidth, fdepth, schematic_data, pos, rotation, swap_wd, build_material
|
||||
for _, built_house in pairs(plan) do
|
||||
schematic_data = built_house.building
|
||||
pos = built_house.pos
|
||||
rotation = built_house.rotation
|
||||
build_material = built_house.surface_mat
|
||||
swap_wd = rotation == "90" or rotation == "270"
|
||||
fwidth = swap_wd and schematic_data.hdepth or schematic_data.hwidth
|
||||
fdepth = swap_wd and schematic_data.hwidth or schematic_data.hdepth
|
||||
fheight = schematic_data.hheight
|
||||
local pos2 = {
|
||||
x = pos.x + fwidth - 1,
|
||||
y = math_min(pos.y + fheight + 4, maxp.y),
|
||||
z = pos.z + fdepth - 1
|
||||
}
|
||||
ground(pos, {x = pos2.x, y = pos.y + 1, z = pos2.z}, minp, maxp, pr, build_material)
|
||||
local node_list = {}
|
||||
for xi = pos.x, pos2.x do
|
||||
for zi = pos.z, pos2.z do
|
||||
for yi = pos.y + 1, pos2.y do
|
||||
node_list[#node_list + 1] = {x = xi, y = yi, z = zi}
|
||||
end
|
||||
end
|
||||
end
|
||||
minetest_bulk_set_node(node_list, {name = "air"})
|
||||
end
|
||||
end
|
||||
|
||||
local function paths(plan, minp, maxp)
|
||||
local starting_point = find_surface({x = plan[1].pos.x + 2, z = plan[1].pos.z + 2}, minp, maxp)
|
||||
if not starting_point then return end
|
||||
starting_point.y = starting_point.y + 1
|
||||
for i = 2, #plan do
|
||||
local p = plan[i]
|
||||
local end_point = p.pos
|
||||
end_point.y = end_point.y + 1
|
||||
local path = minetest.find_path(starting_point, end_point, mcl_mapgen.CS_NODES, 2, 2, "A*_noprefetch")
|
||||
if path then
|
||||
for _, pos in pairs(path) do
|
||||
pos.y = pos.y - 1
|
||||
local surface_mat = minetest.get_node(pos).name
|
||||
if surface_mat == "mcl_core:sand" or surface_mat == "mcl_core:redsand" then
|
||||
minetest.swap_node(pos, {name = "mcl_core:sandstonesmooth2"})
|
||||
else
|
||||
minetest.swap_node(pos, {name = "mcl_core:grass_path"})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function init_nodes(p1, rotation, pr, size)
|
||||
local p2 = vector.subtract(vector.add(p1, size), 1)
|
||||
local nodes = minetest.find_nodes_in_area(p1, p2, {"mcl_itemframes:item_frame", "mcl_furnaces:furnace", "mcl_anvils:anvil", "mcl_chests:chest", "mcl_villages:stonebrickcarved"})
|
||||
for _, pos in pairs(nodes) do
|
||||
local name = minetest_get_node(pos).name
|
||||
local def = minetest_registered_nodes[minetest_get_node(pos).name]
|
||||
def.on_construct(pos)
|
||||
if name == "mcl_chests:chest" then
|
||||
minetest_swap_node(pos, {name = "mcl_chests:chest_small"})
|
||||
fill_chest(pos, pr)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function place_schematics(plan, pr)
|
||||
for _, built_house in pairs(plan) do
|
||||
local pos = built_house.pos
|
||||
local rotation = built_house.rotation
|
||||
local platform_material = built_house.surface_mat
|
||||
local replace_wall = built_house.building.rplc
|
||||
local schem_lua = built_house.building.preloaded_schematic
|
||||
if replace_wall then
|
||||
--Note, block substitution isn't matching node names exactly; so nodes that are to be substituted that have the same prefixes cause bugs.
|
||||
-- Example: Attempting to swap out 'mcl_core:stonebrick'; which has multiple, additional sub-variants: (carved, cracked, mossy). Will currently cause issues, so leaving disabled.
|
||||
if platform_material == "mcl_core:snow" or platform_material == "mcl_core:dirt_with_grass_snow" or platform_material == "mcl_core:podzol" then
|
||||
schem_lua = schem_lua:gsub("mcl_core:tree", "mcl_core:sprucetree")
|
||||
schem_lua = schem_lua:gsub("mcl_core:wood", "mcl_core:sprucewood")
|
||||
elseif platform_material == "mcl_core:sand" or platform_material == "mcl_core:redsand" then
|
||||
schem_lua = schem_lua:gsub("mcl_core:tree", "mcl_core:sandstonecarved")
|
||||
schem_lua = schem_lua:gsub("mcl_core:cobble", "mcl_core:sandstone")
|
||||
schem_lua = schem_lua:gsub("mcl_core:wood", "mcl_core:sandstonesmooth")
|
||||
schem_lua = schem_lua:gsub("mcl_core:brick_block", "mcl_core:redsandstone")
|
||||
end
|
||||
end
|
||||
schem_lua = schem_lua:gsub("mcl_core:dirt_with_grass", platform_material)
|
||||
schem_lua = schem_lua:gsub("mcl_stairs:stair_wood_outer", "mcl_stairs:slab_wood")
|
||||
schem_lua = schem_lua:gsub("mcl_stairs:stair_stone_rough_outer", "air")
|
||||
|
||||
local schematic = loadstring(schem_lua)()
|
||||
-- build foundation for the building an make room above
|
||||
-- place schematic
|
||||
mcl_structures.place_schematic({
|
||||
pos = pos,
|
||||
schematic = schematic,
|
||||
rotation = rotation,
|
||||
on_placed = init_nodes,
|
||||
pr = pr,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- register block for npc spawn
|
||||
--
|
||||
local function spawn_villager(pos)
|
||||
minetest.add_entity({x = pos.x, y = pos.y + 1, z = pos.z}, "mobs_mc:villager")
|
||||
end
|
||||
minetest.register_node("mcl_villages:stonebrickcarved", {
|
||||
description = ("Chiseled Stone Village Bricks"),
|
||||
description = S("Chiseled Stone Village Bricks"),
|
||||
_doc_items_longdesc = doc.sub.items.temp.build,
|
||||
tiles = {"mcl_core_stonebrick_carved.png"},
|
||||
stack_max = 64,
|
||||
|
@ -28,83 +383,141 @@ minetest.register_node("mcl_villages:stonebrickcarved", {
|
|||
is_ground_content = false,
|
||||
_mcl_blast_resistance = 6,
|
||||
_mcl_hardness = 1.5,
|
||||
on_construct = spawn_villager,
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Spawn villagers",
|
||||
nodenames = {"mcl_villages:stonebrickcarved"},
|
||||
interval = 60,
|
||||
chance = 3,
|
||||
action = function(pos, node)
|
||||
-- check the space above
|
||||
local p = table.copy(pos)
|
||||
p.y = p.y + 1
|
||||
if minetest_get_node(p).name ~= "air" then return end
|
||||
p.y = p.y + 1
|
||||
if minetest_get_node(p).name ~= "air" then return end
|
||||
p.y = p.y - 1
|
||||
local villagers_counter = 0
|
||||
for _, obj in pairs(minetest.get_objects_inside_radius(p, 40)) do
|
||||
local lua_entity = obj:get_luaentity()
|
||||
if luaentity and luaentity.name == "mobs_mc:villager" then
|
||||
villagers_counter = villagers_counter + 1
|
||||
if villagers_counter > 7 then return end
|
||||
end
|
||||
end
|
||||
spawn_villager(pos)
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
--[[ Enable for testing, but use MineClone2's own spawn code if/when merging.
|
||||
--
|
||||
-- register inhabitants
|
||||
--
|
||||
if minetest.get_modpath("mobs_mc") then
|
||||
mobs:register_spawn("mobs_mc:villager", --name
|
||||
{"mcl_core:stonebrickcarved"}, --nodes
|
||||
15, --max_light
|
||||
0, --min_light
|
||||
20, --chance
|
||||
7, --active_object_count
|
||||
31000, --max_height
|
||||
nil) --day_toggle
|
||||
end
|
||||
--]]
|
||||
|
||||
--
|
||||
-- on map generation, try to build a settlement
|
||||
--
|
||||
local function build_a_settlement(minp, maxp, blockseed)
|
||||
local pr = PseudoRandom(blockseed)
|
||||
|
||||
-- fill settlement_info with buildings and their data
|
||||
local settlement_info = settlements.create_site_plan(maxp, minp, pr)
|
||||
if not settlement_info then return end
|
||||
|
||||
-- evaluate settlement_info and prepair terrain
|
||||
settlements.terraform(settlement_info, pr)
|
||||
|
||||
-- evaluate settlement_info and build paths between buildings
|
||||
settlements.paths(settlement_info)
|
||||
|
||||
-- evaluate settlement_info and place schematics
|
||||
settlements.place_schematics(settlement_info, pr)
|
||||
local function build_a_village(minp, maxp, pr, placer)
|
||||
minetest.log("action","[mcl_villages] Building village at mapchunk " .. minetest.pos_to_string(minp) .. "..." .. minetest.pos_to_string(maxp))
|
||||
local pr = pr or PseudoRandom(mcl_mapgen.get_block_seed3(minp))
|
||||
local plan = create_site_plan(minp, maxp, pr)
|
||||
if not plan then
|
||||
if placer then
|
||||
if placer:is_player() then
|
||||
minetest.chat_send_player(placer:get_player_name(), S("Map chunk @1 to @2 is not suitable for placing villages.", minetest.pos_to_string(minp), minetest.pos_to_string(maxp)))
|
||||
end
|
||||
|
||||
local function ecb_village(blockpos, action, calls_remaining, param)
|
||||
if calls_remaining >= 1 then return end
|
||||
local minp, maxp, blockseed = param.minp, param.maxp, param.blockseed
|
||||
build_a_settlement(minp, maxp, blockseed)
|
||||
end
|
||||
return
|
||||
end
|
||||
paths(plan, minp, maxp)
|
||||
terraform(plan, minp, maxp, pr)
|
||||
place_schematics(plan, pr)
|
||||
villages[#villages + 1] = minp
|
||||
storage:set_string("villages", minetest.serialize(villages))
|
||||
end
|
||||
|
||||
-- Disable natural generation in singlenode.
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
if mg_name ~= "singlenode" then
|
||||
mcl_mapgen_core.register_generator("villages", nil, function(minp, maxp, blockseed)
|
||||
-- don't build settlement underground
|
||||
if maxp.y < 0 then return end
|
||||
-- randomly try to build settlements
|
||||
if blockseed % 77 ~= 17 then return end
|
||||
-- needed for manual and automated settlement building
|
||||
-- don't build settlements on (too) uneven terrain
|
||||
--local heightmap = minetest.get_mapgen_object("heightmap")
|
||||
local height_difference = settlements.evaluate_heightmap()
|
||||
if height_difference > max_height_difference then return end
|
||||
|
||||
local param={minp=vector.new(minp), maxp=vector.new(maxp), blockseed=blockseed}
|
||||
minetest.emerge_area(minp, maxp, ecb_village, param)
|
||||
end)
|
||||
if not mcl_mapgen.singlenode then
|
||||
local scan_last_node = mcl_mapgen.LAST_BLOCK * mcl_mapgen.BS - 1
|
||||
local scan_offset = mcl_mapgen.BS
|
||||
mcl_mapgen.register_mapgen(function(minp, maxp, chunkseed)
|
||||
if minp.y < minp_min then return end
|
||||
local pr = PseudoRandom(chunkseed * random_multiply + random_offset)
|
||||
local random_number = pr:next(1, chance_per_chunk)
|
||||
perlin_noise = perlin_noise or minetest_get_perlin(noise_params)
|
||||
local noise = perlin_noise:get_3d(minp) * noise_multiplier
|
||||
if (random_number + noise) < struct_threshold then return end
|
||||
local min, max = 9999999, -9999999
|
||||
for i = 1, pr:next(5,10) do
|
||||
local surface_point = find_surface(
|
||||
vector.add(
|
||||
vector.new(
|
||||
pr:next(scan_offset, scan_last_node),
|
||||
0,
|
||||
pr:next(scan_offset, scan_last_node)
|
||||
),
|
||||
minp
|
||||
),
|
||||
minp,
|
||||
maxp
|
||||
)
|
||||
if not surface_point then return end
|
||||
local y = surface_point.y
|
||||
min = math_min(y, min)
|
||||
max = math_max(y, max)
|
||||
end
|
||||
-- manually place villages
|
||||
if minetest.is_creative_enabled("") then
|
||||
minetest.register_craftitem("mcl_villages:tool", {
|
||||
description = "mcl_villages build tool",
|
||||
inventory_image = "default_tool_woodshovel.png",
|
||||
-- build ssettlement
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
if not pointed_thing.under then return end
|
||||
local minp = vector.subtract( pointed_thing.under, half_map_chunk_size)
|
||||
local maxp = vector.add( pointed_thing.under, half_map_chunk_size)
|
||||
build_a_settlement(minp, maxp, math.random(0,32767))
|
||||
local height_difference = max - min
|
||||
if height_difference > max_height_difference then return end
|
||||
build_a_village(minp, maxp, chunkkseed)
|
||||
end, mcl_mapgen.order.VILLAGES)
|
||||
end
|
||||
|
||||
for k, v in pairs(schematic_table) do
|
||||
local schem_lua = minetest.serialize_schematic(
|
||||
v.mts,
|
||||
"lua",
|
||||
{
|
||||
lua_use_comments = false,
|
||||
lua_num_indent_spaces = 0,
|
||||
}
|
||||
):gsub("mcl_core:stonebrickcarved", "mcl_villages:stonebrickcarved") .. " return schematic"
|
||||
v.preloaded_schematic = schem_lua
|
||||
local loaded_schematic = loadstring(schem_lua)()
|
||||
local size = loaded_schematic.size
|
||||
v.hwidth = size.x
|
||||
v.hheight = size.y
|
||||
v.hdepth = size.z
|
||||
v.hsize = math.ceil(math.sqrt((size.x/2)^2 + (size.y/2)^2) * 2 + 1)
|
||||
mcl_structures.register_structure({
|
||||
name = v.name,
|
||||
place_function = function(pos, rotation, pr, placer)
|
||||
local minp = mcl_mapgen.get_chunk_beginning(pos)
|
||||
local maxp = mcl_mapgen.get_chunk_ending(pos)
|
||||
local surface_pos, surface_material = find_surface(pos, minp, maxp)
|
||||
local plan = {
|
||||
[1] = {
|
||||
pos = pos,
|
||||
building = schematic_table[k],
|
||||
rotation = rotation,
|
||||
surface_mat = surface_material or "mcl_core:snow",
|
||||
}
|
||||
}
|
||||
if surface_material then
|
||||
terraform(plan, minp, maxp, pr)
|
||||
end
|
||||
place_schematics(plan, pr)
|
||||
end
|
||||
})
|
||||
mcl_wip.register_experimental_item("mcl_villages:tool")
|
||||
end
|
||||
|
||||
mcl_structures.register_structure({
|
||||
name = "village",
|
||||
place_function = function(pos, rotation, pr, placer)
|
||||
local minp = mcl_mapgen.get_chunk_beginning(pos)
|
||||
local maxp = mcl_mapgen.get_chunk_ending(pos)
|
||||
build_a_village(minp, maxp, pr, placer)
|
||||
end
|
||||
})
|
||||
|
||||
function mcl_villages.get_villages()
|
||||
return villages
|
||||
end
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# textdomain: mcl_villages
|
||||
Chiseled Stone Village Bricks=Точёный каменный блок из деревни
|
||||
Map chunk @1 to @2 is not suitable for placing villages.=Чанк с @1 по @2 непригоден для размещения деревень.
|
|
@ -0,0 +1,3 @@
|
|||
# textdomain: mcl_villages
|
||||
Chiseled Stone Village Bricks=
|
||||
Map chunk @1 to @2 is not suitable for placing villages.=
|
|
@ -1,5 +1,5 @@
|
|||
name = mcl_villages
|
||||
author = Rochambeau
|
||||
description = This mod adds settlements on world generation.
|
||||
depends = mcl_util, mcl_mapgen_core, mcl_structures, mcl_core, mcl_loot
|
||||
author = Rochambeau, MysticTempest, kay27
|
||||
description = This mod adds villages on world generation.
|
||||
depends = mcl_util, mcl_structures, mcl_core, mcl_loot, mcl_mapgen
|
||||
optional_depends = mcl_farming, mobs_mc
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
-------------------------------------------------------------------------------
|
||||
-- generate paths between buildings
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.paths(settlement_info)
|
||||
local starting_point
|
||||
local end_point
|
||||
local distance
|
||||
--for k,v in pairs(settlement_info) do
|
||||
starting_point = settlement_info[1]["pos"]
|
||||
for o,p in pairs(settlement_info) do
|
||||
|
||||
end_point = settlement_info[o]["pos"]
|
||||
if starting_point ~= end_point
|
||||
then
|
||||
-- loop until end_point is reched (distance == 0)
|
||||
while true do
|
||||
|
||||
-- define surrounding pos to starting_point
|
||||
local north_p = {x=starting_point.x+1, y=starting_point.y, z=starting_point.z}
|
||||
local south_p = {x=starting_point.x-1, y=starting_point.y, z=starting_point.z}
|
||||
local west_p = {x=starting_point.x, y=starting_point.y, z=starting_point.z+1}
|
||||
local east_p = {x=starting_point.x, y=starting_point.y, z=starting_point.z-1}
|
||||
-- measure distance to end_point
|
||||
local dist_north_p_to_end = math.sqrt(
|
||||
((north_p.x - end_point.x)*(north_p.x - end_point.x))+
|
||||
((north_p.z - end_point.z)*(north_p.z - end_point.z))
|
||||
)
|
||||
local dist_south_p_to_end = math.sqrt(
|
||||
((south_p.x - end_point.x)*(south_p.x - end_point.x))+
|
||||
((south_p.z - end_point.z)*(south_p.z - end_point.z))
|
||||
)
|
||||
local dist_west_p_to_end = math.sqrt(
|
||||
((west_p.x - end_point.x)*(west_p.x - end_point.x))+
|
||||
((west_p.z - end_point.z)*(west_p.z - end_point.z))
|
||||
)
|
||||
local dist_east_p_to_end = math.sqrt(
|
||||
((east_p.x - end_point.x)*(east_p.x - end_point.x))+
|
||||
((east_p.z - end_point.z)*(east_p.z - end_point.z))
|
||||
)
|
||||
-- evaluate which pos is closer to the end_point
|
||||
if dist_north_p_to_end <= dist_south_p_to_end and
|
||||
dist_north_p_to_end <= dist_west_p_to_end and
|
||||
dist_north_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = north_p
|
||||
distance = dist_north_p_to_end
|
||||
|
||||
elseif dist_south_p_to_end <= dist_north_p_to_end and
|
||||
dist_south_p_to_end <= dist_west_p_to_end and
|
||||
dist_south_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = south_p
|
||||
distance = dist_south_p_to_end
|
||||
|
||||
elseif dist_west_p_to_end <= dist_north_p_to_end and
|
||||
dist_west_p_to_end <= dist_south_p_to_end and
|
||||
dist_west_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = west_p
|
||||
distance = dist_west_p_to_end
|
||||
|
||||
elseif dist_east_p_to_end <= dist_north_p_to_end and
|
||||
dist_east_p_to_end <= dist_south_p_to_end and
|
||||
dist_east_p_to_end <= dist_west_p_to_end
|
||||
then
|
||||
starting_point = east_p
|
||||
distance = dist_east_p_to_end
|
||||
end
|
||||
-- find surface of new starting point
|
||||
local surface_point, surface_mat = settlements.find_surface(starting_point)
|
||||
-- replace surface node with mcl_core:grass_path
|
||||
if surface_point
|
||||
then
|
||||
if surface_mat == "mcl_core:sand" or surface_mat == "mcl_core:redsand" then
|
||||
minetest.swap_node(surface_point,{name="mcl_core:sandstonesmooth2"})
|
||||
else
|
||||
minetest.swap_node(surface_point,{name="mcl_core:grass_path"})
|
||||
end
|
||||
-- don't set y coordinate, surface might be too low or high
|
||||
starting_point.x = surface_point.x
|
||||
starting_point.z = surface_point.z
|
||||
end
|
||||
if distance <= 1 or
|
||||
starting_point == end_point
|
||||
then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,255 +0,0 @@
|
|||
local get_node = mcl_vars.get_node
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- function to copy tables
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.shallowCopy(original)
|
||||
local copy = {}
|
||||
for key, value in pairs(original) do
|
||||
copy[key] = value
|
||||
end
|
||||
return copy
|
||||
end
|
||||
--
|
||||
--
|
||||
--
|
||||
function settlements.round(num, numDecimalPlaces)
|
||||
local mult = 10^(numDecimalPlaces or 0)
|
||||
return math.floor(num * mult + 0.5) / mult
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- function to find surface block y coordinate
|
||||
-- returns surface postion
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.find_surface(pos, wait)
|
||||
local p6 = vector.new(pos)
|
||||
local cnt = 0
|
||||
local itter = 1 -- count up or down
|
||||
local cnt_max = 200
|
||||
-- check, in which direction to look for surface
|
||||
local surface_node
|
||||
if wait then
|
||||
surface_node = get_node(p6, true, 10000000)
|
||||
else
|
||||
surface_node = get_node(p6)
|
||||
end
|
||||
if surface_node.name=="air" or surface_node.name=="ignore" then
|
||||
itter = -1
|
||||
end
|
||||
-- go through nodes an find surface
|
||||
while cnt < cnt_max do
|
||||
-- Check Surface_node and Node above
|
||||
--
|
||||
if settlements.surface_mat[surface_node.name] then
|
||||
local surface_node_plus_1 = get_node({ x=p6.x, y=p6.y+1, z=p6.z})
|
||||
if surface_node_plus_1 and surface_node and
|
||||
(string.find(surface_node_plus_1.name,"air") or
|
||||
string.find(surface_node_plus_1.name,"snow") or
|
||||
string.find(surface_node_plus_1.name,"fern") or
|
||||
string.find(surface_node_plus_1.name,"flower") or
|
||||
string.find(surface_node_plus_1.name,"bush") or
|
||||
string.find(surface_node_plus_1.name,"tree") or
|
||||
string.find(surface_node_plus_1.name,"grass"))
|
||||
then
|
||||
settlements.debug("find_surface7: " ..surface_node.name.. " " .. surface_node_plus_1.name)
|
||||
return p6, surface_node.name
|
||||
else
|
||||
settlements.debug("find_surface2: wrong surface+1")
|
||||
end
|
||||
else
|
||||
settlements.debug("find_surface3: wrong surface "..surface_node.name.." at pos "..minetest.pos_to_string(p6))
|
||||
end
|
||||
|
||||
p6.y = p6.y + itter
|
||||
if p6.y < 0 then
|
||||
settlements.debug("find_surface4: y<0")
|
||||
return nil
|
||||
end
|
||||
cnt = cnt+1
|
||||
surface_node = get_node(p6)
|
||||
end
|
||||
settlements.debug("find_surface5: cnt_max overflow")
|
||||
return nil
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- check distance for new building
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.check_distance(settlement_info, building_pos, building_size)
|
||||
local distance
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
distance = math.sqrt(
|
||||
((building_pos.x - built_house["pos"].x)*(building_pos.x - built_house["pos"].x))+
|
||||
((building_pos.z - built_house["pos"].z)*(building_pos.z - built_house["pos"].z)))
|
||||
if distance < building_size or distance < built_house["hsize"] then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- save list of generated settlements
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.save()
|
||||
local file = io.open(minetest.get_worldpath().."/settlements.txt", "w")
|
||||
if file then
|
||||
file:write(minetest.serialize(settlements_in_world))
|
||||
file:close()
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- load list of generated settlements
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.load()
|
||||
local file = io.open(minetest.get_worldpath().."/settlements.txt", "r")
|
||||
if file then
|
||||
local table = minetest.deserialize(file:read("*all"))
|
||||
if type(table) == "table" then
|
||||
return table
|
||||
end
|
||||
end
|
||||
return {}
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- fill chests
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.fill_chest(pos, pr)
|
||||
-- initialize chest (mts chests don't have meta)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if meta:get_string("infotext") ~= "Chest" then
|
||||
-- For MineClone2 0.70 or before
|
||||
-- minetest.registered_nodes["mcl_chests:chest"].on_construct(pos)
|
||||
--
|
||||
-- For MineClone2 after commit 09ab1482b5 (the new entity chests)
|
||||
minetest.registered_nodes["mcl_chests:chest_small"].on_construct(pos)
|
||||
end
|
||||
-- fill chest
|
||||
local inv = minetest.get_inventory( {type="node", pos=pos} )
|
||||
|
||||
local function get_treasures(prand)
|
||||
local loottable = {{
|
||||
stacks_min = 3,
|
||||
stacks_max = 8,
|
||||
items = {
|
||||
{ itemstring = "mcl_core:diamond", weight = 3, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_core:iron_ingot", weight = 10, amount_min = 1, amount_max = 5 },
|
||||
{ itemstring = "mcl_core:gold_ingot", weight = 5, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_farming:bread", weight = 15, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_core:apple", weight = 15, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_tools:pick_iron", weight = 5 },
|
||||
{ itemstring = "mcl_tools:sword_iron", weight = 5 },
|
||||
{ itemstring = "mcl_armor:chestplate_iron", weight = 5 },
|
||||
{ itemstring = "mcl_armor:helmet_iron", weight = 5 },
|
||||
{ itemstring = "mcl_armor:leggings_iron", weight = 5 },
|
||||
{ itemstring = "mcl_armor:boots_iron", weight = 5 },
|
||||
{ itemstring = "mcl_core:obsidian", weight = 5, amount_min = 3, amount_max = 7 },
|
||||
{ itemstring = "mcl_core:sapling", weight = 5, amount_min = 3, amount_max = 7 },
|
||||
{ itemstring = "mcl_mobitems:saddle", weight = 3 },
|
||||
{ itemstring = "mobs_mc:iron_horse_armor", weight = 1 },
|
||||
{ itemstring = "mobs_mc:gold_horse_armor", weight = 1 },
|
||||
{ itemstring = "mobs_mc:diamond_horse_armor", weight = 1 },
|
||||
}
|
||||
}}
|
||||
local items = mcl_loot.get_multi_loot(loottable, prand)
|
||||
return items
|
||||
end
|
||||
|
||||
local items = get_treasures(pr)
|
||||
mcl_loot.fill_inventory(inv, "main", items, pr)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- initialize furnace
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.initialize_furnace(pos)
|
||||
-- find chests within radius
|
||||
local furnacepos = minetest.find_node_near(pos,
|
||||
7, --radius
|
||||
{"mcl_furnaces:furnace"})
|
||||
-- initialize furnacepos (mts furnacepos don't have meta)
|
||||
if furnacepos
|
||||
then
|
||||
local meta = minetest.get_meta(furnacepos)
|
||||
if meta:get_string("infotext") ~= "furnace"
|
||||
then
|
||||
minetest.registered_nodes["mcl_furnaces:furnace"].on_construct(furnacepos)
|
||||
end
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- initialize anvil
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.initialize_anvil(pos)
|
||||
-- find chests within radius
|
||||
local anvilpos = minetest.find_node_near(pos,
|
||||
7, --radius
|
||||
{"mcl_anvils:anvil"})
|
||||
-- initialize anvilpos (mts anvilpos don't have meta)
|
||||
if anvilpos
|
||||
then
|
||||
local meta = minetest.get_meta(anvilpos)
|
||||
if meta:get_string("infotext") ~= "anvil"
|
||||
then
|
||||
minetest.registered_nodes["mcl_anvils:anvil"].on_construct(anvilpos)
|
||||
end
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- randomize table
|
||||
-------------------------------------------------------------------------------
|
||||
function shuffle(tbl, pr)
|
||||
local table = settlements.shallowCopy(tbl)
|
||||
local size = #table
|
||||
for i = size, 1, -1 do
|
||||
local rand = pr:next(1, size)
|
||||
table[i], table[rand] = table[rand], table[i]
|
||||
end
|
||||
return table
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- evaluate heightmap
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.evaluate_heightmap()
|
||||
local heightmap = minetest.get_mapgen_object("heightmap")
|
||||
-- max height and min height, initialize with impossible values for easier first time setting
|
||||
local max_y = -50000
|
||||
local min_y = 50000
|
||||
-- only evaluate the center square of heightmap 40 x 40
|
||||
local square_start = 1621
|
||||
local square_end = 1661
|
||||
for j = 1 , 40, 1 do
|
||||
for i = square_start, square_end, 1 do
|
||||
-- skip buggy heightmaps, return high value
|
||||
if heightmap[i] == -31000 or heightmap[i] == 31000 then
|
||||
return max_height_difference + 1
|
||||
end
|
||||
if heightmap[i] < min_y then
|
||||
min_y = heightmap[i]
|
||||
end
|
||||
if heightmap[i] > max_y then
|
||||
max_y = heightmap[i]
|
||||
end
|
||||
end
|
||||
-- set next line
|
||||
square_start = square_start + 80
|
||||
square_end = square_end + 80
|
||||
end
|
||||
-- return the difference between highest and lowest pos in chunk
|
||||
local height_diff = max_y - min_y
|
||||
-- filter buggy heightmaps
|
||||
if height_diff <= 1 then
|
||||
return max_height_difference + 1
|
||||
end
|
||||
-- debug info
|
||||
settlements.debug("heightdiff ".. height_diff)
|
||||
return height_diff
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- Set array to list
|
||||
-- https://stackoverflow.com/questions/656199/search-for-an-item-in-a-lua-list
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.Set (list)
|
||||
local set = {}
|
||||
for _, l in ipairs(list) do set[l] = true end
|
||||
return set
|
||||
end
|
|
@ -19,8 +19,7 @@ end
|
|||
local probability_railcaves_in_mapchunk = P(0.33333)
|
||||
setting = tonumber(minetest.settings:get("tsm_railcorridors_probability_railcaves_in_mapchunk"))
|
||||
-- Extra check to prevent mod griefing in singlenode, mcimported worlds.
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
if mg_name == "singlenode" then
|
||||
if mcl_mapgen.singlenode then
|
||||
probability_railcaves_in_mapchunk = P(0)
|
||||
elseif setting then
|
||||
probability_railcaves_in_mapchunk = P(setting)
|
||||
|
@ -96,10 +95,10 @@ end
|
|||
|
||||
-- Max. and min. heights between rail corridors are generated
|
||||
local height_min
|
||||
if mcl_vars.mg_lava then
|
||||
height_min = mcl_vars.mg_lava_overworld_max + 2
|
||||
if mcl_mapgen.lava then
|
||||
height_min = mcl_mapgen.overworld.lava_max + 2
|
||||
else
|
||||
height_min = mcl_vars.mg_bedrock_overworld_max + 2
|
||||
height_min = mcl_mapgen.overworld.bedrock_max + 2
|
||||
end
|
||||
local height_max = mcl_worlds.layer_to_y(60)
|
||||
|
||||
|
@ -1093,7 +1092,7 @@ local function create_corridor_system(main_cave_coords)
|
|||
end
|
||||
|
||||
-- The rail corridor algorithm starts here
|
||||
mcl_mapgen_core.register_generator("railcorridors", nil, function(minp, maxp, blockseed, _pr)
|
||||
mcl_mapgen.register_mapgen(function(minp, maxp, blockseed)
|
||||
-- We re-init the randomizer for every mapchunk as we start generating in the middle of each mapchunk.
|
||||
-- We can't use the mapgen seed as this would make the algorithm depending on the order the mapchunk generate.
|
||||
InitRandomizer(blockseed)
|
||||
|
|
|
@ -81,7 +81,7 @@ local dir_step = storage:get_int("mcl_spawn_dir_step") or 0
|
|||
local dir_ind = storage:get_int("mcl_spawn_dir_ind") or 1
|
||||
local emerge_pos1, emerge_pos2
|
||||
|
||||
local spawn_limit = mcl_vars.mapgen_edge_max
|
||||
local spawn_limit = mcl_mapgen.EDGE_MAX
|
||||
|
||||
|
||||
--Functions
|
||||
|
@ -500,7 +500,11 @@ function mcl_spawn.shadow_worker()
|
|||
|
||||
if success then
|
||||
local wsp_node = minetest.get_node(wsp)
|
||||
if not (wsp_node and wsp_node.name == "ignore")
|
||||
if wsp_node and
|
||||
(
|
||||
(minetest.compare_block_status and (minetest.compare_block_status(wsp, "loaded") or minetest.compare_block_status(wsp, "active")))
|
||||
or minetest.get_node_or_nil(wsp)
|
||||
)
|
||||
and ((not good_for_respawn(wsp)) or ((no_trees_area_counter >= 0) and not can_find_tree(wsp))) then
|
||||
success = false
|
||||
minetest.log("action", "[mcl_spawn] World spawn position isn't safe anymore: "..minetest.pos_to_string(wsp))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name = mcl_spawn
|
||||
author = Wuzzy
|
||||
description = Set and get the player's respawn position
|
||||
depends = mcl_init
|
||||
depends = mcl_mapgen
|
||||
|
|
|
@ -160,3 +160,5 @@ enable_real_maps (Enable Real Maps) bool true
|
|||
[Debugging]
|
||||
# If enabled, this will show the itemstring of an item in the description.
|
||||
mcl_item_id_debug (Item ID Debug) bool false
|
||||
mcl_debug_struct_noise (Show Structures Perlin Noise) bool false
|
||||
mcl_debug_chunk_borders (Show Chunk Borders) bool false
|
||||
|
|
Loading…
Reference in New Issue