From cd9926f9e53a2532296ff7019287559c3e7ea1ea Mon Sep 17 00:00:00 2001 From: Rogier Date: Wed, 18 May 2016 16:54:45 +0200 Subject: Restore previous pine as cedar Commit ad0cbbc0f disabled the previous moretrees pine, and aliased it to the default minetest pine. The default pine is a completely different tree though, with different apppearance and different textures. This commit restores the previous pine tree, renaming it to cedar to avoid a tree name clash with the default game. Any existing moretrees pine trees will be converted to cedar, so that their appearance does not change. Moretrees pine trees that have already been converted to the default pine tree are not converted back. --- biome_defs.lua | 2 +- crafts.lua | 10 +++++----- default_settings.txt | 2 +- init.lua | 8 ++++---- node_defs.lua | 12 +++++++----- textures/moretrees_cedar_cone.png | Bin 0 -> 315 bytes textures/moretrees_cedar_leaves.png | Bin 0 -> 205 bytes textures/moretrees_cedar_nuts.png | Bin 0 -> 369 bytes textures/moretrees_cedar_sapling.png | Bin 0 -> 202 bytes textures/moretrees_cedar_trunk.png | Bin 0 -> 1074 bytes textures/moretrees_cedar_trunk_top.png | Bin 0 -> 451 bytes textures/moretrees_cedar_wood.png | Bin 0 -> 648 bytes textures/moretrees_pine_cone.png | Bin 315 -> 0 bytes textures/moretrees_pine_nuts.png | Bin 369 -> 0 bytes tree_biomes.txt | 5 ++++- tree_models.lua | 8 ++++---- 16 files changed, 26 insertions(+), 21 deletions(-) create mode 100644 textures/moretrees_cedar_cone.png create mode 100644 textures/moretrees_cedar_leaves.png create mode 100644 textures/moretrees_cedar_nuts.png create mode 100644 textures/moretrees_cedar_sapling.png create mode 100644 textures/moretrees_cedar_trunk.png create mode 100644 textures/moretrees_cedar_trunk_top.png create mode 100644 textures/moretrees_cedar_wood.png delete mode 100644 textures/moretrees_pine_cone.png delete mode 100644 textures/moretrees_pine_nuts.png diff --git a/biome_defs.lua b/biome_defs.lua index 34d8e4e..48efee0 100644 --- a/biome_defs.lua +++ b/biome_defs.lua @@ -150,7 +150,7 @@ moretrees.spruce_biome = { max_count = 5, } -moretrees.pine_biome = { +moretrees.cedar_biome = { surface = "default:dirt_with_grass", avoid_nodes = moretrees.avoidnodes, avoid_radius = 10, diff --git a/crafts.lua b/crafts.lua index 515a097..395f602 100644 --- a/crafts.lua +++ b/crafts.lua @@ -80,9 +80,9 @@ minetest.register_craftitem("moretrees:spruce_nuts", { on_use = minetest.item_eat(1), }) -minetest.register_craftitem("moretrees:pine_nuts", { - description = S("Roasted Pine Cone Nuts"), - inventory_image = "moretrees_pine_nuts.png", +minetest.register_craftitem("moretrees:cedar_nuts", { + description = S("Roasted Cedar Cone Nuts"), + inventory_image = "moretrees_cedar_nuts.png", on_use = minetest.item_eat(1), }) @@ -138,8 +138,8 @@ minetest.register_craft({ minetest.register_craft({ type = "cooking", - output = "moretrees:pine_nuts 4", - recipe = "moretrees:pine_cone", + output = "moretrees:cedar_nuts 4", + recipe = "moretrees:cedar_cone", }) minetest.register_craft({ diff --git a/default_settings.txt b/default_settings.txt index a34ea23..1bb85f5 100644 --- a/default_settings.txt +++ b/default_settings.txt @@ -6,7 +6,7 @@ moretrees.enable_apple_tree = true moretrees.enable_oak = true moretrees.enable_sequoia = true moretrees.enable_palm = true -moretrees.enable_pine = true +moretrees.enable_cedar = true moretrees.enable_rubber_tree = true moretrees.enable_willow = true moretrees.enable_acacia = true diff --git a/init.lua b/init.lua index d2c5128..843958b 100644 --- a/init.lua +++ b/init.lua @@ -85,7 +85,7 @@ if moretrees.spawn_saplings then moretrees.spawn_oak_object = "moretrees:oak_sapling_ongen" moretrees.spawn_sequoia_object = "moretrees:sequoia_sapling_ongen" moretrees.spawn_palm_object = "moretrees:palm_sapling_ongen" - moretrees.spawn_pine_object = "moretrees:pine_sapling_ongen" + moretrees.spawn_cedar_object = "moretrees:cedar_sapling_ongen" moretrees.spawn_rubber_tree_object = "moretrees:rubber_tree_sapling_ongen" moretrees.spawn_willow_object = "moretrees:willow_sapling_ongen" moretrees.spawn_acacia_object = "moretrees:acacia_sapling_ongen" @@ -100,7 +100,7 @@ else moretrees.spawn_oak_object = moretrees.oak_model moretrees.spawn_sequoia_object = moretrees.sequoia_model moretrees.spawn_palm_object = moretrees.palm_model - moretrees.spawn_pine_object = moretrees.pine_model + moretrees.spawn_cedar_object = moretrees.cedar_model moretrees.spawn_rubber_tree_object = moretrees.rubber_tree_model moretrees.spawn_willow_object = moretrees.willow_model moretrees.spawn_acacia_object = moretrees.acacia_model @@ -131,8 +131,8 @@ if moretrees.enable_palm then biome_lib:register_generate_plant(moretrees.palm_biome, moretrees.spawn_palm_object) end -if moretrees.enable_pine then - biome_lib:register_generate_plant(moretrees.pine_biome, moretrees.spawn_pine_object) +if moretrees.enable_cedar then + biome_lib:register_generate_plant(moretrees.cedar_biome, moretrees.spawn_cedar_object) end if moretrees.enable_rubber_tree then diff --git a/node_defs.lua b/node_defs.lua index 8328bef..94b7ed0 100644 --- a/node_defs.lua +++ b/node_defs.lua @@ -10,12 +10,12 @@ moretrees.treelist = { {"birch", "Birch Tree"}, {"palm", "Palm Tree", "coconut", "Coconut", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 1.0 }, {"spruce", "Spruce Tree", "spruce_cone", "Spruce Cone", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 }, + {"cedar", "Cedar Tree", "cedar_cone", "Cedar Cone", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 }, {"willow", "Willow Tree"}, {"rubber_tree", "Rubber Tree"}, {"fir", "Douglas Fir", "fir_cone", "Fir Cone", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 }, {"jungletree", "Jungle Tree", nil, nil, nil, nil, "default_junglesapling.png" }, - {"pine", "Pine Tree", "pine_cone", "Pine Cone", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8, "default_pine_sapling.png" }, {"acacia", "Acacia Tree", nil, nil, nil, nil, "default_acacia_sapling.png" }, } @@ -424,7 +424,9 @@ minetest.register_alias("moretrees:acacia_planks", "default:acacia_wood") minetest.register_alias("moretrees:acacia_sapling", "default:acacia_sapling") minetest.register_alias("moretrees:acacia_leaves", "default:acacia_leaves") -minetest.register_alias("moretrees:pine_trunk", "default:pine_tree") -minetest.register_alias("moretrees:pine_planks", "default:pine_wood") -minetest.register_alias("moretrees:pine_sapling", "default:pine_sapling") -minetest.register_alias("moretrees:pine_leaves", "default:pine_needles") +minetest.register_alias("moretrees:pine_trunk", "moretrees:cedar_trunk") +minetest.register_alias("moretrees:pine_planks", "moretrees:cedar_planks") +minetest.register_alias("moretrees:pine_sapling", "moretrees:cedar_sapling") +minetest.register_alias("moretrees:pine_leaves", "moretrees:cedar_leaves") +minetest.register_alias("moretrees:pine_cone", "moretrees:cedar_cone") +minetest.register_alias("moretrees:pine_nuts", "moretrees:cedar_nuts") diff --git a/textures/moretrees_cedar_cone.png b/textures/moretrees_cedar_cone.png new file mode 100644 index 0000000..5e1fae9 Binary files /dev/null and b/textures/moretrees_cedar_cone.png differ diff --git a/textures/moretrees_cedar_leaves.png b/textures/moretrees_cedar_leaves.png new file mode 100644 index 0000000..e6de482 Binary files /dev/null and b/textures/moretrees_cedar_leaves.png differ diff --git a/textures/moretrees_cedar_nuts.png b/textures/moretrees_cedar_nuts.png new file mode 100644 index 0000000..e39f895 Binary files /dev/null and b/textures/moretrees_cedar_nuts.png differ diff --git a/textures/moretrees_cedar_sapling.png b/textures/moretrees_cedar_sapling.png new file mode 100644 index 0000000..42f8ecc Binary files /dev/null and b/textures/moretrees_cedar_sapling.png differ diff --git a/textures/moretrees_cedar_trunk.png b/textures/moretrees_cedar_trunk.png new file mode 100644 index 0000000..ea685e3 Binary files /dev/null and b/textures/moretrees_cedar_trunk.png differ diff --git a/textures/moretrees_cedar_trunk_top.png b/textures/moretrees_cedar_trunk_top.png new file mode 100644 index 0000000..01aed1d Binary files /dev/null and b/textures/moretrees_cedar_trunk_top.png differ diff --git a/textures/moretrees_cedar_wood.png b/textures/moretrees_cedar_wood.png new file mode 100644 index 0000000..8680bd5 Binary files /dev/null and b/textures/moretrees_cedar_wood.png differ diff --git a/textures/moretrees_pine_cone.png b/textures/moretrees_pine_cone.png deleted file mode 100644 index 5e1fae9..0000000 Binary files a/textures/moretrees_pine_cone.png and /dev/null differ diff --git a/textures/moretrees_pine_nuts.png b/textures/moretrees_pine_nuts.png deleted file mode 100644 index e39f895..0000000 Binary files a/textures/moretrees_pine_nuts.png and /dev/null differ diff --git a/tree_biomes.txt b/tree_biomes.txt index 3e4533c..fdba90d 100644 --- a/tree_biomes.txt +++ b/tree_biomes.txt @@ -11,7 +11,7 @@ oak 0 to +10 + 4 to +16 n/a n/a dirt_with grass 332 15 sequoia 0 to +10 -30 to +50 n/a n/a dirt_with grass 333 10 birch +10 to +15 -20 to +10 n/a n/a dirt_with grass 334 5 spruce above +20 -20 to +10 n/a n/a dirt_with grass 335 10 -pine n/a n/a water, 15 5 dirt_with grass 336 10 +cedar n/a n/a water, 15 5 dirt_with grass 336 10 willow - 5 to + 5 n/a water, 15 5 dirt_with grass 337 20 acacia n/a n/a n/a n/a dirt_with_grass, desert_sand n/a 15 @@ -32,3 +32,6 @@ where the humidity is low (but not bone dry). Fir trees appear in a snow biome only with older versions of SPlizard's Snow Biomes mod. In more recent versions, these trees will not grow, due to an engine bug. + +Cedar trees replace, and are identical to, the original pine trees, as the minetest default game now has (a completely +different type of) pine trees. diff --git a/tree_models.lua b/tree_models.lua index 3443057..c534089 100644 --- a/tree_models.lua +++ b/tree_models.lua @@ -138,20 +138,20 @@ moretrees.spruce_model2={ fruit_chance=8 } -moretrees.pine_model={ +moretrees.cedar_model={ axiom="FFFFFcccdddB///cFdFB////cFdFB///cFdFB///cFdFA///cFdFA///cFdFB[FF]f", rules_a="[&&&TTTT[++^TFdd][--&TFd]//Tdd[+^Fd][--&Fdd]]", rules_b="[&&&TTT[++^Fdd][--&Fdd]//dd[+^d][--&Fd]]", rules_c="/", rules_d="F", - trunk="default:pine_tree", - leaves="default:pine_needles", + trunk="moretrees:cedar_trunk", + leaves="moretrees:cedar_leaves", angle=30, iterations=2, random_level=0, trunk_type="single", thin_branches=true, - fruit="moretrees:pine_cone", + fruit="moretrees:cedar_cone", fruit_chance=8 } -- cgit v1.2.3 From 9ced339ce5cbdc48a7d9417786585f6f9c968ce1 Mon Sep 17 00:00:00 2001 From: Rogier Date: Mon, 27 Jun 2016 23:21:29 +0200 Subject: Add dependency on vessels mod Acorn coconut milk and muffin batter recipes use a drinking glass. --- depends.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/depends.txt b/depends.txt index c666762..6d36526 100644 --- a/depends.txt +++ b/depends.txt @@ -1,5 +1,6 @@ default biome_lib +vessels stairs? moreblocks? intllib? -- cgit v1.2.3 From afab0692df2d99c36473568602d1cc4059aa2e65 Mon Sep 17 00:00:00 2001 From: Rogier Date: Wed, 18 May 2016 22:54:19 +0200 Subject: Add date palm Spawns in hot and dry desert, but requires water. This makes it a bit harder to find, but where found, it can be more abundant. If found in the middle of a desert, its presence indicates a water source below the surface. As an additional optional feature, dates (slowly) grow back after harvesting. --- LICENSE | 7 + biome_defs.lua | 34 ++ crafts.lua | 6 + date_palm.lua | 731 +++++++++++++++++++++++++++++ default_settings.txt | 25 + init.lua | 8 + node_defs.lua | 5 + textures/moretrees_date.png | Bin 0 -> 2118 bytes textures/moretrees_date_palm_leaves.png | Bin 0 -> 757 bytes textures/moretrees_date_palm_sapling.png | Bin 0 -> 261 bytes textures/moretrees_date_palm_trunk.png | Bin 0 -> 1196 bytes textures/moretrees_date_palm_trunk_top.png | Bin 0 -> 673 bytes textures/moretrees_date_palm_wood.png | Bin 0 -> 735 bytes textures/moretrees_dates.png | Bin 0 -> 9421 bytes textures/moretrees_dates_f0.png | Bin 0 -> 3848 bytes textures/moretrees_dates_f1.png | Bin 0 -> 4137 bytes textures/moretrees_dates_f2.png | Bin 0 -> 9070 bytes textures/moretrees_dates_f3.png | Bin 0 -> 8295 bytes textures/moretrees_dates_f4.png | Bin 0 -> 9237 bytes textures/moretrees_dates_fn.png | Bin 0 -> 2589 bytes textures/moretrees_dates_m0.png | Bin 0 -> 4138 bytes textures/moretrees_dates_n.png | Bin 0 -> 2107 bytes tree_biomes.txt | 2 + tree_models.lua | 25 + 24 files changed, 843 insertions(+) create mode 100644 date_palm.lua create mode 100644 textures/moretrees_date.png create mode 100644 textures/moretrees_date_palm_leaves.png create mode 100644 textures/moretrees_date_palm_sapling.png create mode 100644 textures/moretrees_date_palm_trunk.png create mode 100644 textures/moretrees_date_palm_trunk_top.png create mode 100644 textures/moretrees_date_palm_wood.png create mode 100644 textures/moretrees_dates.png create mode 100644 textures/moretrees_dates_f0.png create mode 100644 textures/moretrees_dates_f1.png create mode 100644 textures/moretrees_dates_f2.png create mode 100644 textures/moretrees_dates_f3.png create mode 100644 textures/moretrees_dates_f4.png create mode 100644 textures/moretrees_dates_fn.png create mode 100644 textures/moretrees_dates_m0.png create mode 100644 textures/moretrees_dates_n.png diff --git a/LICENSE b/LICENSE index c4742e6..7966b3f 100644 --- a/LICENSE +++ b/LICENSE @@ -4,6 +4,13 @@ Minetest mod moretrees All source code: © 2013, Vanessa Ezekowitz Published under the terms and conditions of the WTFPL. +Date palm code (date_palm.lua) + © 2016, Rogier + Published under the terms and conditions of the WTFPL. +All date palm textures: + © 2016, Rogier + Published under the terms and conditions of CC-BY-SA-3.0 Unported. + - Three of the date palm textures are modifications of existing moretrees textures All sapling textures (textures/*_sapling.png): © 2013, Tim Huppertz Published under the terms and conditions of CC-BY-SA-3.0 Unported. diff --git a/biome_defs.lua b/biome_defs.lua index 48efee0..46228f5 100644 --- a/biome_defs.lua +++ b/biome_defs.lua @@ -24,6 +24,40 @@ moretrees.palm_biome = { max_count = 10, } +moretrees.date_palm_biome = { + surface = "default:desert_sand", + avoid_nodes = moretrees.avoidnodes, + avoid_radius = 10, + seed_diff = 339, + min_elevation = -1, + max_elevation = 10, + near_nodes = {"default:water_source"}, + near_nodes_size = 20, + near_nodes_count = 100, + near_nodes_vertical = 20, + temp_min = -0.20, + humidity_max = 0.20, + rarity = 10, + max_count = 30, +} + +moretrees.date_palm_biome_2 = { + surface = "default:desert_sand", + avoid_nodes = moretrees.avoidnodes, + avoid_radius = 10, + seed_diff = 340, + min_elevation = 11, + max_elevation = 30, + near_nodes = {"default:water_source"}, + near_nodes_size = 1, + near_nodes_count = 1, + near_nodes_vertical = 30, + temp_min = -0.20, + humidity_max = 0.20, + rarity = 10, + max_count = 30, +} + moretrees.apple_tree_biome = { surface = "default:dirt_with_grass", avoid_nodes = moretrees.avoidnodes, diff --git a/crafts.lua b/crafts.lua index 395f602..68b556e 100644 --- a/crafts.lua +++ b/crafts.lua @@ -63,6 +63,12 @@ minetest.register_craftitem("moretrees:raw_coconut", { on_use = minetest.item_eat(4), }) +minetest.register_craftitem("moretrees:date", { + description = S("Date"), + inventory_image = "moretrees_date.png", + on_use = minetest.item_eat(1), +}) + minetest.register_craftitem("moretrees:acorn_muffin_batter", { description = S("Acorn Muffin batter"), inventory_image = "moretrees_acorn_muffin_batter.png", diff --git a/date_palm.lua b/date_palm.lua new file mode 100644 index 0000000..a0e574f --- /dev/null +++ b/date_palm.lua @@ -0,0 +1,731 @@ +-- Date palms. +-- +-- Date palms grow in hot and dry desert, but they require water. This makes them +-- a bit harder to find. If found in the middle of the desert, their presence +-- indicates a water source below the surface. +-- +-- As an additional feature (which can be disabled), dates automatically regrow after +-- harvesting (provided a male tree is sufficiently nearby). +-- If regrowing is enabled, then ripe dates will not hang forever. Most will disappear +-- (e.g. eaten by birds, ...), and a small fraction will drop as items. + +-- © 2016, Rogier +-- License: WTFPL + +local S = moretrees.intllib + +-- Some constants + +local dates_drop_ichance = 4 +local stems_drop_ichance = 4 +local flowers_wither_ichance = 3 + +-- implementation + +-- Make the date palm fruit trunk a real trunk (it is generated as a fruit) +local trunk = minetest.registered_nodes["moretrees:date_palm_trunk"] +local ftrunk = {} +local fftrunk = {} +local mftrunk = {} +for k,v in pairs(trunk) do + ftrunk[k] = v +end +ftrunk.tiles = {} +for k,v in pairs(trunk.tiles) do + ftrunk.tiles[k] = v +end +ftrunk.drop = "moretrees:date_palm_trunk" +ftrunk.after_destruct = function(pos, oldnode) + local dates = minetest.find_nodes_in_area({x=pos.x-2, y=pos.y, z=pos.z-2}, {x=pos.x+2, y=pos.y, z=pos.z+2}, {"group:moretrees_dates"}) + for _,datespos in pairs(dates) do + -- minetest.dig_node(datespos) does not cause nearby dates to be dropped :-( ... + local items = minetest.get_node_drops(minetest.get_node(datespos).name) + minetest.remove_node(datespos) + for _, itemname in pairs(items) do + minetest.add_item(datespos, itemname) + end + end +end +for k,v in pairs(ftrunk) do + mftrunk[k] = v + fftrunk[k] = v +end +fftrunk.tiles = {} +mftrunk.tiles = {} +for k,v in pairs(trunk.tiles) do + fftrunk.tiles[k] = v + mftrunk.tiles[k] = v +end +-- Make the different types of trunk distinguishable (but not too easily) +ftrunk.tiles[1] = "moretrees_date_palm_trunk_top.png^[transformR180" +ftrunk.description = ftrunk.description.." (gen)" +fftrunk.tiles[1] = "moretrees_date_palm_trunk_top.png^[transformR90" +mftrunk.tiles[1] = "moretrees_date_palm_trunk_top.png^[transformR-90" +minetest.register_node("moretrees:date_palm_fruit_trunk", ftrunk) +minetest.register_node("moretrees:date_palm_ffruit_trunk", fftrunk) +minetest.register_node("moretrees:date_palm_mfruit_trunk", mftrunk) + +-- ABM to grow new date blossoms +local date_regrow_abm_spec = { + nodenames = { "moretrees:date_palm_ffruit_trunk", "moretrees:date_palm_mfruit_trunk" }, + interval = moretrees.dates_flower_interval, + chance = moretrees.dates_flower_chance, + action = function(pos, node, active_object_count, active_object_count_wider) + local dates = minetest.find_nodes_in_area({x=pos.x-2, y=pos.y, z=pos.z-2}, {x=pos.x+2, y=pos.y, z=pos.z+2}, "group:moretrees_dates") + + -- New blossom interval increases exponentially with number of dates already hanging + -- In addition: if more dates are hanging, the chance of picking an empty spot decreases as well... + if math.random(2^#dates) <= 2 then + -- Grow in area of 5x5 round trunk; higher probability in 3x3 area close to trunk + local dx=math.floor((math.random(50)-18)/16) + local dz=math.floor((math.random(50)-18)/16) + local datepos = {x=pos.x+dx, y=pos.y, z=pos.z+dz} + local datenode = minetest.get_node(datepos) + if datenode.name == "air" then + if node.name == "moretrees:date_palm_ffruit_trunk" then + minetest.set_node(datepos, {name="moretrees:dates_f0"}) + else + minetest.set_node(datepos, {name="moretrees:dates_m0"}) + end + end + end + end +} +if moretrees.dates_regrow then + minetest.register_abm(date_regrow_abm_spec) +end + +-- Choose male or female palm, and spawn initial dates +-- (Instead of dates, a dates fruit trunk is generated with the tree. This +-- ABM converts the trunk to a female or male fruit trunk, and spawns some +-- hanging dates) +minetest.register_abm({ + nodenames = { "moretrees:date_palm_fruit_trunk" }, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local type + if math.random(100) <= moretrees.dates_female_percent then + type = "f" + minetest.swap_node(pos, {name="moretrees:date_palm_ffruit_trunk"}) + else + type = "m" + minetest.swap_node(pos, {name="moretrees:date_palm_mfruit_trunk"}) + end + local dates1 = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, "air") + local genpos + for _,genpos in pairs(dates1) do + if math.random(100) <= 20 then + if type == "m" then + minetest.set_node(genpos, {name = "moretrees:dates_n"}) + else + minetest.set_node(genpos, {name = "moretrees:dates_f4"}) + end + end + end + local dates2 = minetest.find_nodes_in_area({x=pos.x-2, y=pos.y, z=pos.z-2}, {x=pos.x+2, y=pos.y, z=pos.z+2}, "air") + for _,genpos in pairs(dates2) do + if math.random(100) <= 5 then + if type == "m" then + minetest.set_node(genpos, {name = "moretrees:dates_n"}) + else + minetest.set_node(genpos, {name = "moretrees:dates_f4"}) + end + end + end + end, +}) + +-- Dates growing functions. + +-- This is a bit complex, as the purpose is to find male flowers at horizontal distances of over +-- 100 nodes. As searching such a large area is time consuming, this is optimized in four ways: +-- - The search result (the locations of male trees) is cached, so that it can be used again +-- - Only 1/9th of the desired area is searched at a time. A new search is only performed if no male +-- flowers are found in the previously searched parts. +-- - Search results are shared with other female palms nearby. +-- - If previous searches for male palms have consumed too much CPU time, the search is skipped +-- (This means no male palms will be found, and the pollination of the flowers affected will be +-- delayed. If this happens repeatedly, eventually, the female flowers will wither...) +-- A caching method was selected that is suited for the case where most date trees are long-lived, +-- and where the number of trees nearby is limited: +-- - Locations of male palms are stored as metadata for every female palm. This means that a player +-- visiting a remote area with some date palms will not cause extensive searches for male palms as +-- long overdue blossoming ABMs are triggered for every date palm. +-- - Even when male palms *are* cut down, a cache refill will only be performed if the cached results do not +-- contain a male palm with blossoms. +-- The method will probably perform suboptimally: +-- - If female palms are frequently chopped down and replanted. +-- Freshly grown palms will need to search for male palms again +-- (this is mitigated by the long blossoming interval, which increases the chance that search +-- results have already been shared) +-- - If an area contains a large number of male and female palms. +-- In this area, every female palm will have an almost identical list of male palm locations +-- as metadata. +-- - If all male palms within range of a number of female palms have been chopped down (with possibly +-- new ones planted). Although an attempt was made to share search results in this case as well, +-- a number of similar searches will unavoidably be performed by the different female palms. +-- - If no male palms are in range of a female palm. In that case, there will be frequent searches +-- for newly-grown male palms. + +-- Search statistics - used to limit the search load. +local sect_search_stats = {} -- Search statistics - server-wide +local function reset_sect_search_stats() + sect_search_stats.count = 0 -- # of searches + sect_search_stats.skip = 0 -- # of times skipped + sect_search_stats.sum = 0 -- total time spent + sect_search_stats.min = 999999999 -- min time spent + sect_search_stats.max = 0 -- max time spent +end +reset_sect_search_stats() +sect_search_stats.last_us = 0 -- last time a search was done (microseconds, max: 2^32) +sect_search_stats.last_s = 0 -- last time a search was done (system time in seconds) + +-- Find male trunks in one section (=1/9 th) of the searchable area. +-- sect is -4 to 4, where 0 is the center section +local function find_fruit_trunks_near(ftpos, sect) + local r = moretrees.dates_pollination_distance + 2 * math.sqrt(2) + local sect_hr = math.floor(r / 3 + 0.9999) + local sect_vr = math.floor(r / 2 + 0.9999) + local t0us = core.get_us_time() + local t0s = os.time() + + -- Compute elapsed time since last search. + -- Unfortunately, the time value wraps after about 71 minutes (2^32 microseconds), + -- so it must be corrected to obtain the actual elapsed time. + if t0us < sect_search_stats.last_us then + -- Correct a simple wraparound. + -- This is not sufficient, as the time value may have wrapped more than once... + sect_search_stats.last_us = sect_search_stats.last_us - 2^32 + end + if t0s - sect_search_stats.last_s > 2^32/1000000 then + -- One additional correction is enough for our purposes. + -- For exact results, more corrections may be needed though... + -- (and even not applying this correction at all would still only yield + -- a minimal risk of a non-serious miscalculation...) + sect_search_stats.last_us = sect_search_stats.last_us - 2^32 + end + + -- Skip the search if it is consuming too much CPU time + if sect_search_stats.count > 0 and moretrees.dates_blossom_search_iload > 0 + and sect_search_stats.sum / sect_search_stats.count > moretrees.dates_blossom_search_time_treshold + and t0us - sect_search_stats.last_us < moretrees.dates_blossom_search_iload * (sect_search_stats.sum / sect_search_stats.count) then + sect_search_stats.skip = sect_search_stats.skip + 1 + return nil + end + + local all_palms = minetest.find_nodes_in_area( + { x = ftpos.x + 2 * sect.x * sect_hr - sect_hr, + y = ftpos.y - sect_vr, + z = ftpos.z + 2 * sect.z * sect_hr - sect_hr }, + { x = ftpos.x + 2 * sect.x * sect_hr + sect_hr, + y = ftpos.y + sect_vr, + z = ftpos.z + 2 * sect.z * sect_hr + sect_hr }, + {"moretrees:date_palm_mfruit_trunk", "moretrees:date_palm_ffruit_trunk"}) + + -- Collect different palms in separate lists. + local female_palms = {} + local male_palms = {} + local all_male_palms = {} + for _, pos in pairs(all_palms) do + if pos.x ~= ftpos.x or pos.y ~= ftpos.y or pos.z ~= ftpos.z then + local node = minetest.get_node(pos) + if node and node.name == "moretrees:date_palm_ffruit_trunk" then + table.insert(female_palms,pos) + elseif node then + table.insert(all_male_palms,pos) + -- In sector 0, all palms are of interest. + -- In other sectors, forget about palms that are too far away. + if sect == 0 then + table.insert(male_palms,pos) + else + local ssq = 0 + for _, c in pairs({"x", "z"}) do + local dc = pos[c] - ftpos[c] + ssq = ssq + dc * dc + end + if math.sqrt(ssq) <= r then + table.insert(male_palms,pos) + end + end + end + end + end + + -- Update search statistics + local t1us = core.get_us_time() + if t1us < t0us then + -- Wraparound. Assume the search lasted less than 2^32 microseconds (~71 min) + -- (so no need to apply another correction) + t0us = t0us - 2^32 + end + sect_search_stats.last_us = t0us + sect_search_stats.last_s = t0s + sect_search_stats.count = sect_search_stats.count + 1 + sect_search_stats.sum = sect_search_stats.sum + t1us-t0us + if t1us - t0us < sect_search_stats.min then + sect_search_stats.min = t1us - t0us + end + if t1us - t0us > sect_search_stats.max then + sect_search_stats.max = t1us - t0us + end + + return male_palms, female_palms, all_male_palms +end + +local function dates_print_search_stats(log) + local stats + if sect_search_stats.count > 0 then + stats = string.format("Male date tree searching stats: count: %d/%d: average: %d µs (%d..%d)", + sect_search_stats.count, sect_search_stats.count + sect_search_stats.skip, + sect_search_stats.sum/sect_search_stats.count, sect_search_stats.min, sect_search_stats.max) + else + stats = string.format("Male date tree searching stats: (not yet available)") + end + if log then + minetest.log("action", "[moretrees] " .. stats) + end + return true, stats +end + +minetest.register_chatcommand("dates_stats", { + description = "Print male date palm search statistics", + params = "|chat|log|reset", + privs = { server = true }, + func = function(name, param) + param = string.lower(string.trim(param)) + if param == "" or param == "chat" then + return dates_print_search_stats(false) + elseif param == "log" then + return dates_print_search_stats(true) + elseif param == "reset" then + reset_sect_search_stats() + return true + else + return false, "Invalid subcommand; expected: '' or 'chat' or 'log' or 'reset'" + end + end, +}) + +-- Find the female trunk near the female flowers to be pollinated +local function find_female_trunk(fbpos) + local trunks = minetest.find_nodes_in_area({x=fbpos.x-2, y=fbpos.y, z=fbpos.z-2}, + {x=fbpos.x+2, y=fbpos.y, z=fbpos.z+2}, + "moretrees:date_palm_ffruit_trunk") + local ftpos + local d = 99 + for x, pos in pairs(trunks) do + local ssq = 0 + for _, c in pairs({"x", "z"}) do + local dc = pos[c] - fbpos[c] + ssq = ssq + dc * dc + end + if math.sqrt(ssq) < d then + ftpos = pos + d = math.sqrt(ssq) + end + end + return ftpos +end + +-- Find male blossom near a male trunk, +-- the male blossom must be in range of a specific female blossom as well +local function find_male_blossom_near_trunk(fbpos, mtpos) + local r = moretrees.dates_pollination_distance + local blossoms = minetest.find_nodes_in_area({x=mtpos.x-2, y=mtpos.y, z=mtpos.z-2}, + {x=mtpos.x+2, y=mtpos.y, z=mtpos.z+2}, + "moretrees:dates_m0") + for x, mbpos in pairs(blossoms) do + local ssq = 0 + for _, c in pairs({"x", "z"}) do + local dc = mbpos[c] - fbpos[c] + ssq = ssq + dc * dc + end + if math.sqrt(ssq) <= r then + return mbpos + end + end + +end + +-- Find a male blossom in range of a specific female blossom, +-- using a nested list of male blossom positions +local function find_male_blossom_in_mpalms(ftpos, fbpos, mpalms) + -- Process the elements of mpalms.sect (index -4 .. 4) in random order + -- First, compute the order in which the sectors will be searched + local sect_index = {} + local sect_rnd = {} + for i = -4,4 do + local n = math.random(1023) + sect_index[n] = i + table.insert(sect_rnd, n) + end + table.sort(sect_rnd) + + -- Search the sectors + local sect_old = 0 + local sect_time = minetest.get_gametime() + for _, n in pairs(sect_rnd) do + -- Record the oldest sector, so that it can be searched if no male + -- blossoms were found + if not mpalms.sect_time[sect_index[n]] then + sect_old = sect_index[n] + sect_time = 0 + elseif mpalms.sect_time[sect_index[n]] < sect_time then + sect_old = sect_index[n] + sect_time = mpalms.sect_time[sect_index[n]] + end + if mpalms.sect[sect_index[n]] and #mpalms.sect[sect_index[n]] then + for px, mtpos in pairs(mpalms.sect[sect_index[n]]) do + local node = minetest.get_node(mtpos) + if node and node.name == "moretrees:date_palm_mfruit_trunk" then + local mbpos = find_male_blossom_near_trunk(fbpos, mtpos) + if mbpos then + return mbpos + end + elseif node and node.name ~= "ignore" then + -- no more male trunk here. + mpalms.sect[sect_index[n]][px] = nil + end + end + end + end + return nil, sect_old +end + +-- Find a male blossom in range of a specific female blossom, +-- using the cache associated with the given female trunk +-- If necessary, recompute part of the cache +local last_search_result = {} +local function find_male_blossom_with_ftrunk(fbpos,ftpos) + local meta = minetest.get_meta(ftpos) + local mpalms + local cache_changed = true + + -- Load cache. If distance has changed, start with empty cache instead. + local mpalms_dist = meta:get_int("male_palms_dist") + if mpalms_dist and mpalms_dist == moretrees.dates_pollination_distance then + mpalms = meta:get_string("male_palms") + if mpalms and mpalms ~= "" then + mpalms = minetest.deserialize(mpalms) + cache_changed = false + end + end + if not mpalms or not mpalms.sect then + mpalms = {} + mpalms.sect = {} + mpalms.sect_time = {} + meta:set_int("male_palms_dist", moretrees.dates_pollination_distance) + cache_changed = true + end + local fpalms_list + local all_mpalms_list + local sector0_searched = false + + -- Always make sure that sector 0 is cached + if not mpalms.sect[0] then + mpalms.sect[0], fpalms_list, all_mpalms_list = find_fruit_trunks_near(ftpos, {x = 0, z = 0}) + mpalms.sect_time[0] = minetest.get_gametime() + sector0_searched = true + cache_changed = true + last_search_result.female = fpalms_list + last_search_result.male = all_mpalms_list + end + + -- Find male palms + local mbpos, sect_old = find_male_blossom_in_mpalms(ftpos, fbpos, mpalms) + + -- If not found, (re)generate the cache for an additional sector. But don't search it yet (for performance reasons) + -- (Use the globally cached results if possible) + if not mbpos and not sector0_searched then + if not mpalms.sect_time[0] or mpalms.sect_time[0] == 0 or math.random(3) == 1 then + -- Higher probability of re-searching the center sector + sect_old = 0 + end + -- Use globally cached result if possible + mpalms.sect[sect_old] = nil + if sect_old == 0 and mpalms.sect_time[0] and mpalms.sect_time[0] > 0 + and last_search_result.male and #last_search_result.male then + for _, pos in pairs(last_search_result.female) do + if pos.x == ftpos.x and pos.y == ftpos.y and pos.z == ftpos.z then + mpalms.sect[sect_old] = last_search_result.male + -- Next time, don't use the cached result + mpalms.sect_time[sect_old] = nil + cache_changed = true + end + end + end + -- Else do a new search + if not mpalms.sect[sect_old] then + mpalms.sect[sect_old], fpalms_list, all_mpalms_list = find_fruit_trunks_near(ftpos, {x = (sect_old + 4) % 3 - 1, z = (sect_old + 4) / 3 - 1}) + cache_changed = true + if sect_old == 0 then + -- Save the results if it is sector 0 + -- (chance of reusing results from another sector are smaller) + last_search_result.female = fpalms_list + last_search_result.male = all_mpalms_list + end + if mpalms.sect[sect_old] then + mpalms.sect_time[sect_old] = minetest.get_gametime() + else + mpalms.sect_time[sect_old] = nil + end + end + end + + -- Share search results with other female trunks in the same area + -- Note that the list of female trunks doesn't (shouldn't :-) contain the current female trunk. + if fpalms_list and #fpalms_list and #all_mpalms_list then + local all_mpalms = {} + all_mpalms.sect = {} + all_mpalms.sect_time = {} + all_mpalms.sect[0] = all_mpalms_list + -- Don't set sect_time[0], so that the cached sector will be re-searched soon (if necessary) + local all_mpalms_serialized = minetest.serialize(all_mpalms) + for _, pos in pairs(fpalms_list) do + local fmeta = minetest.get_meta(pos) + local fdist = fmeta:get_int("male_palms_dist") + if not fdist or fdist ~= moretrees.dates_pollination_distance then + fmeta:set_string("male_palms", all_mpalms_serialized) + fmeta:set_int("male_palms_dist", moretrees.dates_pollination_distance) + end + end + end + + -- Save cache. + if cache_changed then + meta:set_string("male_palms", minetest.serialize(mpalms)) + end + + return mbpos +end + +-- Find a male blossom in range of a specific female blossom +local function find_male_blossom(fbpos) + local ftpos = find_female_trunk(fbpos) + if ftpos then + return find_male_blossom_with_ftrunk(fbpos, ftpos) + end + return nil +end + +-- Growing function for dates +local dates_growfn = function(pos, elapsed) + local node = minetest.get_node(pos) + local delay = moretrees.dates_grow_interval + local r = moretrees.dates_pollination_distance + local action + if not node then + return + elseif not moretrees.dates_regrow then + if string.find(node.name, "moretrees:dates_f") then + minetest.swap_node(pos, {name="moretrees:dates_f4"}) + elseif string.find(node.name, "moretrees:dates_m") then + minetest.swap_node(pos, {name="moretrees:dates_n"}) + else + minetest.remove_node(pos) + end + return + elseif node.name == "moretrees:dates_f0" and find_male_blossom(pos) then + -- Pollinate flowers + minetest.swap_node(pos, {name="moretrees:dates_f1"}) + action = "pollinate" + elseif string.match(node.name, "0$") then + -- Make female unpollinated and male flowers last a bit longer + if math.random(flowers_wither_ichance) == 1 then + if node.name == "moretrees:dates_f0" then + minetest.swap_node(pos, {name="moretrees:dates_fn"}) + else + minetest.swap_node(pos, {name="moretrees:dates_n"}) + end + action = "wither" + else + action = "nowither" + end + elseif node.name == "moretrees:dates_f4" then + -- Remove dates, and optionally drop them as items + if math.random(dates_drop_ichance) == 1 then + if moretrees.dates_item_drop_ichance > 0 and math.random(moretrees.dates_item_drop_ichance) == 1 then + local items = minetest.get_node_drops(minetest.get_node(pos).name) + for _, itemname in pairs(items) do + minetest.add_item(pos, itemname) + end + end + minetest.swap_node(pos, {name="moretrees:dates_n"}) + action = "drop" + else + action = "nodrop" + end + elseif string.match(node.name, "n$") then + -- Remove stems. + if math.random(stems_drop_ichance) == 1 then + minetest.remove_node(pos) + return "stemdrop" + end + action = "nostemdrop" + else + -- Grow dates + local offset = 18 + local n = string.sub(node.name, offset) + minetest.swap_node(pos, {name=string.sub(node.name, 1, offset-1)..n+1}) + action = "grow" + end + -- Don't catch up when elapsed time is large. Regular visits are needed for growth... + local timer = minetest.get_node_timer(pos) + timer:start(delay + math.random(moretrees.dates_grow_interval)) + return action +end + +-- Alternate growth function for dates. +-- It calls the primary growth function, but also measures CPU time consumed. +-- Use this function to analyze date growing performance. +local stat = {} +stat.count = 0 +local dates_growfn_profiling = function(pos, elapsed) + local t0 = core.get_us_time() + local action = dates_growfn(pos, elapsed) + local t1 = core.get_us_time() + if t1 < t0 then + t1 = t1 + 2^32 + end + stat.count = stat.count + 1 + if not stat[action] then + stat[action] = {} + stat[action].count = 0 + stat[action].sum = 0 + stat[action].min = 9999999999 + stat[action].max = 0 + end + stat[action].count = stat[action].count + 1 + stat[action].sum = stat[action].sum + t1-t0 + if t1-t0 < stat[action].min then + stat[action].min = t1-t0 + end + if t1-t0 > stat[action].max then + stat[action].max = t1-t0 + end + + if stat.count % 10 == 0 then + io.write(".") + io.flush() + end + if stat.count % 100 == 0 then + print(string.format("Date grow statistics %5d:", stat.count)) + local sum = 0 + local count = 0 + if sect_search_stats.count > 0 and stat.pollinate and stat.pollinate.count > 0 then + print(string.format("\t%-10s: %6d (%4.1f%%): %6dus (%d..%d)", + "search", sect_search_stats.count, + 100*sect_search_stats.count/stat.pollinate.count, + sect_search_stats.sum/sect_search_stats.count, + sect_search_stats.min, sect_search_stats.max)) + else + print(string.format("\t%-10s: %6d (%4.1f%%): %6dus (%d..%d)", + "search", sect_search_stats.count, + 0, 0, 0, 0)) + end + for action,data in pairs(stat) do + if action ~= "count" then + count = count + data.count + sum = sum + data.sum + print(string.format("\t%-10s: %6d (%4.1f%%): %6dus (%d..%d)", + action, data.count, + 100*data.count/stat.count, data.sum/data.count, + data.min, data.max)) + end + end + print(string.format("\t%-10s: %6d ( 100%%): %6dus", + "TOTAL", count, sum/count)) + end +end + +-- Register dates + +local dates_starttimer = function(pos, elapsed) + local timer = minetest.get_node_timer(pos) + local base_interval = moretrees.dates_grow_interval * 2 / 3 + timer:set(base_interval + math.random(base_interval), elapsed or 0) +end + +local dates_drop = { + items = { + {items = { "moretrees:date" }}, + {items = { "moretrees:date" }}, + {items = { "moretrees:date" }}, + {items = { "moretrees:date" }}, + {items = { "moretrees:date" }, rarity = 2 }, + {items = { "moretrees:date" }, rarity = 2 }, + {items = { "moretrees:date" }, rarity = 2 }, + {items = { "moretrees:date" }, rarity = 2 }, + {items = { "moretrees:date" }, rarity = 5 }, + {items = { "moretrees:date" }, rarity = 5 }, + {items = { "moretrees:date" }, rarity = 5 }, + {items = { "moretrees:date" }, rarity = 5 }, + {items = { "moretrees:date" }, rarity = 20 }, + {items = { "moretrees:date" }, rarity = 20 }, + {items = { "moretrees:date" }, rarity = 20 }, + {items = { "moretrees:date" }, rarity = 20 }, + } +} + +for _,suffix in ipairs({"f0", "f1", "f2", "f3", "f4", "m0", "fn", "n"}) do + local name + if suffix == "f0" or suffix == "m0" then + name = S("Date Flowers") + elseif suffix == "n" or suffix == "fn" then + name = S("Date Stem") + else + name = S("Dates") + end + local dropfn = suffix == "f4" and dates_drop or "" + local datedef = { + description = name, + tiles = {"moretrees_dates_"..suffix..".png"}, + visual_scale = 2, + drawtype = "plantlike", + paramtype = "light", + sunlight_propagates = true, + walkable = false, + groups = { fleshy=3, dig_immediate=3, flammable=2, moretrees_dates=1 }, + inventory_image = "moretrees_dates_"..suffix..".png^[transformR0", + wield_image = "moretrees_dates_"..suffix..".png^[transformR90", + sounds = default.node_sound_defaults(), + drop = dropfn, + selection_box = { + type = "fixed", + fixed = {-0.3, -0.3, -0.3, 0.3, 3.5, 0.3} + }, + on_timer = dates_growfn, + on_construct = moretrees.dates_regrow and dates_starttimer, + + } + minetest.register_node("moretrees:dates_"..suffix, datedef) +end + +-- If regrowing was previously disabled, but is enabled now, make sure timers are started for existing dates +if moretrees.dates_regrow then + local spec = { + name = "moretrees:restart_dates_regrow_timer", + nodenames = "group:moretrees_dates", + action = function(pos, node, active_object_count, active_object_count_wider) + local timer = minetest.get_node_timer(pos) + if not timer:is_started() then + dates_starttimer(pos) + else + local timeout = timer:get_timeout() + local elapsed = timer:get_elapsed() + if timeout - elapsed > moretrees.dates_grow_interval * 4/3 then + dates_starttimer(pos, math.random(moretrees.dates_grow_interval * 4/3)) + end + end + end, + } + if minetest.register_lbm then + minetest.register_lbm(spec) + else + spec.interval = 3557 + spec.chance = 10 + minetest.register_abm(spec) + end +end + diff --git a/default_settings.txt b/default_settings.txt index 1bb85f5..2bfb276 100644 --- a/default_settings.txt +++ b/default_settings.txt @@ -6,6 +6,7 @@ moretrees.enable_apple_tree = true moretrees.enable_oak = true moretrees.enable_sequoia = true moretrees.enable_palm = true +moretrees.enable_date_palm = true moretrees.enable_cedar = true moretrees.enable_rubber_tree = true moretrees.enable_willow = true @@ -57,6 +58,30 @@ moretrees.firs_remove_default_trees = false moretrees.firs_remove_interval = 2 moretrees.firs_remove_chance = 150 +-- Date palm settings + +moretrees.dates_regrow = true +moretrees.dates_female_percent = 57 -- Ratio of female to male trees - tune this to improve # of generated trees that actually bear fruit + -- ~57% gives near optimal results for groups of 3 random trees, while it is only slightly suboptimal + -- for groups of 2 and 4 random trees (~2% less fruit than optimal). + -- Optimal values per group size: 2: 50%, 3: 57.78%, 4: 63%, 5: 66.9%, 6: 69.9%, [...], 12: 79.8% + -- So 57% is optimal for small groups of trees. As larger groups have more female palms anyway, a + -- less than optimal proportion of female to male trees is not a problem. +moretrees.dates_pollination_distance = 120 +moretrees.dates_blossom_search_time_treshold = 1000 -- If average male blossom search time exceeds this, start limiting the search load. +moretrees.dates_blossom_search_iload = 10 -- Inverse fraction of CPU time that male blossom searching search may consume. + -- As searching a large area (radius: dates_pollination_distance/3 per attempt) can cause lag, + -- this limits the search frequency server-wide so that the impact on server lag is minimised + -- For personal servers, this can be set lower, or even to 1 or 0 (0 disables load limiting). + -- Obtain the current average search time using /dates_stats +moretrees.dates_flower_interval = 59 +moretrees.dates_flower_chance = 181 +moretrees.dates_grow_interval = 2 * moretrees.dates_flower_interval * moretrees.dates_flower_chance + -- As date palms have a high yield, don't grow dates too fast + -- The actual interval will vary randomly between 67% and 133% of this value. + -- 2 * 59 * 181 ~ 6 hours. So by default flowers become dates in about one (human) day. +moretrees.dates_item_drop_ichance = 10 -- inverse probability of ripe dates dropping as items (instead of disappearing) + -- Sapling settings moretrees.sapling_interval = 500 diff --git a/init.lua b/init.lua index 843958b..7d32f00 100644 --- a/init.lua +++ b/init.lua @@ -73,6 +73,7 @@ moretrees.cutting_tools = { dofile(modpath.."/tree_models.lua") dofile(modpath.."/node_defs.lua") +dofile(modpath.."/date_palm.lua") dofile(modpath.."/biome_defs.lua") dofile(modpath.."/saplings.lua") dofile(modpath.."/crafts.lua") @@ -85,6 +86,7 @@ if moretrees.spawn_saplings then moretrees.spawn_oak_object = "moretrees:oak_sapling_ongen" moretrees.spawn_sequoia_object = "moretrees:sequoia_sapling_ongen" moretrees.spawn_palm_object = "moretrees:palm_sapling_ongen" + moretrees.spawn_date_palm_object = "moretrees:date_palm_sapling_ongen" moretrees.spawn_cedar_object = "moretrees:cedar_sapling_ongen" moretrees.spawn_rubber_tree_object = "moretrees:rubber_tree_sapling_ongen" moretrees.spawn_willow_object = "moretrees:willow_sapling_ongen" @@ -100,6 +102,7 @@ else moretrees.spawn_oak_object = moretrees.oak_model moretrees.spawn_sequoia_object = moretrees.sequoia_model moretrees.spawn_palm_object = moretrees.palm_model + moretrees.spawn_date_palm_object = moretrees.date_palm_model moretrees.spawn_cedar_object = moretrees.cedar_model moretrees.spawn_rubber_tree_object = moretrees.rubber_tree_model moretrees.spawn_willow_object = moretrees.willow_model @@ -131,6 +134,11 @@ if moretrees.enable_palm then biome_lib:register_generate_plant(moretrees.palm_biome, moretrees.spawn_palm_object) end +if moretrees.enable_date_palm then + biome_lib:register_generate_plant(moretrees.date_palm_biome, moretrees.spawn_date_palm_object) + biome_lib:register_generate_plant(moretrees.date_palm_biome_2, moretrees.spawn_date_palm_object) +end + if moretrees.enable_cedar then biome_lib:register_generate_plant(moretrees.cedar_biome, moretrees.spawn_cedar_object) end diff --git a/node_defs.lua b/node_defs.lua index 94b7ed0..791d339 100644 --- a/node_defs.lua +++ b/node_defs.lua @@ -9,6 +9,7 @@ moretrees.treelist = { {"sequoia", "Giant Sequoia"}, {"birch", "Birch Tree"}, {"palm", "Palm Tree", "coconut", "Coconut", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 1.0 }, + {"date_palm", "Date Palm Tree", "date_palm_fruit_trunk", "Date Palm Tree", {0, 0, 0, 0, 0, 0}, 0.0 }, {"spruce", "Spruce Tree", "spruce_cone", "Spruce Cone", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 }, {"cedar", "Cedar Tree", "cedar_cone", "Cedar Cone", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 }, {"willow", "Willow Tree"}, @@ -123,6 +124,8 @@ for i in ipairs(moretrees.treelist) do if treename == "palm" then droprarity = 20 decay = moretrees.palm_leafdecay_radius + elseif treename == "date_palm" then + decay = moretrees.palm_leafdecay_radius end local moretrees_leaves_inventory_image = nil @@ -430,3 +433,5 @@ minetest.register_alias("moretrees:pine_sapling", "moretrees:cedar_sapling") minetest.register_alias("moretrees:pine_leaves", "moretrees:cedar_leaves") minetest.register_alias("moretrees:pine_cone", "moretrees:cedar_cone") minetest.register_alias("moretrees:pine_nuts", "moretrees:cedar_nuts") + +minetest.register_alias("moretrees:dates", "moretrees:dates_f4") diff --git a/textures/moretrees_date.png b/textures/moretrees_date.png new file mode 100644 index 0000000..ed743b5 Binary files /dev/null and b/textures/moretrees_date.png differ diff --git a/textures/moretrees_date_palm_leaves.png b/textures/moretrees_date_palm_leaves.png new file mode 100644 index 0000000..de0f569 Binary files /dev/null and b/textures/moretrees_date_palm_leaves.png differ diff --git a/textures/moretrees_date_palm_sapling.png b/textures/moretrees_date_palm_sapling.png new file mode 100644 index 0000000..9596028 Binary files /dev/null and b/textures/moretrees_date_palm_sapling.png differ diff --git a/textures/moretrees_date_palm_trunk.png b/textures/moretrees_date_palm_trunk.png new file mode 100644 index 0000000..b8fa986 Binary files /dev/null and b/textures/moretrees_date_palm_trunk.png differ diff --git a/textures/moretrees_date_palm_trunk_top.png b/textures/moretrees_date_palm_trunk_top.png new file mode 100644 index 0000000..329ba46 Binary files /dev/null and b/textures/moretrees_date_palm_trunk_top.png differ diff --git a/textures/moretrees_date_palm_wood.png b/textures/moretrees_date_palm_wood.png new file mode 100644 index 0000000..c531e3c Binary files /dev/null and b/textures/moretrees_date_palm_wood.png differ diff --git a/textures/moretrees_dates.png b/textures/moretrees_dates.png new file mode 100644 index 0000000..cd8d578 Binary files /dev/null and b/textures/moretrees_dates.png differ diff --git a/textures/moretrees_dates_f0.png b/textures/moretrees_dates_f0.png new file mode 100644 index 0000000..b75d59a Binary files /dev/null and b/textures/moretrees_dates_f0.png differ diff --git a/textures/moretrees_dates_f1.png b/textures/moretrees_dates_f1.png new file mode 100644 index 0000000..535150b Binary files /dev/null and b/textures/moretrees_dates_f1.png differ diff --git a/textures/moretrees_dates_f2.png b/textures/moretrees_dates_f2.png new file mode 100644 index 0000000..e2e299c Binary files /dev/null and b/textures/moretrees_dates_f2.png differ diff --git a/textures/moretrees_dates_f3.png b/textures/moretrees_dates_f3.png new file mode 100644 index 0000000..eef43f0 Binary files /dev/null and b/textures/moretrees_dates_f3.png differ diff --git a/textures/moretrees_dates_f4.png b/textures/moretrees_dates_f4.png new file mode 100644 index 0000000..78f38f9 Binary files /dev/null and b/textures/moretrees_dates_f4.png differ diff --git a/textures/moretrees_dates_fn.png b/textures/moretrees_dates_fn.png new file mode 100644 index 0000000..db88913 Binary files /dev/null and b/textures/moretrees_dates_fn.png differ diff --git a/textures/moretrees_dates_m0.png b/textures/moretrees_dates_m0.png new file mode 100644 index 0000000..4ff61e7 Binary files /dev/null and b/textures/moretrees_dates_m0.png differ diff --git a/textures/moretrees_dates_n.png b/textures/moretrees_dates_n.png new file mode 100644 index 0000000..c12a3d9 Binary files /dev/null and b/textures/moretrees_dates_n.png differ diff --git a/tree_biomes.txt b/tree_biomes.txt index fdba90d..22e1032 100644 --- a/tree_biomes.txt +++ b/tree_biomes.txt @@ -6,6 +6,8 @@ jungle tree - 5 to +10 above +15 water, 20 10 dirt_with_grass 329 5 fir above +25 -20 to +10 n/a n/a dirt_with_grass 359 8 firs on snow above +15 -20 to +10 n/a n/a snow:snow 359 8 palm - 1 to + 1 +15 to +32 water, 15 10 sand 330 5 +date palm - 1 to +10 above +39 water, 20h,20v 100 desert_sand 339 10 +date palm +11 to +30 above +39 water, 1h,30v 1 desert_sand 340 10 apple + 1 to +10 +23 to +32 n/a n/a dirt_with grass 331 15 oak 0 to +10 + 4 to +16 n/a n/a dirt_with grass 332 15 sequoia 0 to +10 -30 to +50 n/a n/a dirt_with grass 333 10 diff --git a/tree_models.lua b/tree_models.lua index c534089..a2bfe25 100644 --- a/tree_models.lua +++ b/tree_models.lua @@ -105,6 +105,31 @@ moretrees.palm_model={ fruit_chance=0 } +-- Dates can't be generated as fruit, because there is no support for the +-- special (male and female) fruit trunks that allow dates to regrow at the +-- correct position in the tree. +-- So, a generic fruit trunk is spawned. An ABM will convert it to a male +-- or female fruit trunk, and generate the actual dates. +moretrees.date_palm_model={ + axiom="TTTTddddddddddccccccccccRT[TGGGGT]".. + "ccccc[&&a]ccccc[&&a]ccccc[&&a]ccccc[&&a]ccccc[&&a]ccccc[&&a]".. + "GGccccc[&a]ccccc[&a]ccccc[&a]ccccc[&a]ccccc[&a]ccccc[&a]".. + "GGccccc[a]ccccc[a]ccccc[a]ccccc[a]ccccc[a]ccccc[a]", + rules_a="Gffb&bbb[++f--&ffff&ff][--f++&ffff&ff]&ff&ff&bb&bb&bb", + rules_b="f", + rules_c="/", + rules_d="F", + trunk="moretrees:date_palm_trunk", + leaves="moretrees:date_palm_leaves", + angle=18, + iterations=1, + random_level=0, + trunk_type="single", + thin_branches=false, + fruit="moretrees:date_palm_fruit_trunk", + fruit_chance=0 +} + moretrees.spruce_model1={ axiom="FFFFFAFFFFFFBFFFFFFCFFFFFFDFFFFFF[&&&F^^FF][&&&++F^^FF][&&&++++F^^FF][&&&++++++F^^FF][&&&--F^^FF][&&&----F^^FF][FFFFf]", rules_a="[&&&FFFFFF^^FFF][&&&++FFFFFF^^FFF][&&&++++FFFFFF^^FFF][&&&++++++FFFFFF^^FFF][&&&--FFFFFF^^FFF][&&&----FFFFFF^^FFF]", -- cgit v1.2.3 From c87a169fdd1ff0b6a08407ff2564f52c15def3cf Mon Sep 17 00:00:00 2001 From: Rogier Date: Fri, 20 May 2016 12:33:10 +0200 Subject: Add recipes with dates (and nuts, and coconut) Using a combination of dates, nuts and coconut, an extremely high energy date-nut cake can be baked (32 units of food). It's main purpose is to be a very concentrated transport mechanism of food, but it can be used for instant replenishment of a starving soul. In practise, it will be used to craft date-nut energy bars, which merely have a good nutritional value (4 units). Because of its exceptional nature, the cake requires special ingredients (all three types of nuts, as well as coconuts), and given the ingredients, 3 steps are needed (including one cooking step) to bake it. All of the ingredients themselves, except dates, are not found in nature, but must also be prepared. --- LICENSE | 3 +- crafts.lua | 77 +++++++++++++++++++++++++++++++++ depends.txt | 1 + textures/moretrees_date_nut_bar.png | Bin 0 -> 685 bytes textures/moretrees_date_nut_batter.png | Bin 0 -> 608 bytes textures/moretrees_date_nut_cake.png | Bin 0 -> 695 bytes textures/moretrees_date_nut_snack.png | Bin 0 -> 450 bytes 7 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 textures/moretrees_date_nut_bar.png create mode 100644 textures/moretrees_date_nut_batter.png create mode 100644 textures/moretrees_date_nut_cake.png create mode 100644 textures/moretrees_date_nut_snack.png diff --git a/LICENSE b/LICENSE index 7966b3f..b7c0f1f 100644 --- a/LICENSE +++ b/LICENSE @@ -7,10 +7,11 @@ All source code: Date palm code (date_palm.lua) © 2016, Rogier Published under the terms and conditions of the WTFPL. -All date palm textures: +All date & date palm textures and date-based food: © 2016, Rogier Published under the terms and conditions of CC-BY-SA-3.0 Unported. - Three of the date palm textures are modifications of existing moretrees textures + - The date cake batter is a modification of the acorn muffin batter All sapling textures (textures/*_sapling.png): © 2013, Tim Huppertz Published under the terms and conditions of CC-BY-SA-3.0 Unported. diff --git a/crafts.lua b/crafts.lua index 68b556e..9a0982b 100644 --- a/crafts.lua +++ b/crafts.lua @@ -69,6 +69,29 @@ minetest.register_craftitem("moretrees:date", { on_use = minetest.item_eat(1), }) +minetest.register_craftitem("moretrees:date_nut_snack", { + description = S("Date & nut snack"), + inventory_image = "moretrees_date_nut_snack.png", + on_use = minetest.item_eat(4), +}) + +minetest.register_craftitem("moretrees:date_nut_batter", { + description = S("Date-nut cake batter"), + inventory_image = "moretrees_date_nut_batter.png", +}) + +minetest.register_craftitem("moretrees:date_nut_cake", { + description = S("Date-nut cake"), + inventory_image = "moretrees_date_nut_cake.png", + on_use = minetest.item_eat(32), +}) + +minetest.register_craftitem("moretrees:date_nut_bar", { + description = S("Date-nut energy bar"), + inventory_image = "moretrees_date_nut_bar.png", + on_use = minetest.item_eat(4), +}) + minetest.register_craftitem("moretrees:acorn_muffin_batter", { description = S("Acorn Muffin batter"), inventory_image = "moretrees_acorn_muffin_batter.png", @@ -115,6 +138,60 @@ for i in ipairs(moretrees.cutting_tools) do }) end +minetest.register_craft({ + type = "shapeless", + output = "moretrees:date_nut_snack", + recipe = { + "moretrees:date", + "moretrees:date", + "moretrees:date", + "moretrees:spruce_nuts", + "moretrees:cedar_nuts", + "moretrees:fir_nuts", + } +}) + +-- The date-nut cake is an exceptional food item due to its highly +-- concentrated nature (32 food units). Because of that, it requires +-- many different ingredients, and, starting from the base ingredients +-- found or harvested in nature, it requires many steps to prepare. +local flour +if minetest.registered_nodes["farming:flour"] then + flour = "farming:flour" +else + flour = "moretrees:acorn_muffin_batter" +end +minetest.register_craft({ + type = "shapeless", + output = "moretrees:date_nut_batter", + recipe = { + "moretrees:date_nut_snack", + "moretrees:date_nut_snack", + "moretrees:date_nut_snack", + "moretrees:coconut_milk", + "moretrees:date_nut_snack", + "moretrees:raw_coconut", + "moretrees:coconut_milk", + flour, + "moretrees:raw_coconut", + }, + replacements = { + { "moretrees:coconut_milk", "vessels:drinking_glass 2" } + } +}) + +minetest.register_craft({ + type = "cooking", + output = "moretrees:date_nut_cake", + recipe = "moretrees:date_nut_batter", +}) + +minetest.register_craft({ + type = "shapeless", + output = "moretrees:date_nut_bar 8", + recipe = {"moretrees:date_nut_cake"}, +}) + minetest.register_craft({ type = "shapeless", output = "moretrees:acorn_muffin_batter", diff --git a/depends.txt b/depends.txt index 6d36526..7896571 100644 --- a/depends.txt +++ b/depends.txt @@ -4,4 +4,5 @@ vessels stairs? moreblocks? intllib? +farming? diff --git a/textures/moretrees_date_nut_bar.png b/textures/moretrees_date_nut_bar.png new file mode 100644 index 0000000..6895001 Binary files /dev/null and b/textures/moretrees_date_nut_bar.png differ diff --git a/textures/moretrees_date_nut_batter.png b/textures/moretrees_date_nut_batter.png new file mode 100644 index 0000000..47d8e08 Binary files /dev/null and b/textures/moretrees_date_nut_batter.png differ diff --git a/textures/moretrees_date_nut_cake.png b/textures/moretrees_date_nut_cake.png new file mode 100644 index 0000000..5084e71 Binary files /dev/null and b/textures/moretrees_date_nut_cake.png differ diff --git a/textures/moretrees_date_nut_snack.png b/textures/moretrees_date_nut_snack.png new file mode 100644 index 0000000..1766dab Binary files /dev/null and b/textures/moretrees_date_nut_snack.png differ -- cgit v1.2.3 From 75e8027bf7ca581556f91e8c1444c865a77c482d Mon Sep 17 00:00:00 2001 From: Rogier Date: Thu, 19 May 2016 13:26:52 +0200 Subject: Make cocos palm regrow coconuts. This feature is optional, and can be turned off. Existing cocos trees are converted. --- LICENSE | 5 +- cocos_palm.lua | 283 +++++++++++++++++++++++++++++++++++++++ default_settings.txt | 15 +++ init.lua | 1 + node_defs.lua | 2 +- textures/moretrees_coconut_0.png | Bin 0 -> 877 bytes textures/moretrees_coconut_1.png | Bin 0 -> 429 bytes textures/moretrees_coconut_2.png | Bin 0 -> 1009 bytes tree_models.lua | 9 +- 9 files changed, 310 insertions(+), 5 deletions(-) create mode 100644 cocos_palm.lua create mode 100644 textures/moretrees_coconut_0.png create mode 100644 textures/moretrees_coconut_1.png create mode 100644 textures/moretrees_coconut_2.png diff --git a/LICENSE b/LICENSE index b7c0f1f..7cffc99 100644 --- a/LICENSE +++ b/LICENSE @@ -4,13 +4,14 @@ Minetest mod moretrees All source code: © 2013, Vanessa Ezekowitz Published under the terms and conditions of the WTFPL. -Date palm code (date_palm.lua) +Date & cocos palm code (date_palm.lua, cocos_palm.lua) © 2016, Rogier Published under the terms and conditions of the WTFPL. -All date & date palm textures and date-based food: +All date & date palm textures, date-based food, cocos flower & green coconuts: © 2016, Rogier Published under the terms and conditions of CC-BY-SA-3.0 Unported. - Three of the date palm textures are modifications of existing moretrees textures + - The green coconuts are a modification of the brown coconut - The date cake batter is a modification of the acorn muffin batter All sapling textures (textures/*_sapling.png): © 2013, Tim Huppertz diff --git a/cocos_palm.lua b/cocos_palm.lua new file mode 100644 index 0000000..8dea25f --- /dev/null +++ b/cocos_palm.lua @@ -0,0 +1,283 @@ +local S = moretrees.intllib + +-- © 2016, Rogier + +-- Some constants + +local coconut_drop_ichance = 8 + +-- Make the cocos palm fruit trunk a real trunk (it is generated as a fruit) +local trunk = minetest.registered_nodes["moretrees:palm_trunk"] +local ftrunk = {} +local gftrunk = {} +for k,v in pairs(trunk) do + ftrunk[k] = v + gftrunk[k] = v +end +ftrunk.tiles = {} +gftrunk.tiles = {} +for k,v in pairs(trunk.tiles) do + ftrunk.tiles[k] = v + gftrunk.tiles[k] = v +end +ftrunk.drop = "moretrees:palm_trunk" +gftrunk.drop = "moretrees:palm_trunk" +ftrunk.after_destruct = function(pos, oldnode) + local coconuts = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, {"group:moretrees_coconut"}) + for _,coconutpos in pairs(coconuts) do + -- minetest.dig_node(coconutpos) does not cause nearby coconuts to be dropped :-( ... + --minetest.dig_node(coconutpos) + local items = minetest.get_node_drops(minetest.get_node(coconutpos).name) + minetest.remove_node(coconutpos) + for _, itemname in pairs(items) do + minetest.add_item(coconutpos, itemname) + end + end +end +-- Make the different trunk types distinguishable (but barely) +ftrunk.tiles[1] = "moretrees_palm_trunk_top.png^[transformR90" +gftrunk.tiles[1] = "moretrees_palm_trunk_top.png^[transformR180" +gftrunk.description = gftrunk.description.." (gen)" +minetest.register_node("moretrees:palm_fruit_trunk", ftrunk) +minetest.register_node("moretrees:palm_fruit_trunk_gen", gftrunk) + +local coconut_regrow_abm_spec = { + nodenames = { "moretrees:palm_fruit_trunk" }, + interval = moretrees.coconut_flower_interval, + chance = moretrees.coconut_flower_chance, + action = function(pos, node, active_object_count, active_object_count_wider) + local coconuts = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, "group:moretrees_coconut") + -- Expected growth interval increases exponentially with number of coconuts already hanging. + -- Also: if more coconuts are hanging, the chance of picking an empty spot decreases as well... + if math.random(2^#coconuts) <= 2 then + -- Grow in area of 3x3 round trunk + local dx=math.floor(math.random(3)-2) + local dz=math.floor(math.random(3)-2) + local coconutpos = {x=pos.x+dx, y=pos.y, z=pos.z+dz} + local coconutnode = minetest.get_node(coconutpos) + if coconutnode.name == "air" then + minetest.set_node(coconutpos, {name="moretrees:coconut_0"}) + end + end + end +} +if moretrees.coconuts_regrow then + minetest.register_abm(coconut_regrow_abm_spec) +end + +-- Spawn initial coconuts + +-- Spawn initial coconuts +-- (Instead of coconuts, a generated-palm fruit trunk is generated with the tree. This +-- ABM converts the trunk to a regular fruit trunk, and spawns some coconuts) +minetest.register_abm({ + nodenames = { "moretrees:palm_fruit_trunk_gen" }, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + minetest.swap_node(pos, {name="moretrees:palm_fruit_trunk"}) + local poslist = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, "air") + local genlist = {} + for k,v in pairs(poslist) do + genlist[k] = {x = math.random(100), pos = v} + end + table.sort(genlist, function(a, b) return a.x < b.x; end) + local gen + local count = 0 + for _,gen in pairs(genlist) do + minetest.set_node(gen.pos, {name = "moretrees:coconut_3"}) + count = count + 1 + if count == 4 then + break + end + end + end, +}) + +-- Register coconuts, and make them regrow + +local coconut_growfn = function(pos, elapsed) + local node = minetest.get_node(pos) + local delay = moretrees.coconut_grow_interval + if not node then + return + elseif not moretrees.coconuts_regrow then + -- Regrowing has been turned off. Make coconust grow instantly + minetest.swap_node(pos, {name="moretrees:coconut_3"}) + return + elseif node.name == "moretrees:coconut_3" then + -- Drop coconuts (i.e. remove them), so that new coconuts can grow. + -- Coconuts will drop as items with a small chance + if math.random(coconut_drop_ichance) == 1 then + if moretrees.coconut_item_drop_ichance > 0 and math.random(moretrees.coconut_item_drop_ichance) == 1 then + local items = minetest.get_node_drops(minetest.get_node(pos).name) + for _, itemname in pairs(items) do + minetest.add_item(pos, itemname) + end + end + minetest.remove_node(pos) + end + else + -- Grow coconuts to the next stage + local offset = string.len("moretrees:coconut_x") + local n = string.sub(node.name, offset) + minetest.swap_node(pos, {name=string.sub(node.name, 1, offset-1)..n+1}) + end + -- Don't catch up when elapsed time is large. Regular visits are needed for growth... + local timer = minetest.get_node_timer(pos) + timer:start(delay + math.random(moretrees.coconut_grow_interval)) +end + +local coconut_starttimer = function(pos, elapsed) + local timer = minetest.get_node_timer(pos) + local base_interval = moretrees.coconut_grow_interval * 2 / 3 + timer:set(base_interval + math.random(base_interval), elapsed or 0) +end + +for _,suffix in ipairs({"_0", "_1", "_2", "_3", ""}) do + local name + if suffix == "_0" then + name = S("Coconut Flower") + else + name = S("Coconut") + end + local drop = "" + local coco_group = 1 + local tile = "moretrees_coconut"..suffix..".png" + local timerfn = coconut_growfn + local constructfn = coconut_starttimer + if suffix == "_3" then + drop = "moretrees:coconut" + tile = "moretrees_coconut.png" + elseif suffix == "" then + drop = nil + coco_group = nil + timerfn = nil + constructfn = nil + end + local coconutdef = { + description = name, + tiles = {tile}, + drawtype = "plantlike", + paramtype = "light", + sunlight_propagates = true, + walkable = false, + groups = { fleshy=3, dig_immediate=3, flammable=2, moretrees_coconut=coco_group }, + inventory_image = tile.."^[transformR180", + wield_image = tile.."^[transformR180", + sounds = default.node_sound_defaults(), + drop = drop, + selection_box = { + type = "fixed", + fixed = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3} + }, + on_timer = timerfn, + on_construct = constructfn, + + } + minetest.register_node("moretrees:coconut"..suffix, coconutdef) +end + +-- convert exisiting cocos palms. This is a bit tricky... +-- Try to make sure that this is indeed a generated tree, and not manually-placed trunks and/or coconuts +if moretrees.coconuts_convert_existing_palms then + local spec = { + name = "moretrees:convert_existing_cocos_palms_to_regrow_coconuts", + nodenames = "moretrees:coconut", + action = function(pos, node, active_object_count, active_object_count_wider) + local trunks + local cvtrunks + local leaves + local coconuts + -- One regular trunk must be adjacent to the coconut + trunks = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, "moretrees:palm_trunk") + if #trunks ~= 1 then + return + end + local tpos = trunks[1] + -- 1 or 2 other trunks must be one level below to the trunk being converted. + trunks = minetest.find_nodes_in_area({x=tpos.x-1, y=tpos.y-1, z=tpos.z-1}, {x=tpos.x+1, y=tpos.y-1, z=tpos.z+1}, "moretrees:palm_trunk") + if #trunks < 1 or #trunks > 2 then + return + end + -- 1 or 2 other trunks must be two levels below to the trunk being converted. + trunks = minetest.find_nodes_in_area({x=tpos.x-1, y=tpos.y-2, z=tpos.z-1}, {x=tpos.x+1, y=tpos.y-2, z=tpos.z+1}, "moretrees:palm_trunk") + if #trunks < 1 or #trunks > 2 then + return + end + -- 1 or 2 trunks must at the level of the trunk being converted. + cvtrunks = minetest.find_nodes_in_area({x=tpos.x-1, y=tpos.y, z=tpos.z-1}, {x=tpos.x+1, y=tpos.y, z=tpos.z+1}, "moretrees:palm_trunk") + if #cvtrunks < 1 or #cvtrunks > 2 then + return + end + -- No trunks may be one level above the trunk being converted. + trunks = minetest.find_nodes_in_area({x=tpos.x-1, y=tpos.y+1, z=tpos.z-1}, {x=tpos.x+1, y=tpos.y+1, z=tpos.z+1}, "moretrees:palm_trunk") + if #trunks ~= 0 then + return + end + -- Leaves must be one level above the trunk being converted. + leaves = minetest.find_nodes_in_area({x=tpos.x-1, y=tpos.y+1, z=tpos.z-1}, {x=tpos.x+1, y=tpos.y+1, z=tpos.z+1}, "moretrees:palm_leaves") + if #leaves == 0 then + return + end + -- Leaves must be two levels above the trunk being converted. + leaves = minetest.find_nodes_in_area({x=tpos.x-1, y=tpos.y+2, z=tpos.z-1}, {x=tpos.x+1, y=tpos.y+2, z=tpos.z+1}, "moretrees:palm_leaves") + if #leaves == 0 then + return + end + -- No cocos fruit trunk may already be adjacent to the coconut + trunks = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, "moretrees:palm_fruit_trunk") + if #trunks ~= 0 then + return + end + -- No cocos fruit trunk may be adjacent to or below the trunk being converted. + trunks = minetest.find_nodes_in_area({x=tpos.x-1, y=tpos.y-2, z=tpos.z-1}, {x=tpos.x+1, y=tpos.y, z=tpos.z+1}, "moretrees:palm_fruit_trunk") + if #trunks ~= 0 then + return + end + -- Convert trunk and all coconuts nearby. Maybe convert 2 trunks, just in case... + for _, tpos in pairs(cvtrunks) do + minetest.swap_node(tpos, {name = "moretrees:palm_fruit_trunk"}) + coconuts = minetest.find_nodes_in_area({x=tpos.x-1, y=tpos.y, z=tpos.z-1}, {x=tpos.x+1, y=tpos.y, z=tpos.z+1}, "moretrees:coconut") + for _, coconutpos in pairs(coconuts) do + minetest.set_node(coconutpos, {name = "moretrees:coconut_3"}) + end + end + end, + } + if minetest.register_lbm then + minetest.register_lbm(spec) + else + spec.interval = 3691 + spec.chance = 10 + minetest.register_abm(spec) + end +end + +-- If regrowing was previously disabled, but is enabled now, make sure timers are started for existing coconuts +if moretrees.coconuts_regrow then + local spec = { + name = "moretrees:restart_coconut_regrow_timer", + nodenames = "group:moretrees_coconut", + action = function(pos, node, active_object_count, active_object_count_wider) + local timer = minetest.get_node_timer(pos) + if not timer:is_started() then + coconut_starttimer(pos) + else + local timeout = timer:get_timeout() + local elapsed = timer:get_elapsed() + if timeout - elapsed > moretrees.coconut_grow_interval * 4/3 then + coconut_starttimer(pos, math.random(moretrees.coconut_grow_interval * 4/3)) + end + end + end, + } + if minetest.register_lbm then + minetest.register_lbm(spec) + else + spec.interval = 3659 + spec.chance = 10 + minetest.register_abm(spec) + end +end + diff --git a/default_settings.txt b/default_settings.txt index 2bfb276..e3e1193 100644 --- a/default_settings.txt +++ b/default_settings.txt @@ -58,6 +58,21 @@ moretrees.firs_remove_default_trees = false moretrees.firs_remove_interval = 2 moretrees.firs_remove_chance = 150 +-- Cocos palm settings + +moretrees.coconuts_regrow = true +moretrees.coconuts_convert_existing_palms = true -- Converting existing palm trees will make coconuts regrow on them as well + -- Else, they will only regrow on newly-spawned palms + -- However, conversion is not an exact science, and although an attempt is + -- made to detect whether a trunk belongs to an actual palm, some coconut trunks + -- and some coconuts may be incorrectly converted. +moretrees.coconut_flower_interval = 59 +moretrees.coconut_flower_chance = 67 +moretrees.coconut_grow_interval = 2 * moretrees.coconut_flower_interval * moretrees.coconut_flower_chance + -- Actual interval will randomly vary between 67% and 133% of this value + -- 2 * 59 * 67 ~ 2 hours. So flowers become coconuts in about 6 hours +moretrees.coconut_item_drop_ichance = 10 -- inverse probability of ripe coconuts dropping as items (instead of disappearing) + -- Date palm settings moretrees.dates_regrow = true diff --git a/init.lua b/init.lua index 7d32f00..2c50fd9 100644 --- a/init.lua +++ b/init.lua @@ -74,6 +74,7 @@ moretrees.cutting_tools = { dofile(modpath.."/tree_models.lua") dofile(modpath.."/node_defs.lua") dofile(modpath.."/date_palm.lua") +dofile(modpath.."/cocos_palm.lua") dofile(modpath.."/biome_defs.lua") dofile(modpath.."/saplings.lua") dofile(modpath.."/crafts.lua") diff --git a/node_defs.lua b/node_defs.lua index 791d339..b1df5f7 100644 --- a/node_defs.lua +++ b/node_defs.lua @@ -8,7 +8,7 @@ moretrees.treelist = { {"oak", "Oak Tree", "acorn", "Acorn", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 }, {"sequoia", "Giant Sequoia"}, {"birch", "Birch Tree"}, - {"palm", "Palm Tree", "coconut", "Coconut", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 1.0 }, + {"palm", "Palm Tree", "palm_fruit_trunk_gen", "Palm Tree", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 1.0 }, {"date_palm", "Date Palm Tree", "date_palm_fruit_trunk", "Date Palm Tree", {0, 0, 0, 0, 0, 0}, 0.0 }, {"spruce", "Spruce Tree", "spruce_cone", "Spruce Cone", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 }, {"cedar", "Cedar Tree", "cedar_cone", "Cedar Cone", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 }, diff --git a/textures/moretrees_coconut_0.png b/textures/moretrees_coconut_0.png new file mode 100644 index 0000000..644a65f Binary files /dev/null and b/textures/moretrees_coconut_0.png differ diff --git a/textures/moretrees_coconut_1.png b/textures/moretrees_coconut_1.png new file mode 100644 index 0000000..e2889bc Binary files /dev/null and b/textures/moretrees_coconut_1.png differ diff --git a/textures/moretrees_coconut_2.png b/textures/moretrees_coconut_2.png new file mode 100644 index 0000000..86c8cf5 Binary files /dev/null and b/textures/moretrees_coconut_2.png differ diff --git a/tree_models.lua b/tree_models.lua index a2bfe25..791bddb 100644 --- a/tree_models.lua +++ b/tree_models.lua @@ -88,8 +88,13 @@ moretrees.birch_model2={ thin_branches=true } +-- Coconuts can't be generated as fruit, because there is no support for the +-- special fruit trunks that allow coconuts to regrow at the correct position +-- in the tree. +-- So, a placeholder fruit trunk is spawned. An ABM will convert it to the final +-- fruit trunk, and generate the actual coconuts. moretrees.palm_model={ - axiom="FFcccccc&FFFFFddd[^&&&GR][^///&&&GR][^//////&&&GR][^***&&&GR]FA//A//A//A//A//A", + axiom="FFcccccc&FFFFFdddRA//A//A//A//A//A", rules_a="[&fb&bbb[++f--&ffff&ff][--f++&ffff&ff]&ffff&bbbb&b]", rules_b="f", rules_c="/", @@ -101,7 +106,7 @@ moretrees.palm_model={ random_level=0, trunk_type="single", thin_branches=true, - fruit="moretrees:coconut", + fruit="moretrees:palm_fruit_trunk_gen", fruit_chance=0 } -- cgit v1.2.3 From 9dd610e0e6bef340a31fd05effcfc0f254c115f1 Mon Sep 17 00:00:00 2001 From: Rogier Date: Tue, 28 Jun 2016 17:45:08 +0200 Subject: fixup! Add date palm Add an option to allow dates to grow unpollinated as well. Female palms will be pollinated randomly. --- date_palm.lua | 33 ++++++++++++++++++++++++--------- default_settings.txt | 17 ++++++++++++++++- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/date_palm.lua b/date_palm.lua index a0e574f..6d00b3b 100644 --- a/date_palm.lua +++ b/date_palm.lua @@ -22,6 +22,15 @@ local flowers_wither_ichance = 3 -- implementation +local dates_regrow_prob +if moretrees.dates_regrow_unpollinated_percent <= 0 then + dates_regrow_prob = 0 +elseif moretrees.dates_regrow_unpollinated_percent >= 100 then + dates_regrow_prob = 1 +else + dates_regrow_prob = 1 - math.pow(moretrees.dates_regrow_unpollinated_percent/100, 1/flowers_wither_ichance) +end + -- Make the date palm fruit trunk a real trunk (it is generated as a fruit) local trunk = minetest.registered_nodes["moretrees:date_palm_trunk"] local ftrunk = {} @@ -91,7 +100,7 @@ local date_regrow_abm_spec = { end end } -if moretrees.dates_regrow then +if moretrees.dates_regrow_pollinated or moretrees.dates_regrow_unpollinated_percent > 0 then minetest.register_abm(date_regrow_abm_spec) end @@ -517,7 +526,8 @@ local dates_growfn = function(pos, elapsed) local action if not node then return - elseif not moretrees.dates_regrow then + elseif not moretrees.dates_regrow_pollinated and dates_regrow_prob == 0 then + -- Regrowing of dates is disabled. if string.find(node.name, "moretrees:dates_f") then minetest.swap_node(pos, {name="moretrees:dates_f4"}) elseif string.find(node.name, "moretrees:dates_m") then @@ -526,7 +536,11 @@ local dates_growfn = function(pos, elapsed) minetest.remove_node(pos) end return - elseif node.name == "moretrees:dates_f0" and find_male_blossom(pos) then + elseif node.name == "moretrees:dates_f0" and math.random(100) <= 100 * dates_regrow_prob then + -- Dates grow unpollinated + minetest.swap_node(pos, {name="moretrees:dates_f1"}) + action = "nopollinate" + elseif node.name == "moretrees:dates_f0" and moretrees.dates_regrow_pollinated and find_male_blossom(pos) then -- Pollinate flowers minetest.swap_node(pos, {name="moretrees:dates_f1"}) action = "pollinate" @@ -614,13 +628,13 @@ local dates_growfn_profiling = function(pos, elapsed) local sum = 0 local count = 0 if sect_search_stats.count > 0 and stat.pollinate and stat.pollinate.count > 0 then - print(string.format("\t%-10s: %6d (%4.1f%%): %6dus (%d..%d)", + print(string.format("\t%-12s: %6d (%4.1f%%): %6dus (%d..%d)", "search", sect_search_stats.count, 100*sect_search_stats.count/stat.pollinate.count, sect_search_stats.sum/sect_search_stats.count, sect_search_stats.min, sect_search_stats.max)) else - print(string.format("\t%-10s: %6d (%4.1f%%): %6dus (%d..%d)", + print(string.format("\t%-12s: %6d (%4.1f%%): %6dus (%d..%d)", "search", sect_search_stats.count, 0, 0, 0, 0)) end @@ -628,13 +642,13 @@ local dates_growfn_profiling = function(pos, elapsed) if action ~= "count" then count = count + data.count sum = sum + data.sum - print(string.format("\t%-10s: %6d (%4.1f%%): %6dus (%d..%d)", + print(string.format("\t%-12s: %6d (%4.1f%%): %6dus (%d..%d)", action, data.count, 100*data.count/stat.count, data.sum/data.count, data.min, data.max)) end end - print(string.format("\t%-10s: %6d ( 100%%): %6dus", + print(string.format("\t%-12s: %6d ( 100%%): %6dus", "TOTAL", count, sum/count)) end end @@ -696,14 +710,15 @@ for _,suffix in ipairs({"f0", "f1", "f2", "f3", "f4", "m0", "fn", "n"}) do fixed = {-0.3, -0.3, -0.3, 0.3, 3.5, 0.3} }, on_timer = dates_growfn, - on_construct = moretrees.dates_regrow and dates_starttimer, + on_construct = (moretrees.dates_regrow_pollinated or moretrees.dates_regrow_unpollinated_percent > 0) + and dates_starttimer, } minetest.register_node("moretrees:dates_"..suffix, datedef) end -- If regrowing was previously disabled, but is enabled now, make sure timers are started for existing dates -if moretrees.dates_regrow then +if moretrees.dates_regrow_pollinated or moretrees.dates_regrow_unpollinated_percent > 0 then local spec = { name = "moretrees:restart_dates_regrow_timer", nodenames = "group:moretrees_dates", diff --git a/default_settings.txt b/default_settings.txt index e3e1193..862ab7f 100644 --- a/default_settings.txt +++ b/default_settings.txt @@ -75,7 +75,22 @@ moretrees.coconut_item_drop_ichance = 10 -- inverse probability of ripe coconu -- Date palm settings -moretrees.dates_regrow = true +-- Suggested configuration alternatives: +-- - Dates grow only when pollinated: +-- - Set dates_regrow_pollinated to true +-- - Set dates_regrow_unpollinated_percent to 0 +-- - Disable pollination: +-- - Set dates_regrow_pollinated to false +-- - Set dates_regrow_unpollinated_percent to some larger positive value, e.g. 95 +-- - Dates grow, but more and faster if male flowers are nearby +-- - Set dates_regrow_pollinated to true +-- - Set dates_regrow_unpollinated_percent to some small positive value, e.g. 33 +-- - Optional but recommended: Reduce the pollination distance, e.g. to 30 + +moretrees.dates_regrow_pollinated = true -- Enable pollination. If enabled, male trees are required for dates to grow. + -- If disabled, dates_regrow_unpollinated_percent must be non-zero for dates to regrow. +moretrees.dates_regrow_unpollinated_percent = 0 -- Percentage of female dates becoming dates without being pollinated. + -- If 0, dates_regrow_pollinated must be enabled for dates to grow. moretrees.dates_female_percent = 57 -- Ratio of female to male trees - tune this to improve # of generated trees that actually bear fruit -- ~57% gives near optimal results for groups of 3 random trees, while it is only slightly suboptimal -- for groups of 2 and 4 random trees (~2% less fruit than optimal). -- cgit v1.2.3 From 90283664076f2f399d7351cc36838c1d9b788e12 Mon Sep 17 00:00:00 2001 From: Rogier Date: Fri, 1 Jul 2016 11:11:45 +0200 Subject: fixup! Add date palm Some textual improvements --- date_palm.lua | 4 ++-- default_settings.txt | 11 +++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/date_palm.lua b/date_palm.lua index 6d00b3b..0c40b72 100644 --- a/date_palm.lua +++ b/date_palm.lua @@ -285,11 +285,11 @@ end local function dates_print_search_stats(log) local stats if sect_search_stats.count > 0 then - stats = string.format("Male date tree searching stats: count: %d/%d: average: %d µs (%d..%d)", + stats = string.format("Male date tree searching stats: searches: %d/%d: average: %d µs (%d..%d)", sect_search_stats.count, sect_search_stats.count + sect_search_stats.skip, sect_search_stats.sum/sect_search_stats.count, sect_search_stats.min, sect_search_stats.max) else - stats = string.format("Male date tree searching stats: (not yet available)") + stats = string.format("Male date tree searching stats: searches: 0/0: average: (no searches yet)") end if log then minetest.log("action", "[moretrees] " .. stats) diff --git a/default_settings.txt b/default_settings.txt index 862ab7f..0a5fc88 100644 --- a/default_settings.txt +++ b/default_settings.txt @@ -79,7 +79,7 @@ moretrees.coconut_item_drop_ichance = 10 -- inverse probability of ripe coconu -- - Dates grow only when pollinated: -- - Set dates_regrow_pollinated to true -- - Set dates_regrow_unpollinated_percent to 0 --- - Disable pollination: +-- - Dates grow without pollination. Pollination disabled: -- - Set dates_regrow_pollinated to false -- - Set dates_regrow_unpollinated_percent to some larger positive value, e.g. 95 -- - Dates grow, but more and faster if male flowers are nearby @@ -87,6 +87,13 @@ moretrees.coconut_item_drop_ichance = 10 -- inverse probability of ripe coconu -- - Set dates_regrow_unpollinated_percent to some small positive value, e.g. 33 -- - Optional but recommended: Reduce the pollination distance, e.g. to 30 +-- Note that it should not be necessary to disable pollination for performance +-- reasons. A lot of effort has gone into ensuring that date growing will not cause lag. +-- +-- If lag is suspected, use the chat command '/dates_stats' to obtain the male dates +-- search time, as well as the counts of total number of searches requested and the +-- number of searches actually performed. + moretrees.dates_regrow_pollinated = true -- Enable pollination. If enabled, male trees are required for dates to grow. -- If disabled, dates_regrow_unpollinated_percent must be non-zero for dates to regrow. moretrees.dates_regrow_unpollinated_percent = 0 -- Percentage of female dates becoming dates without being pollinated. @@ -98,7 +105,7 @@ moretrees.dates_female_percent = 57 -- Ratio of female to male trees - tune th -- So 57% is optimal for small groups of trees. As larger groups have more female palms anyway, a -- less than optimal proportion of female to male trees is not a problem. moretrees.dates_pollination_distance = 120 -moretrees.dates_blossom_search_time_treshold = 1000 -- If average male blossom search time exceeds this, start limiting the search load. +moretrees.dates_blossom_search_time_treshold = 1000 -- If average male blossom search time (in microseconds) exceeds this, start limiting the search load. moretrees.dates_blossom_search_iload = 10 -- Inverse fraction of CPU time that male blossom searching search may consume. -- As searching a large area (radius: dates_pollination_distance/3 per attempt) can cause lag, -- this limits the search frequency server-wide so that the impact on server lag is minimised -- cgit v1.2.3 From d72574d28835e30e9d7fa7644268876e6920421a Mon Sep 17 00:00:00 2001 From: Rogier Date: Fri, 1 Jul 2016 16:06:29 +0200 Subject: Add poplar tree Poplars exist in two kinds: small and large trees. Both use the same nodes, except for the sapling. Poplar leaves may drop one or the other sapling. Poplar trees require a humid environment, and water nearby. Provided there is water, an occasional poplar will grow under less humid conditions. --- LICENSE | 5 +- biome_defs.lua | 91 ++++++++++++++++++++++++++++ default_settings.txt | 1 + init.lua | 12 ++++ node_defs.lua | 40 ++++++++++++ textures/moretrees_poplar_leaves.png | Bin 0 -> 563 bytes textures/moretrees_poplar_sapling.png | Bin 0 -> 447 bytes textures/moretrees_poplar_small_sapling.png | Bin 0 -> 347 bytes textures/moretrees_poplar_trunk-1.png | Bin 0 -> 1217 bytes textures/moretrees_poplar_trunk.png | Bin 0 -> 980 bytes textures/moretrees_poplar_trunk_top.png | Bin 0 -> 751 bytes textures/moretrees_poplar_wood.png | Bin 0 -> 726 bytes tree_biomes.txt | 1 + tree_models.lua | 31 ++++++++++ 14 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 textures/moretrees_poplar_leaves.png create mode 100644 textures/moretrees_poplar_sapling.png create mode 100644 textures/moretrees_poplar_small_sapling.png create mode 100644 textures/moretrees_poplar_trunk-1.png create mode 100644 textures/moretrees_poplar_trunk.png create mode 100644 textures/moretrees_poplar_trunk_top.png create mode 100644 textures/moretrees_poplar_wood.png diff --git a/LICENSE b/LICENSE index 7cffc99..ecc5c14 100644 --- a/LICENSE +++ b/LICENSE @@ -7,13 +7,14 @@ All source code: Date & cocos palm code (date_palm.lua, cocos_palm.lua) © 2016, Rogier Published under the terms and conditions of the WTFPL. -All date & date palm textures, date-based food, cocos flower & green coconuts: +All date & date palm textures, date-based food, cocos flower & green coconuts, +and all poplar textures: © 2016, Rogier Published under the terms and conditions of CC-BY-SA-3.0 Unported. - Three of the date palm textures are modifications of existing moretrees textures - The green coconuts are a modification of the brown coconut - The date cake batter is a modification of the acorn muffin batter -All sapling textures (textures/*_sapling.png): +All other sapling textures (textures/*_sapling.png): © 2013, Tim Huppertz Published under the terms and conditions of CC-BY-SA-3.0 Unported. All other textures: diff --git a/biome_defs.lua b/biome_defs.lua index 46228f5..463f4b8 100644 --- a/biome_defs.lua +++ b/biome_defs.lua @@ -196,6 +196,97 @@ moretrees.cedar_biome = { max_count = 10, } + +-- Poplar requires a lot of water. +moretrees.poplar_biome = { + surface = "default:dirt_with_grass", + avoid_nodes = moretrees.avoidnodes, + avoid_radius = 6, + seed_diff = 341, + min_elevation = 0, + max_elevation = 50, + near_nodes = {"default:water_source"}, + near_nodes_size = 15, + near_nodes_vertical = 5, + near_nodes_count = 1, + humidity_min = -0.7, + humidity_max = -1, + rarity = 50, + max_count = 15, +} + +-- The humidity requirement it quite restrictive (apparently). +-- Spawn an occasional poplar elsewhere. +moretrees.poplar_biome_2 = { + surface = "default:dirt_with_grass", + avoid_nodes = moretrees.avoidnodes, + avoid_radius = 6, + seed_diff = 341, + min_elevation = 0, + max_elevation = 50, + near_nodes = {"default:water_source"}, + near_nodes_size = 15, + near_nodes_vertical = 4, + near_nodes_count = 10, + humidity_min = 0.1, + humidity_max = -0.6, + rarity = 50, + max_count = 1, +} + +-- Subterranean lakes provide enough water for poplars to grow +moretrees.poplar_biome_3 = { + surface = "default:dirt_with_grass", + avoid_nodes = moretrees.avoidnodes, + avoid_radius = 6, + seed_diff = 342, + min_elevation = 0, + max_elevation = 50, + near_nodes = {"default:water_source"}, + near_nodes_size = 1, + near_nodes_vertical = 25, + near_nodes_count = 1, + humidity_min = -0.5, + humidity_max = -1, + rarity = 0, + max_count = 30, +} + +moretrees.poplar_small_biome = { + surface = "default:dirt_with_grass", + avoid_nodes = moretrees.avoidnodes, + avoid_radius = 4, + seed_diff = 343, + min_elevation = 0, + max_elevation = 50, + near_nodes = {"default:water_source"}, + near_nodes_size = 10, + near_nodes_vertical = 5, + near_nodes_count = 1, + humidity_min = -0.7, + humidity_max = -1, + rarity = 50, + max_count = 10, +} + +moretrees.poplar_small_biome_2 = { + surface = "default:dirt_with_grass", + avoid_nodes = moretrees.avoidnodes, + avoid_radius = 4, + seed_diff = 343, + min_elevation = 0, + max_elevation = 50, + near_nodes = {"default:water_source"}, + near_nodes_size = 10, + near_nodes_vertical = 4, + near_nodes_count = 5, + humidity_min = 0.1, + humidity_max = -0.6, + rarity = 50, + max_count = 3, +} + + moretrees.fir_biome = { surface = "default:dirt_with_grass", avoid_nodes = moretrees.avoidnodes, diff --git a/default_settings.txt b/default_settings.txt index 0a5fc88..257baec 100644 --- a/default_settings.txt +++ b/default_settings.txt @@ -15,6 +15,7 @@ moretrees.enable_birch = true moretrees.enable_spruce = true moretrees.enable_jungle_tree = true moretrees.enable_fir = true +moretrees.enable_poplar = true moretrees.enable_beech = false -- set this to true to make moretrees spawn saplings at mapgen time instead diff --git a/init.lua b/init.lua index 2c50fd9..8189ffd 100644 --- a/init.lua +++ b/init.lua @@ -97,6 +97,8 @@ if moretrees.spawn_saplings then moretrees.spawn_jungletree_object = "moretrees:jungletree_sapling_ongen" moretrees.spawn_fir_object = "moretrees:fir_sapling_ongen" moretrees.spawn_fir_snow_object = "snow:sapling_pine" + moretrees.spawn_poplar_object = "moretrees:poplar_sapling_ongen" + moretrees.spawn_poplar_small_object = "moretrees:poplar_small_sapling_ongen" else moretrees.spawn_beech_object = moretrees.beech_model moretrees.spawn_apple_tree_object = moretrees.apple_tree_model @@ -113,6 +115,8 @@ else moretrees.spawn_jungletree_object = "moretrees.grow_jungletree" moretrees.spawn_fir_object = "moretrees.grow_fir" moretrees.spawn_fir_snow_object = "moretrees.grow_fir_snow" + moretrees.spawn_poplar_object = moretrees.poplar_model + moretrees.spawn_poplar_small_object = moretrees.poplar_small_model end if moretrees.enable_beech then @@ -175,6 +179,14 @@ if moretrees.enable_fir then end end +if moretrees.enable_poplar then + biome_lib:register_generate_plant(moretrees.poplar_biome, moretrees.spawn_poplar_object) + biome_lib:register_generate_plant(moretrees.poplar_biome_2, moretrees.spawn_poplar_object) + biome_lib:register_generate_plant(moretrees.poplar_biome_3, moretrees.spawn_poplar_object) + biome_lib:register_generate_plant(moretrees.poplar_small_biome, moretrees.spawn_poplar_small_object) + biome_lib:register_generate_plant(moretrees.poplar_small_biome_2, moretrees.spawn_poplar_small_object) +end + -- Code to spawn a birch tree function moretrees.grow_birch(pos) diff --git a/node_defs.lua b/node_defs.lua index b1df5f7..1c0796b 100644 --- a/node_defs.lua +++ b/node_defs.lua @@ -12,6 +12,8 @@ moretrees.treelist = { {"date_palm", "Date Palm Tree", "date_palm_fruit_trunk", "Date Palm Tree", {0, 0, 0, 0, 0, 0}, 0.0 }, {"spruce", "Spruce Tree", "spruce_cone", "Spruce Cone", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 }, {"cedar", "Cedar Tree", "cedar_cone", "Cedar Cone", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 }, + {"poplar", "Poplar Tree"}, + {"poplar_small", "Poplar Tree"}, {"willow", "Willow Tree"}, {"rubber_tree", "Rubber Tree"}, {"fir", "Douglas Fir", "fir_cone", "Fir Cone", {-0.2, -0.5, -0.2, 0.2, 0, 0.2}, 0.8 }, @@ -72,6 +74,7 @@ for i in ipairs(moretrees.treelist) do if treename ~= "jungletree" -- the default game provides jungle tree, acacia, and pine trunk/planks nodes. and treename ~= "acacia" + and treename ~= "poplar_small" and treename ~= "pine" then saptex = "moretrees_"..treename.."_sapling.png" @@ -273,6 +276,43 @@ for i in ipairs(moretrees.treelist) do end end +-- Add small poplar saplings + +local poplar_sapling = minetest.registered_nodes["moretrees:poplar_sapling"] +local poplar_sapling_ongen = minetest.registered_nodes["moretrees:poplar_sapling_ongen"] +local poplar_small_sapling = {} +local poplar_small_sapling_ongen = {} +for k,v in pairs(poplar_sapling) do + poplar_small_sapling[k] = v +end +for k,v in pairs(poplar_sapling_ongen) do + poplar_small_sapling_ongen[k] = v +end +poplar_small_sapling.tiles = {"moretrees_poplar_small_sapling.png"} +poplar_small_sapling.inventory_image = "moretrees_poplar_small_sapling.png" +poplar_small_sapling_ongen.tiles_ongen = {"moretrees_poplar_small_sapling.png"} +poplar_small_sapling_ongen.inventory_image_ongen = "moretrees_poplar_small_sapling.png" +poplar_small_sapling_ongen.drop = "moretrees:poplar_small_sapling" +minetest.register_node("moretrees:poplar_small_sapling", poplar_small_sapling) +minetest.register_node("moretrees:poplar_small_sapling_ongen", poplar_small_sapling_ongen) +if moretrees.spawn_saplings then + table.insert(moretrees.avoidnodes, "moretrees:poplar_sapling") + table.insert(moretrees.avoidnodes, "moretrees:poplar_small_sapling_ongen") +end + +local poplar_leaves_drop = minetest.registered_nodes["moretrees:poplar_leaves"].drop +minetest.override_item("moretrees:poplar_leaves", { + drop = { + max_items = poplar_leaves_drop.maxitems, + items = { + {items = {"moretrees:poplar_sapling"}, rarity = 1.33 * poplar_leaves_drop.items[1].rarity }, + {items = {"moretrees:poplar_small_sapling"}, rarity = 1.33 * poplar_leaves_drop.items[1].rarity }, + {items = {"moretrees:poplar_leaves"} } + } + } +}) + + -- Extra nodes for jungle trees: local jungleleaves = {"yellow","red"} diff --git a/textures/moretrees_poplar_leaves.png b/textures/moretrees_poplar_leaves.png new file mode 100644 index 0000000..64568bc Binary files /dev/null and b/textures/moretrees_poplar_leaves.png differ diff --git a/textures/moretrees_poplar_sapling.png b/textures/moretrees_poplar_sapling.png new file mode 100644 index 0000000..9d5f32a Binary files /dev/null and b/textures/moretrees_poplar_sapling.png differ diff --git a/textures/moretrees_poplar_small_sapling.png b/textures/moretrees_poplar_small_sapling.png new file mode 100644 index 0000000..fb9bd03 Binary files /dev/null and b/textures/moretrees_poplar_small_sapling.png differ diff --git a/textures/moretrees_poplar_trunk-1.png b/textures/moretrees_poplar_trunk-1.png new file mode 100644 index 0000000..e4e1540 Binary files /dev/null and b/textures/moretrees_poplar_trunk-1.png differ diff --git a/textures/moretrees_poplar_trunk.png b/textures/moretrees_poplar_trunk.png new file mode 100644 index 0000000..47672fb Binary files /dev/null and b/textures/moretrees_poplar_trunk.png differ diff --git a/textures/moretrees_poplar_trunk_top.png b/textures/moretrees_poplar_trunk_top.png new file mode 100644 index 0000000..4c55858 Binary files /dev/null and b/textures/moretrees_poplar_trunk_top.png differ diff --git a/textures/moretrees_poplar_wood.png b/textures/moretrees_poplar_wood.png new file mode 100644 index 0000000..55e6b44 Binary files /dev/null and b/textures/moretrees_poplar_wood.png differ diff --git a/tree_biomes.txt b/tree_biomes.txt index 22e1032..0dd0345 100644 --- a/tree_biomes.txt +++ b/tree_biomes.txt @@ -18,6 +18,7 @@ willow - 5 to + 5 n/a water, 15 5 dirt_with grass 337 20 acacia n/a n/a n/a n/a dirt_with_grass, desert_sand n/a 15 rubber - 5 to + 5 above +32 water, 15 10 dirt_with_grass 338 20 +poplar n/a -10 to +26 water, 15h,5v 1 dirt_with_grass 341,342,343 10 beech n/a n/a n/a n/a dirt_with_grass 2 10 diff --git a/tree_models.lua b/tree_models.lua index 791bddb..9372fe9 100644 --- a/tree_models.lua +++ b/tree_models.lua @@ -43,6 +43,37 @@ moretrees.oak_model={ fruit_chance=3, } +moretrees.poplar_model={ + axiom="TTTaaBCCCCCCCCCCCcccBBB[[f]&&G++f++Gf++Gf++Gf++G--]G[[f]&&G++f++Gf++Gf++Gf++G--]Gff", + rules_a="T", + rules_b="[[T]&&G++f++ff++ff++ff++f--]G", + rules_c="[[T]&&G++f++ff++ff++ff++f--G++[d]G[d]G++G[d]G[d]G[d]G++G[d]G[d]G[d]G++G[d]G[d]G[d]G++G[d]G]G", + rules_d="f", + trunk="air", + trunk="moretrees:poplar_trunk", + leaves="moretrees:poplar_leaves", + angle=45, + iterations=0, + random_level=0, + trunk_type="single", + thin_branches=false, +} + +moretrees.poplar_small_model={ + axiom="TT[T]BCCCCccBBff", + rules_a="T", + rules_b="[[f]&&G++f++Gf++Gf++Gf++G--]G", + rules_c="[[T]&&G++f++[d]Gf++[d]Gf++[d]Gf++[d]G--]G", + rules_d="f", + trunk="moretrees:poplar_trunk", + leaves="moretrees:poplar_leaves", + angle=45, + iterations=0, + random_level=0, + trunk_type="single", + thin_branches=false, +} + moretrees.sequoia_model={ axiom="FFFFFFFFFFddccA///cccFddcFA///ddFcFA/cFFddFcdBddd/A/ccdcddd/ccAddddcFBcccAccFdFcFBcccc/BFdFFcFFdcccc/B", rules_a="[&&&GGF[++^FFdd][--&Fddd]//Fdd[+^Fd][--&Fdd]]////[&&&GGF[++^FFdd][--&Fddd]//Fdd[+^Fd][--&Fdd]]////[&&&GGF[++^FFdd][--&Fddd]//Fdd[+^Fd][--&Fdd]]", -- cgit v1.2.3 From 23ac37fc4c64213d93388f04b4a8016d4070180d Mon Sep 17 00:00:00 2001 From: Rogier Date: Sun, 3 Jul 2016 07:31:35 +0200 Subject: Add new screenshot featuring all trees & instructions for recreating it The previous screenshot showed only a few of the available trees. The new one shows all of them (except acacia, which is disabled, and in the default game anyway, and beech). As finding a suitable spot where even a significant proportion of trees is only visible at all is near impossible, this scene was crafted, and instructions and a script for recreating it are included. --- screenshot.lua | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ screenshot.png | Bin 115537 -> 103526 bytes 2 files changed, 168 insertions(+) create mode 100644 screenshot.lua diff --git a/screenshot.lua b/screenshot.lua new file mode 100644 index 0000000..cb2ad7a --- /dev/null +++ b/screenshot.lua @@ -0,0 +1,168 @@ +-- Usage: +-- - Create a new world +-- - Set world mapgen: v6 +-- - Set world seed: 2625051331357512570 +-- - Enable the moretrees mod +-- - Edit the moretrees source +-- - Disable all trees in default_settings.lua +-- - Recommended: make saplings grow fast in default_settings.lua: +-- sapling_interval = 5 +-- sapling_chance = 1 +-- - Apply the patch below to moretrees +-- (so that jungle trees are always large, and differently-colored): +-- use 'git apply --ignore-space-change' +-- - Make sure this file (you are reading) will be loaded when minetest starts ! +-- (e.g. add 'dofile(modpath.."/screenshot.lua")' to init.lua) +-- - Start minetest +-- - Goto 700,y,-280 (approximately) +-- - Make sure the world is loaded between x = 650 .. 780 and z = -350 .. -180 +-- - Give the chat command '/make-scene' +-- - Wait & walk/fly around until all trees have grown +-- - goto the platform at 780, 30, -277 +-- - Set the viewing range to 300, with fog enabled +-- - Take a screenshot. + +-- Patch to apply to moretrees +--[[ +diff --git a/init.lua b/init.lua +index 8189ffd..afd4644 100644 +--- a/init.lua ++++ b/init.lua +@@ -225,9 +225,12 @@ moretrees.ct_rules_b1 = "[-FBf][+FBf]" + moretrees.ct_rules_a2 = "FF[FF][&&-FBF][&&+FBF][&&---FBF][&&+++FBF]F/A" + moretrees.ct_rules_b2 = "[-fB][+fB]" + ++local jleaves = 1 + function moretrees.grow_jungletree(pos) + local r1 = math.random(2) + local r2 = math.random(3) ++ r1 = jleaves ++ jleaves = jleaves % 2 + 1 + if r1 == 1 then + moretrees.jungletree_model.leaves2 = "moretrees:jungletree_leaves_red" + else +@@ -235,6 +238,7 @@ function moretrees.grow_jungletree(pos) + end + moretrees.jungletree_model.leaves2_chance = math.random(25, 75) + ++ r2=3 + if r2 == 1 then + moretrees.jungletree_model.trunk_type = "single" + moretrees.jungletree_model.iterations = 2 +]] + + +minetest.register_chatcommand("make-scene", { + func = function() + minetest.place_node({x=780, y=30, z=-277}, {name="default:obsidian"}) + minetest.place_node({x=780, y=30, z=-278}, {name="default:obsidian"}) + minetest.place_node({x=781, y=30, z=-277}, {name="default:obsidian"}) + minetest.place_node({x=781, y=30, z=-278}, {name="default:obsidian"}) + minetest.place_node({x=781, y=30, z=-276}, {name="default:obsidian"}) + minetest.place_node({x=780, y=30, z=-276}, {name="default:obsidian"}) + + for z = -360, -300 do + dy=2 + for x = 630 + (-z - 360)/3, 660 + (-z - 300)/3 do + for y = 5, 22 do + minetest.place_node({x=x, y=y, z=z}, {name="default:desert_stone"}) + end + for y = 23, 25 + dy do + minetest.place_node({x=x, y=y, z=z}, {name="default:desert_sand"}) + end + dy = 0 + end + end + + minetest.place_node({x=717, y=2, z=-298}, {name = "moretrees:palm_sapling"}) + minetest.place_node({x=713, y=2, z=-302}, {name = "moretrees:palm_sapling"}) + minetest.place_node({x=713, y=2, z=-307}, {name = "moretrees:palm_sapling"}) + minetest.place_node({x=717, y=2, z=-318}, {name = "moretrees:palm_sapling"}) + minetest.place_node({x=723, y=2, z=-320}, {name = "moretrees:palm_sapling"}) + + minetest.place_node({x=645, y=26, z=-314}, {name="moretrees:date_palm_sapling"}) + minetest.place_node({x=653, y=26, z=-322}, {name="moretrees:date_palm_sapling"}) + minetest.place_node({x=649, y=26, z=-334}, {name="moretrees:date_palm_sapling"}) + minetest.place_node({x=662, y=26, z=-342}, {name="moretrees:date_palm_sapling"}) + + minetest.place_node({x=672, y=5, z=-305}, {name="moretrees:oak_sapling"}) + minetest.place_node({x=690, y=6, z=-322}, {name="moretrees:oak_sapling"}) + minetest.place_node({x=695, y=7, z=-335}, {name="moretrees:oak_sapling"}) + minetest.place_node({x=699, y=4, z=-301}, {name="moretrees:oak_sapling"}) + + minetest.place_node({x=751, y=5, z=-254}, {name="moretrees:apple_tree_sapling"}) + minetest.place_node({x=729, y=3, z=-275}, {name="moretrees:apple_tree_sapling"}) + minetest.place_node({x=747, y=4, z=-270}, {name="moretrees:apple_tree_sapling"}) + + minetest.place_node({x=671, y=5, z=-283}, {name="default:junglesapling"}) + minetest.place_node({x=680, y=4, z=-287}, {name="default:junglesapling"}) + minetest.place_node({x=702, y=4, z=-288}, {name="default:junglesapling"}) + + minetest.place_node({x=646, y=12, z=-199}, {name="moretrees:spruce_sapling"}) + minetest.place_node({x=644, y=14, z=-177}, {name="moretrees:spruce_sapling"}) + minetest.place_node({x=678, y=9, z=-211}, {name="moretrees:spruce_sapling"}) + minetest.place_node({x=663, y=10, z=-215}, {name="moretrees:spruce_sapling"}) + + minetest.place_node({x=637, y=3, z=-263}, {name="moretrees:sequoia_sapling"}) + minetest.place_node({x=625, y=3, z=-250}, {name="moretrees:sequoia_sapling"}) + minetest.place_node({x=616, y=3, z=-233}, {name="moretrees:sequoia_sapling"}) + minetest.place_node({x=635, y=3, z=-276}, {name="moretrees:sequoia_sapling"}) + minetest.place_node({x=681, y=11, z=-260}, {name="moretrees:sequoia_sapling"}) + minetest.place_node({x=682, y=10, z=-247}, {name="moretrees:sequoia_sapling"}) + + minetest.place_node({x=737, y=7, z=-195}, {name="moretrees:cedar_sapling"}) + minetest.place_node({x=720, y=8, z=-189}, {name="moretrees:cedar_sapling"}) + minetest.place_node({x=704, y=7, z=-187}, {name="moretrees:cedar_sapling"}) + + minetest.place_node({x=731, y=2, z=-227}, {name="moretrees:poplar_sapling"}) + minetest.place_node({x=721, y=2, z=-233}, {name="moretrees:poplar_sapling"}) + minetest.place_node({x=712, y=1, z=-237}, {name="moretrees:poplar_sapling"}) + minetest.place_node({x=743, y=3, z=-228}, {name="moretrees:poplar_small_sapling"}) + minetest.place_node({x=750, y=3, z=-230}, {name="moretrees:poplar_small_sapling"}) + minetest.place_node({x=731, y=5, z=-233}, {name="moretrees:poplar_small_sapling"}) + + minetest.place_node({x=702, y=2, z=-274}, {name="moretrees:birch_sapling"}) + minetest.place_node({x=697, y=2, z=-271}, {name="moretrees:birch_sapling"}) + minetest.place_node({x=696, y=2, z=-264}, {name="moretrees:birch_sapling"}) + minetest.place_node({x=710, y=2, z=-265}, {name="moretrees:birch_sapling"}) + + minetest.place_node({x=707, y=8, z=-247}, {name="moretrees:fir_sapling"}) + minetest.place_node({x=699, y=10, z=-254}, {name="moretrees:fir_sapling"}) + minetest.place_node({x=729, y=5, z=-261}, {name="moretrees:fir_sapling"}) + minetest.place_node({x=732, y=5, z=-252}, {name="moretrees:fir_sapling"}) + minetest.place_node({x=741, y=4, z=-262}, {name="moretrees:fir_sapling"}) + + minetest.place_node({x=751, y=2, z=-286}, {name="moretrees:willow_sapling"}) + + minetest.place_node({x=760, y=5, z=-223}, {name="moretrees:rubber_tree_sapling"}) + minetest.place_node({x=762, y=5, z=-230}, {name="moretrees:rubber_tree_sapling"}) + minetest.place_node({x=766, y=5, z=-243}, {name="moretrees:rubber_tree_sapling"}) + minetest.place_node({x=764, y=6, z=-252}, {name="moretrees:rubber_tree_sapling"}) + end +}) + +--[[ +The following is a search/replace command suitable for vi (/vim) or sed, to convert minetest log +messages to equivalent lua commands: + +s/.*\(\(moretrees\|default\)[^ ]*\) at (\([-0-9]\+\),\([-0-9]\+\),\([-0-9]\+\)).*/\t\tminetest.place_node({x=\3, y=\4, z=\5}, {name="\1"})/ + +E.g. a minetest log line of the following kind: + 2016-07-03 11:30:50: ACTION[Server]: singleplayer places node moretrees:rubber_tree_sapling at (760,5,-223) +Becomes: + minetest.place_node({x=760, y=5, z=-223}, {name="moretrees:rubber_tree_sapling"}) +(Except that the example log line above has an extra space added, so it won't be converted) + +vi/vim users: Add the minetest log lines to this file, then enter the following command, with + replaced with the search/replace expression above. + :% + +sed users: Add the minetest log lines to this file, then execute the following command at the shell +prompt with replaced by the search/replace expression above. Don't forget the +single-quotes. + sed '' < screenshot.lua > screenshot-new.lua + +Windows users: You're probably out of luck. And the effort of doing such a thing is probably +larger anyway than the effort of copying an existing line and typing things manually. +]] + diff --git a/screenshot.png b/screenshot.png index cae4346..b9ab5de 100644 Binary files a/screenshot.png and b/screenshot.png differ -- cgit v1.2.3 From 471a11f92dcdf9f78ce25268fbcaaa627907b257 Mon Sep 17 00:00:00 2001 From: Vanessa Ezekowitz Date: Sun, 21 Aug 2016 15:56:02 -0400 Subject: pine_sapling_ongen -> cedar_sapling_ongen alias --- node_defs.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/node_defs.lua b/node_defs.lua index 1c0796b..e5f8127 100644 --- a/node_defs.lua +++ b/node_defs.lua @@ -473,5 +473,6 @@ minetest.register_alias("moretrees:pine_sapling", "moretrees:cedar_sapling") minetest.register_alias("moretrees:pine_leaves", "moretrees:cedar_leaves") minetest.register_alias("moretrees:pine_cone", "moretrees:cedar_cone") minetest.register_alias("moretrees:pine_nuts", "moretrees:cedar_nuts") +minetest.register_alias("moretrees:pine_sapling_ongen", "moretrees:cedar_sapling_ongen") minetest.register_alias("moretrees:dates", "moretrees:dates_f4") -- cgit v1.2.3