Compare commits

...

23 Commits

Author SHA1 Message Date
trans_soup 6e205f15b7 slightly change readme. 2023-10-17 12:01:37 +02:00
trans_soup 31b2242c38 make leaves fall down when unsupported.
also refactor leaves registration code.
2023-10-17 11:25:13 +02:00
trans_soup d884e75a24 fix: account for moved api function.
change something that should've been changed before, when the api
function in question was moved.
2023-10-17 11:24:18 +02:00
trans_soup 19d63efcf5 refactor log registration.
rename log and sapling textures to be more clear. rewrite node
registration code to account for this, and to be overall cleaner.
2023-10-17 11:23:32 +02:00
trans_soup 5a3d81787c add several utility functions related to tables.
create api functions `any`, `every`, and `underride`.

`any` and `every` checks if a condition is true for any and every item
in a table, respectively.
`underride` returns a table that defaults to a provided table, for
items that aren't specified in the other provided table.
2023-10-17 11:19:55 +02:00
trans_soup 33fbd7c35e move `get_neighbors` from `util_node` to `util_vector`. 2023-10-17 11:19:03 +02:00
trans_soup d753612f0b separate falling node and loose node handling. 2023-10-17 11:18:14 +02:00
trans_soup 548d33d146 fix minor error. 2023-10-17 10:33:48 +02:00
trans_soup 18117daade make living logs have same texture as dead logs. 2023-10-17 10:30:12 +02:00
trans_soup aaeef448f0 make decomposing leaves sometimes not create dirt.
add a 1/2 chance for decomposing leaves to disappear instead of becoming
dirt.
2023-10-17 10:27:41 +02:00
trans_soup 5d98c3dadc add `growing_leaves` node.
create node representing growing leaves, and use it where previously
living leaves was used. this allows for a distinction between leaves
that will try to create more leaves, leaves that can provide nutrients
to other leaves, and leaves that are dead, whereas previously the first
2 of those couldn't be distinguished.
2023-10-17 10:26:15 +02:00
trans_soup 0ff0c9274f tweak leaves spread chance. 2023-10-17 10:19:27 +02:00
trans_soup 790e00ef5c rework sapling growth.
saplings now grow straight up and attempt to grow leaves on their sides.
2023-10-17 10:17:13 +02:00
trans_soup 5879ecbd67 add `get_sides_of` utility to api. 2023-10-17 10:16:12 +02:00
trans_soup 1ef3759ae6 tweak to leaves decomposition.
leaves will now start decomposing if they're touching either a dirty
node, or already decomposing leaves.
2023-10-17 10:15:13 +02:00
trans_soup 8dccef9389 refactor: fix modname being hard-coded into string. 2023-10-17 09:48:48 +02:00
trans_soup 20b2dfa0c7 refactor: remove unused locals. 2023-10-17 09:47:24 +02:00
trans_soup 8ff3df7f7f remove old sapling texture. 2023-10-17 09:46:14 +02:00
trans_soup d28bfbdaf3 add `root_alive` node. 2023-10-17 09:45:49 +02:00
trans_soup a3012de73f refactor: clean up leaves registration. 2023-10-17 09:44:42 +02:00
trans_soup c41d161802 make saplings look identical to living logs. 2023-10-17 09:43:25 +02:00
trans_soup 098e07a1e6 tweak running. 2023-10-16 21:59:12 +02:00
trans_soup 812e0a7e3b tweak leaves decomposition time. 2023-10-16 21:48:53 +02:00
18 changed files with 231 additions and 121 deletions

View File

@ -20,12 +20,12 @@ you can turn a log into planks by pummeling it with stone. there must be air on
you can grow a tree by placing a dirty node (dirt or grass) on top of a nut. this will create a sapling, which will grow into something vaguely resembling a tree (including roots in the ground). note that there's currently no way to get nuts, so you'll have to use cheats for now if you want trees.
you can create dirt by placing leaves next to dirt or grass; eventually they'll start decomposing. this does not work for growing leaves (which are unobtainable as an item anyways).
you can create dirt by placing leaves next to dirt or grass; eventually they'll start decomposing. this does not work for growing or living leaves (which are unobtainable as items anyways).
you start running over time as you move. this also makes you jump higher (although it does not make you take less fall damage).
# warning
updates might introduce changes that are not backwards-compatible. i'll probably use [semantic versioning](https://semver.org/) eventually.
updates might introduce changes that are not backwards-compatible. will probably use [semantic versioning](https://semver.org/) eventually.
i'll try to make sure new code includes ways of converting stuff in old worlds to work with the new code, but don't guarantee it.
will try to make sure new code includes ways of converting stuff in old worlds to work with the new code, but don't guarantee it.

View File

@ -0,0 +1,29 @@
-- TODO: collapse nodes when the node under them is removed.
local function attempt_collapse_at (pos, node)
node = node or minetest.get_node(pos)
local below = pos + blockgame.vector.dirs.down
if minetest.get_node(below).name ~= "air" then return end
local node_def = minetest.registered_nodes[node.name]
if type(node_def.fall_check) == "function" then
if not node_def.fall_check(pos, node) then return end
end
minetest.spawn_falling_node(pos)
end
-- collapse nodes that somehow managed to stay in the air.
blockgame.register_abm({
label = "collapse falling nodes",
nodenames = {"group:can_fall"},
neighbors = {"air"},
interval = 15,
chance = 1,
action = attempt_collapse_at,
})
return {
attempt_collapse_at = attempt_collapse_at,
}

View File

@ -17,7 +17,8 @@ load_file("util_node")
load_file("wrappers")
load_file("random_tick")
load_file("loose_nodes")
load_file("falling_node")
load_file("loose_node")
load_file("increasing_abm")
load_file("cleanup")

View File

@ -1,27 +1,7 @@
-- TODO: collapse nodes when the node under them is removed.
local fall_api = load_file("falling_node")
local attempt_collapse_at = fall_api.attempt_collapse_at
local function attempt_collapse_at (pos)
local below = pos + blockgame.vector.dirs.down
if minetest.get_node(below).name ~= "air" then return end
minetest.spawn_falling_node(pos)
end
local function place_loose_node (itemstack, placer, pointed)
local result = minetest.item_place(itemstack, placer, pointed)
attempt_collapse_at(pointed.above)
return result
end
-- collapse nodes that somehow managed to stay in the air.
blockgame.register_abm({
label = "collapse collapsible nodes",
nodenames = {"group:loose"},
neighbors = {"air"},
interval = 15,
chance = 1,
action = attempt_collapse_at,
})
local function attempt_settle_at (pos)
local below = pos + blockgame.vector.dirs.down
@ -33,13 +13,19 @@ end
-- settle nodes that are still (in the future, it will take some time for loose nodes that are still to settle).
blockgame.register_abm({
label = "settle collapsible nodes",
label = "settle loose nodes",
nodenames = {"group:loose"},
interval = 30,
chance = 10,
action = attempt_settle_at,
})
local function place_loose_node (itemstack, placer, pointed)
local result = minetest.item_place(itemstack, placer, pointed)
attempt_collapse_at(pointed.above)
return result
end
function blockgame.register_loose_version (name)
@ -51,6 +37,7 @@ function blockgame.register_loose_version (name)
groups[key] = value
end
groups.loose = 1
groups.can_fall = 1
blockgame.register_node(name .. "_loose", {
description = "Loose " .. def.description,

View File

@ -48,14 +48,3 @@ function blockgame.random_walk (data)
end
return pos
end
function blockgame.get_neighbors (pos, neighborhood)
neighborhood = neighborhood or blockgame.vector.dirs
local neighbors = {}
for _, dir in pairs(neighborhood) do
table.insert(neighbors, pos + dir)
end
return neighbors
end

View File

@ -26,3 +26,26 @@ function blockgame.shuffle (tab)
end
return result
end
function blockgame.any (tab, check)
for key, value in pairs(tab) do
if check(value, key, tab) then return true end
end
return false
end
function blockgame.every (tab, check)
for key, value in pairs(tab) do
if not check(value, key, tab) then return false end
end
return true
end
function blockgame.underride (tab, template)
local tab = tab or {}
local result = blockgame.shallow_copy_table(template)
for key, value in pairs(tab) do
result[key] = value
end
return result
end

View File

@ -34,3 +34,16 @@ end
function api.get_below (pos)
return pos + api.dirs.down
end
function api.get_neighbors (pos, neighborhood)
neighborhood = neighborhood or blockgame.vector.dirs
local neighbors = {}
for _, dir in pairs(neighborhood) do
table.insert(neighbors, pos + dir)
end
return neighbors
end
function api.get_sides_of (pos)
return api.get_neighbors(pos, api.sides)
end

View File

@ -1,12 +1,12 @@
local utils = load_file("util_misc")
local walk_speed = 1
local walk_time = 2
local walk_time = 4
local speedup_time = 6
local run_factor = 3
local slowdown_factor = 8
local run_factor = 2.5
local slowdown_factor = 12
local jump_height = 1
local jump_factor = 1.5
local jump_factor = 1.4
local speed_data = {}

View File

@ -10,10 +10,10 @@ local leaves_decomposing = modname .. ":leaves_decomposing"
-- END OF NODE NAMES
blockgame.register_increasing_abm({
id = "bg_tree:begin_decompose",
id = modname .. ":begin_decompose",
label = "decompose leaves",
nodenames = {leaves},
neighbors = {"group:dirty"},
neighbors = {"group:dirty", leaves_decomposing},
interval = 15,
chance = 4,
rate = function (pos, node, data)
@ -28,21 +28,25 @@ blockgame.register_increasing_abm({
})
blockgame.register_increasing_abm({
id = "bg_tree:decompose",
id = modname .. ":decompose",
label = "decompose leaves",
nodenames = {leaves_decomposing},
neighbors = {"group:dirty"},
interval = 30,
chance = 10,
interval = 20,
chance = 8,
rate = function (pos, node, data)
-- TODO: decompose faster depending on surrounding dirty nodes & other decomposing leaves.
-- can probably do that with a flood fill that counts up a "score" depending on the nodes it encounters.
return data.value + math.random(1, 9)
end,
check = function (pos, node, data)
return data.value >= 30
return data.value >= 25
end,
action = function (pos, node, data)
minetest.set_node(pos, {name = "bg_terrain:dirt"})
if blockgame.chance(2) then
minetest.set_node(pos, {name = "bg_terrain:dirt"})
else
minetest.remove_node(pos)
end
end,
})

View File

@ -64,33 +64,12 @@ blockgame.register_abm({
neighbors = {"group:dirty", log_alive},
interval = 15,
chance = 4,
action = function (pos, node, active_object_count, active_object_count_wider)
local below = vec.get_below(pos)
action = function (pos, node)
if blockgame.chance(4) then
local root_source = api.find_bottom_log(pos, 8)
if root_source ~= nil then
spread_roots_from(root_source + blockgame.vector.dirs.down)
end
end
if blockgame.chance(2) then
extend_leaves_from(pos)
end
if blockgame.chance(2) then
local side = vec.random_side()
local target = pos + side
blockgame.attempt_place(target, {name = log_alive})
end
if blockgame.chance(4) then
minetest.set_node(pos, {name = log_alive})
if minetest.get_node(below).name == log_alive and blockgame.chance(4) then return end
blockgame.attempt_place(pos + vector.new(0, 1, 0), {name = modname .. ":sapling"})
end
end,
})

View File

@ -1,23 +1,21 @@
local modname = minetest.get_current_modname()
local api = blockgame.tree
local vec = blockgame.vector
-- NODE NAMES
local log = modname .. ":log"
local log_alive = modname .. ":log_alive"
local leaves = modname .. ":leaves"
local leaves_growing = modname .. ":leaves_growing"
local leaves_alive = modname .. ":leaves_alive"
local root = modname .. ":root"
-- END OF NODE NAMES
local max_grow_distance = 2
-- TODO: turn this into an increasing ABM.
blockgame.register_abm({
label = "grow leaves",
nodenames = {leaves_alive},
neighbors = {log_alive, leaves_alive},
nodenames = {leaves_growing},
neighbors = {log_alive, leaves_growing, leaves_alive},
interval = 15,
chance = 8,
action = function (pos, node)
@ -26,12 +24,13 @@ blockgame.register_abm({
local distance = meta:get_int("leaf_distance") or 1
if distance >= max_grow_distance then return end
local neighbors = blockgame.get_neighbors(pos)
local neighbors = blockgame.vector.get_neighbors(pos)
for _, target in pairs(neighbors) do
if blockgame.chance(6) then
blockgame.attempt_place(target, {name = leaves_alive})
if blockgame.chance(2) then
blockgame.attempt_place(target, {name = leaves_growing})
minetest.get_meta(target):set_int("leaf_distance", distance + 1)
end
end
minetest.set_node(pos, {name = leaves_alive})
end,
})

View File

@ -0,0 +1,55 @@
local modname = minetest.get_current_modname()
-- NODE NAMES
local sapling = modname .. ":sapling"
local log_alive = modname .. ":log_alive"
local leaves_growing = modname .. ":leaves_growing"
local root_alive = modname .. ":root_alive"
-- END OF NODE NAMES
local function supports_sapling (name)
if name == log_alive or name == root_alive then return true end
return minetest.get_item_group(name, "dirty") > 0
end
blockgame.register_increasing_abm({
id = modname .. ":grow_sapling",
label = "grow sapling",
nodenames = {sapling},
neighbors = {"group:dirty", log_alive},
interval = 15,
chance = 4,
rate = function (pos, node, data)
-- TODO: find connected living logs and leaves, and nearby light levels, to calculate growth rate.
return data.value + math.random(1, 99)
end,
check = function (pos, node, data)
if data.value < 200 then return false end
local below = pos + blockgame.vector.dirs.down
local below_name = minetest.get_node(below).name
if not supports_sapling(below_name) then return false end
local above = pos + blockgame.vector.dirs.up
if minetest.get_node(above).name ~= "air" then return false end
return true
end,
action = function (pos, node, data)
-- TODO: decrease energy (`data.value`) when growing, but don't completely reset it to 0.
-- (this will require the api adding support for increasing_abm actions modifying their data.)
local above = pos + blockgame.vector.dirs.up
if not blockgame.chance(4) then
minetest.set_node(above, {name = sapling})
end
minetest.set_node(pos, {name = log_alive})
local sides = blockgame.vector.get_sides_of(pos)
for _, side in pairs(sides) do
blockgame.attempt_place(side, {name = leaves_growing})
end
end,
})

View File

@ -4,6 +4,7 @@ load_file("node")
load_file("decoration")
load_file("grow")
load_file("grow_sapling")
load_file("grow_leaves")
load_file("decompose")

View File

@ -1,59 +1,86 @@
local modname = minetest.get_current_modname()
blockgame.register_node(modname .. ":log", {
description = "Log",
tiles = {
modname .. "_log_top.png",
modname .. "_log_top.png",
modname .. "_log.png",
},
groups = {
local function reg_log (name, def)
def = def or {}
def.description = def.description or "Log"
local texture = def.texture or name
def.tiles = blockgame.underride(def.tiles, {
modname .. "_" .. texture .. "_top.png",
modname .. "_" .. texture .. "_top.png",
modname .. "_" .. texture .. ".png",
})
def.groups = blockgame.underride(def.groups, {
woody = 1,
supports_leaves = 1,
})
blockgame.register_node(modname .. ":" .. name, def)
end
reg_log("log")
reg_log("log_alive", {
groups = {
planty = 1,
},
texture = "log",
drop = modname .. ":log",
})
blockgame.register_node(modname .. ":log_alive", {
description = "Growing Log",
tiles = {
modname .. "_log_top_alive.png",
modname .. "_log_top_alive.png",
modname .. "_log_alive.png",
},
reg_log("sapling", {
groups = {
woody = 1,
planty = 1,
},
drop = modname .. ":log",
})
blockgame.reg_simple_node("sapling", "Sapling", {
planty = 1,
})
local function reg_leaves (name, desc, groups, drop)
blockgame.register_node(modname .. ":" .. name, {
description = desc,
drawtype = "glasslike",
tiles = {
modname .. "_" .. name .. ".png",
},
paramtype = "light",
sunlight_propagates = true,
groups = groups,
drop = drop,
})
local function leaves_fall_check (pos, node)
return blockgame.every(blockgame.vector.get_neighbors(pos), function (pos)
return minetest.get_item_group(minetest.get_node(pos).name, "supports_leaves") == 0
end)
end
reg_leaves("leaves", "Leaves", {
planty = 1,
air_flowable = 1,
local function reg_leaves (name, def)
def.description = def.description or name
def.texture = def.texture or name
def.tiles = {modname .. "_" .. def.texture .. ".png"}
def.drawtype = "glasslike"
def.paramtype = "light"
def.sunlight_propagates = true
def.groups = blockgame.underride(def.groups, {
planty = 1,
supports_leaves = 1,
air_flowable = 1,
can_fall = 1,
})
blockgame.register_node(modname .. ":" .. name, def)
end
reg_leaves("leaves", {
description = "Leaves",
})
reg_leaves("leaves_alive", "Growing Leaves", {
planty = 1,
air_flowable = 1,
}, modname .. ":leaves")
reg_leaves("leaves_decomposing", "Decomposing Leaves", {
planty = 1,
air_flowable = 1,
reg_leaves("leaves_growing", {
description = "Growing Leaves",
drop = modname .. ":leaves",
texture = "leaves_alive",
fall_check = leaves_fall_check,
})
reg_leaves("leaves_alive", {
description = "Leaves",
drop = modname .. ":leaves",
fall_check = leaves_fall_check,
})
reg_leaves("leaves_decomposing", {
description = "Decomposing Leaves",
groups = {
supports_leaves = 0,
},
})
blockgame.reg_simple_node("nut", "Nut", {
@ -63,3 +90,6 @@ blockgame.reg_simple_node("nut", "Nut", {
blockgame.reg_simple_node("root", "Root", {
woody = 1,
})
blockgame.reg_simple_node("root_alive", "Growing Root", {
woody = 1,
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 B

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB