Compare commits

..

No commits in common. "master" and "v6" have entirely different histories.
master ... v6

36 changed files with 610 additions and 1892 deletions

34
LICENSE
View file

@ -6,9 +6,9 @@
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
(This is the first released version of the Lesser GPL. It also counts
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.)
the version number 2.1.]
Preamble
@ -55,7 +55,7 @@ modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
@ -111,7 +111,7 @@ modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
@ -158,7 +158,7 @@ Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
@ -216,7 +216,7 @@ instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
@ -267,7 +267,7 @@ Library will still fall under Section 6.)
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
@ -329,7 +329,7 @@ restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
@ -370,7 +370,7 @@ subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
@ -422,7 +422,7 @@ conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
@ -456,7 +456,7 @@ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
@ -470,8 +470,8 @@ safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@ -485,8 +485,7 @@ convey the exclusion of warranty; and each file should have at least the
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
@ -495,10 +494,9 @@ school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random
Hacker.
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
{signature of Ty Coon}, 1 April 1990
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View file

@ -1,13 +1,13 @@
# fun_caves
Fun Caves replaces the default caves with a dense system of mostly flat (and easier to navigate) caverns, with biomes owing much to caverealms. Once you go underground, you should find everything you need to survive without ever returning to the surface.
Fun Caves is an attempt to convert the mapgen V6 caves into a lua mod, so they can be used with any mapgen. I've translated the C++ code into lua in the most mechanical way possible. I honestly have no idea how half of it works, and I don't intend to spend a lot of time on it in the future, so anyone who likes this mod is encouraged to fork and/or tinker with it and submit pull requests.
#![screenshot](https://github.com/duane-r/fun_caves/raw/master/textures/screenshot3.jpg)
![screenshot](https://github.com/duane-r/fun_caves/raw/master/textures/screenshot.jpg)
The source is available on github.
Code: LGPL2, textures: CC-BY-SA and CC0
Code: LGPL2, textures: none
Mod dependencies: default, dye, flowers, vessels
Mod dependencies: default
Download: https://github.com/duane-r/fun_caves/archive/master.zip

659
abms.lua
View file

@ -1,659 +0,0 @@
-- Fun_Caves abms.lua
-- Copyright Duane Robertson (duane@duanerobertson.com), 2017
-- Distributed under the LGPLv2.1 (https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html)
-------------------------------------------------------------------
-- Abms
-------------------------------------------------------------------
-- player surface damage
local dps_delay = 3
local last_dps_check = 0
local cold_delay = 5
local dps_count = cold_delay
local mushrooms = {"flowers:mushroom_brown", "flowers:mushroom_red"}
local time_factor = (fun_caves_mod.time_factor or 10)
local light_max = (fun_caves_mod.light_max or 10)
-- fungal tree nodes
local fungal_tree_leaves = {}
for i = 1, 4 do
fungal_tree_leaves[#fungal_tree_leaves+1] = "fun_caves:fungal_tree_leaves_"..i
end
local is_fungal_leaf = {}
for _, leaf in ipairs(fungal_tree_leaves) do
is_fungal_leaf[leaf] = true
end
local fungal_nodes = {}
for _, leaf in pairs(fungal_tree_leaves) do
fungal_nodes[#fungal_nodes+1] = {name = leaf}
end
fungal_nodes[#fungal_nodes+1] = {name = 'fun_caves:fungal_tree_fruit'}
local fungi_to_explode = {} -- see below
local exploding_fungi = fun_caves_mod.exploding_fungi
if not exploding_fungi then
exploding_fungi = {}
end
-- hot spike parameters
local spike_air = {}
spike_air['default:lava_source'] = true
spike_air['default:lava_source'] = true
spike_air['default:lava_flowing'] = true
local spike_soil = {}
spike_soil['fun_caves:hot_cobble'] = true
spike_soil['fun_caves:black_sand'] = true
------------------------------------------------------------
-- all the fun_caves globalstep functions
------------------------------------------------------------
local hot_stuff = {"group:surface_hot"}
local cold_stuff = {"group:surface_cold"}
local poison_stuff = {"group:poison"}
local minetest_find_nodes_in_area = minetest.find_nodes_in_area
minetest.register_globalstep(function(dtime)
if not (dtime and type(dtime) == 'number') then
return
end
local time = minetest.get_gametime()
if not (time and type(time) == 'number') then
return
end
-- Execute only after an interval.
if not last_dps_check or time - last_dps_check < dps_delay then
return
end
local players = minetest.get_connected_players()
if not (players and type(players) == 'table') then
return
end
for i = 1, #players do
local player = players[i]
local pos = player:getpos()
pos = vector.round(pos)
local player_name = player:get_player_name()
-- environmental damage
if fun_caves_mod.DEBUG and player:get_hp() < 20 then
-- Regenerate the player while testing.
print("HP: "..player:get_hp())
player:set_hp(20)
return
else
local minp = vector.subtract(pos, 0.5)
local maxp = vector.add(pos, 0.5)
-- ... from standing on or near hot objects.
local counts = minetest_find_nodes_in_area(minp, maxp, hot_stuff)
if not (counts and type(counts) == 'table') then
return
end
if #counts > 1 then
player:set_hp(player:get_hp() - 1)
end
-- ... from standing on or near poison.
local counts = minetest_find_nodes_in_area(minp, maxp, poison_stuff)
if not (counts and type(counts) == 'table') then
return
end
if #counts > 1 then
player:set_hp(player:get_hp() - 1)
end
-- ... from standing on or near cold objects (less often).
if dps_count % cold_delay == 0 then
counts = minetest_find_nodes_in_area(minp, maxp, cold_stuff)
if not (counts and type(counts) == 'table') then
return
end
if #counts > 1 then
player:set_hp(player:get_hp() - 1)
end
end
end
end
-- Set this outside of the player loop, to affect everyone.
if dps_count % cold_delay < 1 then
dps_count = cold_delay
end
last_dps_check = minetest.get_gametime()
if not (last_dps_check and type(last_dps_check) == 'number') then
last_dps_check = 0
end
dps_count = dps_count - 1
end)
------------------------------------------------------------
-- destruction
------------------------------------------------------------
minetest.register_abm({
nodenames = {"fun_caves:hot_cobble",},
neighbors = {"group:water"},
interval = time_factor,
chance = 30,
catch_up = false,
action = function(pos, node)
if not (pos and node) then
return
end
minetest.set_node(pos, {name = "default:cobble"})
minetest.sound_play("default_cool_lava",
{pos = pos, max_hear_distance = 16, gain = 0.25})
end,
})
-- Exploding fungal fruit
minetest.register_abm({
nodenames = {"fun_caves:fungal_tree_fruit"},
interval = 12 * time_factor,
chance = 400,
catch_up = false,
action = function(pos, node)
if not (pos and node) then
return
end
fun_caves_mod.soft_boom(pos)
end
})
-- Destroy mushroom caps in the light.
minetest.register_abm({
nodenames = {"fun_caves:giant_mushroom_cap", "fun_caves:huge_mushroom_cap"},
interval = 3 * time_factor,
chance = 200,
action = function(pos, node)
if not (pos and node) then
return
end
if (minetest.get_node_light(pos, nil) or 99) >= light_max + 2 then
minetest.remove_node(pos)
return
end
end
})
-- * Replace this with an after_destruct call *
--minetest.register_abm({
-- nodenames = {"fun_caves:giant_mushroom_cap", "fun_caves:huge_mushroom_cap"},
-- interval = time_factor,
-- chance = 20,
-- action = function(pos, node)
-- if not (pos and node) then
-- return
-- end
--
-- pos.y = pos.y - 1
-- local node_below = minetest.get_node_or_nil(pos)
-- if not (node_below and node_below.name == 'fun_caves:giant_mushroom_stem') then
-- pos.y = pos.y + 1
-- minetest.remove_node(pos)
-- return
-- end
-- end
--})
--minetest.register_abm({
-- nodenames = {"fire:basic_flame"},
-- interval = 2 * time_factor,
-- chance = 50,
-- action = function(p0, node, _, _)
-- minetest.remove_node(p0)
-- end,
--})
------------------------------------------------------------
-- creation
------------------------------------------------------------
-- fungal spread
minetest.register_abm({
nodenames = fungal_tree_leaves,
neighbors = {"air", "group:liquid"},
interval = 4 * time_factor,
chance = 200,
catch_up = false,
action = function(pos, node)
if not (pos and node) then
return
end
if (minetest.get_node_light(pos, nil) or 99) >= light_max + 2 then
minetest.remove_node(pos)
return
end
if math.random(40) == 1 then
minetest.set_node(pos, fungal_nodes[#fungal_nodes])
return
end
if math.random(100) == 1 then
minetest.set_node(pos, fungal_nodes[math.random(#fungal_nodes - 1)])
return
end
pos.y = pos.y - 1
local grow_node = minetest.get_node_or_nil(pos)
if grow_node and grow_node.name == "air" then
minetest.set_node(pos, node)
return
end
pos.x = pos.x + math.random(-1, 1)
pos.y = pos.y + math.random(-1, 1) + 1
pos.z = pos.z + math.random(-1, 1)
grow_node = minetest.get_node_or_nil(pos)
if grow_node and grow_node.name == "air" and (minetest.get_node_light(pos, nil) or 99) <= light_max then
minetest.set_node(pos, node)
return
elseif grow_node and is_fungal_leaf[grow_node.name] and grow_node.name ~= node.name then
minetest.remove_node(pos)
return
end
end
})
-- mushroom growth -- caps regenerate in time
local huge_mushroom_cap_node = {name = 'fun_caves:huge_mushroom_cap'}
minetest.register_abm({
nodenames = {"fun_caves:giant_mushroom_stem"},
neighbors = {'air'},
interval = 4 * time_factor,
chance = 200,
action = function(pos, node)
if not (pos and node) then
return
end
pos.y = pos.y + 1
local node_up = minetest.get_node_or_nil(pos)
if not node_up or node_up.name ~= "air" then
return
end
if (minetest.get_node_light(pos, nil) or 99) <= light_max then
minetest.set_node(pos, huge_mushroom_cap_node)
end
end
})
-- new fungi
local mushroom_nodes = {}
for _, mushroom in pairs(mushrooms) do
mushroom_nodes[#mushroom_nodes+1] = {name = mushroom}
end
minetest.register_abm({
nodenames = {"default:dirt"},
neighbors = {'fun_caves:stone_with_lichen', 'fun_caves:stone_with_algae', 'fun_caves:giant_mushroom_stem'},
interval = 10 * time_factor,
chance = 500,
catch_up = false,
action = function(pos, node)
if not (pos and node and pos.y < 0) then
return
end
pos.y = pos.y + 1
local grow_node = minetest.get_node_or_nil(pos)
if grow_node and grow_node.name == "air"
and (minetest.get_node_light(pos, nil) or 99) <= light_max then
if math.random(4) == 1 then
minetest.set_node(pos, fungal_nodes[math.random(#fungal_nodes - 1)])
else
minetest.set_node(pos, mushroom_nodes[math.random(#mushroom_nodes)])
end
end
end
})
-- mushroom growth -- small into huge
local giant_mushroom_stem_node = {name = 'fun_caves:giant_mushroom_stem'}
minetest.register_abm({
nodenames = mushrooms,
interval = 20 * time_factor,
chance = 700,
catch_up = false,
action = function(pos, node)
if not (pos and node and pos.y < 0) then
return
end
local pos_up = {x=pos.x,y=pos.y+1,z=pos.z}
local node_up = minetest.get_node_or_nil(pos_up)
if not node_up or node_up.name ~= "air" then
return
end
local node_under = minetest.get_node_or_nil({x = pos.x, y = pos.y - 1, z = pos.z})
if not node_under
or minetest.get_item_group(node_under.name, "soil") == 0
or (minetest.get_node_light(pos_up, nil) or 99) > light_max then
return
end
minetest.set_node(pos_up, huge_mushroom_cap_node)
minetest.set_node(pos, giant_mushroom_stem_node)
end
})
-- mushroom growth -- huge into giant
local giant_mushroom_cap_node = {name = "fun_caves:giant_mushroom_cap"}
minetest.register_abm({
nodenames = {"fun_caves:huge_mushroom_cap"},
interval = 40 * time_factor,
chance = 2000,
catch_up = false,
action = function(pos, node)
if not (pos and node) then
return
end
local pos_up = {x=pos.x,y=pos.y+1,z=pos.z}
local node_up = minetest.get_node_or_nil(pos_up)
if not node_up or node_up.name ~= "air" then
return
end
-- Check for soil.
local node_under = minetest.get_node_or_nil({x = pos.x, y = pos.y - 2, z = pos.z})
if not node_under
or minetest.get_item_group(node_under.name, "soil") == 0
or (minetest.get_node_light(pos_up, nil) or 99) > light_max then
return
end
minetest.set_node(pos_up, giant_mushroom_cap_node)
minetest.set_node(pos, {name = "fun_caves:giant_mushroom_stem"})
end
})
-- Spike spread and death
minetest.register_abm({
nodenames = fun_caves_mod.hot_spikes,
interval = 40 * time_factor,
chance = 2000,
action = function(pos, node)
if not (pos and node and pos.y < 0) then
return
end
if not (fun_caves_mod.hot_spike and fun_caves_mod.hot_spikes) then
return
end
local spike_num = fun_caves_mod.hot_spike[node.name]
if not spike_num then
return
end
if spike_num < #fun_caves_mod.hot_spikes then
minetest.set_node(pos, {name=fun_caves_mod.hot_spikes[spike_num+1]})
return
end
pos.x = pos.x + math.random(-2, 2)
pos.y = pos.y + math.random(-1, 1)
pos.z = pos.z + math.random(-2, 2)
local new_node = minetest.get_node_or_nil(pos)
if not (new_node and spike_air[new_node.name]) then
return
end
local node_under = minetest.get_node_or_nil({x = pos.x, y = pos.y - 1, z = pos.z})
if not (node_under and spike_soil[node_under.name]) then
return
end
minetest.set_node(pos, {name = fun_caves_mod.hot_spikes[1]})
end
})
------------------------------------------------------------
-- explosive functions
------------------------------------------------------------
-- All of this is copied from TNT, but modified to leave stone intact.
-- Fill a list with data for content IDs, after all nodes are registered
local cid_data = {}
minetest.after(0, function()
for name, def in pairs(minetest.registered_nodes) do
cid_data[minetest.get_content_id(name)] = {
name = name,
--drops = def.drops,
flammable = def.groups.flammable,
choppy = def.groups.choppy,
fleshy = def.groups.fleshy,
snappy = def.groups.snappy,
on_blast = def.on_blast,
}
end
-- This also has to be done after content ids are established.
for i = 1, 4 do
fungi_to_explode[minetest.get_content_id("fun_caves:fungal_tree_leaves_"..i)] = true
end
fungi_to_explode[minetest.get_content_id('fun_caves:fungal_tree_fruit')] = true
fungi_to_explode[minetest.get_content_id('fun_caves:giant_mushroom_cap')] = true
fungi_to_explode[minetest.get_content_id('fun_caves:giant_mushroom_stem')] = true
fungi_to_explode[minetest.get_content_id('fun_caves:huge_mushroom_cap')] = true
end)
local function add_effects(pos, radius)
if not (pos and radius and type(radius) == 'number') then
return
end
minetest.add_particlespawner({
amount = 128,
time = 1,
minpos = vector.subtract(pos, radius / 2),
maxpos = vector.add(pos, radius / 2),
minvel = {x=-20, y=-20, z=-20},
maxvel = {x=20, y=20, z=20},
minacc = vector.new(),
maxacc = vector.new(),
minexptime = 1,
maxexptime = 3,
minsize = 8,
maxsize = 16,
texture = "tnt_smoke.png",
})
end
local function destroy(pos, cid)
if not (pos and cid) then
return
end
local def = cid_data[cid]
if not (def and def.flammable and def.flammable > 0 and not minetest.is_protected(pos, "")) then
return
end
if def.on_blast then
def.on_blast(vector.new(pos), 1)
return
end
if def.snappy == nil and def.choppy == nil and def.fleshy == nil and def.name ~= "fire:basic_flame" then
return
end
if exploding_fungi or fungi_to_explode[cid] then
minetest.remove_node(pos)
end
end
local math_random = math.random
local function explode(pos, radius)
if not (pos and radius and type(radius) == 'number') then
return
end
local pos = vector.round(pos)
local vm = VoxelManip()
local p1 = vector.subtract(pos, radius)
local p2 = vector.add(pos, radius)
local minp, maxp = vm:read_from_map(p1, p2)
local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
local data = vm:get_data()
local p = {}
local c_air = minetest.get_content_id("air")
for z = -radius, radius do
for y = -radius, 4*radius do
local vi = a:index(pos.x + (-radius), pos.y + y, pos.z + z)
for x = -radius, radius do
if (x * x) + (y * y / 4) + (z * z) <=
(radius * radius) + math_random(-radius, radius) then
local cid = data[vi]
p.x = pos.x + x
p.y = pos.y + y
p.z = pos.z + z
if cid ~= c_air then
destroy(p, cid)
end
end
vi = vi + 1
end
end
end
end
local function calc_velocity(pos1, pos2, old_vel, power)
if not (pos1 and pos2 and old_vel and power) then
return
end
local vel = vector.direction(pos1, pos2)
vel = vector.normalize(vel)
vel = vector.multiply(vel, power)
-- Divide by distance
local dist = vector.distance(pos1, pos2)
dist = math.max(dist, 1)
vel = vector.divide(vel, dist)
-- Add old velocity
vel = vector.add(vel, old_vel)
return vel
end
local function entity_physics(pos, radius)
if not (pos and radius and type(radius) == 'number') then
return
end
-- Make the damage radius larger than the destruction radius
radius = radius * 2
local objs = minetest.get_objects_inside_radius(pos, radius)
if not (objs and type(objs) == 'table') then
return
end
local math_max = math.max
local vector_distance = vector.distance
for _, obj in pairs(objs) do
local obj_pos = obj:getpos()
local obj_vel = obj:getvelocity()
local dist = math_max(1, vector_distance(pos, obj_pos))
if obj_vel ~= nil then
obj:setvelocity(calc_velocity(pos, obj_pos,
obj_vel, radius * 10))
end
local damage = (4 / dist) * radius
obj:set_hp(obj:get_hp() - damage)
end
end
fun_caves_mod.soft_boom = function(pos)
if not pos then
return
end
local node = minetest.get_node_or_nil(pos)
if not node then
return
end
if exploding_fungi then
minetest.sound_play("tnt_explode", {pos=pos, gain=1.5, max_hear_distance=2*64})
end
local radius = 5
minetest.remove_node(pos)
explode(pos, radius)
if exploding_fungi then
entity_physics(pos, radius)
add_effects(pos, radius)
end
end
-----------------------------------------------
-- testing only -- remove before distribution
-----------------------------------------------
-- Mushroom spread and death
--minetest.register_abm({
-- nodenames = mushrooms,
-- interval = 1 * time_factor,
-- chance = 50,
-- action = function(pos, node)
-- if minetest.get_node_light(pos, nil) >= light_max + 2 then
-- minetest.remove_node(pos)
-- return
-- end
-- local random = {
-- x = pos.x + math.random(-2, 2),
-- y = pos.y + math.random(-1, 1),
-- z = pos.z + math.random(-2, 2)
-- }
-- local random_node = minetest.get_node_or_nil(random)
-- if not random_node or random_node.name ~= "air" then
-- return
-- end
-- local node_under = minetest.get_node_or_nil({x = random.x,
-- y = random.y - 1, z = random.z})
-- if not node_under then
-- return
-- end
--
-- if (minetest.get_item_group(node_under.name, "soil") ~= 0 or
-- minetest.get_item_group(node_under.name, "tree") ~= 0) and
-- minetest.get_node_light(pos, 0.5) <= light_max and
-- minetest.get_node_light(random, 0.5) <= light_max then
-- minetest.set_node(random, {name = node.name})
-- end
-- end
--})

View file

@ -1,69 +0,0 @@
-- Fun_Caves cavegen.lua
-- Copyright Duane Robertson (duane@duanerobertson.com), 2017
-- Distributed under the LGPLv2.1 (https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html)
fun_caves_mod.cave_width = 0.05 -- figurative width
local max_depth = -28000
fun_caves_mod.cave_noise_1 = {offset = 0, scale = 1, seed = 3901, spread = {x = 40, y = 10, z = 40}, octaves = 3, persist = 1, lacunarity = 2}
fun_caves_mod.cave_noise_2 = {offset = 0, scale = 1, seed = -8402, spread = {x = 40, y = 20, z = 40}, octaves = 3, persist = 1, lacunarity = 2}
local cave_noise_3 = {offset = 15, scale = 10, seed = 3721, spread = {x = 40, y = 40, z = 40}, octaves = 3, persist = 1, lacunarity = 2}
fun_caves_mod.cavegen = function(minp, maxp, data, area, node, heightmap)
if not (minp and maxp and data and area and node and type(data) == 'table') then
return
end
local temp_y = (minp.y+maxp.y)/2
if temp_y > -28000 or temp_y < -30999 then return end
local csize = vector.add(vector.subtract(maxp, minp), 1)
local map_max = {x = csize.x, y = csize.y + 2, z = csize.z}
local map_min = {x = minp.x, y = minp.y - 1, z = minp.z}
local cave_1, cave_2, cave_3
cave_1 = minetest.get_perlin_map(fun_caves_mod.cave_noise_1, map_max):get3dMap_flat(map_min)
cave_2 = minetest.get_perlin_map(fun_caves_mod.cave_noise_2, map_max):get3dMap_flat(map_min)
cave_3 = minetest.get_perlin_map(cave_noise_3, {x=csize.x, y=csize.z}):get2dMap_flat({x=minp.x, y=minp.z})
if not (cave_1 and cave_2 and cave_3) then
return
end
local index = 0
local index3d = 0
local cave_width = fun_caves_mod.cave_width
local write
for z = minp.z, maxp.z do
for x = minp.x, maxp.x do
index = index + 1
index3d = (z - minp.z) * (csize.y + 2) * csize.x + (x - minp.x) + 1
local ivm = area:index(x, minp.y, z)
local height = heightmap[index]
for y = minp.y, maxp.y do
if ((y <= maxp.y and y >= minp.y) or (data[ivm] == node['default:stone'])) and y < height - cave_3[index] and cave_1[index3d] * cave_2[index3d] > cave_width then
data[ivm] = node["air"]
write = true
if y > 0 and cave_3[index] < 1 and y == height then
-- Clear the air above a cave mouth.
local ivm2 = ivm
for y2 = y + 1, maxp.y + 8 do
ivm2 = ivm2 + area.ystride
if data[ivm2] ~= node["default:water_source"] then
data[ivm2] = node["air"]
write = true
end
end
end
end
ivm = ivm + area.ystride
index3d = index3d + csize.x
end
end
end
return write
end

222
deco.lua
View file

@ -1,222 +0,0 @@
-- Fun_Caves deco.lua
-- Copyright Duane Robertson (duane@duanerobertson.com), 2017
-- Distributed under the LGPLv2.1 (https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html)
dofile(fun_caves_mod.path .. "/nodes.lua")
dofile(fun_caves_mod.path .. "/fungal_tree.lua")
local deco_depth = -5 -- place cave stuff this far beneath the surface
local water_level = 1
local fluid_compression = -22000 -- the depth to start planting lava/water
local max_depth = -27960
local csize
local node_match_cache = {}
local biome_noise = {offset = 0.0, scale = 1.0, spread = {x = 400, y = 400, z = 400}, seed = 903, octaves = 3, persist = 0.5, lacunarity = 2.0}
-- Air needs to be placed prior to decorations.
fun_caves_mod.decogen = function(minp, maxp, data, area, node, heightmap)
if not (minp and maxp and data and area and node and type(data) == 'table' and fun_caves_mod.cave_biomes and fun_caves_mod.make_fungal_tree) then
return
end
local temp_y = (minp.y+maxp.y)/2
if temp_y > -28000 or temp_y < -30999 then return end
csize = vector.add(vector.subtract(maxp, minp), 1)
local map_max = {x = csize.x, y = csize.y + 2, z = csize.z}
local map_min = {x = minp.x, y = minp.y - 1, z = minp.z}
local biome_n = minetest.get_perlin_map(biome_noise, map_max):get3dMap_flat(map_min)
local write
local index = 0
local index3d = 0
local math_max = math.max
local math_min = math.min
local math_log = math.log
local math_random = math.random
for z = minp.z, maxp.z do
for x = minp.x, maxp.x do
index = index + 1
index3d = (z - minp.z) * (csize.y + 2) * csize.x + (x - minp.x) + 1
local ivm = area:index(x, minp.y, z)
local height = heightmap[index]
for y = minp.y-1, maxp.y+1 do
if y <= height + deco_depth and (height < max_depth or y < 0) then
for deco_non_loop = 1, 1 do
if not (data[ivm] == node["air"] or data[ivm] == node["default:stone"]) then
break
end
local biome
local biome_val = biome_n[index3d]
-- Compress biomes at the surface to avoid fluids.
if y > fluid_compression then
biome_val = biome_val / math_max(1, math_log(y - fluid_compression))
end
for _, bi in pairs(fun_caves_mod.cave_biomes) do
if biome_val >= bi.biome_val_low and biome_val < bi.biome_val_high then
biome = bi
end
end
--biome = fun_caves_mod.cave_biomes['salt']
if not biome then
print(("* Fun Caves: Error in biome selection: %s"):format(biome_val))
biome = fun_caves_mod.cave_biomes['algae']
end
local node_below
if y > minp.y then
node_below = data[ivm - area.ystride]
end
local node_above = data[ivm + area.ystride]
if data[ivm] == node["default:stone"] then
if node_above == node["air"] and biome and biome.dirt and math_random(biome.dirt_chance) == 1 then
data[ivm] = node[biome.dirt]
write = true
break
end
local air_above = false
for i = 1, biome.stone_depth do
if data[ivm + area.ystride * i] == node["air"] then
air_above = true
end
end
if air_above then
if biome and biome.deco and math_random(biome.deco_chance) == 1 then
data[ivm] = node[biome.deco]
write = true
break
else
data[ivm] = node[biome.floor_node]
write = true
break
end
end
local air_below = false
for i = 1, biome.stone_depth do
if data[ivm - area.ystride * i] == node["air"] then
air_below = true
end
end
-- Prevent server-crashing sandslides.
if not air_above and biome.floor_node == "default:sand" then
data[ivm] = node["default:sandstone"]
write = true
break
end
if air_below then
if biome and biome.deco and math_random(biome.deco_chance) == 1 then
data[ivm] = node[biome.deco]
write = true
break
else
data[ivm] = node[biome.ceiling_node]
write = true
break
end
end
end
if data[ivm] == node["air"] and y < maxp.y then
-- hanging down
-- stone hasn't yet been changed
if biome and biome.stalactite and node_above == node["default:stone"] and math_random(biome.stalactite_chance) == 1 then
data[ivm] = node[biome.stalactite]
write = true
break
end
-- fluids
if y > minp.y and biome and biome.fluid and node_below == node[biome.floor_node] and math_random(biome.fluid_chance) == 1 then
data[ivm] = node[biome.fluid]
write = true
break
-- standing up
elseif node_below == node[biome.floor_node] and biome and biome.stalagmite and math_random(biome.stalagmite_chance) == 1 then
if type(biome.stalagmite) == 'table' then
data[ivm] = node[biome.stalagmite[math_random(#biome.stalagmite)]]
else
data[ivm] = node[biome.stalagmite]
end
write = true
break
-- vegetation
elseif node_below == node["default:dirt"] and biome and biome.fungi then
if math_random(10) == 1 then
data[ivm] = node["flowers:mushroom_red"]
write = true
break
elseif math_random(10) == 1 then
data[ivm] = node["flowers:mushroom_brown"]
write = true
break
elseif node_above == node["air"] and math_random(10) == 1 then
data[ivm] = node["fun_caves:giant_mushroom_stem"]
write = true
break
elseif math_random(30) == 1 then
local air_count = 0
local j
for i = 1, 12 do
j = ivm + area.ystride * i
if j <= #data and data[j] == node["air"] then
air_count = air_count + 1
end
end
if air_count > 5 then
fun_caves_mod.make_fungal_tree(data, area, ivm, math_random(2, math_min(air_count, 12)))
end
end
elseif node_below == node["fun_caves:giant_mushroom_stem"] and data[ivm - area.ystride * 2] == node["fun_caves:giant_mushroom_stem"] then
data[ivm] = node["fun_caves:giant_mushroom_cap"]
write = true
break
elseif node_below == node["fun_caves:giant_mushroom_stem"] then
if node_above == node["air"] and math_random(3) == 1 then
data[ivm] = node["fun_caves:giant_mushroom_stem"]
write = true
break
else
data[ivm] = node["fun_caves:huge_mushroom_cap"]
write = true
break
end
end
end
end
elseif y < height and data[ivm] == node["air"] and (data[ivm - area.ystride] == node['default:stone'] or data[ivm - area.ystride] == node['default:sandstone']) then
-- This just places non-abm dirt inside caves.
-- Its value is questionable.
data[ivm - area.ystride] = node["fun_caves:dirt"]
write = true
end
ivm = ivm + area.ystride
index3d = index3d + csize.x
end
end
end
return write
end

View file

@ -1,9 +1 @@
default
bucket?
dye
flowers
mobs?
ramoid?
underworlds?
vessels
wooden_bucket?

View file

@ -1,188 +0,0 @@
-- Fun_Caves fungal_tree.lua
-- Copyright Duane Robertson (duane@duanerobertson.com), 2017
-- Distributed under the LGPLv2.1 (https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html)
local colors = {}
colors["^[colorize:#FF00FF:60"] = "dye:violet"
colors["^[colorize:#0000FF:60"] = "dye:blue"
colors["^[colorize:#FF4500:80"] = "dye:green"
colors[""] = "dye:white"
local fungal_tree_leaves = {}
local newnode = fun_caves_mod.clone_node("farming:straw")
newnode.description = "Dry Fiber"
minetest.register_node("fun_caves:dry_fiber", newnode)
minetest.register_node("fun_caves:fungal_tree_fruit", {
description = "Fungal tree fruit",
drawtype = "plantlike",
visual_scale = 0.75,
tiles = {"fun_caves_fungal_tree_fruit.png"},
--inventory_image = ".png",
paramtype = "light",
sunlight_propagates = true,
light_source = 6,
walkable = false,
is_ground_content = false,
selection_box = {
type = "fixed",
fixed = {-0.2, -0.5, -0.2, 0.2, 0, 0.2}
},
groups = {fleshy = 3, dig_immediate = 3, flammable = 2},
--on_use = minetest.item_eat(2),
sounds = default.node_sound_leaves_defaults(),
on_timer = fun_caves_mod.soft_boom,
on_punch = fun_caves_mod.soft_boom,
})
local fruit = minetest.get_content_id("fun_caves:fungal_tree_fruit")
function fun_caves_mod.make_fungal_tree(data, area, ivm, height)
if not (data and area and ivm and height and type(data) == 'table' and type(ivm) == 'number' and type(height) == 'number') then
return
end
local leaf = minetest.get_content_id(fungal_tree_leaves[math.random(#fungal_tree_leaves)])
local air = minetest.get_content_id('air')
for y = 0, height do
local radius = 1
if y > 1 and y < height - 2 then
radius = 2
end
for z = -radius,radius do
for x = -radius,radius do
local sr = math.random(1,100)
local i = ivm + z*area.zstride + y*area.ystride + x
if data[i] == air then
if x == 0 and y == 0 and z == 0 then
data[i] = leaf
elseif sr == 1 then
data[i] = fruit
elseif sr < 50 then
data[i] = leaf
end
end
end
end
end
end
-- multicolored growths
local count = 0
for color, dye in pairs(colors) do
count = count + 1
local name = "fun_caves:fungal_tree_leaves_"..count
fungal_tree_leaves[#fungal_tree_leaves+1] = name
minetest.register_node(name, {
description = "Fungal tree growths",
drawtype = "allfaces_optional",
waving = 1,
visual_scale = 1.3,
tiles = {"fun_caves_fungal_tree_leaves.png"..color},
paramtype = "light",
is_ground_content = false,
groups = {snappy=3, flammable=3, plant=1},
drop = {
max_items = 1,
items = {
--{items = {"fun_caves:"..tree.name.."_sapling"}, rarity = tree.drop_rarity },
{items = {name} }
}
},
sounds = default.node_sound_leaves_defaults(),
after_place_node = default.after_place_leaves,
})
minetest.register_craft({
type = "cooking",
output = "fun_caves:dry_fiber",
recipe = name,
cooktime = 2,
})
if dye then
minetest.register_craft({
output = dye,
recipe = {
{name}
}
})
end
end
minetest.register_craft({
type = "fuel",
recipe = "fun_caves:dry_fiber",
burntime = 5,
})
minetest.register_craft({
output = "dye:yellow",
recipe = {
{"flowers:mushroom_brown"}
}
})
minetest.register_craftitem("fun_caves:wooden_bowl", {
description = "Wooden Bowl",
drawtype = "plantlike",
paramtype = "light",
tiles = {"fun_caves_wooden_bowl.png"},
inventory_image = "fun_caves_wooden_bowl.png",
groups = {bowl = 1, dig_immediate = 3},
})
minetest.register_craft({
output = 'fun_caves:wooden_bowl 20',
recipe = {
{'group:wood', '', 'group:wood'},
{'group:wood', '', 'group:wood'},
{'', 'group:wood', ''},
},
})
minetest.register_craftitem("fun_caves:disgusting_gruel", {
description = "Disgusting Gruel",
drawtype = "plantlike",
paramtype = "light",
tiles = {"fun_caves_disgusting_gruel.png"},
inventory_image = "fun_caves_disgusting_gruel.png",
on_use = minetest.item_eat(2),
groups = {dig_immediate = 3},
})
minetest.register_craftitem("fun_caves:disgusting_gruel_raw", {
description = "Bowl Of Gluey Paste",
drawtype = "plantlike",
paramtype = "light",
tiles = {"fun_caves_disgusting_gruel_raw.png"},
inventory_image = "fun_caves_disgusting_gruel_raw.png",
groups = {dig_immediate = 3},
})
minetest.register_craft({
type = "cooking",
output = "fun_caves:disgusting_gruel",
recipe = 'fun_caves:disgusting_gruel_raw',
cooktime = 2,
})
minetest.register_craft({
output = "fun_caves:disgusting_gruel_raw",
type = 'shapeless',
recipe = {
'fun_caves:dry_fiber',
'group:water_bucket',
'group:bowl',
},
replacements = {
{'bucket:bucket_water', 'bucket:bucket_water'},
{'bucket:bucket_river_water', 'bucket:bucket_river_water'},
{'wooden_bucket:bucket_wood_water', 'wooden_bucket:bucket_wood_water'},
{'wooden_bucket:bucket_wood_river_water', 'wooden_bucket:bucket_wood_river_water'},
},
})

View file

@ -1,32 +1,84 @@
-- Fun_Caves init.lua
-- Copyright Duane Robertson (duane@duanerobertson.com), 2017
-- Distributed under the LGPLv2.1 (https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html)
fun_caves = {}
fun_caves.version = "1.0"
fun_caves.path = minetest.get_modpath(minetest.get_current_modname())
fun_caves.world = false
fun_caves_mod = {}
fun_caves_mod.version = "2.0"
fun_caves_mod.time_factor = 1 -- affects growth abms
fun_caves_mod.light_max = 8 -- light intensity for mushroom growth
fun_caves_mod.path = minetest.get_modpath(minetest.get_current_modname())
fun_caves_mod.world = minetest.get_worldpath()
if fun_caves.world then
minetest.register_on_mapgen_init(function(mgparams)
minetest.set_mapgen_params({mgname="singlenode", flags="nolight"})
end)
function fun_caves_mod.clone_node(name)
if not (name and type(name) == 'string') then
return
if default then
if default.register_ores then
default.register_ores()
end
if default.register_blobs then
default.register_blobs()
end
if default.register_biomes then
default.register_biomes()
end
if default.register_decorations then
default.register_decorations()
end
if flowers.register_decorations then
flowers.register_decorations()
end
end
else
minetest.set_mapgen_params({flags="nocaves"})
end
-- Modify a node to add a group
function minetest.add_group(node, groups)
local def = minetest.registered_items[node]
if not def then
return false
end
local def_groups = def.groups or {}
for group, value in pairs(groups) do
if value ~= 0 then
def_groups[group] = value
else
def_groups[group] = nil
end
end
minetest.override_item(node, {groups = def_groups})
return true
end
function fun_caves.clone_node(name)
local node = minetest.registered_nodes[name]
local node2 = table.copy(node)
return node2
end
function fun_caves.node(name)
if not fun_caves.node_cache then
fun_caves.node_cache = {}
end
minetest.register_on_mapgen_init(function(mgparams)
--minetest.set_mapgen_setting('mg_flags', "nocaves, nodungeons", true)
--minetest.set_mapgen_setting('mg_flags', "nocaves", true)
end)
if not fun_caves.node_cache[name] then
fun_caves.node_cache[name] = minetest.get_content_id(name)
if name ~= "ignore" and fun_caves.node_cache[name] == 127 then
print("*** Failure to find node: "..name)
end
end
return fun_caves.node_cache[name]
end
dofile(fun_caves_mod.path .. "/mapgen.lua")
dofile(fun_caves_mod.path .. "/abms.lua")
--dofile(fun_caves.path .. "/nodes.lua")
dofile(fun_caves.path .. "/mapgen.lua")
if fun_caves.world then
minetest.register_on_newplayer(fun_caves.respawn)
minetest.register_on_respawnplayer(fun_caves.respawn)
end
-- Inserting helps to ensure that fun_caves operates first.
table.insert(minetest.registered_on_generateds, 1, fun_caves.generate)

View file

@ -1,279 +1,545 @@
-- Fun_Caves mapgen.lua
-- Copyright Duane Robertson (duane@duanerobertson.com), 2017
-- Distributed under the LGPLv2.1 (https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html)
-- Much of this code is translated directly from the Minetest
-- cavegen.cpp, and is likewise distributed under the LGPL2.1
local DEBUG
local max_depth = -28000
local seed_noise = {offset = 0, scale = 32768, seed = 5202, spread = {x = 80, y = 80, z = 80}, octaves = 2, persist = 0.4, lacunarity = 2}
fun_caves_mod.use_bi_hi = true
local ground_nodes = {}
ground_nodes[minetest.get_content_id('default:stone')] = true
ground_nodes[minetest.get_content_id('default:desert_stone')] = true
ground_nodes[minetest.get_content_id('default:sandstone')] = true
ground_nodes[minetest.get_content_id('default:dirt')] = true
ground_nodes[minetest.get_content_id('default:sand')] = true
ground_nodes[minetest.get_content_id('default:dirt_with_grass')] = true
ground_nodes[minetest.get_content_id('default:dirt_with_snow')] = true
ground_nodes[minetest.get_content_id('default:dirt_with_dry_grass')] = true
-- This tables looks up nodes that aren't already stored.
local node = setmetatable({}, {
__index = function(t, k)
if not (t and k and type(t) == 'table') then
return
end
t[k] = minetest.get_content_id(k)
return t[k]
end
})
--local DEBUG = true
local node = fun_caves.node
local data = {}
local p2data = {} -- vm rotation data buffer
local lightmap = {}
local vm, emin, emax, a, csize, heightmap, biomemap
local div_sz_x, div_sz_z, minp, maxp, terrain, cave
local terrain_noise = {offset = 0,
scale = 20, seed = 8829, spread = {x = 40, y = 40, z = 40},
octaves = 6, persist = 0.4, lacunarity = 2}
fun_caves_mod.cave_biomes = {
algae = {
biome_val_low = 0,
biome_val_high = 0.2,
ceiling_node = 'fun_caves:stone_with_algae',
dirt = 'default:dirt',
dirt_chance = 10,
floor_node = 'fun_caves:stone_with_algae',
fungi = true,
stalactite = 'fun_caves:stalactite_slimy',
stalactite_chance = 12,
stalagmite = 'fun_caves:stalagmite_slimy',
stalagmite_chance = 12,
stone_depth = 1,
underwater = true,
},
coal = {
biome_val_low = 0.5,
biome_val_high = 0.6,
ceiling_node = 'fun_caves:black_sand',
deco = 'default:coalblock',
deco_chance = 100,
floor_node = 'fun_caves:black_sand',
stalagmite = 'fun_caves:constant_flame',
stalagmite_chance = 50,
stone_depth = 2,
underwater = false,
},
hot = {
biome_val_low = 0.6,
biome_val_high = 99,
ceiling_node = 'fun_caves:hot_cobble',
floor_node = 'fun_caves:hot_cobble',
fluid = 'default:lava_source',
fluid_chance = 300,
stalagmite = fun_caves_mod.hot_spikes,
stalagmite_chance = 50,
stone_depth = 1,
underwater = false,
},
ice = {
biome_val_low = -99,
biome_val_high = -0.6,
ceiling_node = 'default:ice',
floor_node = 'default:ice',
stalactite = 'fun_caves:icicle_down',
stalactite_chance = 12,
stalagmite = 'fun_caves:icicle_up',
stalagmite_chance = 12,
stone_depth = 2,
underwater = true,
},
ice_thin = {
biome_val_low = -0.6,
biome_val_high = -0.5,
ceiling_node = 'fun_caves:thin_ice',
floor_node = 'fun_caves:thin_ice',
stone_depth = 2,
underwater = true,
},
lichen = {
biome_val_low = -0.3,
biome_val_high = 0,
ceiling_node = 'fun_caves:stone_with_lichen',
dirt = 'default:dirt',
dirt_chance = 10,
floor_node = 'fun_caves:stone_with_lichen',
fungi = true,
stalactite = 'fun_caves:stalactite',
stalactite_chance = 12,
stalagmite = 'fun_caves:stalagmite',
stalagmite_chance = 12,
stone_depth = 1,
underwater = true,
},
lichen_dead = {
biome_val_low = -0.6,
biome_val_high = -0.5,
ceiling_node = 'fun_caves:stone_with_lichen',
floor_node = 'fun_caves:stone_with_lichen',
stalactite = 'fun_caves:stalactite',
stalactite_chance = 12,
stalagmite = 'fun_caves:stalagmite',
stalagmite_chance = 12,
stone_depth = 1,
underwater = true,
},
moss = {
biome_val_low = -0.5,
biome_val_high = -0.3,
ceiling_node = 'fun_caves:stone_with_moss',
deco = 'fun_caves:glowing_fungal_stone',
deco_chance = 50,
floor_node = 'fun_caves:stone_with_moss',
fluid = 'default:water_source',
fluid_chance = 300,
stalactite = 'fun_caves:stalactite_mossy',
stalactite_chance = 12,
stalagmite = 'fun_caves:stalagmite_mossy',
stalagmite_chance = 12,
stone_depth = 1,
underwater = true,
},
salt = {
biome_val_low = 0.2,
biome_val_high = 0.35,
ceiling_node = 'fun_caves:stone_with_salt',
deco = 'fun_caves:radioactive_ore',
deco_chance = 500,
floor_node = 'fun_caves:stone_with_salt',
stone_depth = 2,
underwater = false,
},
sand = {
biome_val_low = 0.35,
biome_val_high = 0.5,
ceiling_node = 'default:sand',
floor_node = 'default:sand',
stone_depth = 2,
underwater = true,
},
}
local cave_noise = {offset = 0, scale = 1,
seed = -3977, spread = {x = 30, y = 30, z = 30}, octaves = 3,
persist = 0.8, lacunarity = 2}
local seed_noise = {offset = 0, scale = 32768,
seed = 5202, spread = {x = 80, y = 80, z = 80}, octaves = 2,
persist = 0.4, lacunarity = 2}
local function generate(p_minp, p_maxp, seed)
if not (p_minp and p_maxp and seed) then
return
if fun_caves.world then
fun_caves.biomes = {}
local biomes = fun_caves.biomes
local biome_names = {}
biome_names["common"] = {}
biome_names["uncommon"] = {}
do
local biome_terrain_scale = {}
biome_terrain_scale["coniferous_forest"] = 0.75
biome_terrain_scale["rainforest"] = 0.33
biome_terrain_scale["underground"] = 1.5
local tree_biomes = {}
tree_biomes["deciduous_forest"] = {"deciduous_trees"}
tree_biomes["coniferous_forest"] = {"conifer_trees"}
tree_biomes["taiga"] = {"conifer_trees"}
tree_biomes["rainforest"] = {"jungle_trees"}
tree_biomes["rainforest_swamp"] = {"jungle_trees"}
tree_biomes["coniferous_forest"] = {"conifer_trees"}
tree_biomes["savanna"] = {"acacia_trees"}
for i, obiome in pairs(minetest.registered_biomes) do
local biome = table.copy(obiome)
biome.special_tree_prob = 2
if biome.name == "savanna" then
biome.special_tree_prob = 30
end
local minp, maxp = p_minp, p_maxp
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
if not (vm and emin and emax) then
return
local rarity = "common"
biome.terrain_scale = biome_terrain_scale[biome] or 0.5
if string.find(biome.name, "ocean") then
biome.terrain_scale = 1
rarity = "uncommon"
end
if string.find(biome.name, "swamp") then
biome.terrain_scale = 0.25
rarity = "uncommon"
end
if string.find(biome.name, "beach") then
biome.terrain_scale = 0.25
rarity = "uncommon"
end
if string.find(biome.name, "^underground$") then
biome.node_top = "default:stone"
rarity = "uncommon"
end
biome.special_trees = tree_biomes[biome.name]
biomes[biome.name] = biome
biome_names[rarity][#biome_names[rarity]+1] = biome.name
end
end
biomes["control"] = {}
end
vm:get_data(data)
local heightmap
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
local csize = vector.add(vector.subtract(maxp, minp), 1)
local write
if false then
local cave_stones = {
"fun_caves:stone_with_moss",
"fun_caves:stone_with_lichen",
"fun_caves:stone_with_algae",
"fun_caves:stone_with_salt",
}
local mushroom_stones = {}
mushroom_stones[node("default:stone")] = true
mushroom_stones[node("fun_caves:stone_with_algae")] = true
mushroom_stones[node("fun_caves:stone_with_lichen")] = true
end
if minetest.get_modpath('ramoid') and ramoid_mod and ramoid_mod.ramoid_depth then
local avg = (minp.y + maxp.y) / 2
if avg > (ramoid_mod.ramoid_depth - 1) * 80 - 32 and avg < ramoid_mod.ramoid_depth * 80 - 32 then
return
local function place_schematic(pos, schem, center)
local rot = math.random(4) - 1
local yslice = {}
if schem.yslice_prob then
for _, ys in pairs(schem.yslice_prob) do
yslice[ys.ypos] = ys.prob
end
end
if minetest.get_modpath('underworlds') and underworlds_mod and underworlds_mod.underzones then
local avg = (minp.y + maxp.y) / 2
for _, uz in pairs(underworlds_mod.underzones) do
if avg <= uz.upper_bound and avg >= uz.lower_bound then
return
if center then
pos.x = pos.x - math.floor(schem.size.x / 2)
pos.z = pos.z - math.floor(schem.size.z / 2)
end
for z1 = 0, schem.size.z - 1 do
for x1 = 0, schem.size.x - 1 do
local x, z
if rot == 0 then
x, z = x1, z1
elseif rot == 1 then
x, z = schem.size.z - z1 - 1, x1
elseif rot == 2 then
x, z = schem.size.x - x1 - 1, schem.size.z - z1 - 1
elseif rot == 3 then
x, z = z1, schem.size.x - x1 - 1
end
local dz = pos.z - minp.z + z
local dx = pos.x - minp.x + x
if pos.x + x > minp.x and pos.x + x < maxp.x and pos.z + z > minp.z and pos.z + z < maxp.z then
local ivm = a:index(pos.x + x, pos.y, pos.z + z)
local isch = z1 * schem.size.y * schem.size.x + x1 + 1
for y = 0, schem.size.y - 1 do
local dy = pos.y - minp.y + y
if math.min(dx, csize.x - dx) + math.min(dy, csize.y - dy) + math.min(dz, csize.z - dz) > bevel then
if yslice[y] or 255 >= math.random(255) then
local prob = schem.data[isch].prob or schem.data[isch].param1 or 255
if prob >= math.random(255) and schem.data[isch].name ~= "air" then
data[ivm] = node(schem.data[isch].name)
end
local param2 = schem.data[isch].param2 or 0
p2data[ivm] = param2
end
end
if fun_caves_mod.use_bi_hi then
heightmap = minetest.get_mapgen_object("heightmap")
ivm = ivm + a.ystride
isch = isch + schem.size.x
end
end
end
end
end
-- Correct heightmap.
if maxp.y < -300 or minp.y > 300 then
for i = 1, #heightmap do
heightmap[i] = (maxp.y < 0) and max_depth or - max_depth
local function get_decoration(biome)
for i, deco in pairs(fun_caves.decorations) do
if not deco.biomes or deco.biomes[biome] then
local range = 1000
if deco.deco_type == "simple" then
if deco.fill_ratio and math.random(range) - 1 < deco.fill_ratio * 1000 then
return deco.decoration
end
else
-- nop
end
end
end
end
local np_cave = {offset = 6, scale = 6, seed = 34329, spread = {x = 250, y = 250, z = 250}, octaves = 3, persist = 0.5, lacunarity = 2}
local function rangelim(x, y, z)
return math.max(math.min(x, z), y)
end
local function carveRoute(this, vec, f, randomize_xz, tunnel_above_ground)
local startp = vector.new(this.orp)
startp = vector.add(startp, this.of)
local fp = vector.add(this.orp, vector.multiply(vec, f))
fp.x = fp.x + 0.1 * math.random(-10, 10)
fp.z = fp.z + 0.1 * math.random(-10, 10)
local cp = vector.new(fp)
local d0 = -this.rs/2
local d1 = d0 + this.rs
if (randomize_xz) then
d0 = d0 + math.random(-1, 1)
d1 = d1 + math.random(-1, 1)
end
for z0 = d0, d1 do
local si = this.rs / 2 - math.max(0, math.abs(z0) - this.rs / 7 - 1)
for x0 = -si - math.random(0,1), si - 1 + math.random(0,1) do
if (tunnel_above_ground) then
--continue
else
local maxabsxz = math.max(math.abs(x0), math.abs(z0))
local si2 = this.rs / 2 - math.max(0, maxabsxz - this.rs / 7 - 1)
for y0 = -si2, si2 do
if (this.large_cave_is_flat) then
-- Make large caves not so tall
if (this.rs > 7 and math.abs(y0) >= this.rs / 3) then
--continue
else
local p = vector.new(cp.x + x0, cp.y + y0, cp.z + z0)
p = vector.add(p, this.of)
if not a:containsp(p) then
--continue
else
local i = a:indexp(vector.round(p))
local c = data[i]
--if (not ndef.get(c).is_ground_content) then
-- ** check for ground content? **
local donotdig = false
if c == node("default:desert_sand") then
donotdig = true
end
if donotdig then
--continue
else
if (this.large_cave) then
local full_ymin = minp.y - 16
local full_ymax = maxp.y + 16
if this.flooded and not this.lava_cave then
data[i] = (p.y <= this.water_level) and node("default:water_source") or node("air")
elseif this.flooded then
data[i] = (p.y < startp.y - 2) and node("default:lava_source") or node("air")
else
data[i] = node("air")
end
else
if (c == node("ignore") or c == node("air")) then
--continue
else
data[i] = node("air")
end
end
end
end
end
end
end
end
end
end
end
local function makeTunnel(this, dirswitch)
if dirswitch and not this.large_cave then
this.main_direction = vector.new(
((math.random() * 20) - 10) / 10,
((math.random() * 20) - 10) / 30,
((math.random() * 20) - 10) / 10
)
this.main_direction = vector.multiply(this.main_direction, math.random(0, 10) / 10)
end
-- Randomize size
local min_d = this.min_tunnel_diameter
local max_d = this.max_tunnel_diameter
this.rs = math.random(min_d, max_d)
local rs_part_max_length_rs = this.rs * this.part_max_length_rs
local maxlen
if this.large_cave then
maxlen = vector.new(
rs_part_max_length_rs,
rs_part_max_length_rs / 2,
rs_part_max_length_rs
)
else
maxlen = vector.new(
rs_part_max_length_rs,
math.random(1, rs_part_max_length_rs),
rs_part_max_length_rs
)
end
local vec = vector.new(
(math.random() * maxlen.x) - maxlen.x / 2,
(math.random() * maxlen.y) - maxlen.y / 2,
(math.random() * maxlen.z) - maxlen.z / 2
)
-- Jump downward sometimes
if not this.large_cave and math.random(0, 12) == 0 then
vec = vector.new(
(math.random() * maxlen.x) - maxlen.x / 2,
(math.random() * (maxlen.y * 2)) - maxlen.y,
(math.random() * maxlen.z) - maxlen.z / 2
)
end
-- Do not make caves that are entirely above ground, to fix
-- shadow bugs caused by overgenerated large caves.
-- It is only necessary to check the startpoint and endpoint.
local orpi = vector.new(this.orp.x, this.orp.y, this.orp.z)
local veci = vector.new(vec.x, vec.y, vec.z)
local h1
local h2
local p1 = vector.add(orpi, veci, this.of, this.rs / 2)
if (p1.z >= minp.z and p1.z <= maxp.z and
p1.x >= minp.x and p1.x <= maxp.x) then
local index1 = math.floor(p1.z - minp.z + 0.5) * csize.x + math.floor(p1.x - minp.x + 0.5) + 1
h1 = heightmap[index1]
else
h1 = this.water_level -- If not in heightmap
end
local p2 = vector.add(orpi, this.of, this.rs / 2)
if (p2.z >= minp.z and p2.z <= maxp.z and
p2.x >= minp.x and p2.x <= maxp.x) then
local index2 = math.floor(p2.z - minp.z + 0.5) * csize.x + math.floor(p2.x - minp.x + 0.5) + 1
h2 = heightmap[index2]
else
h2 = this.water_level
end
-- If startpoint and endpoint are above ground,
-- disable placing of nodes in carveRoute while
-- still running all pseudorandom calls to ensure
-- caves consistent with existing worlds.
local tunnel_above_ground = p1.y > h1 and p2.y > h2
vec = vector.add(vec, this.main_direction)
local rp = vector.add(this.orp, vec)
if (rp.x < 0) then
rp.x = 0
elseif (rp.x >= this.ar.x) then
rp.x = this.ar.x - 1
end
if (rp.y < this.route_y_min) then
rp.y = this.route_y_min
elseif (rp.y >= this.route_y_max) then
rp.y = this.route_y_max - 1
end
if (rp.z < 0) then
rp.z = 0
elseif (rp.z >= this.ar.z) then
rp.z = this.ar.z - 1
end
vec = vector.subtract(rp, this.orp)
local veclen = vector.length(vec)
-- As odd as it sounds, veclen is *exactly* 0.0 sometimes, causing a FPE
if (veclen < 0.05) then
veclen = 1.0
end
-- Every second section is rough
local randomize_xz = (math.random(1, 2) == 1)
-- Carve routes
for f = 0, 1, 1.0 / veclen do
--print(dump(vec))
carveRoute(this, vec, f, randomize_xz, tunnel_above_ground)
end
this.orp = rp
end
local function makeCave(this, max_stone_height)
this.max_stone_y = max_stone_height
this.main_direction = vector.new(0, 0, 0)
--print(dump(this))
-- Allowed route area size in nodes
this.ar = vector.add(vector.subtract(maxp, minp), 1)
-- Area starting point in nodes
this.of = minp
-- Allow a bit more
--(this should be more than the maximum radius of the tunnel)
local max_spread_amount = 16
local insure = 10
local more = math.max(max_spread_amount - this.max_tunnel_diameter / 2 - insure, 1)
this.ar = vector.add(this.ar, vector.multiply(vector.new(1,0,1), (more * 2)))
this.of = vector.subtract(this.of, vector.multiply(vector.new(1,0,1), more))
this.route_y_min = 0
-- Allow half a diameter + 7 over stone surface
this.route_y_max = -this.of.y + this.max_stone_y + this.max_tunnel_diameter / 2 + 7
-- Limit maximum to area
this.route_y_max = rangelim(this.route_y_max, 0, this.ar.y - 1)
if this.large_cave then
local min = 0
if minp.y < this.water_level and maxp.y > this.water_level then
min = this.water_level - this.max_tunnel_diameter/3 - this.of.y
this.route_y_max = this.water_level + this.max_tunnel_diameter/3 - this.of.y
end
this.route_y_min = math.random(min, min + this.max_tunnel_diameter)
this.route_y_min = rangelim(this.route_y_min, 0, this.route_y_max)
end
local route_start_y_min = this.route_y_min
local route_start_y_max = this.route_y_max
route_start_y_min = rangelim(route_start_y_min, 0, this.ar.y-1)
route_start_y_max = rangelim(route_start_y_max, route_start_y_min, this.ar.y-1)
-- Randomize starting position
this.orp = vector.new(
(math.random() * this.ar.x) + 0.5,
(math.random(route_start_y_min, route_start_y_max)) + 0.5,
(math.random() * this.ar.z) + 0.5
)
-- Generate some tunnel starting from orp
for j = 0, this.tunnel_routepoints do
--print(dump(this.orp))
makeTunnel(this, j % this.dswitchint == 0)
end
end
local function CaveV6(is_large_cave)
local this = {}
this.water_level = 1
this.large_cave = is_large_cave
this.min_tunnel_diameter = 2
this.max_tunnel_diameter = math.random(2, 6)
this.dswitchint = math.random(1, 14)
this.flooded = true
this.lava_cave = false
if maxp.y < this.water_level and minp.y / 31000 - math.random() < -0.5 then
this.lava_cave = true
end
if this.large_cave then
this.part_max_length_rs = math.random(2,4)
this.tunnel_routepoints = math.random(5, math.random(15,30))
this.min_tunnel_diameter = 5
this.max_tunnel_diameter = math.random(7, math.random(8,24))
else
this.part_max_length_rs = math.random(2,9)
this.tunnel_routepoints = math.random(10, math.random(15,30))
end
this.large_cave_is_flat = (math.random(0,1) == 0)
return this
end
local function getBiome(x, z)
return nil
end
local function generateCaves(max_stone_y)
local cave_amount = minetest.get_perlin(np_cave):get2d({x=minp.x, y=minp.y})
local volume_nodes = (maxp.x - minp.x + 1) * (maxp.y - minp.y + 1) * 16
cave_amount = math.max(0.0, cave_amount)
local caves_count = cave_amount * volume_nodes / 50000
local bruises_count = 1
if (math.random(1, 6) == 1) then
bruises_count = math.random(0, math.random(0, 2))
end
if (getBiome(minp.x, minp.z) == "desert") then
caves_count = caves_count / 3
bruises_count = caves_count / 3
end
for i = 0, caves_count + bruises_count do
local large_cave = (i >= caves_count)
local cave = CaveV6(large_cave)
--print(dump(cave))
makeCave(cave, max_stone_y)
end
end
function fun_caves.generate(p_minp, p_maxp, seed)
minp, maxp = p_minp, p_maxp
vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
vm:get_data(data)
--p2data = vm:get_param2_data()
a = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
csize = vector.add(vector.subtract(maxp, minp), 1)
heightmap = minetest.get_mapgen_object("heightmap")
local max_stone_height = -40000
local index = 0
for z = minp.z, maxp.z do
for x = minp.x, maxp.x do
index = index + 1
local height = heightmap[index]
if height and height < maxp.y - 1 and height > minp.y then
--nop
else
height = - max_depth
local ivm2 = area:index(x, maxp.y + 8, z)
for y = maxp.y + 8, minp.y - 8, -1 do
if ground_nodes[data[ivm2]] then
height = (y < maxp.y + 8) and y or max_depth
break
end
ivm2 = ivm2 - area.ystride
end
heightmap[index] = height
end
if max_stone_height < heightmap[index] then
max_stone_height = heightmap[index]
end
end
end
for fake_loop = 1, 1 do
if fun_caves_mod.cavegen and fun_caves_mod.decogen then
local h2, write_cave
write_cave = fun_caves_mod.cavegen(minp, maxp, data, area, node, heightmap)
write = write or write_cave
local write_deco
write_deco = fun_caves_mod.decogen(minp, maxp, data, area, node, heightmap)
write = write or write_deco
end
-- Deal with memory issues. This, of course, is supposed to be automatic.
local mem = math.floor(collectgarbage("count")/1024)
if mem > 400 then
print("Fun Caves: Manually collecting garbage...")
collectgarbage("collect")
end
-- use the same seed (based on perlin noise).
math.randomseed(minetest.get_perlin(seed_noise):get2d({x=minp.x, y=minp.z}))
-- Keep this first after seeding!
local px = math.floor((minp.x + 32) / csize.x)
local pz = math.floor((minp.z + 32) / csize.z)
generateCaves(max_stone_height)
--local index = 0
--local index3d = 0
--for z = minp.z, maxp.z do
-- local dz = z - minp.z
-- for x = minp.x, maxp.x do
-- index = index + 1
-- local dx = x - minp.x
-- index3d = dz * csize.y * csize.x + dx + 1
-- local ivm = a:index(x, minp.y, z)
-- for y = minp.y, maxp.y do
-- local dy = y - minp.y
-- ivm = ivm + a.ystride
-- index3d = index3d + csize.x
-- end
-- end
--end
if write then
vm:set_data(data)
--minetest.generate_ores(vm, minp, maxp)
--minetest.generate_decorations(vm, minp, maxp)
--vm:set_param2_data(p2data)
if DEBUG then
vm:set_lighting({day = 8, night = 8})
vm:set_lighting({day = 15, night = 15})
else
vm:set_lighting({day = 0, night = 0}, minp, maxp)
vm:set_lighting({day = 0, night = 0})
vm:calc_lighting()
end
vm:update_liquids()
vm:write_to_map()
end
vm, a, lightmap, heightmap, biomemap, terrain, cave = nil, nil, nil, nil, nil, nil, nil
end
if fun_caves_mod.path then
dofile(fun_caves_mod.path .. "/cavegen.lua")
dofile(fun_caves_mod.path .. "/deco.lua")
end
local function pgenerate(...)
local status, err = pcall(generate, ...)
--local status, err = true
--generate(...)
if not status then
print('Fun Caves: Could not generate terrain:')
print(dump(err))
collectgarbage("collect")
end
end
-- Inserting helps to ensure that fun_caves_mod operates first.
--table.insert(minetest.registered_on_generateds, 1, pgenerate)
minetest.register_on_generated(pgenerate)

451
nodes.lua
View file

@ -1,451 +0,0 @@
-- Fun_Caves nodes.lua
-- Copyright Duane Robertson (duane@duanerobertson.com), 2017
-- Distributed under the LGPLv2.1 (https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html)
local light_max = fun_caves_mod.light_max or 10
if minetest.registered_items['underworlds:black_sand'] then
minetest.register_alias("fun_caves:black_sand", 'underworlds:black_sand')
else
-- black (oily) sand
local newnode = fun_caves_mod.clone_node("default:sand")
newnode.description = "Black Sand"
newnode.tiles = {"fun_caves_black_sand.png"}
newnode.groups['falling_node'] = 0
minetest.register_node("fun_caves:black_sand", newnode)
end
if minetest.registered_items['underworlds:hot_cobble'] then
minetest.register_alias("fun_caves:hot_cobble", 'underworlds:hot_cobble')
else
-- cobble, hot - cobble with lava instead of mortar XD
minetest.register_node("fun_caves:hot_cobble", {
description = "Hot Cobble",
tiles = {"caverealms_hot_cobble.png"},
is_ground_content = true,
groups = {crumbly=2, surface_hot=3},
--light_source = 2,
damage_per_second = 1,
sounds = default.node_sound_stone_defaults({
footstep = {name="default_stone_footstep", gain=0.25},
}),
})
end
if minetest.registered_items['underworlds:glowing_fungal_stone'] then
minetest.register_alias("fun_caves:glowing_fungal_stone", 'underworlds:glowing_fungal_stone')
minetest.register_alias("fun_caves:glowing_fungus", 'underworlds:glowing_fungus')
else
-- Glowing fungal stone provides an eerie light.
minetest.register_node("fun_caves:glowing_fungal_stone", {
description = "Glowing Fungal Stone",
tiles = {"default_stone.png^vmg_glowing_fungal.png",},
is_ground_content = true,
light_source = light_max - 4,
groups = {cracky=3, stone=1},
drop = {items={ {items={"default:cobble"},}, {items={"fun_caves:glowing_fungus",},},},},
sounds = default.node_sound_stone_defaults(),
})
-- Glowing fungus grows underground.
minetest.register_craftitem("fun_caves:glowing_fungus", {
description = "Glowing Fungus",
drawtype = "plantlike",
paramtype = "light",
tiles = {"vmg_glowing_fungus.png"},
inventory_image = "vmg_glowing_fungus.png",
groups = {dig_immediate = 3},
})
end
-- moon glass (glows)
if not minetest.registered_items['elixirs:moon_glass'] then
newnode = fun_caves_mod.clone_node("default:glass")
newnode.description = "Glowing Glass"
newnode.light_source = default.LIGHT_MAX
minetest.register_node("fun_caves:moon_glass", newnode)
end
-- Moon juice is extracted from glowing fungus, to make glowing materials.
minetest.register_craftitem("fun_caves:moon_juice", {
description = "Moon Juice",
drawtype = "plantlike",
paramtype = "light",
tiles = {"vmg_moon_juice.png"},
inventory_image = "vmg_moon_juice.png",
--groups = {dig_immediate = 3, attached_node = 1},
groups = {dig_immediate = 3, vessel = 1},
sounds = default.node_sound_glass_defaults(),
})
-- mushroom cap, giant
local cap = {
description = "Giant Mushroom Cap",
tiles = {"vmg_mushroom_giant_cap.png", "vmg_mushroom_giant_under.png", "vmg_mushroom_giant_cap.png"},
is_ground_content = false,
paramtype = "light",
drawtype = "nodebox",
node_box = { type = "fixed",
fixed = {
{-0.3, -0.25, -0.3, 0.3, 0.5, 0.3},
{-0.3, -0.25, -0.4, 0.3, 0.4, -0.3},
{-0.3, -0.25, 0.3, 0.3, 0.4, 0.4},
{-0.4, -0.25, -0.3, -0.3, 0.4, 0.3},
{0.3, -0.25, -0.3, 0.4, 0.4, 0.3},
{-0.4, -0.5, -0.4, 0.4, -0.25, 0.4},
{-0.5, -0.5, -0.4, -0.4, -0.25, 0.4},
{0.4, -0.5, -0.4, 0.5, -0.25, 0.4},
{-0.4, -0.5, -0.5, 0.4, -0.25, -0.4},
{-0.4, -0.5, 0.4, 0.4, -0.25, 0.5},
} },
light_source = light_max,
groups = {fleshy=1, falling_node = 1, dig_immediate=3, flammable=2, plant=1},
}
minetest.register_node("fun_caves:giant_mushroom_cap", cap)
-- mushroom cap, huge
minetest.register_node("fun_caves:huge_mushroom_cap", {
description = "Huge Mushroom Cap",
tiles = {"vmg_mushroom_giant_cap.png", "vmg_mushroom_giant_under.png", "vmg_mushroom_giant_cap.png"},
is_ground_content = false,
paramtype = "light",
drawtype = "nodebox",
node_box = { type = "fixed",
fixed = {
{-0.5, -0.5, -0.33, 0.5, -0.33, 0.33},
{-0.33, -0.5, 0.33, 0.33, -0.33, 0.5},
{-0.33, -0.5, -0.33, 0.33, -0.33, -0.5},
{-0.33, -0.33, -0.33, 0.33, -0.17, 0.33},
} },
light_source = light_max,
groups = {fleshy=1, falling_node = 1, dig_immediate=3, flammable=2, plant=1},
})
-- mushroom stem, giant or huge
minetest.register_node("fun_caves:giant_mushroom_stem", {
description = "Giant Mushroom Stem",
tiles = {"vmg_mushroom_giant_stem.png", "vmg_mushroom_giant_stem.png", "vmg_mushroom_giant_stem.png"},
is_ground_content = false,
groups = {choppy=2, flammable=2, plant=1},
sounds = default.node_sound_wood_defaults(),
sunlight_propagates = true,
paramtype = "light",
drawtype = "nodebox",
node_box = { type = "fixed", fixed = { {-0.25, -0.5, -0.25, 0.25, 0.5, 0.25}, }},
})
-- obsidian, glowing
minetest.register_node("fun_caves:glow_obsidian", {
description = "Glowing Obsidian",
tiles = {"caverealms_glow_obsidian.png"},
is_ground_content = true,
groups = {stone=2, crumbly=1},
--light_source = 7,
sounds = default.node_sound_stone_defaults({
footstep = {name="default_stone_footstep", gain=0.25},
}),
})
-- obsidian, glowing, 2 - has traces of lava
minetest.register_node("fun_caves:glow_obsidian_2", {
description = "Hot Glow Obsidian",
tiles = {"caverealms_glow_obsidian2.png"},
is_ground_content = true,
groups = {stone=2, crumbly=1, surface_hot=3, igniter=1},
damage_per_second = 1,
--light_source = 9,
sounds = default.node_sound_stone_defaults({
footstep = {name="default_stone_footstep", gain=0.25},
}),
})
-- salt
minetest.register_node("fun_caves:stone_with_salt", {
description = "Cave Stone with Salt",
tiles = {"caverealms_salty2.png"},
paramtype = "light",
use_texture_alpha = true,
drawtype = "glasslike",
sunlight_propagates = false,
is_ground_content = true,
groups = {stone=1, crumbly=3, cracky=3},
sounds = default.node_sound_glass_defaults(),
})
-- salt, radioactive ore
newnode = fun_caves_mod.clone_node("fun_caves:stone_with_salt")
newnode.description = "Salt With Radioactive Ore"
newnode.tiles = {"fun_caves_radioactive_ore.png"}
newnode.light_source = 4
minetest.register_node("fun_caves:radioactive_ore", newnode)
if minetest.registered_items['underworlds:thin_ice'] then
minetest.register_alias("fun_caves:thin_ice", 'underworlds:thin_ice')
else
-- ice, thin -- transparent
minetest.register_node("fun_caves:thin_ice", {
description = "Thin Ice",
tiles = {"caverealms_thin_ice.png"},
is_ground_content = true,
groups = {cracky=3},
sounds = default.node_sound_glass_defaults(),
use_texture_alpha = true,
light_source = 1,
drawtype = "glasslike",
sunlight_propagates = true,
freezemelt = "default:water_source",
paramtype = "light",
})
end
-- What's a cave without speleothems?
local spel = {
{type1="stalactite", type2="stalagmite", tile="default_stone.png"},
{type1="stalactite_slimy", type2="stalagmite_slimy", tile="default_stone.png^fun_caves_algae.png"},
{type1="stalactite_mossy", type2="stalagmite_mossy", tile="default_stone.png^fun_caves_moss.png"},
{type1="icicle_down", type2="icicle_up", desc="Icicle", tile="caverealms_thin_ice.png", drop="default:ice"},
}
if minetest.registered_items['underworlds:stalactite'] then
for _, desc in pairs(spel) do
minetest.register_alias("fun_caves:"..desc.type1, 'underworlds:'..desc.type1)
minetest.register_alias("fun_caves:"..desc.type2, 'underworlds:'..desc.type2)
end
else
for _, desc in pairs(spel) do
minetest.register_node("fun_caves:"..desc.type1, {
description = (desc.desc or "Stalactite"),
tiles = {desc.tile},
is_ground_content = true,
walkable = false,
paramtype = "light",
drop = (desc.drop or "fun_caves:stalactite"),
drawtype = "nodebox",
node_box = { type = "fixed",
fixed = {
{-0.07, 0.0, -0.07, 0.07, 0.5, 0.07},
{-0.04, -0.25, -0.04, 0.04, 0.0, 0.04},
{-0.02, -0.5, -0.02, 0.02, 0.25, 0.02},
} },
groups = {rock=1, cracky=3},
sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("fun_caves:"..desc.type2, {
description = (desc.desc or "Stalagmite"),
tiles = {desc.tile},
is_ground_content = true,
walkable = false,
paramtype = "light",
drop = "fun_caves:stalagmite",
drawtype = "nodebox",
node_box = { type = "fixed",
fixed = {
{-0.07, -0.5, -0.07, 0.07, 0.0, 0.07},
{-0.04, 0.0, -0.04, 0.04, 0.25, 0.04},
{-0.02, 0.25, -0.02, 0.02, 0.5, 0.02},
} },
groups = {rock=1, cracky=3},
sounds = default.node_sound_stone_defaults(),
})
end
end
-- spikes, hot -- silicon-based life
local spike_size = { 1.0, 1.2, 1.4, 1.6, 1.7 }
fun_caves_mod.hot_spikes = {}
for i in ipairs(spike_size) do
if i == 1 then
nodename = "fun_caves:hot_spike"
else
nodename = "fun_caves:hot_spike_"..i
end
fun_caves_mod.hot_spikes[#fun_caves_mod.hot_spikes+1] = nodename
vs = spike_size[i]
minetest.register_node(nodename, {
description = "Stone Spike",
tiles = {"fun_caves_hot_spike.png"},
inventory_image = "fun_caves_hot_spike.png",
wield_image = "fun_caves_hot_spike.png",
is_ground_content = true,
groups = {cracky=3, oddly_breakable_by_hand=1, surface_hot=3},
damage_per_second = 1,
sounds = default.node_sound_stone_defaults(),
paramtype = "light",
drawtype = "plantlike",
walkable = false,
light_source = i * 2,
buildable_to = true,
visual_scale = vs,
selection_box = {
type = "fixed",
fixed = {-0.5*vs, -0.5*vs, -0.5*vs, 0.5*vs, -5/16*vs, 0.5*vs},
}
})
end
fun_caves_mod.hot_spike = {}
for i = 1, #fun_caves_mod.hot_spikes do
fun_caves_mod.hot_spike[fun_caves_mod.hot_spikes[i]] = i
end
-- stone with algae
newnode = fun_caves_mod.clone_node("default:stone")
newnode.description = "Cave Stone With Algae"
newnode.tiles = {"default_stone.png^fun_caves_algae.png"}
newnode.groups = {stone=1, cracky=3, crumbly=3}
newnode.sounds = default.node_sound_dirt_defaults({
footstep = {name="default_grass_footstep", gain=0.25},
})
minetest.register_node("fun_caves:stone_with_algae", newnode)
if minetest.registered_items['underworlds:hot_stone'] then
minetest.register_alias("fun_caves:hot_stone", 'underworlds:hot_stone')
else
-- stone, hot
minetest.register_node("fun_caves:hot_stone", {
description = "Hot Stone",
tiles = {"default_desert_stone.png^[colorize:#FF0000:150"},
is_ground_content = true,
groups = {crumbly=2, surface_hot=3},
light_source = light_max - 5,
damage_per_second = 1,
sounds = default.node_sound_stone_defaults({
footstep = {name="default_stone_footstep", gain=0.25},
}),
})
end
-- stone with lichen
newnode = fun_caves_mod.clone_node("default:stone")
newnode.description = "Cave Stone With Lichen"
newnode.tiles = {"default_stone.png^fun_caves_lichen.png"}
newnode.groups = {stone=1, cracky=3, crumbly=3}
newnode.sounds = default.node_sound_dirt_defaults({
footstep = {name="default_grass_footstep", gain=0.25},
})
minetest.register_node("fun_caves:stone_with_lichen", newnode)
-- stone with moss
newnode = fun_caves_mod.clone_node("default:stone")
newnode.description = "Cave Stone With Moss"
newnode.tiles = {"default_stone.png^fun_caves_moss.png"}
newnode.groups = {stone=1, cracky=3, crumbly=3}
newnode.sounds = default.node_sound_dirt_defaults({
footstep = {name="default_grass_footstep", gain=0.25},
})
minetest.register_node("fun_caves:stone_with_moss", newnode)
------------------------------------
-- recipes
------------------------------------
-- Mushroom stems can be used as wood and leather,
-- ala Journey to the Center of the Earth.
minetest.register_craft({
output = "default:wood",
recipe = {
{"fun_caves:giant_mushroom_stem"}
}
})
if minetest.registered_items['mobs:leather'] then
minetest.register_craft({
output = "mobs:leather",
recipe = {
{"fun_caves:giant_mushroom_cap"}
}
})
end
minetest.register_craft({
output = "dye:red",
recipe = {
{"flowers:mushroom_red"}
}
})
--minetest.register_craft({
-- output = "dye:yellow",
-- recipe = {
-- {"flowers:mushroom_brown"}
-- }
--})
minetest.register_craft({
output = 'default:paper 6',
recipe = {
{'fun_caves:giant_mushroom_stem', 'fun_caves:giant_mushroom_stem', 'fun_caves:giant_mushroom_stem'},
}
})
-- Caps can be cooked and eaten.
minetest.register_node("fun_caves:mushroom_steak", {
description = "Mushroom Steak",
drawtype = "plantlike",
paramtype = "light",
tiles = {"vmg_mushroom_steak.png"},
inventory_image = "vmg_mushroom_steak.png",
on_use = minetest.item_eat(4),
--groups = {dig_immediate = 3, attached_node = 1},
groups = {dig_immediate = 3},
})
minetest.register_craft({
type = "cooking",
output = "fun_caves:mushroom_steak",
recipe = "fun_caves:huge_mushroom_cap",
cooktime = 2,
})
minetest.register_craft({
type = "cooking",
output = "fun_caves:mushroom_steak 2",
recipe = "fun_caves:giant_mushroom_cap",
cooktime = 2,
})
-- moon juice from fungus
minetest.register_craft({
output = "fun_caves:moon_juice",
recipe = {
{"fun_caves:glowing_fungus", "fun_caves:glowing_fungus", "fun_caves:glowing_fungus"},
{"fun_caves:glowing_fungus", "fun_caves:glowing_fungus", "fun_caves:glowing_fungus"},
{"fun_caves:glowing_fungus", "vessels:glass_bottle", "fun_caves:glowing_fungus"},
},
})
minetest.register_craft({
output = "fun_caves:moon_glass",
type = "shapeless",
recipe = {
"fun_caves:moon_juice",
"fun_caves:moon_juice",
"default:glass",
},
})
-- Speleothems can be made into cobblestone, to get them out of inventory.
minetest.register_craft({
output = "default:cobble",
recipe = {
{"", "", ""},
{"fun_caves:stalactite", "fun_caves:stalactite", ""},
{"fun_caves:stalactite", "fun_caves:stalactite", ""},
},
})
minetest.register_craft({
output = "default:cobble",
recipe = {
{"", "", ""},
{"fun_caves:stalagmite", "fun_caves:stalagmite", ""},
{"fun_caves:stalagmite", "fun_caves:stalagmite", ""},
},
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 661 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 330 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 724 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 424 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -1 +0,0 @@
Modified radioactive ore: everamzah

BIN
textures/screenshot.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 788 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 714 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 765 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB