From 9ced339ce5cbdc48a7d9417786585f6f9c968ce1 Mon Sep 17 00:00:00 2001 From: Rogier Date: Mon, 27 Jun 2016 23:21:29 +0200 Subject: [PATCH 1/6] 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? From afab0692df2d99c36473568602d1cc4059aa2e65 Mon Sep 17 00:00:00 2001 From: Rogier Date: Wed, 18 May 2016 22:54:19 +0200 Subject: [PATCH 2/6] 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 0000000000000000000000000000000000000000..ed743b5c79d501dadc1fceaec3e2f9d3bfeeb23f GIT binary patch literal 2118 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 KMNUMnLSTZhT5tvc literal 0 HcmV?d00001 diff --git a/textures/moretrees_date_palm_trunk_top.png b/textures/moretrees_date_palm_trunk_top.png new file mode 100644 index 0000000000000000000000000000000000000000..329ba46482f348353c8301e285aa46be3c02260c GIT binary patch literal 673 zcmV;S0$%-zP)zlpI!jqoQqrnSTRp|w)b?eH+(yO z(*dK0eXaE}B7F7s{az8!vS-Dbvv^{eDB>}Kn-ytue zBocy8uO_m{eb)Fo3fNW$WiqvOzLzUwW#1%Nb80dyOk2SDVKr`grbHS>a|-CW)- z033ZhX6qnFP8A{q2cS_EfC|99a}}zL`g?|DOlFg|-FCKmhM^}(N&+H_oTuXNcPfCC zXS!*mJOdC#5p2wE=RwH)a6LXa1P~<=04e1I(6*bB%P5HoSsXq;l$=*;yGfF&s-~NI z!eVFO0LVo40Q_|4Lh#XO6b9_%%b8`AN~ID30l*?Q>_qqmviK&1^R6 z@27Fr-fYti0007hNklVz?J9`2Nx+S~awlq%SII(BO^TlDsbN^i) z^39i5-upB`7d+C$$B+kfUVtm#e%l28En{DV)1l}b`X004mbbf%O-mhN^tWt2b;07Wj&=gVI8>-*P(R&`yE z+TgxFaLq)PJLfisZO-%H{Nu3WDU+En#;otx`{UuRxof%|LnI$P{ZI<&oK;4L;ETL) z&LQHURV}Mh$fny7LSl?bf?6y5@$2tr^^8%xe)|gkFUv#-!38_XC(395Fh+Bpr3qqH zlsrjo^s{odTCPTIVvGRbAXqb|oE2v5%`hqCVlwZBBQi{F^hGX=F-GYzI7(><;l0JO zJDr+#`_A)(EuWsl1Hqg7_4WNt2*G=AyhTJt5ozLrCxjGv5o08Tgb?0t?jG9>UcI=g zU)BW|#*fpYN|SVR+%lRPKT07H=&swJbYIG{NHYLHCfK5y3n4~ln|Ax;Y;_?otQnI? zZFI`$vaD9i)n?!HR$nZh;Nw3Jf8Sm+mgPJsy-7^Htp70 zyQt>By!`F**=LNVdekvSWlacSQb^n%_m`i3aeH^$TRpT!Ddl4@-sU{3@(CfNEX!(I zZ~xtlqai8cbTa+puRmR|&o7_9S-(EGgUkxa#Jl~wZXaW8y94L^p>0mX@jq*rdtomT RgTMd)002ovPDHLkV1h9gTaN$$ literal 0 HcmV?d00001 diff --git a/textures/moretrees_dates.png b/textures/moretrees_dates.png new file mode 100644 index 0000000000000000000000000000000000000000..cd8d57848af3351cdd9e12275214853c13258a60 GIT binary patch literal 9421 zcmV;;Br@BHP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00006VoOIv0RI600RN!9r;`8x z010qNS#tmY3labT3lag+-G2N4000McNliru-~<;A4=h~(CE@@8BrZurK~#9!?VWj? z9aWk4f9KSG>#lu!U(!iB9kPc6LIMe!VHpG?OW2gxkwr`pMnz#{+!t_w(P4=bML`A~ z7@f$tpokC&kU&UCShCYuy3-b=1OWA5=zE`MfYx^9Lb)9#5) z&v%LfKLfx;OIPAI)sC+kh}90@ug%J9&Pn&~?){>bDPHY%_vulAp_Ctn1O$6>Eo+XN z)u#ej2E0ELAk-D$<5SwNmfhk?jms1?fbRtmY!f;qP{2S%47Z#pS&5{X1TbakN(@#z z=Jy(*+5!AE_?MH8QW_ZlX@t2q2@WUukvzENBBrTGM|G%*fOKm;;`J##-&@S5+WZCp z-p^ma>T1XSUPG%Lz-V)HJfd&kn|-oTS1w_u1=p;gCZVFPsTPTJ65REXYNi>K7t!$Z%>fj2X7JVYfKahX6Q98Imw zFb0MY(IfuYxsUil72J$gZ|?H+5!C6(v{d=Z5{75q1XjnJH4Iq5$mhA$EQRk zil{)4iX~9nQUkMOVrbVM)Q_uy#DD-2EZb!j##c`{DSIP;-vP)1SXpfy)gTlVfYkW3 zRLq?yi39`zJkx-cFJS1^eq{ITMcu@D)QxXP-f%EHG~yg6R_>T}>d2RLIe5hP$wbGd zKYL|kbMLL6`d}!&5Jy5Nb^%M~&(_MN;+?)nz`)^p1d>8QJO}C4G@?-z!+ZM?5K{D$ z4If=}=Fp=8#V?sJv=8n~42u zGgDM<^_dUqc~CirBoRo2p-^^Fq{1IdtrO2$G2=k`2 zNQvM5cjMmuu@k}TQ=rZJ&Tf0msZ^#1K19PXK`1~80l1HJTN4B>qGTEg{2JeJ5Ysit6c7ap!U+n+JW7IsSW-jNxW+zO-+cO)AAEdgwe^h#p<4tV zGz~d1@7$n<+XIT&c2*nciWeAz`L0oj~l_Qo3;K$)#Oeq z@M}!Rg+M4M<#1F9RFYo%xNOGKiW-_GQ7ET?OQw#i^DOH@&9^?w%f3`9l)&r&#P`t< zk3%2PC5i{fnv;wy8Xr?H)<|%oL`fnDJVTBt-I1n-TUM;z@ocrVjuxSr z0zQ55Jkq~;=S26zBoabTNnfTWNm#H+_^ z{ed?U;KhQu_Qis^_WoNx7JcDY&(BCTPTc;@haW9rd#>72N0rc2fNM|aIDW8u=n0Vu zkpv5%3nG#U4T30x2SA~B5V4vlQgIa=45q`GL%lWAPt0}#urK^RCRbZSH3-FV@TV5e z6})_99p{K>2oRMeBvNtIG&exjRFwPs(a=$c2<32ygpr)(8KSsu+KJhF8Als{HQ)XC z8S0l$m=HhQb*4<2LY6F95}Gd!5RwXT-GYg8v-<}(Mf3>#N(pH$puVXEBQi-J#&?FhmcIpY^#}nW@De%bR=CnWK*y-g*Hg2_DMu=rp{+mPgUv1DLipxPh9J0djO zz%M-f?45U9arQ5)zMj(^JFgBYvF$&6YUfjL@~aAfs{nX@Ape%g%2y0Z;buy(tN@~< z0)mM0a2BdWkxa+n6PgrF8)Ex{D~hy5}8gozkmup>*`Z(4!C$c2Whih zAFdw&RDcqZL8%1J0PY8HJs+if1p-B*C<>DoOsIeS+5Ndnu~>ZffmMn;XZsEhDP5R!zmh1OX+-Ma8z!zo!?0#~?>FI6;7n9iU))k|N1xJ>Ump z{tGnb1-uoPb+jmwfGc5?AM-{^=fJUAVSAvK4Z-msR4T~!`Dp57lP{Ww-+uC^y_*&u zGwErsRE$DYQUM{!APC?F0c_WUW!o^B4^NgLOEQv)Xpy|I_P*b3+&ZS+!l7IQUNUuD zT~IN8oTS0o)aEcv1Bxg@Bpj_Z2{7M6x*-MTyWsUU8paiGyZ8tEp8)_BPA-_yc!5s& zxspKUI+lGDXN-aeprQaOiqKRQwT+2Ce(TAdi>s~m-4dz_aM1@(C5?7vLd5f)Zj8$F zok9i7ccCjXk~K+aiUjJoXq_?+vL=Ju4vhW+YB~b_teNzu!`cGB@0zRlj)JlM<$0aI zO!wtq^*H(&Ar29#s>q7MSkMQRyy&aSij6(FG4BcrO$B)EIJj@7RjmARLQ+e+r3#{& z_NU|ENCalFh?eFw^n?OpI4BiMfv1=4@pB!45KLRT68qk4?8}ZB-yX5elSBwDhVATD z8k4*4S-1D4YHJ=1LemHedUFe4l%I&nLd2_>h)Ob&x(q>-APLeN$H8zNR7NbA4riXs zUYtC~nL`Mk0?_wXWB+thcMpJ{yzzrQ;qe57Vi)iZkAt6`ydbxSQg8sbEM1AW<@5XZ zkKITnO_>~;${7kF@9;SIW&qFooM!f|ui3;5r@hShHX+^c{+L`Hnnt~eD*6Z?$~NgN=&2!g#)bGdPkE`B)}0K2a5nc7Wnl1zWuEw`#>%! zh%$(*fC&`veMo``(Pt!JUW=g6MM`GxS+nZv%D?K``SPLHoj!d!ZD?p9!^6X4b}9(P z8sH#zTyb`5rmyF8C!bdfYHa%tpZW9S;BEY3vg4YcH34|WbtQ4no}+4vJzY`aF+}5W zNV0|?2;e(56j6Yjihzp}tWpIwp#`2yefOJBZ~x}Jdv2o}ufCCWc6QQeG>R8rd~wWH zg-|8H;kYEzN78erVd2@%6p1_A11@gZwP)stIXG~(U#Nh&9I;p&LPUXAHbA%!O%tIf z5|9)io6SK?)mSA}{Oq@%*cF=p5Dvu@a5!#QcBZhPvrU??>fX8{l#_g~b+IT~({#mb z5oP0%!F+U*=kq87foZ!SltK~(5Gq2}G#I5aY|Dma+8}@=3gU@##-%r{@6GM4wzknA zv=!irS(9lp&b4SfcBz>&E-PhoC#O^jIS4>y5zUjm{&YH9yJsNzv%%if5@r}lGiSng z9HbHvq|+%Vn*7?7Pbpf-AOv-7vg)U|eU6!}UCXb6BMcBvnBWaFi=$ z6a#?E0-|v}e)=g39(nSmt}*{`=}>e659P9sdQA%C6);M_4DxP$VYmb{V*rkaq#A`H ziAc9KpeY?k&(_EwfR;&(FSjU-HJ5QkcpkdOm@30$0ZN{S;cNjT#XKx9Fj)j+1PVkF zVHj6!t)oGx5@2pzNje^TtT7^8O&kZVWgx0hBx@2#*QOvaj{5OUh@}${1p&c`KNo}o zz@@i7`tsvuW785x6u%WH>J~$g{IVb+=W}EjgQsc`WC0!sDxMRZbjG5m-fg^p3xp;C zE}t`@xn5PCs#VB|PN9gHqM)^<9*L-qh#~=w3q2i$BFk{HWmpxLxgwtCi~+z_0Qk=} zFAx88_uyAciNtxOfPBFu!XqXXvXCVRk_5&%n9N;+;%DlY( zYY%|$VA{kxKV+8AOek~_CA5R^pj(v59=WacXFxa}6BLSF!1C!$8*+upJef1piXvh$ z9qIZSFitS|$}ZH7uLDXJxE6tB*q$HJHq1V;_d@_)2m%`4zajNm)9{HU2z%tl)}C*y zd8NPFn%*nM{4U_p`@SG=c=VYSx*nn2wGd$pnxexl87L1NKuvQE>e?DH)IS2FY?KTl z{%YQ7LrVah6fj(u>({q>Ib0_)ex4-Cr*hZtTv(&0k5)xzL&+XF^jecAPbQ)kr8A~Z zA^rXRW48T!C}TbW(vCI9DP%qgNC*f+U~>?-V3v(>)0*Kkj^a>(2cVgf6j^>p_sBOc zng^A0TyIq5qq95YcrqDR-pd}pYsQ~Vn{(&R z9n;h3m=69Rw_JF_>0;5iJ8xEMX#hb9T!%=sEGYVpY`^)?cXo9@bm;G|T8@P8iwAaX zY1hns`yo+^L|qz!D8s54paFxdh+wJ&1`fyf9V-y-icA}K=a>IyegDb#eV;sa#WFr^ z+BBkR8a8d(G-fM8C=vhw?zr+p(bDjN50?(~CChTWtL2ngPkrTCp(L4YIA^|RlYL>fm zpk{?CDGMpMR?3y(+73iXK&l}PIi?{9ILx9A!*Ss_0af(K?EaqZUC;IwL-B&CF~0~r zQkJfS?*-yx0mu^oPCR3NPcBlI`Wn%sUP0I3umEM-K`vWBVJHhFszZhwy_ z&~n$~3yJRwia;Q64oMc_J1)$?hbf4tO{dV*QoHS@-@i1Y+L}g#P_%*%$FkW|Ni6P1 zgIwiIzieGq$`=>wBoK`V!$b{n4pFQ!L+HJ z^@>`PI6;C$?ZRQuIIPa);C&&G67C+N+sj6cyp~xuYqa7t(Z_G5qdO= zSTq93v=D2IA(_-+j$~k!^FwtDNrNg|zh1f$AFg)%?(;3?@EgNBiyJ! zp&}Yu8{u0Hs33y69<-V$B8mbhUx8!!o~H#=Q5nE6RPFfRYeKaRT()3R8m{vro%tW3 zo)49XsEMi&z>rF%;FZc?js@yDu!q@%ozD|LI9H||3J;J<#t=;>k!-3(wzm(dw2DL`0^1CbFFU?1@?GQSm}ybO zDi7rP`W0U^4tI@x`}Xm!uC6iN`u$5nlK?B z_r2?Y#t5P51Dx8KBCbzQk5Z)-%m?!sWJ(}O1Ox#KI4R}~Ym*nP|J;I;dwve!`;IA3 z&F@gDCd$)wMLSj^^!R*t-{N@@aoRXt@7h+e3J1p@KXE*1ZD}RL!^72--9l}ab)TvR>BV*<+2WU6c5j^R}k_jUic{Th`4xIFOby?Zw4#YmteQjPT> z3@By`FkQg$xm(KRH>&Z}<4&sSq1!iZeib;8bk+@^Yh+KTrioA`008X&{e$#@dsdv2 z>)G2D$ol@EF12pOuV2Ukz^dh-02Xmh{!l8__B5g+vHqjd4&-gPAWO5HM8og#Y^X%lkifaIA?FI|#tB zckkXYd-H)%?E>BwK7iGPKu#wIqFy{v;Smiv+eM~g0lE&Zs4#tw;hqs#!$oMi1cCVt z5$ay`?GMiQIsojrmXp1E_wccP^MUtS0xVq#7r-3^e66mP7uPnIH<*$F8jYf8TF8y$ z5HJp^$fzCP4hIB--NPv6OqeAz&I-n|&m7Zs&D0fyzw(KvLQy?KA>v5+*)lo-1i#<` zX7wJZ-8`^QoaYv7l=3CSbQyKEDQKDmNm0OEhLNEml>Go&OoLjV*qSBeobNxgyQkVZ zMuX671OI<~<KDrQ4bk^Cw3>B2-`kp56I#0~+3c)kzU^Wj(y zz!+TDN2O9inG^VgK#l8SLtX8*)jRvPR9n+%5W2&lzvQh9Awijt>5 zU||Lc0?457Z4(|3K*8l~nUtd^N$JiBxsPt|Yd@EY!u*`$UP%PyEXo47z7I)|A;}^f z&QS0yKM|9kueP?)BD8COBQb=y$mCjQn;L)*{6Sp&(t$^|rD@=|fwS{<8Z1?1snc^k zCTK!etfB7CyPw*%vfBDai%?d8)0yk!~sgyQ(d5)CgSyyc0u+BL`(gWjYwv zA3D~fdj`q?$^iak0^PEv+7d^VQ1t<>JE61YNDU!*#@3FX=cNe?dY7)m!-pHcwY80O zPMQ>|X)`nlu;i##!LQgi9El;M!pO6ePB6Pf2|5QJ1c0Z5FTUjs?(6I2UAuRW`R?DL zgeC!66i$xF5K^)Jr}ij!xhz^AXB^uyjsJKH0KDH!A)zT}M`j3-zcc@g!T$ho4P*HC zp`O@p%Uz5bUeLwUwa>kuOd+A^1RjYYU+W;_PwOd zi}b01j^mIh6aaNHutt zuyx;aM(tahLJaVTV)!iBS{9TazhMe_hdmtEQ09CBWNZ)p7`4ATKEt z>mD9>$;6+VLR>JL&cj6jFM_6jE9CnPb|n0e~==Lf)4NKvYox5F>X*JEW)-;Xz?ggjV;T?qY(;M_`hg8%2?R<%MGaj7v=B5x2mGYmNLWG98x=@%xLU$PSRvh|> zn2p=m+;~LX+)~#+ttOVaut9#s8)!c6O5gEzxeouAH#LQbubD!KC_xSc$W#o4DJ1j> z@K%l>UZyy3KybVX_5BUa!`ALe(c@e=8;`g6pqU|?p1GQ3b8pu!8842Oj-Z# zqpLn+ei3sxE}YmZCpBq-#EtI>9-l#i00b1oHlgwW3OJ}jM%qszLR7bt04`p-601J( zsZ+(l-|eV5#1wMjK~spR3A>`NnLzqDDrWAPiN{w?2Jj+)GnTHz8;zs0 zI+|n6vXc~5t-&!ILsWP{>zrA*`{5_8YHJ(~LYV+Z`iK~_nBQM>g7QRED_#NMp`|PF zk!ovruL#{X@S{^2(*pSSk|Mu`8x_cepslqLHSriUNqSR9P{HOKBhA_^015yWA8!1x znL1c2Wh?izi4y<>jwe<-1;0Po}xF%?FiX*jlVS$jLV*0rUp&62z^JFNZdS5BLw z-*oR&q4{hMM`#*B^BSUpRjz!4QrapZfa?2@7=c7Z4Da5DhPFDy8*7n0kb&j;#ft6y zN^417IlgVz8AegQ^}q`nian&In2*dRjHH#9erL>tS9!kVIPX5Xzgj<14Aix!p+sbqM=G#+(C1L~+uzxryW!fibFGdoJ~X^TS7M4v6Nxx< zQE9d-=Bak6@(F;n9}`u!pVivzJeA42s6T-m)vOBHTrM=zKxh)+NF70|mLu&4bmd@g zY_`4M5@HPvkYiCWFu=2+DLSa{&4lk?NhPsuPFv0H*~v)h4_mi*)z&(igl07hynRQ| zs^yRX{G;cKKiu_l3v+q~s4R+z*QX(?8jL~_0s{!=u*KItC7bh%E9hUCuyn>xmw)xQ zZ%hlbX3Zj^D3Z;aH?wN%e zqNW#0s@Uwi94J@-bHF8vz_JicMUbvdf^&kvGiyikmH)`D+g}gh+Xn~A<#Ooj>l>3d z9|&0mc)Ps*+L-S#PCni{)Nt?MK6<&6s|b$aqNX+tMUfC#HoS@fMIcb(Dk2FL`D`9q zLtS~q^RN5P`u+b|Z5^XQXx0En!bS5C0O%qFAB#sS&E1*kZwZ&D3xY@sgINT=50Mho zwKhSkPoa`8qnIhfasqg+uPBkof`uLRYuEN<$NU>c-xqt`L%FhGlcg)cw{@QUDktQd zl%j3X+~KxpWBLJzaG>ibnkEd-L#b3kX=ntgmPY7_6g)zZDS7Y$UKe=ojR0_3VcnRn zqGLMvcLL{}eD;j_QzH};1)1b#w?6-A02eXPWgE74wiw+*p9&a~zU@#|lpqTPiYmc1 zEEvp385DJmHK=c_-SVZ!UY=ELJ@1xKEdme6*DhE%$IX_nTRyY(a-F$QBPs}owJ$j8 z?g{O?deY7}nwV5k^IhKeW?K3}N+pb7022KH=Qb@82coZT>?%hXKeL}wm z_^0_Z+UGaO|7-OR|ErVB&ryj0RyN=lOQ2;#ax?jMeVnpZ68zH$!N^UI`b;@sk0uFV z8a|j)K|CHsg!xcKK#MBS;}P2qD!-X1u#bc-WYn2&?Ug)&T#@S z6|Ns2Rc;d;8&bd#kLjR(08S|4dIY*IBbCpa$;3y&Am%Yg@Ip0hwB4o!yDxrh99#S=F z+n}oy@l*nC$$>)wqA9(krtZ8iuGze)+VNM5&@_UidQOdz!YLpWNkxK60OE1Pq6xhE z^d{7$<7nt;hE*!V0*7ImJ&q_|^u;xsH%*!_o=luLF*IL>BOx?>fZ8A;X35aG%ms)f zz_eWuzl6T73dT)q1qg?0G8h5^&*P8X+Fv;v{S{1`auo3bM)!7g1=ZG24MI}^RE7nESPT-+9G6Go=abW0x?P}?JZ{3$U`{3Vg-?@u-y-#mG5TXiD@)f7C zrD2(tupY>k6?iEfHH1Tu2qabYckV52jW0OvyxV@hy1Ux3{w)!@d2hwiliG8x{a~T5 zXF8K3FG&&g=G*_c^MwrgKgJ;Ann;bn^XVk)I*lKPz;}{&)V)yXOA_7{wjR T-?(7^00000NkvXXu0mjfaC4O0 literal 0 HcmV?d00001 diff --git a/textures/moretrees_dates_f0.png b/textures/moretrees_dates_f0.png new file mode 100644 index 0000000000000000000000000000000000000000..b75d59a3a70856dc5b62b4665ab6029957dabc08 GIT binary patch literal 3848 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 v9>B~f!Jj~Kd>hjWMN{@lpQ)H~1%L literal 0 HcmV?d00001 diff --git a/textures/moretrees_dates_f1.png b/textures/moretrees_dates_f1.png new file mode 100644 index 0000000000000000000000000000000000000000..535150bfb493e506e5493be49375e039d327fe46 GIT binary patch literal 4137 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 P)u;pfNgLBz93kmHQ~`Gw literal 0 HcmV?d00001 diff --git a/textures/moretrees_dates_f2.png b/textures/moretrees_dates_f2.png new file mode 100644 index 0000000000000000000000000000000000000000..e2e299c8f2578d300cc164247091c3d2b3d63aaf GIT binary patch literal 9070 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 literal 0 HcmV?d00001 diff --git a/textures/moretrees_dates_f3.png b/textures/moretrees_dates_f3.png new file mode 100644 index 0000000000000000000000000000000000000000..eef43f0b873e517ecab4d9c54002a399a459869a GIT binary patch literal 8295 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 literal 0 HcmV?d00001 diff --git a/textures/moretrees_dates_f4.png b/textures/moretrees_dates_f4.png new file mode 100644 index 0000000000000000000000000000000000000000..78f38f981880c679ebd8c8549bb7e68cf288f1bd GIT binary patch literal 9237 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

Lf!oz@)m(qiVKF=!$ rzx=CvmUWc7zJKyh{>eZ2$Kn41lk**bHIkI200000NkvXXu0mjf;L;ZU literal 0 HcmV?d00001 diff --git a/textures/moretrees_dates_fn.png b/textures/moretrees_dates_fn.png new file mode 100644 index 0000000000000000000000000000000000000000..db889130c700814997e1de032991d4d3f22f0ef2 GIT binary patch literal 2589 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 bn@5L_j((Zdv^Tm5ea-;Q+=^0R%DnL(XF!p} literal 0 HcmV?d00001 diff --git a/textures/moretrees_dates_m0.png b/textures/moretrees_dates_m0.png new file mode 100644 index 0000000000000000000000000000000000000000..4ff61e7f8a820e655afe548025b7e2bb0e6a679f GIT binary patch literal 4138 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 W{@hEwR%+Bu9WXVrGOX9fJoq11uz!mH literal 0 HcmV?d00001 diff --git a/textures/moretrees_dates_n.png b/textures/moretrees_dates_n.png new file mode 100644 index 0000000000000000000000000000000000000000..c12a3d992b2fdcf3b3126be10fcf6b4e5064ff27 GIT binary patch literal 2107 zcmZWqdpy(KA3xjJ+$Gnclq4!1HH0+GW|ng8aaTk1+fq#z*R1c@^C-6|VwTCRC>H&) z^n_aUxYZ+Rx-7I(5e;34CVpSfzrS-{=X}n2f6nW5&gXqTmvg?}WOWro6##%b#gpg{ zOK4>%q2aj$ANdFt>!LmV_X3b&4&!V9ey-@p0XSs?zyuWlCoTZ`jMBS)&aeU<0=3v2XQts|8+n}psCzXROaz9V)tLyg&a`8RPYYNn^ zqy4irF4Qpp>-GXck^kyT9+P1tLiAasbArySn@{O1dr|w;5R;2q{|nW}NqRCHGdF5? z=tf%Ei9XyIc7p|}7b&%*GI67cbQ9fkp|0KW<%ppwJ-;YAV&ejo%Uu|Q9$ms_it#F@ z9FX+tj;e_Nfv&GxK?aa4ZLZ4f%ipn&X|b)>=RVoO7{H~XM<#6@t0dDtpPK-(kSWq*v@Ujob<*3*YjVYod>M=9l7k(LHuSy z9w7CmX&e^)nbwpViyPGy7GyC@P}zkfkq_$)C-;<9u#@u~PeP&8f~-RH3|YEs%D%zw zJ!a6GUbz?H1-**tdH(ZV5K)zihC+rMmviBjHe*%rB~7!SYcYKof@1$;2bCe3M{&qP zuIcYapOkf7FV(DJeqvO0Y!>G5d@m#W8fm}3U{i*p-D9^Z;)fnPlqdLW#Vb(%?!5V| z#yfF%s;^FzD8}z5ph4r}+nb|PJ-@Et&U68FAt$R50gQJ#eQ_IFI?`z<%+BgZ?BO~8 zjKy6Ik;_?U*%9grT!*K}P9^P}$&rvqFSW`&OFrit<`{kUlh-O40UNFXjx|l*uc6_n zsACzxS{g`hJ2?gOcFqY|53Kj($ct}`Rfl>|!~p*ckFVGB)3%08W6WnlsMAS3kLV_L zZ;@bxAVhy9Os9lfRhdTtIi$}bk$OpVEUf!aY);E9Jw|53wKOq1Tm$`b6(tQ=2@JZpwct}%qZ9hw?y6yC6c~_kGDCh zV$;n8jBkN+s3ylc^21Zw9L?}Be#L2-C2)6Ql{M>^vN zaBG8FN;MxEAxcll?yt4-AG!W~#rWr|F7=R%+`n+Myd%4!oag=cvTgpMUToOSE|Ma8nk*YFd$>fgEXv~A^q zPqnu}XRyXdd|rHRsK?$rfQMa1_+yOkmDR-WILC$%P04z}WT78%Jd>Ph?h{f_Q<&U) zWF-!ZGZ0@3b49yL6$KSZMjjq~WM7O`qh_=ql;}1OLa}6v0t_^nU6?(H=bN7fVS%q~ z>%*fNSx|QLTkrYs1hxKxeUpe{@WKwaRGBbg8;R-;NMU$D9KVP~ms-9Ku?%^%BUmYi z*fzh)7IKbpVqp51CWqCorxgbxjBGTNcN8H(+U zqzWJCP!rEfwh9Y)@Nrw5N~T+8;?AY)HNSe~V(;DU)|fHNX3!yu%+PEyu`37$dMYLWiwMeYK&A``VjY zA|b&vF^2o-$fF(1 zm?s`Rsy^7l{-e_K6Cx0?v9m!8M-EzQgW;+i6yyZ`y91}Mr=1S9sx&(eE-U0AS_Vzw zbdg_UCd!1y!mu^}W)IidQV~t`Mr=waps6$G=bYvX==yf+QQ&Gbr;4s+=Z7-5dUu|q z>sHKqvT8d_5WeA_d^#cNy60a6S+(iG6-H@K>sgp%(B5`UT;XkiWn9!M30!=^Em_-wq4JX8SezgX$ z@Yh2<5~Lg_)^>HVHR0?u)`)fZ&{$s*?G=V!Wdn+FG#BfrNO87i{4tfbwRbAE9w|@ExL;f3xB9q3`CWbB z#jS>u*LG01R?m*d)qMYJ+kp%m+j$|j6Oq9eZS|VJAt6(`f#kbmtF-a9XGmp{pVnOT zI=Ec8Q8^utM5Te9X9m6b=3kY3hYjA# literal 0 HcmV?d00001 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]", From c87a169fdd1ff0b6a08407ff2564f52c15def3cf Mon Sep 17 00:00:00 2001 From: Rogier Date: Fri, 20 May 2016 12:33:10 +0200 Subject: [PATCH 3/6] 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 0000000000000000000000000000000000000000..6895001119c39cb84d75942f7fd1f42a0c72c147 GIT binary patch literal 685 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7e6l0AZa85pY67#JE_7#My5g&JNk zFq9fFFuY1&V6d9Oz#v{QXIG#N0|TQ`fKP}kP(iCSLyJ5|n+!v(8Yhr!lV|BvWav<0 zY*gi`mt}9%s$Q!;m7w+OELREXUlh!x=8Y*(}TuBF>t`%Mv8akig3j zDa{IE@G&QdF!&2H0!8BGSSPCUcE~U^sPpfv%;?eP*;SL@rzFs)%U&nV-XPD_Ez6lA z%h@i`8C9)?&! z_E-U)NPfn6ai#_N88IT9u_6o+l6=vkED7SAQM`N!JPdKd457jdNqn3@XDlwxPUhuJ z5oB3dkP#uslPt!W!o!;&&XXd-5+lx%Cd9M2ASa%WF_E7qMT$L%mm!s(FO{DuR)`~6 zfF+)vB}$YdS&T7Bg!BLZ|6Jz+Qh=eRSQ6wH%;0nG%GJwPA>i57E3IrbKbEB~&tD$# z)ivaMs_*t4|7S-56*DGzySt=rz1uM#$l)yTh%9Dc;1&X5#!GkW{s0BpOFVsD*&nb; z3$q!kD)}!33a#*TaSX9Iotz-SdYIq9$Z+$9O&d2C6%-Y2{`BF~#!uV|-rQWA+FF{c zHCAe^)LfaJp_Q4b{jx(rTj1)|%h$~>n44TOzh-V|YJ7eBhAl$QVG4P<$=T`2`HvsG zc=F~^*5haI9==p)ab*dp*W_cck6s z2#3yK*A>yuTcYd_MA+<%v^yScbvn}eXr$HANb7wm4)Y>hx`JKTL^y7aayUA>|8kto zjwt&%;Vz5AotK6?_k_AO2f0j*aP0|k-5qa#D9(0zgzLsgheZ+2^CMjLMcba3-8U=3 z<>0LT-cZ+$5ZAsC*ToUeTO#e(L^@uW-LoRnsW;4Zdbn#>sB2S@OO>xfTd?b@aK|a3 zE{npQ=R~;F2RJtbIPaU;UmxJq8RFI+?7C@c@9c2b)?nAZP}iwpu62Hn(_-9f{2V)i z-7388Cxp7T1i9>*(LX8N_5c6>ODscy0mZ;r666=m;PC858i&EipB@ z{j;UT&K;E%KYy?;sBu(G6bv*hbma8Z>}c51vu4hWJxz-yZQ^oq2=$G14i5B=b`STL zKVoiRVq|7$YP?-w!8EItkxE-)e)%B60Fn`tXq|3A;him$*BG%pGA3ua)K)Hjmmw48kU*@q9$&(C&E|MatlMfl;@<H=O_6Kaz!feK>O8!fMLK8e)977~7CnqQf8yFdG-mvN5&Nni1 zV(!@Nsrkbsuy4VHovll!ZtYz=cSDE91bwx<_YYn?dGqMivv-P$oFWq@ef#q1TjAHQ zpUZhCOl0LcagyE2l9hFLOG{g;wgwaHlqt$eix(v)J$@uC6dK~#wrZui>hdMamM%}p z$Z%S7@zS-6S1(^SH!yM9apuO6D?Kssh71gu7UGt*eo+^JZe#Ft^>bP0l+XkKaqi&t literal 0 HcmV?d00001 diff --git a/textures/moretrees_date_nut_snack.png b/textures/moretrees_date_nut_snack.png new file mode 100644 index 0000000000000000000000000000000000000000..1766dab2558cb1fc02a4a7f18d108f3a052558b7 GIT binary patch literal 450 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7e6l0AZa85pY67#JE_7#My5g&JNk zFq9fFFuY1&V6d9Oz#v{QXIG#NP-1d`Plzj!PLW~ll3{3*VQ5uk>rmzbG8&b+I#sxU z+;9ob5OLNZVFnvL>4nJa0`Jj<`$ah1rZ%mHd|ig|a+d978Nl zzrA42*I*#v5_sSVkJ-%xBkz6x-|jf@&7&iJf0D_hFW--*w62)t$8%Y!tA}y+CY994 zd1^hkBnrAVJ(_cUj}|vObDr|8b@Ip7iS~9go}d4WmEl??w@pdvj>Cm<-x&k{d`qm) Z;MYFQF0m+`=PS@w22WQ%mvv4FO#oVNhrR#+ literal 0 HcmV?d00001 From 75e8027bf7ca581556f91e8c1444c865a77c482d Mon Sep 17 00:00:00 2001 From: Rogier Date: Thu, 19 May 2016 13:26:52 +0200 Subject: [PATCH 4/6] 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 0000000000000000000000000000000000000000..644a65f8ec7ce650d68d1549cec46744741b1862 GIT binary patch literal 877 zcmWlWTWl0n7{|}-6c!4#C2FL~1Nva95mO0~rqp!`+t3EtU|XPt1}Y?&n3#}QjWKE{ zsfi{&Ai<=-zNly*h~Z`=rjig5Gzx+4ZfEDRmzn9@_AJ&~Plt zC^v~v?<_*k9FP9~b{|5-={;|a4&VcYjIX318@Ez%LuP?_u$<#TPl3wA{9ke=W@$Vq z9LTIICGFTfUE>;J+>zP3!hn#dh>4oYyE5yEw1bJt`MBq^z|EKROhZmDi%d120g*3uVELjv&n z0k)ep=yP)>`<}TtMZ=4H?WVwdf7xt;cYbySQs3tq=Z1HG-IpdQFXH!EAvh+<6%jS z1(|j-v}q{7JuXTyD~E4MaBq&yr9eztB4f%)z)trw>`h!NE)VDH*3D@82@V7CDFWmJ!3aqXC`<< zGXA*|Ab%_Q4VDN7T1X;51jt~J43K1iAV{*Ma+v=Zix5Y4?F@hMH2t267pspCj(>pA znkSn@pmWjn7zU??b`J!zD~Q!kbRM?UDn>sKh5JX>$Bs^JZ13Lu+KsE%ul?z4h)(c* zbDw&FlO4BDUH$Un*p*u|7tY*VJ4Wq`9O}OoxpZiJU~k*q{q&>w{KDfzY-{(H&94)! zv**qp96K=1ZAr4sww}O>X!N=B6BFkT^86cpf6Pq>LbpHniRu13&wuxhuYLE{DC*&_E>o%l65W{{v~0C2Rly literal 0 HcmV?d00001 diff --git a/textures/moretrees_coconut_1.png b/textures/moretrees_coconut_1.png new file mode 100644 index 0000000000000000000000000000000000000000..e2889bce06ec4581d231b6cf901801296188ffd5 GIT binary patch literal 429 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!Lb6AYF9SoB8UsT^3j@P1pisjL z28L1t28LG&3=CE?7#PG0=Ijcz0ZMcQ_=LCuX(j_EmV6fGIA*3OCMGW?=1gXmY!>DO zW+opdCJ!d25ReFSE;Dm2Gjj$rlP?ocoH?7BrGNH0~1JNAQMv%m~GAkvMUrU2(%@T>Hq)#R!Wb%fUeOf3GxH_gpG@f zooV5(-OP-O9^d+Qn*HXLE8l){UwQxe=O3Fdh=fJIJ#Rk+GhaVb#9)6>N3wZSxikFjEaeZfrh$;Ee$P8rfliirsL$`=N{)69muJ; kV9lacYnSHcel-Zt}%1&z2`pfbDsBk-cykfuk`bs)}j@RhK~hrnAFIwKiA^LMI}GzgU}M(F5Cgam+&4j@z%j?ix{LhGs!nyssSm>7u= z_c0+ZMF9k_`(7l6kPNnPD#nSJWD>HEkSr0*7WbJ1Z(${@z&Hl~;{!r=iPd6)(=krQ zSi`DViRlT-1fg0;XelK+LiB`a*r*Kt~V(^EsmUW|kdFtPunUf|!o^1Wnk(xIjcH4iF~!ZzFT4!^(z1g;>Kd0yOsK+_+*s&^v95S_;KZ%{$F24tbfM3YCeth_w{(JPOI@mcUSj& z^9bzSPTjSiA0Ib9F0JMc3_r%FGF&{Ti+aHzUg3ZS=Mtx+u5WIN zR47t4+hYA?^;d2-wp`t>&D&Lwou4y(R%@&AZu_0Kdxv!TLc;;x_d!Q#amis3bNhEmz{Q+|$7Oq?xxpB!%nIvGIe_*b(E_}s-w4_4cg!!vNqZY0RSs%P6%ygq( zB1=fg?A@M`mX(;E8X6w>r?q-*+p8j*&F`${WvJw8dwW}rp~_$=vUirh{q!MvNAIE= aLAeM;E{|w2KYzCb(jm1XUVdw%_V{0SkwPE< literal 0 HcmV?d00001 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 } From 9dd610e0e6bef340a31fd05effcfc0f254c115f1 Mon Sep 17 00:00:00 2001 From: Rogier Date: Tue, 28 Jun 2016 17:45:08 +0200 Subject: [PATCH 5/6] 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). From 90283664076f2f399d7351cc36838c1d9b788e12 Mon Sep 17 00:00:00 2001 From: Rogier Date: Fri, 1 Jul 2016 11:11:45 +0200 Subject: [PATCH 6/6] 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