--=======-- -- Setup -- --=======-- -- Mod name local modname = minetest.get_current_modname() -- Translation wrapper for descriptive strings local S = minetest.get_translator(modname) -- Explicit local references to globals we use local core, vector = core, vector local pi = math.pi local random = math.random local swap_node = core.swap_node local get_palette_indexes_from_pos = mcl_util.get_palette_indexes_from_pos --=========-- -- Helpers -- --=========-- local function biome_grass_palette_value(def, pos) return get_palette_indexes_from_pos(pos).grass_palette_index end --====================-- -- Grass Registration -- --====================-- -- Grass grows on dirt except in very hot/arid regions botany.register_grass({ label='vl_botany:grass', substrate='mcl_core:dirt', result='mcl_core:dirt_with_grass', -- grows through air check_sides=botany.TOP, -- default param1 is 0 -- set param2 to a grass palette value based on the biome param2=biome_grass_palette_value, -- default weight 1 min_light=4, -- no max_light -- grows only with air on top, by default climate={ regions={ dirt_grows_grass=1, -- in snowy regions almost always turn dirt into snow instead: snow_falls=1/200, }, biomes={ IcePlains=0, IcePlainsSpikes=0, StoneBeach=1/8, MushroomIsland=0, Desert=1/8, Mesa=1/2, MesaBryce=1/2, MesaPlateauF=1/2, MesaPlateauFM=1/2, }, ideal={ boost=1.5, heat=60, humidity=60, } } }) -- Grass-with-snow grows on dirt in cold regions botany.register_grass({ label='vl_botany:snowy_grass', substrate='mcl_core:dirt', result='mcl_core:dirt_with_grass_snow', -- grows through air check_sides=botany.TOP, -- default param1 and param2 are 0 -- default weight 1 min_light=4, -- no max_light -- grows only with air on top, by default climate={ -- only in regions where snow falls regions={ snow_falls=1 } } }) -- Moss grows on cobblestone in hot/humid regions botany.register_grass({ label='vl_botany:humid_moss', substrate='mcl_core:cobble', result='mcl_core:mossycobble', -- grows through air check_sides=botany.ALL_SIDES, -- any air exposure allows moss growth -- default node params (0/0) -- default weight 1 min_light=3, -- no max_light climate={ custom={ { 1, -- custom region has weight 1 { { 80, 65, -pi/16, 5/(50^2), 1, 8 }, -- humidity ~> 65 { 30, 70, -pi/3, 5/(50^2), 1, 12 }, -- heat ~> 30 -- heat requirement decreases as humidity increases } } }, ideal={ boost=3, heat=80, humidity=100 } }, }) -- TODO --====================-- -- Herbs Registration -- --====================-- -- Copy of the grass block that we use as a growth target to prevent -- seeds from taking root everywhere botany.register_alternate_node( "mcl_core:dirt_with_grass", nil, "vl_botany:dirt_with_just_grass", S("Grass Block (no growth)") ) -- A default conversion from grass available anywhere to -- dirt_with_just_grass which won't then be able to host any seeds. -- This keeps rare things from becoming common when they'd otherwise be -- the only available conversion, and leaves some of the ground bare -- instead of putting growables literally everywhere. botany.register_growable({ label="vl_botany:grow_sterile_grass", soil="mcl_core:dirt_with_grass", -- default grows_through = air result="vl_botany:dirt_with_just_grass", weight=3, -- default weight for other rules is 1 -- default param1 is 0 param2=biome_grass_palette_value, -- no light min/max -- default sides = TOP -- no per-biome adjustments -- no min/max humidity/heat climate={ regions={ any=3 }, ideal={ boost=0.3, heat=50, humidity=50 } -- penalty instead of boost } }) -- This rare rule converts just_grass blocks back to normal -- dirt_with_grass that can then be re-sprouted into something else -- potentially. Even though it's rare, since dirt_with_just_grass will -- always be "re-rolled" by this mechanism, over the long term other -- plants will come to dominate, unless they too have a "death" -- mechanism. We use a climate definition similar to the -- dirt_with_just_grass conversion but with more weight instead of less -- weight in the middle so we can make it more likely to re-roll -- dirt_with_just_grass in the middle climate zones where many other -- alternatives should be available. botany.register_rare_rule({ target="vl_botany:dirt_with_just_grass", action=function( plan, pos, node, active_object_count, active_object_count_wider, climate_match ) -- Rare rules already have a low chance of triggering and are -- checked infrequently. This chance makes the conversion even -- rarer. local chance = 1/100 * climate_match -- DEBUG chance = 1 if random() < chance then -- Skip callbacks by using swap_node swap_node( pos, { name="mcl_core:dirt_with_grass", param1=node.param1, param2=node.param2, } ) end end, climate={ regions={ any=1 }, ideal={ boost=1.5, heat=50, humidity=50 } } }) -- See botany/notes.md for info about lifespans, mortality, etc. -- Short "tallgrass" botany.register_simple_herb({ soil="mcl_core:dirt_with_grass", -- default grows_through is air tip="mcl_flowers:tallgrass", -- auto-generate seed -- auto-generate root -- auto-generate sprout -- Default max_height is 1; no need for a stem weight=2, -- Default weight is 1 for other growables param2=biome_grass_palette_value, soil_param2=biome_grass_palette_value, min_light=8, -- no max_light climate={ regions={ arid_grasses=2, temperate_grasses=3, humid_grasses=2, temperate_swamp_plants=2, hot_swamp_plants=2, any=1/100 }, biomes={ -- weight multipliers in various biomes IcePlains=0, IcePlainsSpikes=0, ColdTaiga=1/10, ExtremeHills=1/3, ExtremeHillsM=1/3, ["ExtremeHills+"]=1/3, Taiga=1, MegaTaiga=1, MegaSpruceTaiga=1, StoneBeach=1/100, Plains=1, SunflowerPlains=1/2, Forest=1, FlowerForest=1/2, BirchForest=1, BirchForestM=1, RoofedForest=1/4, Swampland=1, Jungle=1, JungleM=1, JungleEdge=1, JungleEdgeM=1, MushroomIsland=1/8, Desert=1/60, Savanna=1/60, SavannaM=1/60, Mesa=1/60, MesaBryce=1/60, MesaPlateauF=1/60, MesaPlateauFM=1/60, MangroveSwamp=1, BambooJungle=1, BambooJungleM=1, BambooJungleEdge=1, BambooJungleEdgeM=1, }, ideal={ boost=1.5, -- 1.5x weight near ideal heat=50, humidity=50 } }, }) -- Two-block tall grass -- TODO: Prevent growth above height 2 from destroying lower blocks? botany.register_simple_herb({ soil="mcl_core:dirt_with_grass", -- default grows_through is air tip="mcl_flowers:double_grass_top", -- auto-generate seed -- auto-generate root sprout="mcl_flowers:tallgrass", stem="mcl_flowers:double_grass", max_height=2, weight=1, -- Default weight is 1 param2=biome_grass_palette_value, soil_param2=biome_grass_palette_value, min_light=8, -- no max_light climate={ regions={ arid_grasses=1, temperate_grasses=2, humid_grasses=3, temperate_swamp_plants=2, hot_swamp_plants=3 }, biomes={ -- weight multipliers in various biomes Plains=1.2, SunflowerPlains=1.8, FlowerForest=0.8, }, ideal={ boost=2, heat=50, humidity=64 } } }) -- Ferns -- TODO: Ferns on podzol botany.register_simple_herb({ soil="mcl_core:dirt_with_grass", -- default grows_through is air tip="mcl_flowers:fern", -- auto-generate seed -- auto-generate root -- auto-generate sprout -- Default max_height is 1; no need for a stem weight=1/10, -- Default weight is 1 for other growables min_light=8, -- no max_light climate={ regions={ arid_grasses=1/60, temperate_grasses=1/10, humid_grasses=1, cold_connifers=1/8, temperate_swamp_plants=1, hot_swamp_plants=1 }, biomes={ FlowerForest=1.2, RoofedForest=0.8, }, ideal={ boost=2, heat=70, humidity=90 } } }) -- Double-height ferns botany.register_simple_herb({ soil="mcl_core:dirt_with_grass", -- default grows_through is air tip="mcl_flowers:double_fern_top", -- auto-generate seed -- auto-generate root -- auto-generate sprout stem="mcl_flowers:double_fern", max_height=2, weight=1/50, -- Default weight is 1 for other growables min_light=8, -- no max_light climate={ regions={ temperate_grasses=1/300, humid_grasses=1/6, cold_connifers=1/40, temperate_swamp_plants=1/6, hot_swamp_plants=1/4 }, biomes={ FlowerForest=1.3, RoofedForest=0.8, }, ideal={ boost=2, heat=80, humidity=95 } } }) -- Double-height flowers for _, parts in ipairs({ {"mcl_flowers:peony", "mcl_flowers:peony_top", 38, 53}, {"mcl_flowers:rose_bush", "mcl_flowers:rose_bush_top", 35, 42}, {"mcl_flowers:lilac", "mcl_flowers:lilac_top", 40, 50}, {"mcl_flowers:sunflower", "mcl_flowers:sunflower_top", 28, 45}, }) do local stem = parts[1] local flower = parts[2] local ideal_humidity = parts[3] local ideal_heat = parts[4] local hills_multiplier = 1/4 local sunflower_multiplier = 1/80 local plains_weight = 1/60 local swamp_weight = 1/210 local forest_weight = 1/45 local jungle_weight = 1/70 if stem == "mcl_flowers:sunflower" then sunflower_multiplier = 12 plains_weight = 1/40 hills_multiplier = 3 jungle_weight = 1/280 swamp_weight = 1/600 -- almost no sunflowers in swamps forest_weight = 1/220 elseif stem == "mcl_flowers:peony" then jungle_weight = 1/24 swamp_weight = 1/36 plains_weight = 1/100 forest_weight = 1/80 hills_multiplier = 1/2 elseif stem == "mcl_flowers:lilac" then jungle_weight = 1/140 swamp_weight = 1/160 plains_weight = 1/24 forest_weight = 1/80 hills_multiplier = 4 elseif stem == "mcl_flowers:rose_bush" then jungle_weight = 1/50 swamp_weight = 1/80 forest_weight = 1/30 hills_multiplier = 1/2 end botany.register_simple_herb({ soil="mcl_core:dirt_with_grass", -- default grows_through is air tip=flower, -- auto-generate seed -- auto-generate root -- auto-generate sprout stem=stem, max_height=2, weight=1/150, -- Default weight is 1 for other growables min_light=8, -- no max_light climate={ regions={ arid_grasses=plains_weight, temperate_grasses=forest_weight, humid_grasses=jungle_weight, temperate_swamp_plants=swamp_weight, hot_swamp_plants=swamp_weight, }, biomes = { ExtremeHills=hills_multiplier, ExtremeHillsM=hills_multiplier, ["ExtremeHills+"]=hills_multiplier, SunflowerPlains=sunflower_multiplier, -- specialized FlowerForest=10, -- very large multiplier RoofedForest=1/2, }, ideal={ boost=3, heat=ideal_heat, humidity=ideal_humidity } } }) end -- TODO: waterlily; sweet berry bushes; crops; sea grass + kelp -- Flowers (low weight each) for _, parts in ipairs({ {"mcl_flowers:poppy", 34, 58}, {"mcl_flowers:dandelion", 26, 38}, {"mcl_flowers:oxeye_daisy", 40, 40}, {"mcl_flowers:tulip_orange", 32, 35}, {"mcl_flowers:tulip_pink", 32, 35}, {"mcl_flowers:tulip_red", 32, 35}, {"mcl_flowers:tulip_white", 32, 35}, {"mcl_flowers:allium", 40, 60}, {"mcl_flowers:azure_bluet", 40, 65}, {"mcl_flowers:blue_orchid", 63, 70}, {"mcl_flowers:wither_rose", 0, 0}, {"mcl_flowers:lily_of_the_valley", 42, 54}, {"mcl_flowers:cornflower", 38, 43}, }) do -- Extract parts local flower = parts[1] local ideal_humidity = parts[2] local ideal_heat = parts[3] -- Customize weights + min/max values local base_weight = 1/120 local swamp_weight = 1/60 local jungle_weight = 1/45 local forest_weight = 1/80 local plains_weight = 1/60 local flower_forest_multiplier = 14 -- huge base local custom = nil -- Customize by specific type (other types use defaults) if flower == "mcl_flowers:wither_rose" then custom = { {1/700, { { 20, 0, pi/2 + pi/20, 0, 1, 8} }}, -- cold enough {1/800, { { 20, 16, pi, 12/(60^2), 1, 6} } }, -- coldish + dry } base_weight = 1/900 -- very rare (this gets overridden by custom) flower_forest_multiplier = 0 -- not at all in flower forests -- not actually in any region: forest_weight = 0 plains_weight = 0 swamp_weight = 0 jungle_weight = 0 elseif flower == "mcl_flowers:dandelion" then plains_weight = 1/24 jungle_weight = 1/24 swamp_weight = 1/150 flower_forest_multiplier = 6 -- not as much as other flowers elseif flower.sub(1,17) == "mcl_flowers:tulip" then jungle_weight = 1/80 flower_forest_multiplier = 16 -- even more plains_weight = 1/48 jungle_weight = 1/70 elseif flower == "mcl_flowers:blue_orchid" then base_weight = 1/250 forest_weight = 1/210 jungle_weight = 1/36 swamp_weight = 1/48 plains_weight = 1/250 flower_forest_multiplier = 2 -- barely any boost elseif flower == "mcl_flowers:lily_of_the_valley" then base_weight = 1/250 forest_weight = 1/45 jungle_weight = 1/36 swamp_weight = 1/72 plains_weight = 1/150 flower_forest_multiplier = 2 -- barely any boost end -- Register our herb botany.register_simple_herb({ soil="mcl_core:dirt_with_grass", -- default grows_through is air tip=flower, -- auto-generate seed -- auto-generate root -- auto-generate sprout -- Default max_height is 1; no need for a stem weight=base_weight, -- default weight is 1 min_light=8, -- no max_light climate={ regions={ arid_grasses=plains_weight, temperate_grasses=forest_weight, humid_grasses=jungle_weight, temperate_swamp_plants=swamp_weight, hot_swamp_plants=swamp_weight, }, custom=custom, biomes={ SunflowerPlains=1.5, FlowerForest=flower_forest_multiplier }, ideal={ boost=3, humidity=ideal_humidity, heat=ideal_heat, } } }) end --===========================-- -- Roots/branches/etc. Setup -- --===========================-- -- TODO --====================-- -- Trees Registration -- --====================-- -- TODO --==========================-- -- Lock in registered stuff -- --==========================-- botany.sprout()