Merge branch 'master' into mob_head_code_improvments

This commit is contained in:
epCode 2022-10-27 01:34:39 +00:00
commit ef923deff1
13 changed files with 226 additions and 45 deletions

View File

@ -12,6 +12,7 @@ mcl_damage = {
drown = {bypasses_armor = true}, drown = {bypasses_armor = true},
starve = {bypasses_armor = true, bypasses_magic = true}, starve = {bypasses_armor = true, bypasses_magic = true},
cactus = {}, cactus = {},
sweet_berry = {},
fall = {bypasses_armor = true}, fall = {bypasses_armor = true},
fly_into_wall = {bypasses_armor = true}, -- unused fly_into_wall = {bypasses_armor = true}, -- unused
out_of_world = {bypasses_armor = true, bypasses_magic = true, bypasses_invulnerability = true, bypasses_totem = true}, out_of_world = {bypasses_armor = true, bypasses_magic = true, bypasses_invulnerability = true, bypasses_totem = true},

View File

@ -13,6 +13,8 @@ local FLOP_HOR_SPEED = 1.5
local ENTITY_CRAMMING_MAX = 24 local ENTITY_CRAMMING_MAX = 24
local CRAMMING_DAMAGE = 3 local CRAMMING_DAMAGE = 3
local PATHFINDING = "gowp"
-- Localize -- Localize
local S = minetest.get_translator("mcl_mobs") local S = minetest.get_translator("mcl_mobs")
@ -2546,10 +2548,11 @@ local function check_doors(self)
if n.name:find("_b_") then if n.name:find("_b_") then
local def = minetest.registered_nodes[n.name] local def = minetest.registered_nodes[n.name]
local closed = n.name:find("_b_1") local closed = n.name:find("_b_1")
if t < 0.3 or t > 0.8 then if self.state == PATHFINDING then
if not closed and def.on_rightclick then def.on_rightclick(d,n,self) end
else
if closed and def.on_rightclick then def.on_rightclick(d,n,self) end if closed and def.on_rightclick then def.on_rightclick(d,n,self) end
--if not closed and def.on_rightclick then def.on_rightclick(d,n,self) end
else
end end
end end
@ -2560,7 +2563,7 @@ local gowp_etime = 0
local function check_gowp(self,dtime) local function check_gowp(self,dtime)
gowp_etime = gowp_etime + dtime gowp_etime = gowp_etime + dtime
if gowp_etime < 0.2 then return end if gowp_etime < 0.1 then return end
gowp_etime = 0 gowp_etime = 0
local p = self.object:get_pos() local p = self.object:get_pos()
@ -2571,7 +2574,7 @@ local function check_gowp(self,dtime)
return return
end end
-- arrived at location -- arrived at location, finish gowp
local distance_to_targ = vector.distance(p,self._target) local distance_to_targ = vector.distance(p,self._target)
mcl_log("Distance to targ: ".. tostring(distance_to_targ)) mcl_log("Distance to targ: ".. tostring(distance_to_targ))
if distance_to_targ < 2 then if distance_to_targ < 2 then
@ -2587,34 +2590,79 @@ local function check_gowp(self,dtime)
return true return true
end end
if self.waypoints and ( not self.current_target or vector.distance(p,self.current_target) < 2 ) then -- More pathing to be done
if self.waypoints and #self.waypoints > 0 and ( not self.current_target or vector.distance(p,self.current_target) < 2 ) then
-- We have waypoints, and no current target, or we're at it. We need a new current_target.
if not self.current_target then if not self.current_target then
for i, j in pairs (self.waypoints) do for i, j in pairs (self.waypoints) do
mcl_log("Way: ".. tostring(i))
mcl_log("Val: ".. tostring(j)) mcl_log("Val: ".. tostring(j))
end end
--mcl_log("nextwp:".. tostring(self.waypoints) )
end end
self.current_target = table.remove(self.waypoints, 1) self.current_target = table.remove(self.waypoints, 1)
mcl_log("current target:".. tostring(self.current_target) ) mcl_log("current target:".. minetest.pos_to_string(self.current_target) )
--mcl_log("type:".. type(self.current_target) ) --mcl_log("type:".. type(self.current_target) )
go_to_pos(self,self.current_target) go_to_pos(self,self.current_target)
return return
elseif self.current_target then elseif self.current_target then
-- No waypoints left, but have current target. Potentially last waypoint to go to.
mcl_log("self.current_target: ".. minetest.pos_to_string(self.current_target))
mcl_log("pos: ".. minetest.pos_to_string(p))
go_to_pos(self,self.current_target) go_to_pos(self,self.current_target)
-- Do i just delete current_target, and return so we can find final path.
else
-- Not at target, no current waypoints or current_target. Through the door and should be able to path to target.
-- Is a little sensitive and could take 1 - 7 times. A 10 fail count might be a good exit condition.
mcl_log("We don't have waypoints or a current target. Let's try to path to target")
local final_wp = minetest.find_path(p,self._target,150,1,4)
if final_wp then
mcl_log("We might be able to get to target here.")
self.waypoints = final_wp
--go_to_pos(self,self._target)
else
mcl_log("Cannot plot final route to target")
end
end end
if self.current_target and not minetest.line_of_sight(self.object:get_pos(),self.current_target) then --if self.current_target and not minetest.line_of_sight(self.object:get_pos(),self.current_target) then
self.waypoints=minetest.find_path(p,self._target,150,1,4) if self.current_target and (self.waypoints and #self.waypoints == 0) then
if not self.waypoints then self.state = "walk" end --give up local updated_p = self.object:get_pos()
self.current_target = nil local distance_to_cur_targ = vector.distance(updated_p,self.current_target)
mcl_log("Distance to current target: ".. tostring(distance_to_cur_targ))
mcl_log("Current p: ".. minetest.pos_to_string(updated_p))
--if not minetest.line_of_sight(self.object:get_pos(),self._target) then
-- 1.6 is good. is 1.9 better? It could fail less, but will it path to door when it isn't after door
if distance_to_cur_targ > 1.9 then
mcl_log("no LOS to target: ".. minetest.pos_to_string(self.current_target))
go_to_pos(self,self._current_target)
else
mcl_log("Let's go to target: ".. minetest.pos_to_string(self.current_target))
self.current_target = nil
--go_to_pos(self,self._target)
self.waypoints=minetest.find_path(updated_p,self._target,150,1,4)
--if not self.waypoints then
--mcl_log("Give up ")
--self.state = "walk"
--end --give up
end
--self.waypoints=minetest.find_path(p,self._target,150,1,4)
--if not self.waypoints then
--mcl_log("Give up ")
--self.state = "walk"
--end --give up
--self.current_target = nil
return return
end end
if not self.current_target then --if not self.current_target then
--mcl_log("no path") --mcl_log("no path. Give up")
self.state = "walk" --self.state = "walk"
end --end
end end
-- execute current state (stand, walk, run, attacks) -- execute current state (stand, walk, run, attacks)
@ -2663,7 +2711,7 @@ local do_states = function(self, dtime)
end end
-- npc's ordered to stand stay standing -- npc's ordered to stand stay standing
if self.type == "npc" or (self.order == "stand" or self.order == "sleep" or self.order == "work") then if self.order == "stand" or self.order == "sleep" or self.order == "work" then
else else
if self.walk_chance ~= 0 if self.walk_chance ~= 0
@ -2677,7 +2725,7 @@ local do_states = function(self, dtime)
end end
end end
elseif self.state == "gowp" then elseif self.state == PATHFINDING then
check_gowp(self,dtime) check_gowp(self,dtime)
elseif self.state == "walk" then elseif self.state == "walk" then
@ -3194,7 +3242,7 @@ local plane_adjacents = {
local gopath_last = os.time() local gopath_last = os.time()
function mcl_mobs:gopath(self,target,callback_arrived) function mcl_mobs:gopath(self,target,callback_arrived)
if self.state == "gowp" then mcl_log("Already set as gowp, don't set another path until done.") return end if self.state == PATHFINDING then mcl_log("Already set as gowp, don't set another path until done.") return end
if os.time() - gopath_last < 15 then if os.time() - gopath_last < 15 then
mcl_log("Not ready to path yet") mcl_log("Not ready to path yet")
@ -3217,11 +3265,15 @@ function mcl_mobs:gopath(self,target,callback_arrived)
--mcl_log("Found a door near") --mcl_log("Found a door near")
for _,v in pairs(plane_adjacents) do for _,v in pairs(plane_adjacents) do
local pos = vector.add(d,v) local pos = vector.add(d,v)
local n = minetest.get_node(pos) local n = minetest.get_node(pos)
if n.name == "air" then if n.name == "air" then
wp = minetest.find_path(p,pos,150,1,4) wp = minetest.find_path(p,pos,150,1,4)
if wp then if wp then
--mcl_log("Found a path to next to door".. minetest.pos_to_string(pos)) mcl_log("Found a path to next to door".. minetest.pos_to_string(pos))
local other_side_of_door = vector.add(d,-v)
mcl_log("Opposite is: ".. minetest.pos_to_string(other_side_of_door))
table.insert(wp, other_side_of_door)
break break
else else
@ -3241,7 +3293,7 @@ function mcl_mobs:gopath(self,target,callback_arrived)
self.callback_arrived = callback_arrived self.callback_arrived = callback_arrived
table.remove(wp,1) table.remove(wp,1)
self.waypoints = wp self.waypoints = wp
self.state = "gowp" self.state = PATHFINDING
return true return true
else else
self.state = "walk" self.state = "walk"
@ -4292,7 +4344,7 @@ local mob_step = function(self, dtime)
-- attack timer -- attack timer
self.timer = self.timer + dtime self.timer = self.timer + dtime
if self.state ~= "attack" and self.state ~= "gowp" then if self.state ~= "attack" and self.state ~= PATHFINDING then
if self.timer < 1 then if self.timer < 1 then
return return
end end

View File

@ -30,6 +30,8 @@ local DEFAULT_WALK_CHANCE = 33 -- chance to walk in percent, if no player nearby
local PLAYER_SCAN_INTERVAL = 5 -- every X seconds, villager looks for players nearby local PLAYER_SCAN_INTERVAL = 5 -- every X seconds, villager looks for players nearby
local PLAYER_SCAN_RADIUS = 4 -- scan radius for looking for nearby players local PLAYER_SCAN_RADIUS = 4 -- scan radius for looking for nearby players
local PATHFINDING = "gowp"
--[=======[ TRADING ]=======] --[=======[ TRADING ]=======]
-- LIST OF VILLAGER PROFESSIONS AND TRADES -- LIST OF VILLAGER PROFESSIONS AND TRADES
@ -564,7 +566,7 @@ end
local function set_textures(self) local function set_textures(self)
local badge_textures = get_badge_textures(self) local badge_textures = get_badge_textures(self)
mcl_log("Setting textures: " .. tostring(badge_textures)) --mcl_log("Setting textures: " .. tostring(badge_textures))
self.object:set_properties({textures=badge_textures}) self.object:set_properties({textures=badge_textures})
end end
@ -579,7 +581,7 @@ function get_activity(tod)
local lunch_start = 12000 local lunch_start = 12000
local lunch_end = 13500 local lunch_end = 13500
local work_start = 8500 local work_start = 8500
local work_end = 16300 local work_end = 16500
local activity = nil local activity = nil
@ -671,7 +673,7 @@ local function take_bed (entity)
for _,n in pairs(nn) do for _,n in pairs(nn) do
local m=minetest.get_meta(n) local m=minetest.get_meta(n)
--mcl_log("Bed owner: ".. m:get_string("villager")) --mcl_log("Bed owner: ".. m:get_string("villager"))
if m:get_string("villager") == "" and not (entity.state == "gowp") then if m:get_string("villager") == "" and not (entity.state == PATHFINDING) then
mcl_log("Can we path to bed: "..minetest.pos_to_string(n) ) mcl_log("Can we path to bed: "..minetest.pos_to_string(n) )
local gp = mcl_mobs:gopath(entity,n,function(self) local gp = mcl_mobs:gopath(entity,n,function(self)
if self then if self then
@ -817,7 +819,7 @@ local function look_for_job(self, requested_jobsites)
local looking_for_type = jobsites local looking_for_type = jobsites
if requested_jobsites then if requested_jobsites then
mcl_log("Looking for jobs of my type: " .. tostring(requested_jobsites)) --mcl_log("Looking for jobs of my type: " .. tostring(requested_jobsites))
looking_for_type = requested_jobsites looking_for_type = requested_jobsites
else else
mcl_log("Looking for any job type") mcl_log("Looking for any job type")
@ -863,7 +865,7 @@ local function get_a_job(self)
local requested_jobsites = jobsites local requested_jobsites = jobsites
if has_traded (self) then if has_traded (self) then
--mcl_log("Has traded") mcl_log("Has traded so look for job of my type")
requested_jobsites = populate_jobsites(self._profession) requested_jobsites = populate_jobsites(self._profession)
-- Only pass in my jobsite to two functions here -- Only pass in my jobsite to two functions here
else else
@ -884,7 +886,7 @@ local function get_a_job(self)
if n and employ(self,n) then return true end if n and employ(self,n) then return true end
if self.state ~= "gowp" then if self.state ~= PATHFINDING then
mcl_log("Nothing near. Need to look for a job") mcl_log("Nothing near. Need to look for a job")
look_for_job(self, requested_jobsites) look_for_job(self, requested_jobsites)
end end
@ -938,7 +940,7 @@ local function do_work (self)
-- Don't try if looking_for_work, or gowp possibly -- Don't try if looking_for_work, or gowp possibly
if validate_jobsite(self) then if validate_jobsite(self) then
mcl_log("My jobsite is valid. Do i need to travel?") --mcl_log("My jobsite is valid. Do i need to travel?")
local jobsite2 = retrieve_my_jobsite (self) local jobsite2 = retrieve_my_jobsite (self)
local jobsite = self._jobsite local jobsite = self._jobsite
@ -947,9 +949,9 @@ local function do_work (self)
--mcl_log("Villager: ".. minetest.pos_to_string(self.object:get_pos()) .. ", jobsite: " .. minetest.pos_to_string(self._jobsite)) --mcl_log("Villager: ".. minetest.pos_to_string(self.object:get_pos()) .. ", jobsite: " .. minetest.pos_to_string(self._jobsite))
if vector.distance(self.object:get_pos(),self._jobsite) < 2 then if vector.distance(self.object:get_pos(),self._jobsite) < 2 then
mcl_log("Made it to work ok!") --mcl_log("Made it to work ok!")
if not (self.state == "gowp") then if not (self.state == PATHFINDING) then
--mcl_log("Setting order to work.") --mcl_log("Setting order to work.")
self.order = WORK self.order = WORK
else else
@ -1461,6 +1463,7 @@ local trade_inventory = {
-- END OF SPECIAL HANDLING FOR COMPASS -- END OF SPECIAL HANDLING FOR COMPASS
local trader = player_trading_with[name] local trader = player_trading_with[name]
local tradenum = player_tradenum[name] local tradenum = player_tradenum[name]
local trades local trades
trader._traded = true trader._traded = true
if trader and trader._trades then if trader and trader._trades then
@ -1643,23 +1646,31 @@ mcl_mobs:register_mob("mobs_mc:villager", {
return it return it
end, end,
on_rightclick = function(self, clicker) on_rightclick = function(self, clicker)
if self.child or self._profession == "unemployed" or self._profession == "nitwit" then
self.order = nil
return
end
if self.state == PATHFINDING then
self.state = "stand"
end
-- Can we remove now we possibly have fixed root cause
if self.state == "attack" then if self.state == "attack" then
mcl_log("Somehow villager got into an invalid attack state. Removed.") mcl_log("Somehow villager got into an invalid attack state. Removed attack state.")
-- Need to stop villager getting in attack state. This is a workaround to allow players to fix broken villager. -- Need to stop villager getting in attack state. This is a workaround to allow players to fix broken villager.
self.state = "stand" self.state = "stand"
self.attack = nil self.attack = nil
end end
-- Don't do at night. Go to bed? Maybe do_activity needs it's own method
if validate_jobsite(self) then if validate_jobsite(self) then
mcl_mobs:gopath(self,self._jobsite,function() mcl_mobs:gopath(self,self._jobsite,function()
--minetest.log("arrived at jobsite") --minetest.log("arrived at jobsite")
end) end)
else else
self.state = "stand" -- cancel gowp in case it has messed up self.state = "stand" -- cancel gowp in case it has messed up
self.order = nil -- cancel work if working
end end
if self.child or self._profession == "unemployed" or self._profession == "nitwit" then
return
end
-- Initiate trading -- Initiate trading
init_trader_vars(self) init_trader_vars(self)
local name = clicker:get_player_name() local name = clicker:get_player_name()
@ -1733,9 +1744,10 @@ mcl_mobs:register_mob("mobs_mc:villager", {
take_bed (self) take_bed (self)
end end
-- Only check in day or during thunderstorm but wandered_too_far code won't work
if check_bed (self) then if check_bed (self) then
--self.state ~= "go_home" --self.state ~= "go_home"
local wandered_too_far = ( self.state ~= "gowp" ) and (vector.distance(self.object:get_pos(),self._bed) > 50 ) local wandered_too_far = ( self.state ~= PATHFINDING ) and (vector.distance(self.object:get_pos(),self._bed) > 50 )
--if wandered_too_far then minetest.log("Wandered too far! Return home ") end --if wandered_too_far then minetest.log("Wandered too far! Return home ") end
if wandered_too_far then if wandered_too_far then

View File

@ -59,18 +59,18 @@ for _, campfire in pairs(campfires) do
drawtype = "mesh", drawtype = "mesh",
mesh = "mcl_campfires_campfire_lit.obj", mesh = "mcl_campfires_campfire_lit.obj",
tiles = {{ tiles = {{
name="mcl_campfires_" .. campfire.techname .. "_fire.png", name="mcl_campfires_" .. campfire.techname .. "_fire.png",
animation={ animation={
type="vertical_frames", type="vertical_frames",
aspect_w=16, aspect_w=16,
aspect_h=16, aspect_h=16,
length=2.0 length=2.0
}}, }},
{name="mcl_campfires_" .. campfire.techname .. "_log_lit.png", {name="mcl_campfires_" .. campfire.techname .. "_log_lit.png",
animation={ animation={
type="vertical_frames", type="vertical_frames",
aspect_w=16, aspect_w=16,
aspect_h=16, aspect_h=16,
length=2.0 length=2.0
}} }}
}, },

View File

@ -281,6 +281,13 @@ local function apply_bone_meal(pointed_thing)
if math.random(1, 100) <= 75 then if math.random(1, 100) <= 75 then
return mcl_farming:grow_plant("plant_beetroot", pos, n, 1, true) return mcl_farming:grow_plant("plant_beetroot", pos, n, 1, true)
end end
elseif string.find(n.name, "mcl_farming:sweet_berry_bush_") then
mcl_dye.add_bone_meal_particle(pos)
if n.name == "mcl_farming:sweet_berry_bush_3" then
return minetest.add_item(vector.offset(pos,math.random()-0.5,math.random()-0.5,math.random()-0.5),"mcl_farming:sweet_berry")
else
return mcl_farming:grow_plant("plant_sweet_berry_bush", pos, n, 1, true)
end
elseif n.name == "mcl_cocoas:cocoa_1" or n.name == "mcl_cocoas:cocoa_2" then elseif n.name == "mcl_cocoas:cocoa_1" or n.name == "mcl_cocoas:cocoa_2" then
mcl_dye.add_bone_meal_particle(pos) mcl_dye.add_bone_meal_particle(pos)
-- Cocoa: Advance by 1 stage -- Cocoa: Advance by 1 stage

View File

@ -27,3 +27,6 @@ dofile(minetest.get_modpath("mcl_farming").."/potatoes.lua")
-- ========= BEETROOT ========= -- ========= BEETROOT =========
dofile(minetest.get_modpath("mcl_farming").."/beetroot.lua") dofile(minetest.get_modpath("mcl_farming").."/beetroot.lua")
-- ========= SWEET BERRY =========
dofile(minetest.get_modpath("mcl_farming").."/sweet_berry.lua")

View File

@ -0,0 +1,87 @@
local S = minetest.get_translator(minetest.get_current_modname())
local planton = {"mcl_core:dirt_with_grass", "mcl_core:dirt", "mcl_core:podzol", "mcl_core:coarse_dirt", "mcl_farming:soil", "mcl_farming:soil_wet", "mcl_moss:moss"}
for i=0, 3 do
local texture = "mcl_farming_sweet_berry_bush_" .. i .. ".png"
local node_name = "mcl_farming:sweet_berry_bush_" .. i
local groups = {sweet_berry=1, dig_immediate=3, not_in_creative_inventory=1,plant=1,attached_node=1,dig_by_water=1,destroy_by_lava_flow=1,dig_by_piston=1, flammable=3, fire_encouragement=60, fire_flammability=20, compostability=30}
if i > 0 then
groups.sweet_berry_thorny = 1
end
minetest.register_node(node_name, {
drawtype = "plantlike",
tiles = {texture},
description = S("Sweet Berry Bush (Stage @1)", i),
paramtype = "light",
sunlight_propagates = true,
paramtype2 = "meshoptions",
place_param2 = 3,
liquid_viscosity = 15,
liquidtype = "source",
liquid_alternative_flowing = node_name,
liquid_alternative_source = node_name,
liquid_renewable = false,
liquid_range = 0,
walkable = false,
drop = (i>=2) and ("mcl_farming:sweet_berry" .. (i==3 and " 3" or "")) or "",
selection_box = {
type = "fixed",
fixed = {-6 / 16, -0.5, -6 / 16, 6 / 16, (-0.30 + (i*0.25)), 6 / 16},
},
inventory_image = texture,
wield_image = texture,
groups = groups,
sounds = mcl_sounds.node_sound_leaves_defaults(),
_mcl_blast_resistance = 0,
_mcl_hardness = 0,
})
minetest.register_alias("mcl_sweet_berry:sweet_berry_bush_" .. i, node_name)
end
minetest.register_craftitem("mcl_farming:sweet_berry", {
description = S("Sweet Berry"),
inventory_image = "mcl_farming_sweet_berry.png",
_mcl_saturation = 0.4,
groups = { food = 2, eatable = 1, compostability=30 },
on_secondary_use = minetest.item_eat(1),
on_place = function(itemstack, placer, pointed_thing)
if pointed_thing.type == "node" and table.indexof(planton,minetest.get_node(pointed_thing.under).name) ~= -1 and minetest.get_node(pointed_thing.above).name == "air" then
minetest.set_node(pointed_thing.above,{name="mcl_farming:sweet_berry_bush_0"})
if not minetest.is_creative_enabled(placer:get_player_name()) then
itemstack:take_item()
end
return itemstack
end
return minetest.do_item_eat(1, nil, itemstack, placer, pointed_thing)
end,
})
minetest.register_alias("mcl_sweet_berry:sweet_berry", "mcl_farming:sweet_berry")
-- TODO: Find proper interval and chance values for sweet berry bushes. Current interval and chance values are copied from mcl_farming:beetroot which has similar growth stages.
mcl_farming:add_plant("plant_sweet_berry_bush", "mcl_farming:sweet_berry_bush_3", {"mcl_farming:sweet_berry_bush_0", "mcl_farming:sweet_berry_bush_1", "mcl_farming:sweet_berry_bush_2"}, 68, 3)
local function berry_damage_check(obj)
local p = obj:get_pos()
if not p then return end
if not minetest.find_node_near(p,0.4,{"group:sweet_berry_thorny"},true) then return end
local v = obj:get_velocity()
if v.x < 0.1 and v.y < 0.1 and v.z < 0.1 then return end
mcl_util.deal_damage(obj, 0.5, {type = "sweet_berry"})
end
local etime = 0
minetest.register_globalstep(function(dtime)
etime = dtime + etime
if etime < 0.5 then return end
etime = 0
for _,pl in pairs(minetest.get_connected_players()) do
berry_damage_check(pl)
end
for _,ent in pairs(minetest.luaentities) do
if ent.is_mob then
berry_damage_check(ent.object)
end
end
end)

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 800 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 B

View File

@ -2851,6 +2851,25 @@ local function register_decorations()
flags = "place_center_x,place_center_z, force_placement", flags = "place_center_x,place_center_z, force_placement",
}) })
minetest.register_decoration({
deco_type = "simple",
place_on = {"mcl_core:dirt_with_grass","mcl_core:podzol"},
sidelen = 16,
noise_params = {
offset = 0,
scale = 0.012,
spread = {x = 100, y = 100, z = 100},
seed = 354,
octaves = 1,
persist = 0.5,
lacunarity = 1.0,
flags = "absvalue"
},
biomes = {"Taiga","ColdTaiga","MegaTaiga","MegaSpruceTaiga", "Forest"},
y_max = mcl_vars.mg_overworld_max,
y_min = 2,
decoration = "mcl_sweet_berry:sweet_berry_bush_3"
})
-- Large ice spike -- Large ice spike
minetest.register_decoration({ minetest.register_decoration({